try:
self.__poly = parent.poly_field()(el);
except:
- self.__raw = parent.base()(el);
- self.__poly = self.parent().to_poly(self.__raw);
+ try:
+ self.__poly = self.parent().to_poly(el);
+ except:
+ self.__raw = parent.base()(el);
+ self.__poly = self.parent().to_poly(self.__raw);
self.simplify(); # We try to simplify the element from the beginning
def simplify(self):
self.__poly = self.parent().simplify(self.poly());
+ return self;
def variables(self):
'''
@cached_method
def is_zero(self):
result = (self.poly() == 0 );
- map_to_values = {repr(var) : self.parent().to_real(var)(0)};
- if((not result) and (self(**map_to_values) == 0 )):
+ map_to_values = {repr(var) : self.parent().to_real(var)(0) for var in self.poly().variables()};
+ if((not result) and (self.poly()(**map_to_values) == 0)):
if(not (self.__raw is None)):
result = (self.raw() == 0);
else:
self.__poly_field = self.__poly_ring.fraction_field();
self.__gen = self.__poly_ring.gens()[0];
self.__used = 0;
+ self.stop = False;
## Initializing the map of variables
self.__map_of_vars = {}; # Map where each variable is associated with a 'base' object
return tuple(self.poly_ring()(key) for key in self.map_of_vars().keys());
def _to_poly_element(self, element):
- if(not (element in self.base())):
+ if(element.parent() is self):
+ return element.poly();
+ elif(not (element in self.base())):
raise TypeError("Element is not in the base ring.\n\tExpected: %s\n\tGot: %s" %(element.parent(), self.base()));
## We try to cast to a polynomial. If we can do it, it means no further operations has to be done
## Otherwise, we add the element to the variables and return it
self.__add_function(element, gen=True);
return self.__gen[self.__map_to_vars[element]];
+
+ def _relations(self):
+ '''
+ Returns a Groebner Basis of the relations ideals known in this conversion system.
+ '''
+ if(self._ConversionSystem__relations is None):
+ self._ConversionSystem__relations = [];
+ self._ConversionSystem__rel_ideal = ideal([Integer(0)]);
+
+ return self._ConversionSystem__relations;
+
+ def _groebner_basis(self):
+ if(len(self._ConversionSystem__relations) >= 1):
+ gens_in_relations = list(set(sum([[str(v) for v in el.variables()] for el in self._ConversionSystem__relations], [])));
+ Poly = PolynomialRing(self.poly_ring().base_ring(), gens_in_relations, order='deglex');
+ rels = [Poly(el) for el in self._ConversionSystem__relations];
+ self._ConversionSystem__rel_ideal = ideal(Poly, rels);
+ return self._ConversionSystem__rel_ideal.groebner_basis();
+ return [self.poly_ring().base_ring().zero()];
+
+ def _simplify(self, poly):
+ gens = list(set([str(g) for g in self._ConversionSystem__rel_ideal.parent().ring().gens() if g != 1] + [str(g) for g in poly.variables()]));
+ Poly = PolynomialRing(self.poly_ring().base_ring(), gens);
+ try:
+ poly = Poly(poly);
+ except TypeError:
+ return poly;
+ try:
+ return self.poly_ring()(poly.reduce([Poly(el) for el in self._ConversionSystem__relations]));
+ except AttributeError:
+ return self.poly_ring()(poly);
################################################################################################
### Other Methods for LazyRing
self.__map_of_derivatives = {};
def derivative(self, el, times=1):
- raise NotImplementedError("method derivative not implemented");
+ '''
+ Method that computes the derivative of an element in the LazyDDRing. It performs a casting to 'self' before starting the algorithm.
+ '''
+ el = self(el);
+
+ if(times == 0):
+ return el;
+ elif(times > 1):
+ return self.derivative(self.derivative(el, times-1));
+
+ ## Splitting the derivative into the monomials
+ poly = el.poly();
+ if(poly == 0):
+ return self.zero();
+ coeffs = poly.coefficients();
+ monomials = poly.monomials();
+
+ ## Base case (monomial case)
+ if(len(monomials) == 1):
+ gens = poly.variables();
+ degrees = [poly.degree(g) for g in gens];
+
+ res = sum(prod(gens[j]**(degrees[j]-kronecker_delta(i,j)) for j in range(len(gens)))*degrees[i]*self.get_derivative(gens[i]) for i in range(len(gens)));
+
+ return self(coeffs[0]*res);
+ else: ## Generic case (polynomial)
+ return self(sum(coeffs[i]*self.derivative(monomials[i]) for i in range(len(coeffs))));
def get_derivative(self, el):
- raise NotImplementedError("method get_derivative not implemented");
+ return self(self.__map_of_derivatives[el]).poly();
################################################################################################
### Other Integral Domain methods
## For each variable in X.poly(), we get the new polynomial
translate = {}
for var in X.variables():
- translate[var] = self.to_poly(other.map_of_vars()[var]);
+ translate[var] = self.to_poly(other.map_of_vars()[str(var)]);
## We now plugin the expressions
return _LazyDDFunction(self, pol(**translate));
def __str__(self):
final = "%s with %d variables\n{\n" %(repr(self),len(self.__gens));
for g in self.__gens:
- final += "\t%s : %s,\n" %(g, repr(self.__map_of_vars[g]));
+ final += "\t%s : %s,\n" %(g, repr(self.__map_of_vars[str(g)]));
final += "}";
return final
break;
## Create the tranformation into f
+
+ # Companion matrix
+ companion = f.equation.companion();
+ companion = Matrix(self, [[self(companion[i][j]) for j in range(companion.ncols())] for i in range(companion.nrows())]);
if(order < f.getOrder()): # Relation found
C = [];
- companion = f.equation.companion();
for i in range(order):
new_row = [companion[i][j] for j in range(order)];
if(i == relation[0]):
C = Matrix(self,C);
self.__trans[f] = (relation[1][1],C);
else:
- self.__trans[f] = (self.poly_ring().zero(),Matrix(self, f.equation.companion()));
+ self.__trans[f] = (self.poly_ring().zero(),Matrix(self, companion));
## Adding f as a vertex (edges must be added outside this function)
self.__r_graph.add_vertex(f);
## If f will become a generator, add it to the used variables
if(gen):
current = f;
+ before = self.__used;
for i in range(order):
+ print "** Adding a new variable (%d)" %self.__used;
self.__gens += [self.__gen[self.__used]];
- self.__map_of_vars[self.__gens[-1]] = current;
+ self.__map_of_vars[str(self.__gens[-1])] = current;
self.__map_to_vars[current] = self.__used;
+ self.__map_of_derivatives[self.__gen[self.__used]] = self.__gen[self.__used+1];
self.__used += 1;
current = current.derivative();
+
+ trans = self.__trans[f];
+ self.__map_of_derivatives[self.__gen[before+order-1]] = sum([self.__gen[before+i]*trans[1][i][-1] for i in range(order)], trans[0]);
return;
from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing_dense as isDenseIPolynomial;
from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing_sparse as isSparseIPolynomial;
+from sage.structure.element import is_Matrix;
+from sage.structure.element import is_Vector;
+
class ConversionSystem(object):
## Main bulder
def __init__(self, base):
## Pulbic methods
def add_relations(self, *relations):
if(self.is_polynomial()):
- try:
- ## Adding the new relations
- self._relations(); # We make sure the relations are initialized
-
- self.__add_relation(relations);
-
- ## Changing the ideal and computing a groebner basis
- if(len(self.__relations) >= _sage_const_1 ):
- self.__rel_ideal = ideal(self.poly_ring(), self.__relations);
- self.__relations = self.__rel_ideal.groebner_basis();
- except TypeError as e:
- raise e;
+ ## Adding the new relations
+ self._relations(); # We make sure the relations are initialized
+
+ self.__add_relation(relations);
+
+ ## Changing the ideal and computing a groebner basis
+ self.__relations = self._groebner_basis();
def clean_relations(self):
self.__relations = [];
+
+ def _add_relation(self, poly):
+ '''
+ Auxiliar method to add a polynomial to the relations of the conversion system
+ '''
+ reduced = self.simplify(poly);
+ if(reduced != _sage_const_0 ):
+ self.__relations += [reduced];
+
+ def _groebner_basis(self):
+ '''
+ Auxiliar method to compute the groebner basis for the current set of relations on the conversion system
+ '''
+ if(len(self.__relations) >= _sage_const_1 ):
+ self.__rel_ideal = ideal(self.poly_ring(), self.__relations);
+ return self.__rel_ideal.groebner_basis();
+ return [self.poly_ring().zero()];
def to_poly(self, element):
'''
n = self.to_poly(element.numerator());
d = self.to_poly(element.denominator());
return self.poly_field()(n/d);
- elif(isinstance(element, sage.matrix.matrix.Matrix)):
+ elif(isinstance(element.parent(), ConversionSystem)):
+ if(element.parent() is self):
+ return self._to_poly_element(element);
+ poly = element.parent().to_poly(element);
+ try:
+ n = self.to_poly(element.parent().to_real(poly.numerator()));
+ d = self.to_poly(element.parent().to_real(poly.denominator()));
+ return self.poly_field()(n/d);
+ except AttributeError:
+ return self.to_poly(element.parent().to_real(poly));
+ elif(is_Matrix(element)):
R = self.poly_ring();
if(element.parent().base().is_field()):
R = self.poly_field();
return Matrix(R, [self.to_poly(row) for row in element]);
- elif(isinstance(element, sage.modules.free_module_element.FreeModuleElement)):
+ elif(is_Vector(element)):
R = self.poly_ring();
if(element.parent().base().is_field()):
R = self.poly_field();
return [self.to_poly(el) for el in element];
elif(isinstance(element, set)):
return set([self.to_poly(el) for el in element]);
- elif(isinstance(relation, tuple)):
+ elif(isinstance(element, tuple)):
return tuple([self.to_poly(el) for el in element]);
else:
raise TypeError("Wrong type: Impossible to get polynomial value of element (%s)" %(element));
n = self.to_real(poly.numerator());
d = self.to_real(poly.denominator());
return n/d;
- elif(isinstance(poly, sage.matrix.matrix.Matrix)):
+ elif(is_Matrix(poly)):
R = self.base();
if(poly.parent().base().is_field()):
R = R.fraction_field();
return Matrix(R, [self.to_real(row) for row in poly]);
- elif(isinstance(poly, sage.modules.free_module_element.FreeModuleElement)):
+ elif(is_Vector(poly)):
R = self.base();
if(poly.parent().base().is_field()):
R = R.fraction_field();
if(element in self.poly_ring()):
element = self.poly_ring()(element);
try: # Weird case: fraction field fall in polynomial field
- n = self.poly_ring()(element.numerator()).reduce(self._relations());
- d = self.poly_ring()(element.denominator()).reduce(self._relations());
+ n = self._simplify(self.poly_ring()(element.numerator()));
+ d = self._simplify(self.poly_ring()(element.denominator()));
return n/d;
except AttributeError:
try:
- return self.poly_ring()(element).reduce(self._relations());
+ return self._simplify(self.poly_ring()(element));
except AttributeError:
return self.poly_ring()(element);
elif(element in self.poly_field()):
return self.to_real(self.simplify(self.to_poly(element)));
else:
return element;
+
+ def _simplify(self, poly):
+ '''
+ Auxiliar method that make the simplification of an element in self.poly_ring().
+ '''
+ try:
+ return poly.reduce(self._relations());
+ except AttributeError:
+ return poly;
def mix_conversion(self, conversion):
'''
This method can be overwritten if needed.
'''
+ polynomial = self.poly_ring()(polynomial);
variables = polynomial.variables();
if(len(variables) == 0):
return self.base()(polynomial);
- return polynomial(**{str(v) : self.map_of_vars()[str(v)] for v in variables});
+ return self.base()(polynomial(**{str(v) : self.map_of_vars()[str(v)] for v in variables}));
# multi = (len(variables) > _sage_const_1 );
# res = self.base().zero();
# for (k,v) in polynomial.dict().items():
for el in relation:
self.__add_relation(el);
elif(relation in self.poly_ring()):
- reduced = self.simplify(relation);
- if(reduced != _sage_const_0 ):
- self.__relations += [reduced];
+ self._add_relation(self.poly_ring()(relation));
elif(relation in self.poly_field()):
- reduced = self.simplify(relation.numerator());
- if(reduced != _sage_const_0 ):
- self.__relations += [reduced];
+ self._add_relation(self.poly_ring()(relation.numerator()));
else:
try:
self.__add_relation(self.to_poly(relation));
self.__create_poly_field();
def _to_poly_element(self, element):
- if(not (element in self.base())):
+ if(element.parent() is self):
+ return element.poly();
+ elif(not (element in self.base())):
raise TypeError("Element is not in the base ring.\n\tExpected: %s\n\tGot: %s" %(element.parent(), self.base()));
## We try to cast to a polynomial. If we can do it, it means no further operations has to be done