def test_PolyRing___getitem__(): R, x,y,z = ring("x,y,z", ZZ) assert R[0:] == PolyRing("x,y,z", ZZ, lex) assert R[1:] == PolyRing("y,z", ZZ, lex) assert R[2:] == PolyRing("z", ZZ, lex) assert R[3:] == ZZ
def __init__(self, symbols, domain, order): from sympy.polys.rings import PolyRing self.ring = PolyRing(symbols, domain, order) self.dtype = FracElement self.symbols = self.ring.symbols self.ngens = len(self.symbols) self.domain = self.ring.domain self.order = self.ring.order self.gens = self._gens()
def test_PolyElement_drop(): R, x,y,z = ring("x,y,z", ZZ) assert R(1).drop(0).ring == PolyRing("y,z", ZZ, lex) assert R(1).drop(0).drop(0).ring == PolyRing("z", ZZ, lex) assert isinstance(R(1).drop(0).drop(0).drop(0), R.dtype) is False raises(ValueError, lambda: z.drop(0).drop(0).drop(0)) raises(ValueError, lambda: x.drop(0))
def test_PolyRing_is_(): R = PolyRing("x", QQ, lex) assert R.is_univariate is True assert R.is_multivariate is False R = PolyRing("x,y,z", QQ, lex) assert R.is_univariate is False assert R.is_multivariate is True
def test_sring(): x, y, z, t = symbols("x,y,z,t") R = PolyRing("x,y,z", ZZ, lex) assert sring(x + 2 * y + 3 * z) == (R, R.x + 2 * R.y + 3 * R.z) R = PolyRing("x,y,z", QQ, lex) assert sring(x + 2 * y + z / 3) == (R, R.x + 2 * R.y + R.z / 3) assert sring([x, 2 * y, z / 3]) == (R, [R.x, 2 * R.y, R.z / 3]) Rt = PolyRing("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2 * t * y + 3 * t**2 * z, x, y, z) == (R, R.x + 2 * Rt.t * R.y + 3 * Rt.t**2 * R.z) Rt = PolyRing("t", QQ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + t * y / 2 + t**2 * z / 3, x, y, z) == (R, R.x + Rt.t * R.y / 2 + Rt.t**2 * R.z / 3) Rt = FracField("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2 * y / t + t**2 * z / 3, x, y, z) == (R, R.x + 2 * R.y / Rt.t + Rt.t**2 * R.z / 3) r = sqrt(2) - sqrt(3) R, a = sring(r, extension=True) assert R.domain == QQ.algebraic_field(r) assert R.gens == () assert a == R.domain.from_sympy(r)
def __new__(cls, iterative, F, n, *gens, **args): """Compute a reduced Groebner basis for a system of polynomials. """ options.allowed_flags(args, ['polys', 'method']) try: polys, opt = parallel_poly_from_expr(F, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('groebner', len(F), exc) from sympy.polys.rings import PolyRing ring = PolyRing(opt.gens, opt.domain, opt.order) polys = [ring.from_dict(poly.rep.to_dict()) for poly in polys if poly] if iterative: G = iter_groebner(polys, n, ring, method=opt.method ) #Assumes last element is the "new" polynomial else: G = _groebner(polys, ring, method=opt.method) G = [Poly._from_dict(g, opt) for g in G] return cls._new(G, opt)
def test_pickling_polys_rings(): # NOTE: can't use protocols < 2 because we have to execute __new__ to # make sure caching of rings works properly. from sympy.polys.rings import PolyRing ring = PolyRing("x,y,z", ZZ, lex) for c in (PolyRing, ring): check(c, exclude=[0, 1]) for c in (ring.dtype, ring.one): check(c, exclude=[0, 1], check_attr=False) # TODO: Py3k
def test_PolyRing___init__(): x, y, z = map(Symbol, "xyz") assert len(PolyRing("x,y,z", ZZ, lex).gens) == 3 assert len(PolyRing(x, ZZ, lex).gens) == 1 assert len(PolyRing(("x", "y", "z"), ZZ, lex).gens) == 3 assert len(PolyRing((x, y, z), ZZ, lex).gens) == 3 raises(GeneratorsNeeded, lambda: PolyRing([], ZZ, lex)) raises(GeneratorsError, lambda: PolyRing(0, ZZ, lex))
def test_PolyRing_drop(): R, x,y,z = ring("x,y,z", ZZ) assert R.drop(x) == PolyRing("y,z", ZZ, lex) assert R.drop(y) == PolyRing("x,z", ZZ, lex) assert R.drop(z) == PolyRing("x,y", ZZ, lex) assert R.drop(0) == PolyRing("y,z", ZZ, lex) assert R.drop(0).drop(0) == PolyRing("z", ZZ, lex) assert R.drop(0).drop(0).drop(0) == ZZ assert R.drop(1) == PolyRing("x,z", ZZ, lex) assert R.drop(2) == PolyRing("x,y", ZZ, lex) assert R.drop(2).drop(1) == PolyRing("x", ZZ, lex) assert R.drop(2).drop(1).drop(0) == ZZ raises(ValueError, lambda: R.drop(3)) raises(ValueError, lambda: R.drop(x).drop(y))
def __init__(self, domain_or_ring, symbols=None, order=None): from sympy.polys.rings import PolyRing if isinstance(domain_or_ring, PolyRing) and symbols is None and order is None: ring = domain_or_ring else: ring = PolyRing(symbols, domain_or_ring, order) self.ring = ring self.dtype = ring.dtype self.gens = ring.gens self.ngens = ring.ngens self.symbols = ring.symbols self.domain = ring.domain # TODO: remove this self.dom = self.domain
def __new__(cls, symbols, domain, order=lex): from sympy.polys.rings import PolyRing ring = PolyRing(symbols, domain, order) symbols = ring.symbols ngens = ring.ngens domain = ring.domain order = ring.order _hash_tuple = (cls.__name__, symbols, ngens, domain, order) obj = _field_cache.get(_hash_tuple) if obj is None: obj = object.__new__(cls) obj._hash_tuple = _hash_tuple obj._hash = hash(_hash_tuple) obj.ring = ring obj.dtype = type("FracElement", (FracElement, ), {"field": obj}) obj.symbols = symbols obj.ngens = ngens obj.domain = domain obj.order = order obj.zero = obj.dtype(ring.zero) obj.one = obj.dtype(ring.one) obj.gens = obj._gens() for symbol, generator in zip(obj.symbols, obj.gens): if isinstance(symbol, Symbol): name = symbol.name if not hasattr(obj, name): setattr(obj, name, generator) _field_cache[_hash_tuple] = obj return obj
def test_sring(): x, y, z, t = symbols("x,y,z,t") R = PolyRing("x,y,z", ZZ, lex) assert sring(x + 2*y + 3*z) == (R, R.x + 2*R.y + 3*R.z) R = PolyRing("x,y,z", QQ, lex) assert sring(x + 2*y + z/3) == (R, R.x + 2*R.y + R.z/3) assert sring([x, 2*y, z/3]) == (R, [R.x, 2*R.y, R.z/3]) Rt = PolyRing("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2*t*y + 3*t**2*z, x, y, z) == (R, R.x + 2*Rt.t*R.y + 3*Rt.t**2*R.z) Rt = PolyRing("t", QQ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + t*y/2 + t**2*z/3, x, y, z) == (R, R.x + Rt.t*R.y/2 + Rt.t**2*R.z/3) Rt = FracField("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2*y/t + t**2*z/3, x, y, z) == (R, R.x + 2*R.y/Rt.t + Rt.t**2*R.z/3)
def __init__(self, domain_or_ring, symbols=None, order=None): from sympy.polys.rings import PolyRing if isinstance(domain_or_ring, PolyRing) and symbols is None and order is None: ring = domain_or_ring else: ring = PolyRing(symbols, domain_or_ring, order) self.ring = ring self.dtype = ring.dtype self.gens = ring.gens self.ngens = ring.ngens self.symbols = ring.symbols self.domain = ring.domain if symbols: if ring.domain.is_Field and ring.domain.is_Exact and len(symbols)==1: self.is_PID = True # TODO: remove this self.dom = self.domain
def to_ring(self): from sympy.polys.rings import PolyRing return PolyRing(self.symbols, self.domain, self.order)
def poly_ring(self, *symbols): # TODO:, order=lex): """Returns a polynomial ring, i.e. `K[X]`. """ from sympy.polys.rings import PolyRing return PolyRing(symbols, self.field, order).to_domain()
def test_PolyRing___init__(): x, y, z, t = map(Symbol, "xyzt") assert len(PolyRing("x,y,z", ZZ, lex).gens) == 3 assert len(PolyRing(x, ZZ, lex).gens) == 1 assert len(PolyRing(("x", "y", "z"), ZZ, lex).gens) == 3 assert len(PolyRing((x, y, z), ZZ, lex).gens) == 3 raises(GeneratorsNeeded, lambda: PolyRing([], ZZ, lex)) raises(GeneratorsError, lambda: PolyRing(0, ZZ, lex)) assert PolyRing("x", ZZ[t], lex).domain == ZZ[t] assert PolyRing("x", 'ZZ[t]', lex).domain == ZZ[t] assert PolyRing("x", PolyRing("t", ZZ, lex), lex).domain == ZZ[t] raises(GeneratorsError, lambda: PolyRing("x", PolyRing("x", ZZ, lex), lex)) _lex = Symbol("lex") assert PolyRing("x", ZZ, lex).order == lex assert PolyRing("x", ZZ, _lex).order == lex assert PolyRing("x", ZZ, 'lex').order == lex R1 = PolyRing("x,y", ZZ, lex) R2 = PolyRing("x,y", ZZ, lex) R3 = PolyRing("x,y,z", ZZ, lex) assert R1.x == R1.gens[0] assert R1.y == R1.gens[1] assert R1.x == R2.x assert R1.y == R2.y assert R1.x != R3.x assert R1.y != R3.y
def _integrate(field=None): irreducibles = set() atans = set() pairs = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_part, atan_part = [], [] x, y = symbols('x y', cls=Wild, exclude=[I]) for poly in list(irreducibles): m = poly.match(x + I*y) if m[y] == 0: # No coefficient of I continue pairs.add((m[x], m[y])) # It is enough to save the coefficients irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x,-y) in pairs: pairs.remove((x,-y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x*x + y*y) atans.add(atan(x/y)) else: irreducibles.add(x + I*y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(ordered(zip(irreducibles, B)))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(ordered(zip(atans, C)))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.subs(solution).subs( list(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))
def _integrate(field=None): irreducibles = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_coeffs, log_part = [], [] B = _symbols('B', len(irreducibles)) # Note: the ordering matters here for poly, b in reversed(list(ordered(zip(irreducibles, B)))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancelation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) numer = ring.from_expr(raw_numer) solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.subs(solution).subs( list(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))
class FracField(DefaultPrinting): def __init__(self, symbols, domain, order): from sympy.polys.rings import PolyRing self.ring = PolyRing(symbols, domain, order) self.dtype = FracElement self.symbols = self.ring.symbols self.ngens = len(self.symbols) self.domain = self.ring.domain self.order = self.ring.order self.gens = self._gens() def _gens(self): """Return a list of polynomial generators. """ return tuple([ self.dtype(self, gen) for gen in self.ring.gens ]) _hash = None def __hash__(self): _hash = self._hash if _hash is None: self._hash = _hash = hash((self.symbols, self.domain, self.order)) return _hash def __eq__(self, other): return isinstance(other, FracField) and self.ring == other.ring def __ne__(self, other): return not self.__eq__(other) def new(self, numer, denom=None): return self.dtype(self, numer, denom) def domain_new(self, element): return self.domain.convert(element) def ground_new(self, element): try: return self.new(self.ring.ground_new(element)) except CoercionFailed: domain = self.domain if domain.has_Ring and domain.has_assoc_Field: ground_field = domain.get_field() element = ground_field.convert(element) numer = ground_field.numer(element) denom = ground_field.denom(element) return self.new(numer, denom) else: raise def field_new(self, element): if isinstance(element, FracElement): if self == element.field: return element else: raise NotImplementedError("conversion") elif isinstance(element, PolyElement): if self.ring == element.ring: return self.new(element) else: raise NotImplementedError("conversion") elif isinstance(element, tuple) and len(element) == 2: numer, denom = map(self.ring.ring_new, element) return self.new(numer, denom) elif isinstance(element, basestring): raise NotImplementedError("parsing") elif isinstance(element, Expr): return self.from_expr(element) else: return self.ground_new(element) __call__ = field_new def _rebuild_expr(self, expr, mapping): domain = self.domain def _rebuild(expr): generator = mapping.get(expr) if generator is not None: return generator elif expr.is_Add: return reduce(add, map(_rebuild, expr.args)) elif expr.is_Mul: return reduce(mul, map(_rebuild, expr.args)) elif expr.is_Pow and expr.exp.is_Integer: return _rebuild(expr.base)**int(expr.exp) else: try: return domain.convert(expr) except CoercionFailed: if domain.has_Ring and domain.has_assoc_Field: return domain.get_field().convert(expr) else: raise return _rebuild(sympify(expr)) def from_expr(self, expr): mapping = dict(zip(self.symbols, self.gens)) try: frac = self._rebuild_expr(expr, mapping) except CoercionFailed: raise ValueError("expected an expression convertible to a rational function in %s, got %s" % (self, expr)) else: return self.field_new(frac) @property def zero(self): return self.new(self.ring.zero) @property def one(self): return self.new(self.ring.one) def to_domain(self): from sympy.polys.domains.fractionfield import FractionField return FractionField(self) def to_ring(self): from sympy.polys.rings import PolyRing return PolyRing(self.symbols, self.domain, self.order)
def _integrate(field=None): irreducibles = set() for poly in reducibles: for z in poly.atoms(Symbol): if z in V: break else: continue irreducibles |= set(root_factors(poly, z, filter=field)) log_coeffs, log_part = [], [] B = _symbols('B', len(irreducibles)) for i, poly in enumerate(irreducibles): if poly.has(*V): log_coeffs.append(B[i]) log_part.append(log_coeffs[-1] * log(poly)) coeffs = poly_coeffs + log_coeffs # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancelation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(coeffs, ground) ring = PolyRing(V, coeff_ring) numer = ring.from_expr(raw_numer) solution = solve_lin_sys(numer.coeffs(), coeff_ring) if solution is None: return None else: solution = [ (k.as_expr(), v.as_expr()) for k, v in solution.items() ] return candidate.subs(solution).subs(list(zip(coeffs, [S.Zero]*len(coeffs))))
def _integrate(field=None): irreducibles = set() atans = set() pairs = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_part, atan_part = [], [] for poly in list(irreducibles): m = collect(poly, I, evaluate=False) y = m.get(I, S.Zero) if y: x = m.get(S.One, S.Zero) if x.has(I) or y.has(I): continue # nontrivial x + I*y pairs.add((x, y)) irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x, -y) in pairs: pairs.remove((x, -y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x*x + y*y) atans.add(atan(x/y)) else: irreducibles.add(x + I*y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(ordered(zip(irreducibles, B)))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(ordered(zip(atans, C)))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set([]) def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.subs(solution).subs( list(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))
def _integrate(field=None): atans = set() pairs = set() if field == 'Q': irreducibles = set(reducibles) else: setV = set(V) irreducibles = set() for poly in ordered(reducibles): zV = setV & set(iterfreeargs(poly)) for z in ordered(zV): s = set(root_factors(poly, z, filter=field)) irreducibles |= s break log_part, atan_part = [], [] for poly in ordered(irreducibles): m = collect(poly, I, evaluate=False) y = m.get(I, S.Zero) if y: x = m.get(S.One, S.Zero) if x.has(I) or y.has(I): continue # nontrivial x + I*y pairs.add((x, y)) irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x, -y) in pairs: pairs.remove((x, -y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x*x + y*y) atans.add(atan(x/y)) else: irreducibles.add(x + I*y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(zip(ordered(irreducibles), B))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(zip(ordered(atans), C))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set() def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.has_free(*syms): non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.xreplace(solution).xreplace( dict(zip(poly_coeffs, [S.Zero]*len(poly_coeffs))))
class FracField(DefaultPrinting): def __init__(self, symbols, domain, order): from sympy.polys.rings import PolyRing self.ring = PolyRing(symbols, domain, order) self.dtype = FracElement self.symbols = self.ring.symbols self.ngens = len(self.symbols) self.domain = self.ring.domain self.order = self.ring.order self.gens = self._gens() def _gens(self): """Return a list of polynomial generators. """ return tuple([self.dtype(self, gen) for gen in self.ring.gens]) _hash = None def __hash__(self): _hash = self._hash if _hash is None: self._hash = _hash = hash((self.symbols, self.domain, self.order)) return _hash def __eq__(self, other): return isinstance(other, FracField) and self.ring == other.ring def __ne__(self, other): return not self.__eq__(other) def new(self, numer, denom=None): return self.dtype(self, numer, denom) def domain_new(self, element): return self.domain.convert(element) def ground_new(self, element): try: return self.new(self.ring.ground_new(element)) except CoercionFailed: domain = self.domain if domain.has_Ring and domain.has_assoc_Field: ground_field = domain.get_field() element = ground_field.convert(element) numer = ground_field.numer(element) denom = ground_field.denom(element) return self.new(numer, denom) else: raise def field_new(self, element): if isinstance(element, FracElement): if self == element.field: return element else: raise NotImplementedError("conversion") elif isinstance(element, PolyElement): if self.ring == element.ring: return self.new(element) else: raise NotImplementedError("conversion") elif isinstance(element, tuple) and len(element) == 2: numer, denom = map(self.ring.ring_new, element) return self.new(numer, denom) elif isinstance(element, basestring): raise NotImplementedError("parsing") elif isinstance(element, Expr): return self.from_expr(element) else: return self.ground_new(element) __call__ = field_new def _rebuild_expr(self, expr, mapping): domain = self.domain def _rebuild(expr): generator = mapping.get(expr) if generator is not None: return generator elif expr.is_Add: return reduce(add, map(_rebuild, expr.args)) elif expr.is_Mul: return reduce(mul, map(_rebuild, expr.args)) elif expr.is_Pow and expr.exp.is_Integer: return _rebuild(expr.base) ** int(expr.exp) else: try: return domain.convert(expr) except CoercionFailed: if domain.has_Ring and domain.has_assoc_Field: return domain.get_field().convert(expr) else: raise return _rebuild(sympify(expr)) def from_expr(self, expr): mapping = dict(zip(self.symbols, self.gens)) try: frac = self._rebuild_expr(expr, mapping) except CoercionFailed: raise ValueError("expected an expression convertible to a rational function in %s, got %s" % (self, expr)) else: return self.field_new(frac) @property def zero(self): return self.new(self.ring.zero) @property def one(self): return self.new(self.ring.one) def to_domain(self): from sympy.polys.domains.fractionfield import FractionField return FractionField(self) def to_ring(self): from sympy.polys.rings import PolyRing return PolyRing(self.symbols, self.domain, self.order)