1""" 2This module contain solvers for all kinds of equations: 3 4 - algebraic or transcendental, use solve() 5 6 - recurrence, use rsolve() 7 8 - differential, use dsolve() 9 10 - nonlinear (numerically), use nsolve() 11 (you will need a good starting point) 12 13""" 14 15from sympy import divisors, binomial, expand_func 16from sympy.core.assumptions import check_assumptions 17from sympy.core.compatibility import (iterable, is_sequence, ordered, 18 default_sort_key) 19from sympy.core.sympify import sympify 20from sympy.core import (S, Add, Symbol, Equality, Dummy, Expr, Mul, 21 Pow, Unequality) 22from sympy.core.exprtools import factor_terms 23from sympy.core.function import (expand_mul, expand_log, 24 Derivative, AppliedUndef, UndefinedFunction, nfloat, 25 Function, expand_power_exp, _mexpand, expand) 26from sympy.integrals.integrals import Integral 27from sympy.core.numbers import ilcm, Float, Rational 28from sympy.core.relational import Relational 29from sympy.core.logic import fuzzy_not 30from sympy.core.power import integer_log 31from sympy.logic.boolalg import And, Or, BooleanAtom 32from sympy.core.basic import preorder_traversal 33 34from sympy.functions import (log, exp, LambertW, cos, sin, tan, acos, asin, atan, 35 Abs, re, im, arg, sqrt, atan2) 36from sympy.functions.elementary.trigonometric import (TrigonometricFunction, 37 HyperbolicFunction) 38from sympy.simplify import (simplify, collect, powsimp, posify, # type: ignore 39 powdenest, nsimplify, denom, logcombine, sqrtdenest, fraction, 40 separatevars) 41from sympy.simplify.sqrtdenest import sqrt_depth 42from sympy.simplify.fu import TR1, TR2i 43from sympy.matrices.common import NonInvertibleMatrixError 44from sympy.matrices import Matrix, zeros 45from sympy.polys import roots, cancel, factor, Poly 46from sympy.polys.polyerrors import GeneratorsNeeded, PolynomialError 47 48from sympy.polys.solvers import sympy_eqs_to_ring, solve_lin_sys 49from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise 50 51from sympy.utilities.lambdify import lambdify 52from sympy.utilities.misc import filldedent 53from sympy.utilities.iterables import (cartes, connected_components, 54 generate_bell, uniq) 55from sympy.utilities.decorator import conserve_mpmath_dps 56 57from mpmath import findroot 58 59from sympy.solvers.polysys import solve_poly_system 60from sympy.solvers.inequalities import reduce_inequalities 61 62from types import GeneratorType 63from collections import defaultdict 64import warnings 65 66 67def recast_to_symbols(eqs, symbols): 68 """ 69 Return (e, s, d) where e and s are versions of *eqs* and 70 *symbols* in which any non-Symbol objects in *symbols* have 71 been replaced with generic Dummy symbols and d is a dictionary 72 that can be used to restore the original expressions. 73 74 Examples 75 ======== 76 77 >>> from sympy.solvers.solvers import recast_to_symbols 78 >>> from sympy import symbols, Function 79 >>> x, y = symbols('x y') 80 >>> fx = Function('f')(x) 81 >>> eqs, syms = [fx + 1, x, y], [fx, y] 82 >>> e, s, d = recast_to_symbols(eqs, syms); (e, s, d) 83 ([_X0 + 1, x, y], [_X0, y], {_X0: f(x)}) 84 85 The original equations and symbols can be restored using d: 86 87 >>> assert [i.xreplace(d) for i in eqs] == eqs 88 >>> assert [d.get(i, i) for i in s] == syms 89 90 """ 91 if not iterable(eqs) and iterable(symbols): 92 raise ValueError('Both eqs and symbols must be iterable') 93 new_symbols = list(symbols) 94 swap_sym = {} 95 for i, s in enumerate(symbols): 96 if not isinstance(s, Symbol) and s not in swap_sym: 97 swap_sym[s] = Dummy('X%d' % i) 98 new_symbols[i] = swap_sym[s] 99 new_f = [] 100 for i in eqs: 101 isubs = getattr(i, 'subs', None) 102 if isubs is not None: 103 new_f.append(isubs(swap_sym)) 104 else: 105 new_f.append(i) 106 swap_sym = {v: k for k, v in swap_sym.items()} 107 return new_f, new_symbols, swap_sym 108 109 110def _ispow(e): 111 """Return True if e is a Pow or is exp.""" 112 return isinstance(e, Expr) and (e.is_Pow or isinstance(e, exp)) 113 114 115def _simple_dens(f, symbols): 116 # when checking if a denominator is zero, we can just check the 117 # base of powers with nonzero exponents since if the base is zero 118 # the power will be zero, too. To keep it simple and fast, we 119 # limit simplification to exponents that are Numbers 120 dens = set() 121 for d in denoms(f, symbols): 122 if d.is_Pow and d.exp.is_Number: 123 if d.exp.is_zero: 124 continue # foo**0 is never 0 125 d = d.base 126 dens.add(d) 127 return dens 128 129 130def denoms(eq, *symbols): 131 """ 132 Return (recursively) set of all denominators that appear in *eq* 133 that contain any symbol in *symbols*; if *symbols* are not 134 provided then all denominators will be returned. 135 136 Examples 137 ======== 138 139 >>> from sympy.solvers.solvers import denoms 140 >>> from sympy.abc import x, y, z 141 142 >>> denoms(x/y) 143 {y} 144 145 >>> denoms(x/(y*z)) 146 {y, z} 147 148 >>> denoms(3/x + y/z) 149 {x, z} 150 151 >>> denoms(x/2 + y/z) 152 {2, z} 153 154 If *symbols* are provided then only denominators containing 155 those symbols will be returned: 156 157 >>> denoms(1/x + 1/y + 1/z, y, z) 158 {y, z} 159 160 """ 161 162 pot = preorder_traversal(eq) 163 dens = set() 164 for p in pot: 165 # Here p might be Tuple or Relational 166 # Expr subtrees (e.g. lhs and rhs) will be traversed after by pot 167 if not isinstance(p, Expr): 168 continue 169 den = denom(p) 170 if den is S.One: 171 continue 172 for d in Mul.make_args(den): 173 dens.add(d) 174 if not symbols: 175 return dens 176 elif len(symbols) == 1: 177 if iterable(symbols[0]): 178 symbols = symbols[0] 179 rv = [] 180 for d in dens: 181 free = d.free_symbols 182 if any(s in free for s in symbols): 183 rv.append(d) 184 return set(rv) 185 186 187def checksol(f, symbol, sol=None, **flags): 188 """ 189 Checks whether sol is a solution of equation f == 0. 190 191 Explanation 192 =========== 193 194 Input can be either a single symbol and corresponding value 195 or a dictionary of symbols and values. When given as a dictionary 196 and flag ``simplify=True``, the values in the dictionary will be 197 simplified. *f* can be a single equation or an iterable of equations. 198 A solution must satisfy all equations in *f* to be considered valid; 199 if a solution does not satisfy any equation, False is returned; if one or 200 more checks are inconclusive (and none are False) then None is returned. 201 202 Examples 203 ======== 204 205 >>> from sympy import symbols 206 >>> from sympy.solvers import checksol 207 >>> x, y = symbols('x,y') 208 >>> checksol(x**4 - 1, x, 1) 209 True 210 >>> checksol(x**4 - 1, x, 0) 211 False 212 >>> checksol(x**2 + y**2 - 5**2, {x: 3, y: 4}) 213 True 214 215 To check if an expression is zero using ``checksol()``, pass it 216 as *f* and send an empty dictionary for *symbol*: 217 218 >>> checksol(x**2 + x - x*(x + 1), {}) 219 True 220 221 None is returned if ``checksol()`` could not conclude. 222 223 flags: 224 'numerical=True (default)' 225 do a fast numerical check if ``f`` has only one symbol. 226 'minimal=True (default is False)' 227 a very fast, minimal testing. 228 'warn=True (default is False)' 229 show a warning if checksol() could not conclude. 230 'simplify=True (default)' 231 simplify solution before substituting into function and 232 simplify the function before trying specific simplifications 233 'force=True (default is False)' 234 make positive all symbols without assumptions regarding sign. 235 236 """ 237 from sympy.physics.units import Unit 238 239 minimal = flags.get('minimal', False) 240 241 if sol is not None: 242 sol = {symbol: sol} 243 elif isinstance(symbol, dict): 244 sol = symbol 245 else: 246 msg = 'Expecting (sym, val) or ({sym: val}, None) but got (%s, %s)' 247 raise ValueError(msg % (symbol, sol)) 248 249 if iterable(f): 250 if not f: 251 raise ValueError('no functions to check') 252 rv = True 253 for fi in f: 254 check = checksol(fi, sol, **flags) 255 if check: 256 continue 257 if check is False: 258 return False 259 rv = None # don't return, wait to see if there's a False 260 return rv 261 262 if isinstance(f, Poly): 263 f = f.as_expr() 264 elif isinstance(f, (Equality, Unequality)): 265 if f.rhs in (S.true, S.false): 266 f = f.reversed 267 B, E = f.args 268 if isinstance(B, BooleanAtom): 269 f = f.subs(sol) 270 if not f.is_Boolean: 271 return 272 else: 273 f = f.rewrite(Add, evaluate=False) 274 275 if isinstance(f, BooleanAtom): 276 return bool(f) 277 elif not f.is_Relational and not f: 278 return True 279 280 if sol and not f.free_symbols & set(sol.keys()): 281 # if f(y) == 0, x=3 does not set f(y) to zero...nor does it not 282 return None 283 284 illegal = {S.NaN, 285 S.ComplexInfinity, 286 S.Infinity, 287 S.NegativeInfinity} 288 if any(sympify(v).atoms() & illegal for k, v in sol.items()): 289 return False 290 291 was = f 292 attempt = -1 293 numerical = flags.get('numerical', True) 294 while 1: 295 attempt += 1 296 if attempt == 0: 297 val = f.subs(sol) 298 if isinstance(val, Mul): 299 val = val.as_independent(Unit)[0] 300 if val.atoms() & illegal: 301 return False 302 elif attempt == 1: 303 if not val.is_number: 304 if not val.is_constant(*list(sol.keys()), simplify=not minimal): 305 return False 306 # there are free symbols -- simple expansion might work 307 _, val = val.as_content_primitive() 308 val = _mexpand(val.as_numer_denom()[0], recursive=True) 309 elif attempt == 2: 310 if minimal: 311 return 312 if flags.get('simplify', True): 313 for k in sol: 314 sol[k] = simplify(sol[k]) 315 # start over without the failed expanded form, possibly 316 # with a simplified solution 317 val = simplify(f.subs(sol)) 318 if flags.get('force', True): 319 val, reps = posify(val) 320 # expansion may work now, so try again and check 321 exval = _mexpand(val, recursive=True) 322 if exval.is_number: 323 # we can decide now 324 val = exval 325 else: 326 # if there are no radicals and no functions then this can't be 327 # zero anymore -- can it? 328 pot = preorder_traversal(expand_mul(val)) 329 seen = set() 330 saw_pow_func = False 331 for p in pot: 332 if p in seen: 333 continue 334 seen.add(p) 335 if p.is_Pow and not p.exp.is_Integer: 336 saw_pow_func = True 337 elif p.is_Function: 338 saw_pow_func = True 339 elif isinstance(p, UndefinedFunction): 340 saw_pow_func = True 341 if saw_pow_func: 342 break 343 if saw_pow_func is False: 344 return False 345 if flags.get('force', True): 346 # don't do a zero check with the positive assumptions in place 347 val = val.subs(reps) 348 nz = fuzzy_not(val.is_zero) 349 if nz is not None: 350 # issue 5673: nz may be True even when False 351 # so these are just hacks to keep a false positive 352 # from being returned 353 354 # HACK 1: LambertW (issue 5673) 355 if val.is_number and val.has(LambertW): 356 # don't eval this to verify solution since if we got here, 357 # numerical must be False 358 return None 359 360 # add other HACKs here if necessary, otherwise we assume 361 # the nz value is correct 362 return not nz 363 break 364 365 if val == was: 366 continue 367 elif val.is_Rational: 368 return val == 0 369 if numerical and val.is_number: 370 return (abs(val.n(18).n(12, chop=True)) < 1e-9) is S.true 371 was = val 372 373 if flags.get('warn', False): 374 warnings.warn("\n\tWarning: could not verify solution %s." % sol) 375 # returns None if it can't conclude 376 # TODO: improve solution testing 377 378 379def solve(f, *symbols, **flags): 380 r""" 381 Algebraically solves equations and systems of equations. 382 383 Explanation 384 =========== 385 386 Currently supported: 387 - polynomial 388 - transcendental 389 - piecewise combinations of the above 390 - systems of linear and polynomial equations 391 - systems containing relational expressions 392 393 Examples 394 ======== 395 396 The output varies according to the input and can be seen by example: 397 398 >>> from sympy import solve, Poly, Eq, Function, exp 399 >>> from sympy.abc import x, y, z, a, b 400 >>> f = Function('f') 401 402 Boolean or univariate Relational: 403 404 >>> solve(x < 3) 405 (-oo < x) & (x < 3) 406 407 408 To always get a list of solution mappings, use flag dict=True: 409 410 >>> solve(x - 3, dict=True) 411 [{x: 3}] 412 >>> sol = solve([x - 3, y - 1], dict=True) 413 >>> sol 414 [{x: 3, y: 1}] 415 >>> sol[0][x] 416 3 417 >>> sol[0][y] 418 1 419 420 421 To get a list of *symbols* and set of solution(s) use flag set=True: 422 423 >>> solve([x**2 - 3, y - 1], set=True) 424 ([x, y], {(-sqrt(3), 1), (sqrt(3), 1)}) 425 426 427 Single expression and single symbol that is in the expression: 428 429 >>> solve(x - y, x) 430 [y] 431 >>> solve(x - 3, x) 432 [3] 433 >>> solve(Eq(x, 3), x) 434 [3] 435 >>> solve(Poly(x - 3), x) 436 [3] 437 >>> solve(x**2 - y**2, x, set=True) 438 ([x], {(-y,), (y,)}) 439 >>> solve(x**4 - 1, x, set=True) 440 ([x], {(-1,), (1,), (-I,), (I,)}) 441 442 Single expression with no symbol that is in the expression: 443 444 >>> solve(3, x) 445 [] 446 >>> solve(x - 3, y) 447 [] 448 449 Single expression with no symbol given. In this case, all free *symbols* 450 will be selected as potential *symbols* to solve for. If the equation is 451 univariate then a list of solutions is returned; otherwise - as is the case 452 when *symbols* are given as an iterable of length greater than 1 - a list of 453 mappings will be returned: 454 455 >>> solve(x - 3) 456 [3] 457 >>> solve(x**2 - y**2) 458 [{x: -y}, {x: y}] 459 >>> solve(z**2*x**2 - z**2*y**2) 460 [{x: -y}, {x: y}, {z: 0}] 461 >>> solve(z**2*x - z**2*y**2) 462 [{x: y**2}, {z: 0}] 463 464 When an object other than a Symbol is given as a symbol, it is 465 isolated algebraically and an implicit solution may be obtained. 466 This is mostly provided as a convenience to save you from replacing 467 the object with a Symbol and solving for that Symbol. It will only 468 work if the specified object can be replaced with a Symbol using the 469 subs method: 470 471 >>> solve(f(x) - x, f(x)) 472 [x] 473 >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x)) 474 [x + f(x)] 475 >>> solve(f(x).diff(x) - f(x) - x, f(x)) 476 [-x + Derivative(f(x), x)] 477 >>> solve(x + exp(x)**2, exp(x), set=True) 478 ([exp(x)], {(-sqrt(-x),), (sqrt(-x),)}) 479 480 >>> from sympy import Indexed, IndexedBase, Tuple, sqrt 481 >>> A = IndexedBase('A') 482 >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1) 483 >>> solve(eqs, eqs.atoms(Indexed)) 484 {A[1]: 1, A[2]: 2} 485 486 * To solve for a symbol implicitly, use implicit=True: 487 488 >>> solve(x + exp(x), x) 489 [-LambertW(1)] 490 >>> solve(x + exp(x), x, implicit=True) 491 [-exp(x)] 492 493 * It is possible to solve for anything that can be targeted with 494 subs: 495 496 >>> solve(x + 2 + sqrt(3), x + 2) 497 [-sqrt(3)] 498 >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2) 499 {y: -2 + sqrt(3), x + 2: -sqrt(3)} 500 501 * Nothing heroic is done in this implicit solving so you may end up 502 with a symbol still in the solution: 503 504 >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y) 505 >>> solve(eqs, y, x + 2) 506 {y: -sqrt(3)/(x + 3), x + 2: -2*x/(x + 3) - 6/(x + 3) + sqrt(3)/(x + 3)} 507 >>> solve(eqs, y*x, x) 508 {x: -y - 4, x*y: -3*y - sqrt(3)} 509 510 * If you attempt to solve for a number remember that the number 511 you have obtained does not necessarily mean that the value is 512 equivalent to the expression obtained: 513 514 >>> solve(sqrt(2) - 1, 1) 515 [sqrt(2)] 516 >>> solve(x - y + 1, 1) # /!\ -1 is targeted, too 517 [x/(y - 1)] 518 >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)] 519 [-x + y] 520 521 * To solve for a function within a derivative, use ``dsolve``. 522 523 Single expression and more than one symbol: 524 525 * When there is a linear solution: 526 527 >>> solve(x - y**2, x, y) 528 [(y**2, y)] 529 >>> solve(x**2 - y, x, y) 530 [(x, x**2)] 531 >>> solve(x**2 - y, x, y, dict=True) 532 [{y: x**2}] 533 534 * When undetermined coefficients are identified: 535 536 * That are linear: 537 538 >>> solve((a + b)*x - b + 2, a, b) 539 {a: -2, b: 2} 540 541 * That are nonlinear: 542 543 >>> solve((a + b)*x - b**2 + 2, a, b, set=True) 544 ([a, b], {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))}) 545 546 * If there is no linear solution, then the first successful 547 attempt for a nonlinear solution will be returned: 548 549 >>> solve(x**2 - y**2, x, y, dict=True) 550 [{x: -y}, {x: y}] 551 >>> solve(x**2 - y**2/exp(x), x, y, dict=True) 552 [{x: 2*LambertW(-y/2)}, {x: 2*LambertW(y/2)}] 553 >>> solve(x**2 - y**2/exp(x), y, x) 554 [(-x*sqrt(exp(x)), x), (x*sqrt(exp(x)), x)] 555 556 Iterable of one or more of the above: 557 558 * Involving relationals or bools: 559 560 >>> solve([x < 3, x - 2]) 561 Eq(x, 2) 562 >>> solve([x > 3, x - 2]) 563 False 564 565 * When the system is linear: 566 567 * With a solution: 568 569 >>> solve([x - 3], x) 570 {x: 3} 571 >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y) 572 {x: -3, y: 1} 573 >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z) 574 {x: -3, y: 1} 575 >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y) 576 {x: 2 - 5*y, z: 21*y - 6} 577 578 * Without a solution: 579 580 >>> solve([x + 3, x - 3]) 581 [] 582 583 * When the system is not linear: 584 585 >>> solve([x**2 + y -2, y**2 - 4], x, y, set=True) 586 ([x, y], {(-2, -2), (0, 2), (2, -2)}) 587 588 * If no *symbols* are given, all free *symbols* will be selected and a 589 list of mappings returned: 590 591 >>> solve([x - 2, x**2 + y]) 592 [{x: 2, y: -4}] 593 >>> solve([x - 2, x**2 + f(x)], {f(x), x}) 594 [{x: 2, f(x): -4}] 595 596 * If any equation does not depend on the symbol(s) given, it will be 597 eliminated from the equation set and an answer may be given 598 implicitly in terms of variables that were not of interest: 599 600 >>> solve([x - y, y - 3], x) 601 {x: y} 602 603 **Additional Examples** 604 605 ``solve()`` with check=True (default) will run through the symbol tags to 606 elimate unwanted solutions. If no assumptions are included, all possible 607 solutions will be returned: 608 609 >>> from sympy import Symbol, solve 610 >>> x = Symbol("x") 611 >>> solve(x**2 - 1) 612 [-1, 1] 613 614 By using the positive tag, only one solution will be returned: 615 616 >>> pos = Symbol("pos", positive=True) 617 >>> solve(pos**2 - 1) 618 [1] 619 620 Assumptions are not checked when ``solve()`` input involves 621 relationals or bools. 622 623 When the solutions are checked, those that make any denominator zero 624 are automatically excluded. If you do not want to exclude such solutions, 625 then use the check=False option: 626 627 >>> from sympy import sin, limit 628 >>> solve(sin(x)/x) # 0 is excluded 629 [pi] 630 631 If check=False, then a solution to the numerator being zero is found: x = 0. 632 In this case, this is a spurious solution since $\sin(x)/x$ has the well 633 known limit (without dicontinuity) of 1 at x = 0: 634 635 >>> solve(sin(x)/x, check=False) 636 [0, pi] 637 638 In the following case, however, the limit exists and is equal to the 639 value of x = 0 that is excluded when check=True: 640 641 >>> eq = x**2*(1/x - z**2/x) 642 >>> solve(eq, x) 643 [] 644 >>> solve(eq, x, check=False) 645 [0] 646 >>> limit(eq, x, 0, '-') 647 0 648 >>> limit(eq, x, 0, '+') 649 0 650 651 **Disabling High-Order Explicit Solutions** 652 653 When solving polynomial expressions, you might not want explicit solutions 654 (which can be quite long). If the expression is univariate, ``CRootOf`` 655 instances will be returned instead: 656 657 >>> solve(x**3 - x + 1) 658 [-1/((-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)) - (-1/2 - 659 sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3, -(-1/2 + 660 sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3 - 1/((-1/2 + 661 sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)), -(3*sqrt(69)/2 + 662 27/2)**(1/3)/3 - 1/(3*sqrt(69)/2 + 27/2)**(1/3)] 663 >>> solve(x**3 - x + 1, cubics=False) 664 [CRootOf(x**3 - x + 1, 0), 665 CRootOf(x**3 - x + 1, 1), 666 CRootOf(x**3 - x + 1, 2)] 667 668 If the expression is multivariate, no solution might be returned: 669 670 >>> solve(x**3 - x + a, x, cubics=False) 671 [] 672 673 Sometimes solutions will be obtained even when a flag is False because the 674 expression could be factored. In the following example, the equation can 675 be factored as the product of a linear and a quadratic factor so explicit 676 solutions (which did not require solving a cubic expression) are obtained: 677 678 >>> eq = x**3 + 3*x**2 + x - 1 679 >>> solve(eq, cubics=False) 680 [-1, -1 + sqrt(2), -sqrt(2) - 1] 681 682 **Solving Equations Involving Radicals** 683 684 Because of SymPy's use of the principle root, some solutions 685 to radical equations will be missed unless check=False: 686 687 >>> from sympy import root 688 >>> eq = root(x**3 - 3*x**2, 3) + 1 - x 689 >>> solve(eq) 690 [] 691 >>> solve(eq, check=False) 692 [1/3] 693 694 In the above example, there is only a single solution to the 695 equation. Other expressions will yield spurious roots which 696 must be checked manually; roots which give a negative argument 697 to odd-powered radicals will also need special checking: 698 699 >>> from sympy import real_root, S 700 >>> eq = root(x, 3) - root(x, 5) + S(1)/7 701 >>> solve(eq) # this gives 2 solutions but misses a 3rd 702 [CRootOf(7*x**5 - 7*x**3 + 1, 1)**15, 703 CRootOf(7*x**5 - 7*x**3 + 1, 2)**15] 704 >>> sol = solve(eq, check=False) 705 >>> [abs(eq.subs(x,i).n(2)) for i in sol] 706 [0.48, 0.e-110, 0.e-110, 0.052, 0.052] 707 708 The first solution is negative so ``real_root`` must be used to see that it 709 satisfies the expression: 710 711 >>> abs(real_root(eq.subs(x, sol[0])).n(2)) 712 0.e-110 713 714 If the roots of the equation are not real then more care will be 715 necessary to find the roots, especially for higher order equations. 716 Consider the following expression: 717 718 >>> expr = root(x, 3) - root(x, 5) 719 720 We will construct a known value for this expression at x = 3 by selecting 721 the 1-th root for each radical: 722 723 >>> expr1 = root(x, 3, 1) - root(x, 5, 1) 724 >>> v = expr1.subs(x, -3) 725 726 The ``solve`` function is unable to find any exact roots to this equation: 727 728 >>> eq = Eq(expr, v); eq1 = Eq(expr1, v) 729 >>> solve(eq, check=False), solve(eq1, check=False) 730 ([], []) 731 732 The function ``unrad``, however, can be used to get a form of the equation 733 for which numerical roots can be found: 734 735 >>> from sympy.solvers.solvers import unrad 736 >>> from sympy import nroots 737 >>> e, (p, cov) = unrad(eq) 738 >>> pvals = nroots(e) 739 >>> inversion = solve(cov, x)[0] 740 >>> xvals = [inversion.subs(p, i) for i in pvals] 741 742 Although ``eq`` or ``eq1`` could have been used to find ``xvals``, the 743 solution can only be verified with ``expr1``: 744 745 >>> z = expr - v 746 >>> [xi.n(chop=1e-9) for xi in xvals if abs(z.subs(x, xi).n()) < 1e-9] 747 [] 748 >>> z1 = expr1 - v 749 >>> [xi.n(chop=1e-9) for xi in xvals if abs(z1.subs(x, xi).n()) < 1e-9] 750 [-3.0] 751 752 Parameters 753 ========== 754 755 f : 756 - a single Expr or Poly that must be zero 757 - an Equality 758 - a Relational expression 759 - a Boolean 760 - iterable of one or more of the above 761 762 symbols : (object(s) to solve for) specified as 763 - none given (other non-numeric objects will be used) 764 - single symbol 765 - denested list of symbols 766 (e.g., ``solve(f, x, y)``) 767 - ordered iterable of symbols 768 (e.g., ``solve(f, [x, y])``) 769 770 flags : 771 dict=True (default is False) 772 Return list (perhaps empty) of solution mappings. 773 set=True (default is False) 774 Return list of symbols and set of tuple(s) of solution(s). 775 exclude=[] (default) 776 Do not try to solve for any of the free symbols in exclude; 777 if expressions are given, the free symbols in them will 778 be extracted automatically. 779 check=True (default) 780 If False, do not do any testing of solutions. This can be 781 useful if you want to include solutions that make any 782 denominator zero. 783 numerical=True (default) 784 Do a fast numerical check if *f* has only one symbol. 785 minimal=True (default is False) 786 A very fast, minimal testing. 787 warn=True (default is False) 788 Show a warning if ``checksol()`` could not conclude. 789 simplify=True (default) 790 Simplify all but polynomials of order 3 or greater before 791 returning them and (if check is not False) use the 792 general simplify function on the solutions and the 793 expression obtained when they are substituted into the 794 function which should be zero. 795 force=True (default is False) 796 Make positive all symbols without assumptions regarding sign. 797 rational=True (default) 798 Recast Floats as Rational; if this option is not used, the 799 system containing Floats may fail to solve because of issues 800 with polys. If rational=None, Floats will be recast as 801 rationals but the answer will be recast as Floats. If the 802 flag is False then nothing will be done to the Floats. 803 manual=True (default is False) 804 Do not use the polys/matrix method to solve a system of 805 equations, solve them one at a time as you might "manually." 806 implicit=True (default is False) 807 Allows ``solve`` to return a solution for a pattern in terms of 808 other functions that contain that pattern; this is only 809 needed if the pattern is inside of some invertible function 810 like cos, exp, ect. 811 particular=True (default is False) 812 Instructs ``solve`` to try to find a particular solution to a linear 813 system with as many zeros as possible; this is very expensive. 814 quick=True (default is False) 815 When using particular=True, use a fast heuristic to find a 816 solution with many zeros (instead of using the very slow method 817 guaranteed to find the largest number of zeros possible). 818 cubics=True (default) 819 Return explicit solutions when cubic expressions are encountered. 820 quartics=True (default) 821 Return explicit solutions when quartic expressions are encountered. 822 quintics=True (default) 823 Return explicit solutions (if possible) when quintic expressions 824 are encountered. 825 826 See Also 827 ======== 828 829 rsolve: For solving recurrence relationships 830 dsolve: For solving differential equations 831 832 """ 833 # keeping track of how f was passed since if it is a list 834 # a dictionary of results will be returned. 835 ########################################################################### 836 837 def _sympified_list(w): 838 return list(map(sympify, w if iterable(w) else [w])) 839 bare_f = not iterable(f) 840 ordered_symbols = (symbols and 841 symbols[0] and 842 (isinstance(symbols[0], Symbol) or 843 is_sequence(symbols[0], 844 include=GeneratorType) 845 ) 846 ) 847 f, symbols = (_sympified_list(w) for w in [f, symbols]) 848 if isinstance(f, list): 849 f = [s for s in f if s is not S.true and s is not True] 850 implicit = flags.get('implicit', False) 851 852 # preprocess symbol(s) 853 ########################################################################### 854 if not symbols: 855 # get symbols from equations 856 symbols = set().union(*[fi.free_symbols for fi in f]) 857 if len(symbols) < len(f): 858 for fi in f: 859 pot = preorder_traversal(fi) 860 for p in pot: 861 if isinstance(p, AppliedUndef): 862 flags['dict'] = True # better show symbols 863 symbols.add(p) 864 pot.skip() # don't go any deeper 865 symbols = list(symbols) 866 867 ordered_symbols = False 868 elif len(symbols) == 1 and iterable(symbols[0]): 869 symbols = symbols[0] 870 871 # remove symbols the user is not interested in 872 exclude = flags.pop('exclude', set()) 873 if exclude: 874 if isinstance(exclude, Expr): 875 exclude = [exclude] 876 exclude = set().union(*[e.free_symbols for e in sympify(exclude)]) 877 symbols = [s for s in symbols if s not in exclude] 878 879 880 # preprocess equation(s) 881 ########################################################################### 882 for i, fi in enumerate(f): 883 if isinstance(fi, (Equality, Unequality)): 884 if 'ImmutableDenseMatrix' in [type(a).__name__ for a in fi.args]: 885 fi = fi.lhs - fi.rhs 886 else: 887 L, R = fi.args 888 if isinstance(R, BooleanAtom): 889 L, R = R, L 890 if isinstance(L, BooleanAtom): 891 if isinstance(fi, Unequality): 892 L = ~L 893 if R.is_Relational: 894 fi = ~R if L is S.false else R 895 elif R.is_Symbol: 896 return L 897 elif R.is_Boolean and (~R).is_Symbol: 898 return ~L 899 else: 900 raise NotImplementedError(filldedent(''' 901 Unanticipated argument of Eq when other arg 902 is True or False. 903 ''')) 904 else: 905 fi = fi.rewrite(Add, evaluate=False) 906 f[i] = fi 907 908 if fi.is_Relational: 909 return reduce_inequalities(f, symbols=symbols) 910 911 if isinstance(fi, Poly): 912 f[i] = fi.as_expr() 913 914 # rewrite hyperbolics in terms of exp 915 f[i] = f[i].replace(lambda w: isinstance(w, HyperbolicFunction) and \ 916 (len(w.free_symbols & set(symbols)) > 0), lambda w: w.rewrite(exp)) 917 918 # if we have a Matrix, we need to iterate over its elements again 919 if f[i].is_Matrix: 920 bare_f = False 921 f.extend(list(f[i])) 922 f[i] = S.Zero 923 924 # if we can split it into real and imaginary parts then do so 925 freei = f[i].free_symbols 926 if freei and all(s.is_extended_real or s.is_imaginary for s in freei): 927 fr, fi = f[i].as_real_imag() 928 # accept as long as new re, im, arg or atan2 are not introduced 929 had = f[i].atoms(re, im, arg, atan2) 930 if fr and fi and fr != fi and not any( 931 i.atoms(re, im, arg, atan2) - had for i in (fr, fi)): 932 if bare_f: 933 bare_f = False 934 f[i: i + 1] = [fr, fi] 935 936 # real/imag handling ----------------------------- 937 if any(isinstance(fi, (bool, BooleanAtom)) for fi in f): 938 if flags.get('set', False): 939 return [], set() 940 return [] 941 942 for i, fi in enumerate(f): 943 # Abs 944 while True: 945 was = fi 946 fi = fi.replace(Abs, lambda arg: 947 separatevars(Abs(arg)).rewrite(Piecewise) if arg.has(*symbols) 948 else Abs(arg)) 949 if was == fi: 950 break 951 952 for e in fi.find(Abs): 953 if e.has(*symbols): 954 raise NotImplementedError('solving %s when the argument ' 955 'is not real or imaginary.' % e) 956 957 # arg 958 fi = fi.replace(arg, lambda a: arg(a).rewrite(atan2).rewrite(atan)) 959 960 # save changes 961 f[i] = fi 962 963 # see if re(s) or im(s) appear 964 freim = [fi for fi in f if fi.has(re, im)] 965 if freim: 966 irf = [] 967 for s in symbols: 968 if s.is_real or s.is_imaginary: 969 continue # neither re(x) nor im(x) will appear 970 # if re(s) or im(s) appear, the auxiliary equation must be present 971 if any(fi.has(re(s), im(s)) for fi in freim): 972 irf.append((s, re(s) + S.ImaginaryUnit*im(s))) 973 if irf: 974 for s, rhs in irf: 975 for i, fi in enumerate(f): 976 f[i] = fi.xreplace({s: rhs}) 977 f.append(s - rhs) 978 symbols.extend([re(s), im(s)]) 979 if bare_f: 980 bare_f = False 981 flags['dict'] = True 982 # end of real/imag handling ----------------------------- 983 984 symbols = list(uniq(symbols)) 985 if not ordered_symbols: 986 # we do this to make the results returned canonical in case f 987 # contains a system of nonlinear equations; all other cases should 988 # be unambiguous 989 symbols = sorted(symbols, key=default_sort_key) 990 991 # we can solve for non-symbol entities by replacing them with Dummy symbols 992 f, symbols, swap_sym = recast_to_symbols(f, symbols) 993 994 # this is needed in the next two events 995 symset = set(symbols) 996 997 # get rid of equations that have no symbols of interest; we don't 998 # try to solve them because the user didn't ask and they might be 999 # hard to solve; this means that solutions may be given in terms 1000 # of the eliminated equations e.g. solve((x-y, y-3), x) -> {x: y} 1001 newf = [] 1002 for fi in f: 1003 # let the solver handle equations that.. 1004 # - have no symbols but are expressions 1005 # - have symbols of interest 1006 # - have no symbols of interest but are constant 1007 # but when an expression is not constant and has no symbols of 1008 # interest, it can't change what we obtain for a solution from 1009 # the remaining equations so we don't include it; and if it's 1010 # zero it can be removed and if it's not zero, there is no 1011 # solution for the equation set as a whole 1012 # 1013 # The reason for doing this filtering is to allow an answer 1014 # to be obtained to queries like solve((x - y, y), x); without 1015 # this mod the return value is [] 1016 ok = False 1017 if fi.free_symbols & symset: 1018 ok = True 1019 else: 1020 if fi.is_number: 1021 if fi.is_Number: 1022 if fi.is_zero: 1023 continue 1024 return [] 1025 ok = True 1026 else: 1027 if fi.is_constant(): 1028 ok = True 1029 if ok: 1030 newf.append(fi) 1031 if not newf: 1032 return [] 1033 f = newf 1034 del newf 1035 1036 # mask off any Object that we aren't going to invert: Derivative, 1037 # Integral, etc... so that solving for anything that they contain will 1038 # give an implicit solution 1039 seen = set() 1040 non_inverts = set() 1041 for fi in f: 1042 pot = preorder_traversal(fi) 1043 for p in pot: 1044 if not isinstance(p, Expr) or isinstance(p, Piecewise): 1045 pass 1046 elif (isinstance(p, bool) or 1047 not p.args or 1048 p in symset or 1049 p.is_Add or p.is_Mul or 1050 p.is_Pow and not implicit or 1051 p.is_Function and not implicit) and p.func not in (re, im): 1052 continue 1053 elif not p in seen: 1054 seen.add(p) 1055 if p.free_symbols & symset: 1056 non_inverts.add(p) 1057 else: 1058 continue 1059 pot.skip() 1060 del seen 1061 non_inverts = dict(list(zip(non_inverts, [Dummy() for _ in non_inverts]))) 1062 f = [fi.subs(non_inverts) for fi in f] 1063 1064 # Both xreplace and subs are needed below: xreplace to force substitution 1065 # inside Derivative, subs to handle non-straightforward substitutions 1066 non_inverts = [(v, k.xreplace(swap_sym).subs(swap_sym)) for k, v in non_inverts.items()] 1067 1068 # rationalize Floats 1069 floats = False 1070 if flags.get('rational', True) is not False: 1071 for i, fi in enumerate(f): 1072 if fi.has(Float): 1073 floats = True 1074 f[i] = nsimplify(fi, rational=True) 1075 1076 # capture any denominators before rewriting since 1077 # they may disappear after the rewrite, e.g. issue 14779 1078 flags['_denominators'] = _simple_dens(f[0], symbols) 1079 # Any embedded piecewise functions need to be brought out to the 1080 # top level so that the appropriate strategy gets selected. 1081 # However, this is necessary only if one of the piecewise 1082 # functions depends on one of the symbols we are solving for. 1083 def _has_piecewise(e): 1084 if e.is_Piecewise: 1085 return e.has(*symbols) 1086 return any([_has_piecewise(a) for a in e.args]) 1087 for i, fi in enumerate(f): 1088 if _has_piecewise(fi): 1089 f[i] = piecewise_fold(fi) 1090 1091 # 1092 # try to get a solution 1093 ########################################################################### 1094 if bare_f: 1095 solution = _solve(f[0], *symbols, **flags) 1096 else: 1097 solution = _solve_system(f, symbols, **flags) 1098 1099 # 1100 # postprocessing 1101 ########################################################################### 1102 # Restore masked-off objects 1103 if non_inverts: 1104 1105 def _do_dict(solution): 1106 return {k: v.subs(non_inverts) for k, v in 1107 solution.items()} 1108 for i in range(1): 1109 if isinstance(solution, dict): 1110 solution = _do_dict(solution) 1111 break 1112 elif solution and isinstance(solution, list): 1113 if isinstance(solution[0], dict): 1114 solution = [_do_dict(s) for s in solution] 1115 break 1116 elif isinstance(solution[0], tuple): 1117 solution = [tuple([v.subs(non_inverts) for v in s]) for s 1118 in solution] 1119 break 1120 else: 1121 solution = [v.subs(non_inverts) for v in solution] 1122 break 1123 elif not solution: 1124 break 1125 else: 1126 raise NotImplementedError(filldedent(''' 1127 no handling of %s was implemented''' % solution)) 1128 1129 # Restore original "symbols" if a dictionary is returned. 1130 # This is not necessary for 1131 # - the single univariate equation case 1132 # since the symbol will have been removed from the solution; 1133 # - the nonlinear poly_system since that only supports zero-dimensional 1134 # systems and those results come back as a list 1135 # 1136 # ** unless there were Derivatives with the symbols, but those were handled 1137 # above. 1138 if swap_sym: 1139 symbols = [swap_sym.get(k, k) for k in symbols] 1140 if isinstance(solution, dict): 1141 solution = {swap_sym.get(k, k): v.subs(swap_sym) 1142 for k, v in solution.items()} 1143 elif solution and isinstance(solution, list) and isinstance(solution[0], dict): 1144 for i, sol in enumerate(solution): 1145 solution[i] = {swap_sym.get(k, k): v.subs(swap_sym) 1146 for k, v in sol.items()} 1147 1148 # undo the dictionary solutions returned when the system was only partially 1149 # solved with poly-system if all symbols are present 1150 if ( 1151 not flags.get('dict', False) and 1152 solution and 1153 ordered_symbols and 1154 not isinstance(solution, dict) and 1155 all(isinstance(sol, dict) for sol in solution) 1156 ): 1157 solution = [tuple([r.get(s, s) for s in symbols]) for r in solution] 1158 1159 # Get assumptions about symbols, to filter solutions. 1160 # Note that if assumptions about a solution can't be verified, it is still 1161 # returned. 1162 check = flags.get('check', True) 1163 1164 # restore floats 1165 if floats and solution and flags.get('rational', None) is None: 1166 solution = nfloat(solution, exponent=False) 1167 1168 if check and solution: # assumption checking 1169 1170 warn = flags.get('warn', False) 1171 got_None = [] # solutions for which one or more symbols gave None 1172 no_False = [] # solutions for which no symbols gave False 1173 if isinstance(solution, tuple): 1174 # this has already been checked and is in as_set form 1175 return solution 1176 elif isinstance(solution, list): 1177 if isinstance(solution[0], tuple): 1178 for sol in solution: 1179 for symb, val in zip(symbols, sol): 1180 test = check_assumptions(val, **symb.assumptions0) 1181 if test is False: 1182 break 1183 if test is None: 1184 got_None.append(sol) 1185 else: 1186 no_False.append(sol) 1187 elif isinstance(solution[0], dict): 1188 for sol in solution: 1189 a_None = False 1190 for symb, val in sol.items(): 1191 test = check_assumptions(val, **symb.assumptions0) 1192 if test: 1193 continue 1194 if test is False: 1195 break 1196 a_None = True 1197 else: 1198 no_False.append(sol) 1199 if a_None: 1200 got_None.append(sol) 1201 else: # list of expressions 1202 for sol in solution: 1203 test = check_assumptions(sol, **symbols[0].assumptions0) 1204 if test is False: 1205 continue 1206 no_False.append(sol) 1207 if test is None: 1208 got_None.append(sol) 1209 1210 elif isinstance(solution, dict): 1211 a_None = False 1212 for symb, val in solution.items(): 1213 test = check_assumptions(val, **symb.assumptions0) 1214 if test: 1215 continue 1216 if test is False: 1217 no_False = None 1218 break 1219 a_None = True 1220 else: 1221 no_False = solution 1222 if a_None: 1223 got_None.append(solution) 1224 1225 elif isinstance(solution, (Relational, And, Or)): 1226 if len(symbols) != 1: 1227 raise ValueError("Length should be 1") 1228 if warn and symbols[0].assumptions0: 1229 warnings.warn(filldedent(""" 1230 \tWarning: assumptions about variable '%s' are 1231 not handled currently.""" % symbols[0])) 1232 # TODO: check also variable assumptions for inequalities 1233 1234 else: 1235 raise TypeError('Unrecognized solution') # improve the checker 1236 1237 solution = no_False 1238 if warn and got_None: 1239 warnings.warn(filldedent(""" 1240 \tWarning: assumptions concerning following solution(s) 1241 can't be checked:""" + '\n\t' + 1242 ', '.join(str(s) for s in got_None))) 1243 1244 # 1245 # done 1246 ########################################################################### 1247 1248 as_dict = flags.get('dict', False) 1249 as_set = flags.get('set', False) 1250 1251 if not as_set and isinstance(solution, list): 1252 # Make sure that a list of solutions is ordered in a canonical way. 1253 solution.sort(key=default_sort_key) 1254 1255 if not as_dict and not as_set: 1256 return solution or [] 1257 1258 # return a list of mappings or [] 1259 if not solution: 1260 solution = [] 1261 else: 1262 if isinstance(solution, dict): 1263 solution = [solution] 1264 elif iterable(solution[0]): 1265 solution = [dict(list(zip(symbols, s))) for s in solution] 1266 elif isinstance(solution[0], dict): 1267 pass 1268 else: 1269 if len(symbols) != 1: 1270 raise ValueError("Length should be 1") 1271 solution = [{symbols[0]: s} for s in solution] 1272 if as_dict: 1273 return solution 1274 assert as_set 1275 if not solution: 1276 return [], set() 1277 k = list(ordered(solution[0].keys())) 1278 return k, {tuple([s[ki] for ki in k]) for s in solution} 1279 1280 1281def _solve(f, *symbols, **flags): 1282 """ 1283 Return a checked solution for *f* in terms of one or more of the 1284 symbols. A list should be returned except for the case when a linear 1285 undetermined-coefficients equation is encountered (in which case 1286 a dictionary is returned). 1287 1288 If no method is implemented to solve the equation, a NotImplementedError 1289 will be raised. In the case that conversion of an expression to a Poly 1290 gives None a ValueError will be raised. 1291 1292 """ 1293 1294 not_impl_msg = "No algorithms are implemented to solve equation %s" 1295 1296 if len(symbols) != 1: 1297 soln = None 1298 free = f.free_symbols 1299 ex = free - set(symbols) 1300 if len(ex) != 1: 1301 ind, dep = f.as_independent(*symbols) 1302 ex = ind.free_symbols & dep.free_symbols 1303 if len(ex) == 1: 1304 ex = ex.pop() 1305 try: 1306 # soln may come back as dict, list of dicts or tuples, or 1307 # tuple of symbol list and set of solution tuples 1308 soln = solve_undetermined_coeffs(f, symbols, ex, **flags) 1309 except NotImplementedError: 1310 pass 1311 if soln: 1312 if flags.get('simplify', True): 1313 if isinstance(soln, dict): 1314 for k in soln: 1315 soln[k] = simplify(soln[k]) 1316 elif isinstance(soln, list): 1317 if isinstance(soln[0], dict): 1318 for d in soln: 1319 for k in d: 1320 d[k] = simplify(d[k]) 1321 elif isinstance(soln[0], tuple): 1322 soln = [tuple(simplify(i) for i in j) for j in soln] 1323 else: 1324 raise TypeError('unrecognized args in list') 1325 elif isinstance(soln, tuple): 1326 sym, sols = soln 1327 soln = sym, {tuple(simplify(i) for i in j) for j in sols} 1328 else: 1329 raise TypeError('unrecognized solution type') 1330 return soln 1331 # find first successful solution 1332 failed = [] 1333 got_s = set() 1334 result = [] 1335 for s in symbols: 1336 xi, v = solve_linear(f, symbols=[s]) 1337 if xi == s: 1338 # no need to check but we should simplify if desired 1339 if flags.get('simplify', True): 1340 v = simplify(v) 1341 vfree = v.free_symbols 1342 if got_s and any([ss in vfree for ss in got_s]): 1343 # sol depends on previously solved symbols: discard it 1344 continue 1345 got_s.add(xi) 1346 result.append({xi: v}) 1347 elif xi: # there might be a non-linear solution if xi is not 0 1348 failed.append(s) 1349 if not failed: 1350 return result 1351 for s in failed: 1352 try: 1353 soln = _solve(f, s, **flags) 1354 for sol in soln: 1355 if got_s and any([ss in sol.free_symbols for ss in got_s]): 1356 # sol depends on previously solved symbols: discard it 1357 continue 1358 got_s.add(s) 1359 result.append({s: sol}) 1360 except NotImplementedError: 1361 continue 1362 if got_s: 1363 return result 1364 else: 1365 raise NotImplementedError(not_impl_msg % f) 1366 symbol = symbols[0] 1367 1368 #expand binomials only if it has the unknown symbol 1369 f = f.replace(lambda e: isinstance(e, binomial) and e.has(symbol), 1370 lambda e: expand_func(e)) 1371 1372 # /!\ capture this flag then set it to False so that no checking in 1373 # recursive calls will be done; only the final answer is checked 1374 flags['check'] = checkdens = check = flags.pop('check', True) 1375 1376 # build up solutions if f is a Mul 1377 if f.is_Mul: 1378 result = set() 1379 for m in f.args: 1380 if m in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}: 1381 result = set() 1382 break 1383 soln = _solve(m, symbol, **flags) 1384 result.update(set(soln)) 1385 result = list(result) 1386 if check: 1387 # all solutions have been checked but now we must 1388 # check that the solutions do not set denominators 1389 # in any factor to zero 1390 dens = flags.get('_denominators', _simple_dens(f, symbols)) 1391 result = [s for s in result if 1392 all(not checksol(den, {symbol: s}, **flags) for den in 1393 dens)] 1394 # set flags for quick exit at end; solutions for each 1395 # factor were already checked and simplified 1396 check = False 1397 flags['simplify'] = False 1398 1399 elif f.is_Piecewise: 1400 result = set() 1401 for i, (expr, cond) in enumerate(f.args): 1402 if expr.is_zero: 1403 raise NotImplementedError( 1404 'solve cannot represent interval solutions') 1405 candidates = _solve(expr, symbol, **flags) 1406 # the explicit condition for this expr is the current cond 1407 # and none of the previous conditions 1408 args = [~c for _, c in f.args[:i]] + [cond] 1409 cond = And(*args) 1410 for candidate in candidates: 1411 if candidate in result: 1412 # an unconditional value was already there 1413 continue 1414 try: 1415 v = cond.subs(symbol, candidate) 1416 _eval_simplify = getattr(v, '_eval_simplify', None) 1417 if _eval_simplify is not None: 1418 # unconditionally take the simpification of v 1419 v = _eval_simplify(ratio=2, measure=lambda x: 1) 1420 except TypeError: 1421 # incompatible type with condition(s) 1422 continue 1423 if v == False: 1424 continue 1425 if v == True: 1426 result.add(candidate) 1427 else: 1428 result.add(Piecewise( 1429 (candidate, v), 1430 (S.NaN, True))) 1431 # set flags for quick exit at end; solutions for each 1432 # piece were already checked and simplified 1433 check = False 1434 flags['simplify'] = False 1435 else: 1436 # first see if it really depends on symbol and whether there 1437 # is only a linear solution 1438 f_num, sol = solve_linear(f, symbols=symbols) 1439 if f_num.is_zero or sol is S.NaN: 1440 return [] 1441 elif f_num.is_Symbol: 1442 # no need to check but simplify if desired 1443 if flags.get('simplify', True): 1444 sol = simplify(sol) 1445 return [sol] 1446 1447 poly = None 1448 # check for a single Add generator 1449 if not f_num.is_Add: 1450 add_args = [i for i in f_num.atoms(Add) 1451 if symbol in i.free_symbols] 1452 if len(add_args) == 1: 1453 gen = add_args[0] 1454 spart = gen.as_independent(symbol)[1].as_base_exp()[0] 1455 if spart == symbol: 1456 try: 1457 poly = Poly(f_num, spart) 1458 except PolynomialError: 1459 pass 1460 1461 result = False # no solution was obtained 1462 msg = '' # there is no failure message 1463 1464 # Poly is generally robust enough to convert anything to 1465 # a polynomial and tell us the different generators that it 1466 # contains, so we will inspect the generators identified by 1467 # polys to figure out what to do. 1468 1469 # try to identify a single generator that will allow us to solve this 1470 # as a polynomial, followed (perhaps) by a change of variables if the 1471 # generator is not a symbol 1472 1473 try: 1474 if poly is None: 1475 poly = Poly(f_num) 1476 if poly is None: 1477 raise ValueError('could not convert %s to Poly' % f_num) 1478 except GeneratorsNeeded: 1479 simplified_f = simplify(f_num) 1480 if simplified_f != f_num: 1481 return _solve(simplified_f, symbol, **flags) 1482 raise ValueError('expression appears to be a constant') 1483 1484 gens = [g for g in poly.gens if g.has(symbol)] 1485 1486 def _as_base_q(x): 1487 """Return (b**e, q) for x = b**(p*e/q) where p/q is the leading 1488 Rational of the exponent of x, e.g. exp(-2*x/3) -> (exp(x), 3) 1489 """ 1490 b, e = x.as_base_exp() 1491 if e.is_Rational: 1492 return b, e.q 1493 if not e.is_Mul: 1494 return x, 1 1495 c, ee = e.as_coeff_Mul() 1496 if c.is_Rational and c is not S.One: # c could be a Float 1497 return b**ee, c.q 1498 return x, 1 1499 1500 if len(gens) > 1: 1501 # If there is more than one generator, it could be that the 1502 # generators have the same base but different powers, e.g. 1503 # >>> Poly(exp(x) + 1/exp(x)) 1504 # Poly(exp(-x) + exp(x), exp(-x), exp(x), domain='ZZ') 1505 # 1506 # If unrad was not disabled then there should be no rational 1507 # exponents appearing as in 1508 # >>> Poly(sqrt(x) + sqrt(sqrt(x))) 1509 # Poly(sqrt(x) + x**(1/4), sqrt(x), x**(1/4), domain='ZZ') 1510 1511 bases, qs = list(zip(*[_as_base_q(g) for g in gens])) 1512 bases = set(bases) 1513 1514 if len(bases) > 1 or not all(q == 1 for q in qs): 1515 funcs = {b for b in bases if b.is_Function} 1516 1517 trig = {_ for _ in funcs if 1518 isinstance(_, TrigonometricFunction)} 1519 other = funcs - trig 1520 if not other and len(funcs.intersection(trig)) > 1: 1521 newf = None 1522 if f_num.is_Add and len(f_num.args) == 2: 1523 # check for sin(x)**p = cos(x)**p 1524 _args = f_num.args 1525 t = a, b = [i.atoms(Function).intersection( 1526 trig) for i in _args] 1527 if all(len(i) == 1 for i in t): 1528 a, b = [i.pop() for i in t] 1529 if isinstance(a, cos): 1530 a, b = b, a 1531 _args = _args[::-1] 1532 if isinstance(a, sin) and isinstance(b, cos 1533 ) and a.args[0] == b.args[0]: 1534 # sin(x) + cos(x) = 0 -> tan(x) + 1 = 0 1535 newf, _d = (TR2i(_args[0]/_args[1]) + 1 1536 ).as_numer_denom() 1537 if not _d.is_Number: 1538 newf = None 1539 if newf is None: 1540 newf = TR1(f_num).rewrite(tan) 1541 if newf != f_num: 1542 # don't check the rewritten form --check 1543 # solutions in the un-rewritten form below 1544 flags['check'] = False 1545 result = _solve(newf, symbol, **flags) 1546 flags['check'] = check 1547 1548 # just a simple case - see if replacement of single function 1549 # clears all symbol-dependent functions, e.g. 1550 # log(x) - log(log(x) - 1) - 3 can be solved even though it has 1551 # two generators. 1552 1553 if result is False and funcs: 1554 funcs = list(ordered(funcs)) # put shallowest function first 1555 f1 = funcs[0] 1556 t = Dummy('t') 1557 # perform the substitution 1558 ftry = f_num.subs(f1, t) 1559 1560 # if no Functions left, we can proceed with usual solve 1561 if not ftry.has(symbol): 1562 cv_sols = _solve(ftry, t, **flags) 1563 cv_inv = _solve(t - f1, symbol, **flags)[0] 1564 sols = list() 1565 for sol in cv_sols: 1566 sols.append(cv_inv.subs(t, sol)) 1567 result = list(ordered(sols)) 1568 1569 if result is False: 1570 msg = 'multiple generators %s' % gens 1571 1572 else: 1573 # e.g. case where gens are exp(x), exp(-x) 1574 u = bases.pop() 1575 t = Dummy('t') 1576 inv = _solve(u - t, symbol, **flags) 1577 if isinstance(u, (Pow, exp)): 1578 # this will be resolved by factor in _tsolve but we might 1579 # as well try a simple expansion here to get things in 1580 # order so something like the following will work now without 1581 # having to factor: 1582 # 1583 # >>> eq = (exp(I*(-x-2))+exp(I*(x+2))) 1584 # >>> eq.subs(exp(x),y) # fails 1585 # exp(I*(-x - 2)) + exp(I*(x + 2)) 1586 # >>> eq.expand().subs(exp(x),y) # works 1587 # y**I*exp(2*I) + y**(-I)*exp(-2*I) 1588 def _expand(p): 1589 b, e = p.as_base_exp() 1590 e = expand_mul(e) 1591 return expand_power_exp(b**e) 1592 ftry = f_num.replace( 1593 lambda w: w.is_Pow or isinstance(w, exp), 1594 _expand).subs(u, t) 1595 if not ftry.has(symbol): 1596 soln = _solve(ftry, t, **flags) 1597 sols = list() 1598 for sol in soln: 1599 for i in inv: 1600 sols.append(i.subs(t, sol)) 1601 result = list(ordered(sols)) 1602 1603 elif len(gens) == 1: 1604 1605 # There is only one generator that we are interested in, but 1606 # there may have been more than one generator identified by 1607 # polys (e.g. for symbols other than the one we are interested 1608 # in) so recast the poly in terms of our generator of interest. 1609 # Also use composite=True with f_num since Poly won't update 1610 # poly as documented in issue 8810. 1611 1612 poly = Poly(f_num, gens[0], composite=True) 1613 1614 # if we aren't on the tsolve-pass, use roots 1615 if not flags.pop('tsolve', False): 1616 soln = None 1617 deg = poly.degree() 1618 flags['tsolve'] = True 1619 solvers = {k: flags.get(k, True) for k in 1620 ('cubics', 'quartics', 'quintics')} 1621 soln = roots(poly, **solvers) 1622 if sum(soln.values()) < deg: 1623 # e.g. roots(32*x**5 + 400*x**4 + 2032*x**3 + 1624 # 5000*x**2 + 6250*x + 3189) -> {} 1625 # so all_roots is used and RootOf instances are 1626 # returned *unless* the system is multivariate 1627 # or high-order EX domain. 1628 try: 1629 soln = poly.all_roots() 1630 except NotImplementedError: 1631 if not flags.get('incomplete', True): 1632 raise NotImplementedError( 1633 filldedent(''' 1634 Neither high-order multivariate polynomials 1635 nor sorting of EX-domain polynomials is supported. 1636 If you want to see any results, pass keyword incomplete=True to 1637 solve; to see numerical values of roots 1638 for univariate expressions, use nroots. 1639 ''')) 1640 else: 1641 pass 1642 else: 1643 soln = list(soln.keys()) 1644 1645 if soln is not None: 1646 u = poly.gen 1647 if u != symbol: 1648 try: 1649 t = Dummy('t') 1650 iv = _solve(u - t, symbol, **flags) 1651 soln = list(ordered({i.subs(t, s) for i in iv for s in soln})) 1652 except NotImplementedError: 1653 # perhaps _tsolve can handle f_num 1654 soln = None 1655 else: 1656 check = False # only dens need to be checked 1657 if soln is not None: 1658 if len(soln) > 2: 1659 # if the flag wasn't set then unset it since high-order 1660 # results are quite long. Perhaps one could base this 1661 # decision on a certain critical length of the 1662 # roots. In addition, wester test M2 has an expression 1663 # whose roots can be shown to be real with the 1664 # unsimplified form of the solution whereas only one of 1665 # the simplified forms appears to be real. 1666 flags['simplify'] = flags.get('simplify', False) 1667 result = soln 1668 1669 # fallback if above fails 1670 # ----------------------- 1671 if result is False: 1672 # try unrad 1673 if flags.pop('_unrad', True): 1674 try: 1675 u = unrad(f_num, symbol) 1676 except (ValueError, NotImplementedError): 1677 u = False 1678 if u: 1679 eq, cov = u 1680 if cov: 1681 isym, ieq = cov 1682 inv = _solve(ieq, symbol, **flags)[0] 1683 rv = {inv.subs(isym, xi) for xi in _solve(eq, isym, **flags)} 1684 else: 1685 try: 1686 rv = set(_solve(eq, symbol, **flags)) 1687 except NotImplementedError: 1688 rv = None 1689 if rv is not None: 1690 result = list(ordered(rv)) 1691 # if the flag wasn't set then unset it since unrad results 1692 # can be quite long or of very high order 1693 flags['simplify'] = flags.get('simplify', False) 1694 else: 1695 pass # for coverage 1696 1697 # try _tsolve 1698 if result is False: 1699 flags.pop('tsolve', None) # allow tsolve to be used on next pass 1700 try: 1701 soln = _tsolve(f_num, symbol, **flags) 1702 if soln is not None: 1703 result = soln 1704 except PolynomialError: 1705 pass 1706 # ----------- end of fallback ---------------------------- 1707 1708 if result is False: 1709 raise NotImplementedError('\n'.join([msg, not_impl_msg % f])) 1710 1711 if flags.get('simplify', True): 1712 result = list(map(simplify, result)) 1713 # we just simplified the solution so we now set the flag to 1714 # False so the simplification doesn't happen again in checksol() 1715 flags['simplify'] = False 1716 1717 if checkdens: 1718 # reject any result that makes any denom. affirmatively 0; 1719 # if in doubt, keep it 1720 dens = _simple_dens(f, symbols) 1721 result = [s for s in result if 1722 all(not checksol(d, {symbol: s}, **flags) 1723 for d in dens)] 1724 if check: 1725 # keep only results if the check is not False 1726 result = [r for r in result if 1727 checksol(f_num, {symbol: r}, **flags) is not False] 1728 return result 1729 1730 1731def _solve_system(exprs, symbols, **flags): 1732 if not exprs: 1733 return [] 1734 1735 if flags.pop('_split', True): 1736 # Split the system into connected components 1737 V = exprs 1738 symsset = set(symbols) 1739 exprsyms = {e: e.free_symbols & symsset for e in exprs} 1740 E = [] 1741 sym_indices = {sym: i for i, sym in enumerate(symbols)} 1742 for n, e1 in enumerate(exprs): 1743 for e2 in exprs[:n]: 1744 # Equations are connected if they share a symbol 1745 if exprsyms[e1] & exprsyms[e2]: 1746 E.append((e1, e2)) 1747 G = V, E 1748 subexprs = connected_components(G) 1749 if len(subexprs) > 1: 1750 subsols = [] 1751 for subexpr in subexprs: 1752 subsyms = set() 1753 for e in subexpr: 1754 subsyms |= exprsyms[e] 1755 subsyms = list(sorted(subsyms, key = lambda x: sym_indices[x])) 1756 flags['_split'] = False # skip split step 1757 subsol = _solve_system(subexpr, subsyms, **flags) 1758 if not isinstance(subsol, list): 1759 subsol = [subsol] 1760 subsols.append(subsol) 1761 # Full solution is cartesion product of subsystems 1762 sols = [] 1763 for soldicts in cartes(*subsols): 1764 sols.append(dict(item for sd in soldicts 1765 for item in sd.items())) 1766 # Return a list with one dict as just the dict 1767 if len(sols) == 1: 1768 return sols[0] 1769 return sols 1770 1771 polys = [] 1772 dens = set() 1773 failed = [] 1774 result = False 1775 linear = False 1776 manual = flags.get('manual', False) 1777 checkdens = check = flags.get('check', True) 1778 1779 for j, g in enumerate(exprs): 1780 dens.update(_simple_dens(g, symbols)) 1781 i, d = _invert(g, *symbols) 1782 g = d - i 1783 g = g.as_numer_denom()[0] 1784 if manual: 1785 failed.append(g) 1786 continue 1787 1788 poly = g.as_poly(*symbols, extension=True) 1789 1790 if poly is not None: 1791 polys.append(poly) 1792 else: 1793 failed.append(g) 1794 1795 if not polys: 1796 solved_syms = [] 1797 else: 1798 if all(p.is_linear for p in polys): 1799 n, m = len(polys), len(symbols) 1800 matrix = zeros(n, m + 1) 1801 1802 for i, poly in enumerate(polys): 1803 for monom, coeff in poly.terms(): 1804 try: 1805 j = monom.index(1) 1806 matrix[i, j] = coeff 1807 except ValueError: 1808 matrix[i, m] = -coeff 1809 1810 # returns a dictionary ({symbols: values}) or None 1811 if flags.pop('particular', False): 1812 result = minsolve_linear_system(matrix, *symbols, **flags) 1813 else: 1814 result = solve_linear_system(matrix, *symbols, **flags) 1815 if failed: 1816 if result: 1817 solved_syms = list(result.keys()) 1818 else: 1819 solved_syms = [] 1820 else: 1821 linear = True 1822 1823 else: 1824 if len(symbols) > len(polys): 1825 from sympy.utilities.iterables import subsets 1826 1827 free = set().union(*[p.free_symbols for p in polys]) 1828 free = list(ordered(free.intersection(symbols))) 1829 got_s = set() 1830 result = [] 1831 for syms in subsets(free, len(polys)): 1832 try: 1833 # returns [] or list of tuples of solutions for syms 1834 res = solve_poly_system(polys, *syms) 1835 if res: 1836 for r in res: 1837 skip = False 1838 for r1 in r: 1839 if got_s and any([ss in r1.free_symbols 1840 for ss in got_s]): 1841 # sol depends on previously 1842 # solved symbols: discard it 1843 skip = True 1844 if not skip: 1845 got_s.update(syms) 1846 result.extend([dict(list(zip(syms, r)))]) 1847 except NotImplementedError: 1848 pass 1849 if got_s: 1850 solved_syms = list(got_s) 1851 else: 1852 raise NotImplementedError('no valid subset found') 1853 else: 1854 try: 1855 result = solve_poly_system(polys, *symbols) 1856 if result: 1857 solved_syms = symbols 1858 # we don't know here if the symbols provided 1859 # were given or not, so let solve resolve that. 1860 # A list of dictionaries is going to always be 1861 # returned from here. 1862 result = [dict(list(zip(solved_syms, r))) for r in result] 1863 except NotImplementedError: 1864 failed.extend([g.as_expr() for g in polys]) 1865 solved_syms = [] 1866 result = None 1867 1868 if result: 1869 if isinstance(result, dict): 1870 result = [result] 1871 else: 1872 result = [{}] 1873 1874 if failed: 1875 # For each failed equation, see if we can solve for one of the 1876 # remaining symbols from that equation. If so, we update the 1877 # solution set and continue with the next failed equation, 1878 # repeating until we are done or we get an equation that can't 1879 # be solved. 1880 def _ok_syms(e, sort=False): 1881 rv = (e.free_symbols - solved_syms) & legal 1882 1883 # Solve first for symbols that have lower degree in the equation. 1884 # Ideally we want to solve firstly for symbols that appear linearly 1885 # with rational coefficients e.g. if e = x*y + z then we should 1886 # solve for z first. 1887 def key(sym): 1888 ep = e.as_poly(sym) 1889 if ep is None: 1890 complexity = (S.Infinity, S.Infinity, S.Infinity) 1891 else: 1892 coeff_syms = ep.LC().free_symbols 1893 complexity = (ep.degree(), len(coeff_syms & rv), len(coeff_syms)) 1894 return complexity + (default_sort_key(sym),) 1895 1896 if sort: 1897 rv = sorted(rv, key=key) 1898 return rv 1899 1900 solved_syms = set(solved_syms) # set of symbols we have solved for 1901 legal = set(symbols) # what we are interested in 1902 # sort so equation with the fewest potential symbols is first 1903 u = Dummy() # used in solution checking 1904 for eq in ordered(failed, lambda _: len(_ok_syms(_))): 1905 newresult = [] 1906 bad_results = [] 1907 got_s = set() 1908 hit = False 1909 for r in result: 1910 # update eq with everything that is known so far 1911 eq2 = eq.subs(r) 1912 # if check is True then we see if it satisfies this 1913 # equation, otherwise we just accept it 1914 if check and r: 1915 b = checksol(u, u, eq2, minimal=True) 1916 if b is not None: 1917 # this solution is sufficient to know whether 1918 # it is valid or not so we either accept or 1919 # reject it, then continue 1920 if b: 1921 newresult.append(r) 1922 else: 1923 bad_results.append(r) 1924 continue 1925 # search for a symbol amongst those available that 1926 # can be solved for 1927 ok_syms = _ok_syms(eq2, sort=True) 1928 if not ok_syms: 1929 if r: 1930 newresult.append(r) 1931 break # skip as it's independent of desired symbols 1932 for s in ok_syms: 1933 try: 1934 soln = _solve(eq2, s, **flags) 1935 except NotImplementedError: 1936 continue 1937 # put each solution in r and append the now-expanded 1938 # result in the new result list; use copy since the 1939 # solution for s in being added in-place 1940 for sol in soln: 1941 if got_s and any([ss in sol.free_symbols for ss in got_s]): 1942 # sol depends on previously solved symbols: discard it 1943 continue 1944 rnew = r.copy() 1945 for k, v in r.items(): 1946 rnew[k] = v.subs(s, sol) 1947 # and add this new solution 1948 rnew[s] = sol 1949 # check that it is independent of previous solutions 1950 iset = set(rnew.items()) 1951 for i in newresult: 1952 if len(i) < len(iset) and not set(i.items()) - iset: 1953 # this is a superset of a known solution that 1954 # is smaller 1955 break 1956 else: 1957 # keep it 1958 newresult.append(rnew) 1959 hit = True 1960 got_s.add(s) 1961 if not hit: 1962 raise NotImplementedError('could not solve %s' % eq2) 1963 else: 1964 result = newresult 1965 for b in bad_results: 1966 if b in result: 1967 result.remove(b) 1968 1969 default_simplify = bool(failed) # rely on system-solvers to simplify 1970 if flags.get('simplify', default_simplify): 1971 for r in result: 1972 for k in r: 1973 r[k] = simplify(r[k]) 1974 flags['simplify'] = False # don't need to do so in checksol now 1975 1976 if checkdens: 1977 result = [r for r in result 1978 if not any(checksol(d, r, **flags) for d in dens)] 1979 1980 if check and not linear: 1981 result = [r for r in result 1982 if not any(checksol(e, r, **flags) is False for e in exprs)] 1983 1984 result = [r for r in result if r] 1985 if linear and result: 1986 result = result[0] 1987 return result 1988 1989 1990def solve_linear(lhs, rhs=0, symbols=[], exclude=[]): 1991 r""" 1992 Return a tuple derived from ``f = lhs - rhs`` that is one of 1993 the following: ``(0, 1)``, ``(0, 0)``, ``(symbol, solution)``, ``(n, d)``. 1994 1995 Explanation 1996 =========== 1997 1998 ``(0, 1)`` meaning that ``f`` is independent of the symbols in *symbols* 1999 that are not in *exclude*. 2000 2001 ``(0, 0)`` meaning that there is no solution to the equation amongst the 2002 symbols given. If the first element of the tuple is not zero, then the 2003 function is guaranteed to be dependent on a symbol in *symbols*. 2004 2005 ``(symbol, solution)`` where symbol appears linearly in the numerator of 2006 ``f``, is in *symbols* (if given), and is not in *exclude* (if given). No 2007 simplification is done to ``f`` other than a ``mul=True`` expansion, so the 2008 solution will correspond strictly to a unique solution. 2009 2010 ``(n, d)`` where ``n`` and ``d`` are the numerator and denominator of ``f`` 2011 when the numerator was not linear in any symbol of interest; ``n`` will 2012 never be a symbol unless a solution for that symbol was found (in which case 2013 the second element is the solution, not the denominator). 2014 2015 Examples 2016 ======== 2017 2018 >>> from sympy.core.power import Pow 2019 >>> from sympy.polys.polytools import cancel 2020 2021 ``f`` is independent of the symbols in *symbols* that are not in 2022 *exclude*: 2023 2024 >>> from sympy.solvers.solvers import solve_linear 2025 >>> from sympy.abc import x, y, z 2026 >>> from sympy import cos, sin 2027 >>> eq = y*cos(x)**2 + y*sin(x)**2 - y # = y*(1 - 1) = 0 2028 >>> solve_linear(eq) 2029 (0, 1) 2030 >>> eq = cos(x)**2 + sin(x)**2 # = 1 2031 >>> solve_linear(eq) 2032 (0, 1) 2033 >>> solve_linear(x, exclude=[x]) 2034 (0, 1) 2035 2036 The variable ``x`` appears as a linear variable in each of the 2037 following: 2038 2039 >>> solve_linear(x + y**2) 2040 (x, -y**2) 2041 >>> solve_linear(1/x - y**2) 2042 (x, y**(-2)) 2043 2044 When not linear in ``x`` or ``y`` then the numerator and denominator are 2045 returned: 2046 2047 >>> solve_linear(x**2/y**2 - 3) 2048 (x**2 - 3*y**2, y**2) 2049 2050 If the numerator of the expression is a symbol, then ``(0, 0)`` is 2051 returned if the solution for that symbol would have set any 2052 denominator to 0: 2053 2054 >>> eq = 1/(1/x - 2) 2055 >>> eq.as_numer_denom() 2056 (x, 1 - 2*x) 2057 >>> solve_linear(eq) 2058 (0, 0) 2059 2060 But automatic rewriting may cause a symbol in the denominator to 2061 appear in the numerator so a solution will be returned: 2062 2063 >>> (1/x)**-1 2064 x 2065 >>> solve_linear((1/x)**-1) 2066 (x, 0) 2067 2068 Use an unevaluated expression to avoid this: 2069 2070 >>> solve_linear(Pow(1/x, -1, evaluate=False)) 2071 (0, 0) 2072 2073 If ``x`` is allowed to cancel in the following expression, then it 2074 appears to be linear in ``x``, but this sort of cancellation is not 2075 done by ``solve_linear`` so the solution will always satisfy the 2076 original expression without causing a division by zero error. 2077 2078 >>> eq = x**2*(1/x - z**2/x) 2079 >>> solve_linear(cancel(eq)) 2080 (x, 0) 2081 >>> solve_linear(eq) 2082 (x**2*(1 - z**2), x) 2083 2084 A list of symbols for which a solution is desired may be given: 2085 2086 >>> solve_linear(x + y + z, symbols=[y]) 2087 (y, -x - z) 2088 2089 A list of symbols to ignore may also be given: 2090 2091 >>> solve_linear(x + y + z, exclude=[x]) 2092 (y, -x - z) 2093 2094 (A solution for ``y`` is obtained because it is the first variable 2095 from the canonically sorted list of symbols that had a linear 2096 solution.) 2097 2098 """ 2099 if isinstance(lhs, Equality): 2100 if rhs: 2101 raise ValueError(filldedent(''' 2102 If lhs is an Equality, rhs must be 0 but was %s''' % rhs)) 2103 rhs = lhs.rhs 2104 lhs = lhs.lhs 2105 dens = None 2106 eq = lhs - rhs 2107 n, d = eq.as_numer_denom() 2108 if not n: 2109 return S.Zero, S.One 2110 2111 free = n.free_symbols 2112 if not symbols: 2113 symbols = free 2114 else: 2115 bad = [s for s in symbols if not s.is_Symbol] 2116 if bad: 2117 if len(bad) == 1: 2118 bad = bad[0] 2119 if len(symbols) == 1: 2120 eg = 'solve(%s, %s)' % (eq, symbols[0]) 2121 else: 2122 eg = 'solve(%s, *%s)' % (eq, list(symbols)) 2123 raise ValueError(filldedent(''' 2124 solve_linear only handles symbols, not %s. To isolate 2125 non-symbols use solve, e.g. >>> %s <<<. 2126 ''' % (bad, eg))) 2127 symbols = free.intersection(symbols) 2128 symbols = symbols.difference(exclude) 2129 if not symbols: 2130 return S.Zero, S.One 2131 2132 # derivatives are easy to do but tricky to analyze to see if they 2133 # are going to disallow a linear solution, so for simplicity we 2134 # just evaluate the ones that have the symbols of interest 2135 derivs = defaultdict(list) 2136 for der in n.atoms(Derivative): 2137 csym = der.free_symbols & symbols 2138 for c in csym: 2139 derivs[c].append(der) 2140 2141 all_zero = True 2142 for xi in sorted(symbols, key=default_sort_key): # canonical order 2143 # if there are derivatives in this var, calculate them now 2144 if isinstance(derivs[xi], list): 2145 derivs[xi] = {der: der.doit() for der in derivs[xi]} 2146 newn = n.subs(derivs[xi]) 2147 dnewn_dxi = newn.diff(xi) 2148 # dnewn_dxi can be nonzero if it survives differentation by any 2149 # of its free symbols 2150 free = dnewn_dxi.free_symbols 2151 if dnewn_dxi and (not free or any(dnewn_dxi.diff(s) for s in free) or free == symbols): 2152 all_zero = False 2153 if dnewn_dxi is S.NaN: 2154 break 2155 if xi not in dnewn_dxi.free_symbols: 2156 vi = -1/dnewn_dxi*(newn.subs(xi, 0)) 2157 if dens is None: 2158 dens = _simple_dens(eq, symbols) 2159 if not any(checksol(di, {xi: vi}, minimal=True) is True 2160 for di in dens): 2161 # simplify any trivial integral 2162 irep = [(i, i.doit()) for i in vi.atoms(Integral) if 2163 i.function.is_number] 2164 # do a slight bit of simplification 2165 vi = expand_mul(vi.subs(irep)) 2166 return xi, vi 2167 if all_zero: 2168 return S.Zero, S.One 2169 if n.is_Symbol: # no solution for this symbol was found 2170 return S.Zero, S.Zero 2171 return n, d 2172 2173 2174def minsolve_linear_system(system, *symbols, **flags): 2175 r""" 2176 Find a particular solution to a linear system. 2177 2178 Explanation 2179 =========== 2180 2181 In particular, try to find a solution with the minimal possible number 2182 of non-zero variables using a naive algorithm with exponential complexity. 2183 If ``quick=True``, a heuristic is used. 2184 2185 """ 2186 quick = flags.get('quick', False) 2187 # Check if there are any non-zero solutions at all 2188 s0 = solve_linear_system(system, *symbols, **flags) 2189 if not s0 or all(v == 0 for v in s0.values()): 2190 return s0 2191 if quick: 2192 # We just solve the system and try to heuristically find a nice 2193 # solution. 2194 s = solve_linear_system(system, *symbols) 2195 def update(determined, solution): 2196 delete = [] 2197 for k, v in solution.items(): 2198 solution[k] = v.subs(determined) 2199 if not solution[k].free_symbols: 2200 delete.append(k) 2201 determined[k] = solution[k] 2202 for k in delete: 2203 del solution[k] 2204 determined = {} 2205 update(determined, s) 2206 while s: 2207 # NOTE sort by default_sort_key to get deterministic result 2208 k = max((k for k in s.values()), 2209 key=lambda x: (len(x.free_symbols), default_sort_key(x))) 2210 x = max(k.free_symbols, key=default_sort_key) 2211 if len(k.free_symbols) != 1: 2212 determined[x] = S.Zero 2213 else: 2214 val = solve(k)[0] 2215 if val == 0 and all(v.subs(x, val) == 0 for v in s.values()): 2216 determined[x] = S.One 2217 else: 2218 determined[x] = val 2219 update(determined, s) 2220 return determined 2221 else: 2222 # We try to select n variables which we want to be non-zero. 2223 # All others will be assumed zero. We try to solve the modified system. 2224 # If there is a non-trivial solution, just set the free variables to 2225 # one. If we do this for increasing n, trying all combinations of 2226 # variables, we will find an optimal solution. 2227 # We speed up slightly by starting at one less than the number of 2228 # variables the quick method manages. 2229 from itertools import combinations 2230 from sympy.utilities.misc import debug 2231 N = len(symbols) 2232 bestsol = minsolve_linear_system(system, *symbols, quick=True) 2233 n0 = len([x for x in bestsol.values() if x != 0]) 2234 for n in range(n0 - 1, 1, -1): 2235 debug('minsolve: %s' % n) 2236 thissol = None 2237 for nonzeros in combinations(list(range(N)), n): 2238 subm = Matrix([system.col(i).T for i in nonzeros] + [system.col(-1).T]).T 2239 s = solve_linear_system(subm, *[symbols[i] for i in nonzeros]) 2240 if s and not all(v == 0 for v in s.values()): 2241 subs = [(symbols[v], S.One) for v in nonzeros] 2242 for k, v in s.items(): 2243 s[k] = v.subs(subs) 2244 for sym in symbols: 2245 if sym not in s: 2246 if symbols.index(sym) in nonzeros: 2247 s[sym] = S.One 2248 else: 2249 s[sym] = S.Zero 2250 thissol = s 2251 break 2252 if thissol is None: 2253 break 2254 bestsol = thissol 2255 return bestsol 2256 2257 2258def solve_linear_system(system, *symbols, **flags): 2259 r""" 2260 Solve system of $N$ linear equations with $M$ variables, which means 2261 both under- and overdetermined systems are supported. 2262 2263 Explanation 2264 =========== 2265 2266 The possible number of solutions is zero, one, or infinite. Respectively, 2267 this procedure will return None or a dictionary with solutions. In the 2268 case of underdetermined systems, all arbitrary parameters are skipped. 2269 This may cause a situation in which an empty dictionary is returned. 2270 In that case, all symbols can be assigned arbitrary values. 2271 2272 Input to this function is a $N\times M + 1$ matrix, which means it has 2273 to be in augmented form. If you prefer to enter $N$ equations and $M$ 2274 unknowns then use ``solve(Neqs, *Msymbols)`` instead. Note: a local 2275 copy of the matrix is made by this routine so the matrix that is 2276 passed will not be modified. 2277 2278 The algorithm used here is fraction-free Gaussian elimination, 2279 which results, after elimination, in an upper-triangular matrix. 2280 Then solutions are found using back-substitution. This approach 2281 is more efficient and compact than the Gauss-Jordan method. 2282 2283 Examples 2284 ======== 2285 2286 >>> from sympy import Matrix, solve_linear_system 2287 >>> from sympy.abc import x, y 2288 2289 Solve the following system:: 2290 2291 x + 4 y == 2 2292 -2 x + y == 14 2293 2294 >>> system = Matrix(( (1, 4, 2), (-2, 1, 14))) 2295 >>> solve_linear_system(system, x, y) 2296 {x: -6, y: 2} 2297 2298 A degenerate system returns an empty dictionary: 2299 2300 >>> system = Matrix(( (0,0,0), (0,0,0) )) 2301 >>> solve_linear_system(system, x, y) 2302 {} 2303 2304 """ 2305 assert system.shape[1] == len(symbols) + 1 2306 2307 # This is just a wrapper for solve_lin_sys 2308 eqs = list(system * Matrix(symbols + (-1,))) 2309 eqs, ring = sympy_eqs_to_ring(eqs, symbols) 2310 sol = solve_lin_sys(eqs, ring, _raw=False) 2311 if sol is not None: 2312 sol = {sym:val for sym, val in sol.items() if sym != val} 2313 return sol 2314 2315 2316def solve_undetermined_coeffs(equ, coeffs, sym, **flags): 2317 r""" 2318 Solve equation of a type $p(x; a_1, \ldots, a_k) = q(x)$ where both 2319 $p$ and $q$ are univariate polynomials that depend on $k$ parameters. 2320 2321 Explanation 2322 =========== 2323 2324 The result of this function is a dictionary with symbolic values of those 2325 parameters with respect to coefficients in $q$. 2326 2327 This function accepts both equations class instances and ordinary 2328 SymPy expressions. Specification of parameters and variables is 2329 obligatory for efficiency and simplicity reasons. 2330 2331 Examples 2332 ======== 2333 2334 >>> from sympy import Eq 2335 >>> from sympy.abc import a, b, c, x 2336 >>> from sympy.solvers import solve_undetermined_coeffs 2337 2338 >>> solve_undetermined_coeffs(Eq(2*a*x + a+b, x), [a, b], x) 2339 {a: 1/2, b: -1/2} 2340 2341 >>> solve_undetermined_coeffs(Eq(a*c*x + a+b, x), [a, b], x) 2342 {a: 1/c, b: -1/c} 2343 2344 """ 2345 if isinstance(equ, Equality): 2346 # got equation, so move all the 2347 # terms to the left hand side 2348 equ = equ.lhs - equ.rhs 2349 2350 equ = cancel(equ).as_numer_denom()[0] 2351 2352 system = list(collect(equ.expand(), sym, evaluate=False).values()) 2353 2354 if not any(equ.has(sym) for equ in system): 2355 # consecutive powers in the input expressions have 2356 # been successfully collected, so solve remaining 2357 # system using Gaussian elimination algorithm 2358 return solve(system, *coeffs, **flags) 2359 else: 2360 return None # no solutions 2361 2362 2363def solve_linear_system_LU(matrix, syms): 2364 """ 2365 Solves the augmented matrix system using ``LUsolve`` and returns a 2366 dictionary in which solutions are keyed to the symbols of *syms* as ordered. 2367 2368 Explanation 2369 =========== 2370 2371 The matrix must be invertible. 2372 2373 Examples 2374 ======== 2375 2376 >>> from sympy import Matrix 2377 >>> from sympy.abc import x, y, z 2378 >>> from sympy.solvers.solvers import solve_linear_system_LU 2379 2380 >>> solve_linear_system_LU(Matrix([ 2381 ... [1, 2, 0, 1], 2382 ... [3, 2, 2, 1], 2383 ... [2, 0, 0, 1]]), [x, y, z]) 2384 {x: 1/2, y: 1/4, z: -1/2} 2385 2386 See Also 2387 ======== 2388 2389 LUsolve 2390 2391 """ 2392 if matrix.rows != matrix.cols - 1: 2393 raise ValueError("Rows should be equal to columns - 1") 2394 A = matrix[:matrix.rows, :matrix.rows] 2395 b = matrix[:, matrix.cols - 1:] 2396 soln = A.LUsolve(b) 2397 solutions = {} 2398 for i in range(soln.rows): 2399 solutions[syms[i]] = soln[i, 0] 2400 return solutions 2401 2402 2403def det_perm(M): 2404 """ 2405 Return the determinant of *M* by using permutations to select factors. 2406 2407 Explanation 2408 =========== 2409 2410 For sizes larger than 8 the number of permutations becomes prohibitively 2411 large, or if there are no symbols in the matrix, it is better to use the 2412 standard determinant routines (e.g., ``M.det()``.) 2413 2414 See Also 2415 ======== 2416 2417 det_minor 2418 det_quick 2419 2420 """ 2421 args = [] 2422 s = True 2423 n = M.rows 2424 list_ = M.flat() 2425 for perm in generate_bell(n): 2426 fac = [] 2427 idx = 0 2428 for j in perm: 2429 fac.append(list_[idx + j]) 2430 idx += n 2431 term = Mul(*fac) # disaster with unevaluated Mul -- takes forever for n=7 2432 args.append(term if s else -term) 2433 s = not s 2434 return Add(*args) 2435 2436 2437def det_minor(M): 2438 """ 2439 Return the ``det(M)`` computed from minors without 2440 introducing new nesting in products. 2441 2442 See Also 2443 ======== 2444 2445 det_perm 2446 det_quick 2447 2448 """ 2449 n = M.rows 2450 if n == 2: 2451 return M[0, 0]*M[1, 1] - M[1, 0]*M[0, 1] 2452 else: 2453 return sum([(1, -1)[i % 2]*Add(*[M[0, i]*d for d in 2454 Add.make_args(det_minor(M.minor_submatrix(0, i)))]) 2455 if M[0, i] else S.Zero for i in range(n)]) 2456 2457 2458def det_quick(M, method=None): 2459 """ 2460 Return ``det(M)`` assuming that either 2461 there are lots of zeros or the size of the matrix 2462 is small. If this assumption is not met, then the normal 2463 Matrix.det function will be used with method = ``method``. 2464 2465 See Also 2466 ======== 2467 2468 det_minor 2469 det_perm 2470 2471 """ 2472 if any(i.has(Symbol) for i in M): 2473 if M.rows < 8 and all(i.has(Symbol) for i in M): 2474 return det_perm(M) 2475 return det_minor(M) 2476 else: 2477 return M.det(method=method) if method else M.det() 2478 2479 2480def inv_quick(M): 2481 """Return the inverse of ``M``, assuming that either 2482 there are lots of zeros or the size of the matrix 2483 is small. 2484 """ 2485 from sympy.matrices import zeros 2486 if not all(i.is_Number for i in M): 2487 if not any(i.is_Number for i in M): 2488 det = lambda _: det_perm(_) 2489 else: 2490 det = lambda _: det_minor(_) 2491 else: 2492 return M.inv() 2493 n = M.rows 2494 d = det(M) 2495 if d == S.Zero: 2496 raise NonInvertibleMatrixError("Matrix det == 0; not invertible") 2497 ret = zeros(n) 2498 s1 = -1 2499 for i in range(n): 2500 s = s1 = -s1 2501 for j in range(n): 2502 di = det(M.minor_submatrix(i, j)) 2503 ret[j, i] = s*di/d 2504 s = -s 2505 return ret 2506 2507 2508# these are functions that have multiple inverse values per period 2509multi_inverses = { 2510 sin: lambda x: (asin(x), S.Pi - asin(x)), 2511 cos: lambda x: (acos(x), 2*S.Pi - acos(x)), 2512} 2513 2514 2515def _tsolve(eq, sym, **flags): 2516 """ 2517 Helper for ``_solve`` that solves a transcendental equation with respect 2518 to the given symbol. Various equations containing powers and logarithms, 2519 can be solved. 2520 2521 There is currently no guarantee that all solutions will be returned or 2522 that a real solution will be favored over a complex one. 2523 2524 Either a list of potential solutions will be returned or None will be 2525 returned (in the case that no method was known to get a solution 2526 for the equation). All other errors (like the inability to cast an 2527 expression as a Poly) are unhandled. 2528 2529 Examples 2530 ======== 2531 2532 >>> from sympy import log 2533 >>> from sympy.solvers.solvers import _tsolve as tsolve 2534 >>> from sympy.abc import x 2535 2536 >>> tsolve(3**(2*x + 5) - 4, x) 2537 [-5/2 + log(2)/log(3), (-5*log(3)/2 + log(2) + I*pi)/log(3)] 2538 2539 >>> tsolve(log(x) + 2*x, x) 2540 [LambertW(2)/2] 2541 2542 """ 2543 if 'tsolve_saw' not in flags: 2544 flags['tsolve_saw'] = [] 2545 if eq in flags['tsolve_saw']: 2546 return None 2547 else: 2548 flags['tsolve_saw'].append(eq) 2549 2550 rhs, lhs = _invert(eq, sym) 2551 2552 if lhs == sym: 2553 return [rhs] 2554 try: 2555 if lhs.is_Add: 2556 # it's time to try factoring; powdenest is used 2557 # to try get powers in standard form for better factoring 2558 f = factor(powdenest(lhs - rhs)) 2559 if f.is_Mul: 2560 return _solve(f, sym, **flags) 2561 if rhs: 2562 f = logcombine(lhs, force=flags.get('force', True)) 2563 if f.count(log) != lhs.count(log): 2564 if isinstance(f, log): 2565 return _solve(f.args[0] - exp(rhs), sym, **flags) 2566 return _tsolve(f - rhs, sym, **flags) 2567 2568 elif lhs.is_Pow: 2569 if lhs.exp.is_Integer: 2570 if lhs - rhs != eq: 2571 return _solve(lhs - rhs, sym, **flags) 2572 2573 if sym not in lhs.exp.free_symbols: 2574 return _solve(lhs.base - rhs**(1/lhs.exp), sym, **flags) 2575 2576 # _tsolve calls this with Dummy before passing the actual number in. 2577 if any(t.is_Dummy for t in rhs.free_symbols): 2578 raise NotImplementedError # _tsolve will call here again... 2579 2580 # a ** g(x) == 0 2581 if not rhs: 2582 # f(x)**g(x) only has solutions where f(x) == 0 and g(x) != 0 at 2583 # the same place 2584 sol_base = _solve(lhs.base, sym, **flags) 2585 return [s for s in sol_base if lhs.exp.subs(sym, s) != 0] 2586 2587 # a ** g(x) == b 2588 if not lhs.base.has(sym): 2589 if lhs.base == 0: 2590 return _solve(lhs.exp, sym, **flags) if rhs != 0 else [] 2591 2592 # Gets most solutions... 2593 if lhs.base == rhs.as_base_exp()[0]: 2594 # handles case when bases are equal 2595 sol = _solve(lhs.exp - rhs.as_base_exp()[1], sym, **flags) 2596 else: 2597 # handles cases when bases are not equal and exp 2598 # may or may not be equal 2599 sol = _solve(exp(log(lhs.base)*lhs.exp)-exp(log(rhs)), sym, **flags) 2600 2601 # Check for duplicate solutions 2602 def equal(expr1, expr2): 2603 _ = Dummy() 2604 eq = checksol(expr1 - _, _, expr2) 2605 if eq is None: 2606 if nsimplify(expr1) != nsimplify(expr2): 2607 return False 2608 # they might be coincidentally the same 2609 # so check more rigorously 2610 eq = expr1.equals(expr2) 2611 return eq 2612 2613 # Guess a rational exponent 2614 e_rat = nsimplify(log(abs(rhs))/log(abs(lhs.base))) 2615 e_rat = simplify(posify(e_rat)[0]) 2616 n, d = fraction(e_rat) 2617 if expand(lhs.base**n - rhs**d) == 0: 2618 sol = [s for s in sol if not equal(lhs.exp.subs(sym, s), e_rat)] 2619 sol.extend(_solve(lhs.exp - e_rat, sym, **flags)) 2620 2621 return list(ordered(set(sol))) 2622 2623 # f(x) ** g(x) == c 2624 else: 2625 sol = [] 2626 logform = lhs.exp*log(lhs.base) - log(rhs) 2627 if logform != lhs - rhs: 2628 try: 2629 sol.extend(_solve(logform, sym, **flags)) 2630 except NotImplementedError: 2631 pass 2632 2633 # Collect possible solutions and check with substitution later. 2634 check = [] 2635 if rhs == 1: 2636 # f(x) ** g(x) = 1 -- g(x)=0 or f(x)=+-1 2637 check.extend(_solve(lhs.exp, sym, **flags)) 2638 check.extend(_solve(lhs.base - 1, sym, **flags)) 2639 check.extend(_solve(lhs.base + 1, sym, **flags)) 2640 elif rhs.is_Rational: 2641 for d in (i for i in divisors(abs(rhs.p)) if i != 1): 2642 e, t = integer_log(rhs.p, d) 2643 if not t: 2644 continue # rhs.p != d**b 2645 for s in divisors(abs(rhs.q)): 2646 if s**e== rhs.q: 2647 r = Rational(d, s) 2648 check.extend(_solve(lhs.base - r, sym, **flags)) 2649 check.extend(_solve(lhs.base + r, sym, **flags)) 2650 check.extend(_solve(lhs.exp - e, sym, **flags)) 2651 elif rhs.is_irrational: 2652 b_l, e_l = lhs.base.as_base_exp() 2653 n, d = (e_l*lhs.exp).as_numer_denom() 2654 b, e = sqrtdenest(rhs).as_base_exp() 2655 check = [sqrtdenest(i) for i in (_solve(lhs.base - b, sym, **flags))] 2656 check.extend([sqrtdenest(i) for i in (_solve(lhs.exp - e, sym, **flags))]) 2657 if e_l*d != 1: 2658 check.extend(_solve(b_l**n - rhs**(e_l*d), sym, **flags)) 2659 for s in check: 2660 ok = checksol(eq, sym, s) 2661 if ok is None: 2662 ok = eq.subs(sym, s).equals(0) 2663 if ok: 2664 sol.append(s) 2665 return list(ordered(set(sol))) 2666 2667 elif lhs.is_Function and len(lhs.args) == 1: 2668 if lhs.func in multi_inverses: 2669 # sin(x) = 1/3 -> x - asin(1/3) & x - (pi - asin(1/3)) 2670 soln = [] 2671 for i in multi_inverses[lhs.func](rhs): 2672 soln.extend(_solve(lhs.args[0] - i, sym, **flags)) 2673 return list(ordered(soln)) 2674 elif lhs.func == LambertW: 2675 return _solve(lhs.args[0] - rhs*exp(rhs), sym, **flags) 2676 2677 rewrite = lhs.rewrite(exp) 2678 if rewrite != lhs: 2679 return _solve(rewrite - rhs, sym, **flags) 2680 except NotImplementedError: 2681 pass 2682 2683 # maybe it is a lambert pattern 2684 if flags.pop('bivariate', True): 2685 # lambert forms may need some help being recognized, e.g. changing 2686 # 2**(3*x) + x**3*log(2)**3 + 3*x**2*log(2)**2 + 3*x*log(2) + 1 2687 # to 2**(3*x) + (x*log(2) + 1)**3 2688 g = _filtered_gens(eq.as_poly(), sym) 2689 up_or_log = set() 2690 for gi in g: 2691 if isinstance(gi, exp) or (gi.is_Pow and gi.base == S.Exp1) or isinstance(gi, log): 2692 up_or_log.add(gi) 2693 elif gi.is_Pow: 2694 gisimp = powdenest(expand_power_exp(gi)) 2695 if gisimp.is_Pow and sym in gisimp.exp.free_symbols: 2696 up_or_log.add(gi) 2697 eq_down = expand_log(expand_power_exp(eq)).subs( 2698 dict(list(zip(up_or_log, [0]*len(up_or_log))))) 2699 eq = expand_power_exp(factor(eq_down, deep=True) + (eq - eq_down)) 2700 rhs, lhs = _invert(eq, sym) 2701 if lhs.has(sym): 2702 try: 2703 poly = lhs.as_poly() 2704 g = _filtered_gens(poly, sym) 2705 _eq = lhs - rhs 2706 sols = _solve_lambert(_eq, sym, g) 2707 # use a simplified form if it satisfies eq 2708 # and has fewer operations 2709 for n, s in enumerate(sols): 2710 ns = nsimplify(s) 2711 if ns != s and ns.count_ops() <= s.count_ops(): 2712 ok = checksol(_eq, sym, ns) 2713 if ok is None: 2714 ok = _eq.subs(sym, ns).equals(0) 2715 if ok: 2716 sols[n] = ns 2717 return sols 2718 except NotImplementedError: 2719 # maybe it's a convoluted function 2720 if len(g) == 2: 2721 try: 2722 gpu = bivariate_type(lhs - rhs, *g) 2723 if gpu is None: 2724 raise NotImplementedError 2725 g, p, u = gpu 2726 flags['bivariate'] = False 2727 inversion = _tsolve(g - u, sym, **flags) 2728 if inversion: 2729 sol = _solve(p, u, **flags) 2730 return list(ordered({i.subs(u, s) 2731 for i in inversion for s in sol})) 2732 except NotImplementedError: 2733 pass 2734 else: 2735 pass 2736 2737 if flags.pop('force', True): 2738 flags['force'] = False 2739 pos, reps = posify(lhs - rhs) 2740 if rhs == S.ComplexInfinity: 2741 return [] 2742 for u, s in reps.items(): 2743 if s == sym: 2744 break 2745 else: 2746 u = sym 2747 if pos.has(u): 2748 try: 2749 soln = _solve(pos, u, **flags) 2750 return list(ordered([s.subs(reps) for s in soln])) 2751 except NotImplementedError: 2752 pass 2753 else: 2754 pass # here for coverage 2755 2756 return # here for coverage 2757 2758 2759# TODO: option for calculating J numerically 2760 2761@conserve_mpmath_dps 2762def nsolve(*args, dict=False, **kwargs): 2763 r""" 2764 Solve a nonlinear equation system numerically: ``nsolve(f, [args,] x0, 2765 modules=['mpmath'], **kwargs)``. 2766 2767 Explanation 2768 =========== 2769 2770 ``f`` is a vector function of symbolic expressions representing the system. 2771 *args* are the variables. If there is only one variable, this argument can 2772 be omitted. ``x0`` is a starting vector close to a solution. 2773 2774 Use the modules keyword to specify which modules should be used to 2775 evaluate the function and the Jacobian matrix. Make sure to use a module 2776 that supports matrices. For more information on the syntax, please see the 2777 docstring of ``lambdify``. 2778 2779 If the keyword arguments contain ``dict=True`` (default is False) ``nsolve`` 2780 will return a list (perhaps empty) of solution mappings. This might be 2781 especially useful if you want to use ``nsolve`` as a fallback to solve since 2782 using the dict argument for both methods produces return values of 2783 consistent type structure. Please note: to keep this consistent with 2784 ``solve``, the solution will be returned in a list even though ``nsolve`` 2785 (currently at least) only finds one solution at a time. 2786 2787 Overdetermined systems are supported. 2788 2789 Examples 2790 ======== 2791 2792 >>> from sympy import Symbol, nsolve 2793 >>> import mpmath 2794 >>> mpmath.mp.dps = 15 2795 >>> x1 = Symbol('x1') 2796 >>> x2 = Symbol('x2') 2797 >>> f1 = 3 * x1**2 - 2 * x2**2 - 1 2798 >>> f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8 2799 >>> print(nsolve((f1, f2), (x1, x2), (-1, 1))) 2800 Matrix([[-1.19287309935246], [1.27844411169911]]) 2801 2802 For one-dimensional functions the syntax is simplified: 2803 2804 >>> from sympy import sin, nsolve 2805 >>> from sympy.abc import x 2806 >>> nsolve(sin(x), x, 2) 2807 3.14159265358979 2808 >>> nsolve(sin(x), 2) 2809 3.14159265358979 2810 2811 To solve with higher precision than the default, use the prec argument: 2812 2813 >>> from sympy import cos 2814 >>> nsolve(cos(x) - x, 1) 2815 0.739085133215161 2816 >>> nsolve(cos(x) - x, 1, prec=50) 2817 0.73908513321516064165531208767387340401341175890076 2818 >>> cos(_) 2819 0.73908513321516064165531208767387340401341175890076 2820 2821 To solve for complex roots of real functions, a nonreal initial point 2822 must be specified: 2823 2824 >>> from sympy import I 2825 >>> nsolve(x**2 + 2, I) 2826 1.4142135623731*I 2827 2828 ``mpmath.findroot`` is used and you can find their more extensive 2829 documentation, especially concerning keyword parameters and 2830 available solvers. Note, however, that functions which are very 2831 steep near the root, the verification of the solution may fail. In 2832 this case you should use the flag ``verify=False`` and 2833 independently verify the solution. 2834 2835 >>> from sympy import cos, cosh 2836 >>> f = cos(x)*cosh(x) - 1 2837 >>> nsolve(f, 3.14*100) 2838 Traceback (most recent call last): 2839 ... 2840 ValueError: Could not find root within given tolerance. (1.39267e+230 > 2.1684e-19) 2841 >>> ans = nsolve(f, 3.14*100, verify=False); ans 2842 312.588469032184 2843 >>> f.subs(x, ans).n(2) 2844 2.1e+121 2845 >>> (f/f.diff(x)).subs(x, ans).n(2) 2846 7.4e-15 2847 2848 One might safely skip the verification if bounds of the root are known 2849 and a bisection method is used: 2850 2851 >>> bounds = lambda i: (3.14*i, 3.14*(i + 1)) 2852 >>> nsolve(f, bounds(100), solver='bisect', verify=False) 2853 315.730061685774 2854 2855 Alternatively, a function may be better behaved when the 2856 denominator is ignored. Since this is not always the case, however, 2857 the decision of what function to use is left to the discretion of 2858 the user. 2859 2860 >>> eq = x**2/(1 - x)/(1 - 2*x)**2 - 100 2861 >>> nsolve(eq, 0.46) 2862 Traceback (most recent call last): 2863 ... 2864 ValueError: Could not find root within given tolerance. (10000 > 2.1684e-19) 2865 Try another starting point or tweak arguments. 2866 >>> nsolve(eq.as_numer_denom()[0], 0.46) 2867 0.46792545969349058 2868 2869 """ 2870 # there are several other SymPy functions that use method= so 2871 # guard against that here 2872 if 'method' in kwargs: 2873 raise ValueError(filldedent(''' 2874 Keyword "method" should not be used in this context. When using 2875 some mpmath solvers directly, the keyword "method" is 2876 used, but when using nsolve (and findroot) the keyword to use is 2877 "solver".''')) 2878 2879 if 'prec' in kwargs: 2880 prec = kwargs.pop('prec') 2881 import mpmath 2882 mpmath.mp.dps = prec 2883 else: 2884 prec = None 2885 2886 # keyword argument to return result as a dictionary 2887 as_dict = dict 2888 from builtins import dict # to unhide the builtin 2889 2890 # interpret arguments 2891 if len(args) == 3: 2892 f = args[0] 2893 fargs = args[1] 2894 x0 = args[2] 2895 if iterable(fargs) and iterable(x0): 2896 if len(x0) != len(fargs): 2897 raise TypeError('nsolve expected exactly %i guess vectors, got %i' 2898 % (len(fargs), len(x0))) 2899 elif len(args) == 2: 2900 f = args[0] 2901 fargs = None 2902 x0 = args[1] 2903 if iterable(f): 2904 raise TypeError('nsolve expected 3 arguments, got 2') 2905 elif len(args) < 2: 2906 raise TypeError('nsolve expected at least 2 arguments, got %i' 2907 % len(args)) 2908 else: 2909 raise TypeError('nsolve expected at most 3 arguments, got %i' 2910 % len(args)) 2911 modules = kwargs.get('modules', ['mpmath']) 2912 if iterable(f): 2913 f = list(f) 2914 for i, fi in enumerate(f): 2915 if isinstance(fi, Equality): 2916 f[i] = fi.lhs - fi.rhs 2917 f = Matrix(f).T 2918 if iterable(x0): 2919 x0 = list(x0) 2920 if not isinstance(f, Matrix): 2921 # assume it's a sympy expression 2922 if isinstance(f, Equality): 2923 f = f.lhs - f.rhs 2924 syms = f.free_symbols 2925 if fargs is None: 2926 fargs = syms.copy().pop() 2927 if not (len(syms) == 1 and (fargs in syms or fargs[0] in syms)): 2928 raise ValueError(filldedent(''' 2929 expected a one-dimensional and numerical function''')) 2930 2931 # the function is much better behaved if there is no denominator 2932 # but sending the numerator is left to the user since sometimes 2933 # the function is better behaved when the denominator is present 2934 # e.g., issue 11768 2935 2936 f = lambdify(fargs, f, modules) 2937 x = sympify(findroot(f, x0, **kwargs)) 2938 if as_dict: 2939 return [{fargs: x}] 2940 return x 2941 2942 if len(fargs) > f.cols: 2943 raise NotImplementedError(filldedent(''' 2944 need at least as many equations as variables''')) 2945 verbose = kwargs.get('verbose', False) 2946 if verbose: 2947 print('f(x):') 2948 print(f) 2949 # derive Jacobian 2950 J = f.jacobian(fargs) 2951 if verbose: 2952 print('J(x):') 2953 print(J) 2954 # create functions 2955 f = lambdify(fargs, f.T, modules) 2956 J = lambdify(fargs, J, modules) 2957 # solve the system numerically 2958 x = findroot(f, x0, J=J, **kwargs) 2959 if as_dict: 2960 return [dict(zip(fargs, [sympify(xi) for xi in x]))] 2961 return Matrix(x) 2962 2963 2964def _invert(eq, *symbols, **kwargs): 2965 """ 2966 Return tuple (i, d) where ``i`` is independent of *symbols* and ``d`` 2967 contains symbols. 2968 2969 Explanation 2970 =========== 2971 2972 ``i`` and ``d`` are obtained after recursively using algebraic inversion 2973 until an uninvertible ``d`` remains. If there are no free symbols then 2974 ``d`` will be zero. Some (but not necessarily all) solutions to the 2975 expression ``i - d`` will be related to the solutions of the original 2976 expression. 2977 2978 Examples 2979 ======== 2980 2981 >>> from sympy.solvers.solvers import _invert as invert 2982 >>> from sympy import sqrt, cos 2983 >>> from sympy.abc import x, y 2984 >>> invert(x - 3) 2985 (3, x) 2986 >>> invert(3) 2987 (3, 0) 2988 >>> invert(2*cos(x) - 1) 2989 (1/2, cos(x)) 2990 >>> invert(sqrt(x) - 3) 2991 (3, sqrt(x)) 2992 >>> invert(sqrt(x) + y, x) 2993 (-y, sqrt(x)) 2994 >>> invert(sqrt(x) + y, y) 2995 (-sqrt(x), y) 2996 >>> invert(sqrt(x) + y, x, y) 2997 (0, sqrt(x) + y) 2998 2999 If there is more than one symbol in a power's base and the exponent 3000 is not an Integer, then the principal root will be used for the 3001 inversion: 3002 3003 >>> invert(sqrt(x + y) - 2) 3004 (4, x + y) 3005 >>> invert(sqrt(x + y) - 2) 3006 (4, x + y) 3007 3008 If the exponent is an Integer, setting ``integer_power`` to True 3009 will force the principal root to be selected: 3010 3011 >>> invert(x**2 - 4, integer_power=True) 3012 (2, x) 3013 3014 """ 3015 eq = sympify(eq) 3016 if eq.args: 3017 # make sure we are working with flat eq 3018 eq = eq.func(*eq.args) 3019 free = eq.free_symbols 3020 if not symbols: 3021 symbols = free 3022 if not free & set(symbols): 3023 return eq, S.Zero 3024 3025 dointpow = bool(kwargs.get('integer_power', False)) 3026 3027 lhs = eq 3028 rhs = S.Zero 3029 while True: 3030 was = lhs 3031 while True: 3032 indep, dep = lhs.as_independent(*symbols) 3033 3034 # dep + indep == rhs 3035 if lhs.is_Add: 3036 # this indicates we have done it all 3037 if indep.is_zero: 3038 break 3039 3040 lhs = dep 3041 rhs -= indep 3042 3043 # dep * indep == rhs 3044 else: 3045 # this indicates we have done it all 3046 if indep is S.One: 3047 break 3048 3049 lhs = dep 3050 rhs /= indep 3051 3052 # collect like-terms in symbols 3053 if lhs.is_Add: 3054 terms = {} 3055 for a in lhs.args: 3056 i, d = a.as_independent(*symbols) 3057 terms.setdefault(d, []).append(i) 3058 if any(len(v) > 1 for v in terms.values()): 3059 args = [] 3060 for d, i in terms.items(): 3061 if len(i) > 1: 3062 args.append(Add(*i)*d) 3063 else: 3064 args.append(i[0]*d) 3065 lhs = Add(*args) 3066 3067 # if it's a two-term Add with rhs = 0 and two powers we can get the 3068 # dependent terms together, e.g. 3*f(x) + 2*g(x) -> f(x)/g(x) = -2/3 3069 if lhs.is_Add and not rhs and len(lhs.args) == 2 and \ 3070 not lhs.is_polynomial(*symbols): 3071 a, b = ordered(lhs.args) 3072 ai, ad = a.as_independent(*symbols) 3073 bi, bd = b.as_independent(*symbols) 3074 if any(_ispow(i) for i in (ad, bd)): 3075 a_base, a_exp = ad.as_base_exp() 3076 b_base, b_exp = bd.as_base_exp() 3077 if a_base == b_base: 3078 # a = -b 3079 lhs = powsimp(powdenest(ad/bd)) 3080 rhs = -bi/ai 3081 else: 3082 rat = ad/bd 3083 _lhs = powsimp(ad/bd) 3084 if _lhs != rat: 3085 lhs = _lhs 3086 rhs = -bi/ai 3087 elif ai == -bi: 3088 if isinstance(ad, Function) and ad.func == bd.func: 3089 if len(ad.args) == len(bd.args) == 1: 3090 lhs = ad.args[0] - bd.args[0] 3091 elif len(ad.args) == len(bd.args): 3092 # should be able to solve 3093 # f(x, y) - f(2 - x, 0) == 0 -> x == 1 3094 raise NotImplementedError( 3095 'equal function with more than 1 argument') 3096 else: 3097 raise ValueError( 3098 'function with different numbers of args') 3099 3100 elif lhs.is_Mul and any(_ispow(a) for a in lhs.args): 3101 lhs = powsimp(powdenest(lhs)) 3102 3103 if lhs.is_Function: 3104 if hasattr(lhs, 'inverse') and lhs.inverse() is not None and len(lhs.args) == 1: 3105 # -1 3106 # f(x) = g -> x = f (g) 3107 # 3108 # /!\ inverse should not be defined if there are multiple values 3109 # for the function -- these are handled in _tsolve 3110 # 3111 rhs = lhs.inverse()(rhs) 3112 lhs = lhs.args[0] 3113 elif isinstance(lhs, atan2): 3114 y, x = lhs.args 3115 lhs = 2*atan(y/(sqrt(x**2 + y**2) + x)) 3116 elif lhs.func == rhs.func: 3117 if len(lhs.args) == len(rhs.args) == 1: 3118 lhs = lhs.args[0] 3119 rhs = rhs.args[0] 3120 elif len(lhs.args) == len(rhs.args): 3121 # should be able to solve 3122 # f(x, y) == f(2, 3) -> x == 2 3123 # f(x, x + y) == f(2, 3) -> x == 2 3124 raise NotImplementedError( 3125 'equal function with more than 1 argument') 3126 else: 3127 raise ValueError( 3128 'function with different numbers of args') 3129 3130 3131 if rhs and lhs.is_Pow and lhs.exp.is_Integer and lhs.exp < 0: 3132 lhs = 1/lhs 3133 rhs = 1/rhs 3134 3135 # base**a = b -> base = b**(1/a) if 3136 # a is an Integer and dointpow=True (this gives real branch of root) 3137 # a is not an Integer and the equation is multivariate and the 3138 # base has more than 1 symbol in it 3139 # The rationale for this is that right now the multi-system solvers 3140 # doesn't try to resolve generators to see, for example, if the whole 3141 # system is written in terms of sqrt(x + y) so it will just fail, so we 3142 # do that step here. 3143 if lhs.is_Pow and ( 3144 lhs.exp.is_Integer and dointpow or not lhs.exp.is_Integer and 3145 len(symbols) > 1 and len(lhs.base.free_symbols & set(symbols)) > 1): 3146 rhs = rhs**(1/lhs.exp) 3147 lhs = lhs.base 3148 3149 if lhs == was: 3150 break 3151 return rhs, lhs 3152 3153 3154def unrad(eq, *syms, **flags): 3155 """ 3156 Remove radicals with symbolic arguments and return (eq, cov), 3157 None, or raise an error. 3158 3159 Explanation 3160 =========== 3161 3162 None is returned if there are no radicals to remove. 3163 3164 NotImplementedError is raised if there are radicals and they cannot be 3165 removed or if the relationship between the original symbols and the 3166 change of variable needed to rewrite the system as a polynomial cannot 3167 be solved. 3168 3169 Otherwise the tuple, ``(eq, cov)``, is returned where: 3170 3171 *eq*, ``cov`` 3172 *eq* is an equation without radicals (in the symbol(s) of 3173 interest) whose solutions are a superset of the solutions to the 3174 original expression. *eq* might be rewritten in terms of a new 3175 variable; the relationship to the original variables is given by 3176 ``cov`` which is a list containing ``v`` and ``v**p - b`` where 3177 ``p`` is the power needed to clear the radical and ``b`` is the 3178 radical now expressed as a polynomial in the symbols of interest. 3179 For example, for sqrt(2 - x) the tuple would be 3180 ``(c, c**2 - 2 + x)``. The solutions of *eq* will contain 3181 solutions to the original equation (if there are any). 3182 3183 *syms* 3184 An iterable of symbols which, if provided, will limit the focus of 3185 radical removal: only radicals with one or more of the symbols of 3186 interest will be cleared. All free symbols are used if *syms* is not 3187 set. 3188 3189 *flags* are used internally for communication during recursive calls. 3190 Two options are also recognized: 3191 3192 ``take``, when defined, is interpreted as a single-argument function 3193 that returns True if a given Pow should be handled. 3194 3195 Radicals can be removed from an expression if: 3196 3197 * All bases of the radicals are the same; a change of variables is 3198 done in this case. 3199 * If all radicals appear in one term of the expression. 3200 * There are only four terms with sqrt() factors or there are less than 3201 four terms having sqrt() factors. 3202 * There are only two terms with radicals. 3203 3204 Examples 3205 ======== 3206 3207 >>> from sympy.solvers.solvers import unrad 3208 >>> from sympy.abc import x 3209 >>> from sympy import sqrt, Rational, root 3210 3211 >>> unrad(sqrt(x)*x**Rational(1, 3) + 2) 3212 (x**5 - 64, []) 3213 >>> unrad(sqrt(x) + root(x + 1, 3)) 3214 (-x**3 + x**2 + 2*x + 1, []) 3215 >>> eq = sqrt(x) + root(x, 3) - 2 3216 >>> unrad(eq) 3217 (_p**3 + _p**2 - 2, [_p, _p**6 - x]) 3218 3219 """ 3220 from sympy import Equality as Eq 3221 3222 uflags = dict(check=False, simplify=False) 3223 3224 def _cov(p, e): 3225 if cov: 3226 # XXX - uncovered 3227 oldp, olde = cov 3228 if Poly(e, p).degree(p) in (1, 2): 3229 cov[:] = [p, olde.subs(oldp, _solve(e, p, **uflags)[0])] 3230 else: 3231 raise NotImplementedError 3232 else: 3233 cov[:] = [p, e] 3234 3235 def _canonical(eq, cov): 3236 if cov: 3237 # change symbol to vanilla so no solutions are eliminated 3238 p, e = cov 3239 rep = {p: Dummy(p.name)} 3240 eq = eq.xreplace(rep) 3241 cov = [p.xreplace(rep), e.xreplace(rep)] 3242 3243 # remove constants and powers of factors since these don't change 3244 # the location of the root; XXX should factor or factor_terms be used? 3245 eq = factor_terms(_mexpand(eq.as_numer_denom()[0], recursive=True), clear=True) 3246 if eq.is_Mul: 3247 args = [] 3248 for f in eq.args: 3249 if f.is_number: 3250 continue 3251 if f.is_Pow: 3252 args.append(f.base) 3253 else: 3254 args.append(f) 3255 eq = Mul(*args) # leave as Mul for more efficient solving 3256 3257 # make the sign canonical 3258 margs = list(Mul.make_args(eq)) 3259 changed = False 3260 for i, m in enumerate(margs): 3261 if m.could_extract_minus_sign(): 3262 margs[i] = -m 3263 changed = True 3264 if changed: 3265 eq = Mul(*margs, evaluate=False) 3266 3267 return eq, cov 3268 3269 def _Q(pow): 3270 # return leading Rational of denominator of Pow's exponent 3271 c = pow.as_base_exp()[1].as_coeff_Mul()[0] 3272 if not c.is_Rational: 3273 return S.One 3274 return c.q 3275 3276 # define the _take method that will determine whether a term is of interest 3277 def _take(d): 3278 # return True if coefficient of any factor's exponent's den is not 1 3279 for pow in Mul.make_args(d): 3280 if not pow.is_Pow: 3281 continue 3282 if _Q(pow) == 1: 3283 continue 3284 if pow.free_symbols & syms: 3285 return True 3286 return False 3287 _take = flags.setdefault('_take', _take) 3288 3289 if isinstance(eq, Eq): 3290 eq = eq.lhs - eq.rhs # XXX legacy Eq as Eqn support 3291 elif not isinstance(eq, Expr): 3292 return 3293 3294 cov, nwas, rpt = [flags.setdefault(k, v) for k, v in 3295 sorted(dict(cov=[], n=None, rpt=0).items())] 3296 3297 # preconditioning 3298 eq = powdenest(factor_terms(eq, radical=True, clear=True)) 3299 eq = eq.as_numer_denom()[0] 3300 eq = _mexpand(eq, recursive=True) 3301 if eq.is_number: 3302 return 3303 3304 # see if there are radicals in symbols of interest 3305 syms = set(syms) or eq.free_symbols # _take uses this 3306 poly = eq.as_poly() 3307 gens = [g for g in poly.gens if _take(g)] 3308 if not gens: 3309 return 3310 3311 # recast poly in terms of eigen-gens 3312 poly = eq.as_poly(*gens) 3313 3314 # - an exponent has a symbol of interest (don't handle) 3315 if any(g.exp.has(*syms) for g in gens): 3316 return 3317 3318 def _rads_bases_lcm(poly): 3319 # if all the bases are the same or all the radicals are in one 3320 # term, `lcm` will be the lcm of the denominators of the 3321 # exponents of the radicals 3322 lcm = 1 3323 rads = set() 3324 bases = set() 3325 for g in poly.gens: 3326 q = _Q(g) 3327 if q != 1: 3328 rads.add(g) 3329 lcm = ilcm(lcm, q) 3330 bases.add(g.base) 3331 return rads, bases, lcm 3332 rads, bases, lcm = _rads_bases_lcm(poly) 3333 3334 covsym = Dummy('p', nonnegative=True) 3335 3336 # only keep in syms symbols that actually appear in radicals; 3337 # and update gens 3338 newsyms = set() 3339 for r in rads: 3340 newsyms.update(syms & r.free_symbols) 3341 if newsyms != syms: 3342 syms = newsyms 3343 # get terms together that have common generators 3344 drad = dict(list(zip(rads, list(range(len(rads)))))) 3345 rterms = {(): []} 3346 args = Add.make_args(poly.as_expr()) 3347 for t in args: 3348 if _take(t): 3349 common = set(t.as_poly().gens).intersection(rads) 3350 key = tuple(sorted([drad[i] for i in common])) 3351 else: 3352 key = () 3353 rterms.setdefault(key, []).append(t) 3354 others = Add(*rterms.pop(())) 3355 rterms = [Add(*rterms[k]) for k in rterms.keys()] 3356 3357 # the output will depend on the order terms are processed, so 3358 # make it canonical quickly 3359 rterms = list(reversed(list(ordered(rterms)))) 3360 3361 ok = False # we don't have a solution yet 3362 depth = sqrt_depth(eq) 3363 3364 if len(rterms) == 1 and not (rterms[0].is_Add and lcm > 2): 3365 eq = rterms[0]**lcm - ((-others)**lcm) 3366 ok = True 3367 else: 3368 if len(rterms) == 1 and rterms[0].is_Add: 3369 rterms = list(rterms[0].args) 3370 if len(bases) == 1: 3371 b = bases.pop() 3372 if len(syms) > 1: 3373 x = b.free_symbols 3374 else: 3375 x = syms 3376 x = list(ordered(x))[0] 3377 try: 3378 inv = _solve(covsym**lcm - b, x, **uflags) 3379 if not inv: 3380 raise NotImplementedError 3381 eq = poly.as_expr().subs(b, covsym**lcm).subs(x, inv[0]) 3382 _cov(covsym, covsym**lcm - b) 3383 return _canonical(eq, cov) 3384 except NotImplementedError: 3385 pass 3386 3387 if len(rterms) == 2: 3388 if not others: 3389 eq = rterms[0]**lcm - (-rterms[1])**lcm 3390 ok = True 3391 elif not log(lcm, 2).is_Integer: 3392 # the lcm-is-power-of-two case is handled below 3393 r0, r1 = rterms 3394 if flags.get('_reverse', False): 3395 r1, r0 = r0, r1 3396 i0 = _rads0, _bases0, lcm0 = _rads_bases_lcm(r0.as_poly()) 3397 i1 = _rads1, _bases1, lcm1 = _rads_bases_lcm(r1.as_poly()) 3398 for reverse in range(2): 3399 if reverse: 3400 i0, i1 = i1, i0 3401 r0, r1 = r1, r0 3402 _rads1, _, lcm1 = i1 3403 _rads1 = Mul(*_rads1) 3404 t1 = _rads1**lcm1 3405 c = covsym**lcm1 - t1 3406 for x in syms: 3407 try: 3408 sol = _solve(c, x, **uflags) 3409 if not sol: 3410 raise NotImplementedError 3411 neweq = r0.subs(x, sol[0]) + covsym*r1/_rads1 + \ 3412 others 3413 tmp = unrad(neweq, covsym) 3414 if tmp: 3415 eq, newcov = tmp 3416 if newcov: 3417 newp, newc = newcov 3418 _cov(newp, c.subs(covsym, 3419 _solve(newc, covsym, **uflags)[0])) 3420 else: 3421 _cov(covsym, c) 3422 else: 3423 eq = neweq 3424 _cov(covsym, c) 3425 ok = True 3426 break 3427 except NotImplementedError: 3428 if reverse: 3429 raise NotImplementedError( 3430 'no successful change of variable found') 3431 else: 3432 pass 3433 if ok: 3434 break 3435 elif len(rterms) == 3: 3436 # two cube roots and another with order less than 5 3437 # (so an analytical solution can be found) or a base 3438 # that matches one of the cube root bases 3439 info = [_rads_bases_lcm(i.as_poly()) for i in rterms] 3440 RAD = 0 3441 BASES = 1 3442 LCM = 2 3443 if info[0][LCM] != 3: 3444 info.append(info.pop(0)) 3445 rterms.append(rterms.pop(0)) 3446 elif info[1][LCM] != 3: 3447 info.append(info.pop(1)) 3448 rterms.append(rterms.pop(1)) 3449 if info[0][LCM] == info[1][LCM] == 3: 3450 if info[1][BASES] != info[2][BASES]: 3451 info[0], info[1] = info[1], info[0] 3452 rterms[0], rterms[1] = rterms[1], rterms[0] 3453 if info[1][BASES] == info[2][BASES]: 3454 eq = rterms[0]**3 + (rterms[1] + rterms[2] + others)**3 3455 ok = True 3456 elif info[2][LCM] < 5: 3457 # a*root(A, 3) + b*root(B, 3) + others = c 3458 a, b, c, d, A, B = [Dummy(i) for i in 'abcdAB'] 3459 # zz represents the unraded expression into which the 3460 # specifics for this case are substituted 3461 zz = (c - d)*(A**3*a**9 + 3*A**2*B*a**6*b**3 - 3462 3*A**2*a**6*c**3 + 9*A**2*a**6*c**2*d - 9*A**2*a**6*c*d**2 + 3463 3*A**2*a**6*d**3 + 3*A*B**2*a**3*b**6 + 21*A*B*a**3*b**3*c**3 - 3464 63*A*B*a**3*b**3*c**2*d + 63*A*B*a**3*b**3*c*d**2 - 3465 21*A*B*a**3*b**3*d**3 + 3*A*a**3*c**6 - 18*A*a**3*c**5*d + 3466 45*A*a**3*c**4*d**2 - 60*A*a**3*c**3*d**3 + 45*A*a**3*c**2*d**4 - 3467 18*A*a**3*c*d**5 + 3*A*a**3*d**6 + B**3*b**9 - 3*B**2*b**6*c**3 + 3468 9*B**2*b**6*c**2*d - 9*B**2*b**6*c*d**2 + 3*B**2*b**6*d**3 + 3469 3*B*b**3*c**6 - 18*B*b**3*c**5*d + 45*B*b**3*c**4*d**2 - 3470 60*B*b**3*c**3*d**3 + 45*B*b**3*c**2*d**4 - 18*B*b**3*c*d**5 + 3471 3*B*b**3*d**6 - c**9 + 9*c**8*d - 36*c**7*d**2 + 84*c**6*d**3 - 3472 126*c**5*d**4 + 126*c**4*d**5 - 84*c**3*d**6 + 36*c**2*d**7 - 3473 9*c*d**8 + d**9) 3474 def _t(i): 3475 b = Mul(*info[i][RAD]) 3476 return cancel(rterms[i]/b), Mul(*info[i][BASES]) 3477 aa, AA = _t(0) 3478 bb, BB = _t(1) 3479 cc = -rterms[2] 3480 dd = others 3481 eq = zz.xreplace(dict(zip( 3482 (a, A, b, B, c, d), 3483 (aa, AA, bb, BB, cc, dd)))) 3484 ok = True 3485 # handle power-of-2 cases 3486 if not ok: 3487 if log(lcm, 2).is_Integer and (not others and 3488 len(rterms) == 4 or len(rterms) < 4): 3489 def _norm2(a, b): 3490 return a**2 + b**2 + 2*a*b 3491 3492 if len(rterms) == 4: 3493 # (r0+r1)**2 - (r2+r3)**2 3494 r0, r1, r2, r3 = rterms 3495 eq = _norm2(r0, r1) - _norm2(r2, r3) 3496 ok = True 3497 elif len(rterms) == 3: 3498 # (r1+r2)**2 - (r0+others)**2 3499 r0, r1, r2 = rterms 3500 eq = _norm2(r1, r2) - _norm2(r0, others) 3501 ok = True 3502 elif len(rterms) == 2: 3503 # r0**2 - (r1+others)**2 3504 r0, r1 = rterms 3505 eq = r0**2 - _norm2(r1, others) 3506 ok = True 3507 3508 new_depth = sqrt_depth(eq) if ok else depth 3509 rpt += 1 # XXX how many repeats with others unchanging is enough? 3510 if not ok or ( 3511 nwas is not None and len(rterms) == nwas and 3512 new_depth is not None and new_depth == depth and 3513 rpt > 3): 3514 raise NotImplementedError('Cannot remove all radicals') 3515 3516 flags.update(dict(cov=cov, n=len(rterms), rpt=rpt)) 3517 neq = unrad(eq, *syms, **flags) 3518 if neq: 3519 eq, cov = neq 3520 eq, cov = _canonical(eq, cov) 3521 return eq, cov 3522 3523from sympy.solvers.bivariate import ( 3524 bivariate_type, _solve_lambert, _filtered_gens) 3525