Note to self: distinguish between roots and factors. All polynomials have roots but not all roots correspond to factors, e.g.
roots of *unfactorable* `x**2 + 5*x + 1` are `[-5/2 - sqrt(21)/2, -5/2 + sqrt(21)/2]` -- notice that we left the integer domain and needed to express solutions in terms of radicals. Roots of `x**2+5*x+6` are integers `[-3, -2]` suggesting that the factors are `x + 3` and `x + 2`. All quadratics can be written as `a*(x - r1)*(x - r2)` but that does not mean that those are factors (lower order expressions which divide the original evenly). see also https://byjus.com/maths/factoring-polynomials/ On Friday, March 11, 2022 at 5:13:35 PM UTC-6 Chris Smith wrote: > Given two expressions, `p` and `q` > > p = x*y + x + y*z > q = p + z > > it is easy to show that `q = (x + z)*(y + 1)`. But I'm wanting to avoid > factoring but would like to know whether a solution for `x` from `p = 0` or > `q = 0` is a factor or not. For `q`, the root `x = -z` represent a simple > factor whereas the root of x = `-yz/(y + 1)` is different. > > I'm lacking the vocabulary to differentiate `-z` from `-yz/(y + 1)`. Is it > that the latter has a denominator while the former does not? (And since the > original expression had no denominator then the `-z` represents a "whole" > factor while the other root does not?) > > As an alternative to factoring, it seems like collection and > identification of similar subexpressions should allow a multivariate > expression to be written in terms of un-factored factors, e.g. `collect(q, > x) -> x*(y + 1) + y*z + z` and then use `factor_terms` on the non-x portion > of the expression to find a matching factor of `y + 1` so the expression > can be separated into two factors, one with `y` and one with `x` and `z`. > This works for less trivial expressions and can be done recursively > something like this: > > def sep(e): > free = e.free_symbols > if not free:return e > x = next(ordered(free)) > c = collect(e.expand(),x) > if not c.is_Add:return c > i,d = c.as_independent(x) > d = d.func(*[factor_terms(di) for di in d.args]) > i = factor_terms(i) > ia, a = i.as_independent(Add, as_Add=False) > if a==1: > return e > _a = sep(a) > D = Dummy() > return factor_terms(ia*D + d.xreplace({a:D})).subs(D, _a) > > eq > v**3*y*z**10 + 4*v**3*y*z**6 + 2*v**3*y*z**5 + 4*v**3*y*z**2 + 4*v**3*y*z > + v**3*y + v**3*z**10 + 4*v**3*z**6 + 2*v**3*z**5 + 4*v**3*z**2 + 4*v**3*z > + v**3 + 3*v**2*x*y*z**10 + 12*v**2*x*y*z**6 + 6*v**2*x*y*z**5 + > 12*v**2*x*y*z**2 + 12*v**2*x*y*z + 3*v**2*x*y + 3*v**2*x*z**10 + > 12*v**2*x*z**6 + 6*v**2*x*z**5 + 12*v**2*x*z**2 + 12*v**2*x*z + 3*v**2*x + > 3*v*x**2*y*z**10 + 12*v*x**2*y*z**6 + 6*v*x**2*y*z**5 + 12*v*x**2*y*z**2 + > 12*v*x**2*y*z + 3*v*x**2*y + 3*v*x**2*z**10 + 12*v*x**2*z**6 + > 6*v*x**2*z**5 + 12*v*x**2*z**2 + 12*v*x**2*z + 3*v*x**2 + x**3*y*z**10 + > 4*x**3*y*z**6 + 2*x**3*y*z**5 + 4*x**3*y*z**2 + 4*x**3*y*z + x**3*y + > x**3*z**10 + 4*x**3*z**6 + 2*x**3*z**5 + 4*x**3*z**2 + 4*x**3*z + x**3 > sep(eq) > (y + 1)*(v**3 + 3*v**2*x + 3*v*x**2 + x**3)*(z**10 + 4*z**6 + 2*z**5 + > 4*z**2 + 4*z + 1) > eq == _.expand() > True > > (It always seems like `factor` is faster than this but factor can be slow, > too. And I don't really need the separated factors "factored" as much as I > just need them separated. > > So maybe that sort of function will answer the question... > > Any thoughts would be appreciated as to what might be the best way to know > when you have a solution that is a whole factors (not a rational factor -- > or whatever it should be called.) > > /c > -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/6cb2b5b1-7d36-41da-a002-9b3e71d660d4n%40googlegroups.com.
