Advanced a bit more in lazyDDRing
authorAntonio Jimenez Pastor <ajpastor@risc.uni-linz.ac.at>
Tue, 29 Jan 2019 16:02:56 +0000 (17:02 +0100)
committerAntonio Jimenez Pastor <ajpastor@risc.uni-linz.ac.at>
Tue, 29 Jan 2019 16:02:56 +0000 (17:02 +0100)
Added a file to manipulate sequence as functions over the integers.

ajpastor/dd_functions/ddExamples.py
ajpastor/dd_functions/lazyDDRing.py
ajpastor/misc/sequence_manipulation.py [new file with mode: 0644]
releases/diff_defined_functions__0.6.zip
releases/old/diff_defined_functions__0.6__19.01.29_17:02:54.zip [new file with mode: 0644]

index 3e5b8f6..f398724 100644 (file)
@@ -1149,8 +1149,8 @@ def GenericHypergeometricFunction(num=[],den=[],init=_sage_const_1 ):
     if(not((numerator,denominator,initial) in __CACHED_HYPERGEOMETRIC)):
         ## Building differential operator
         get_op = lambda p : destiny_ring.element(p).equation;
-        op_num = prod(get_op([el,x]) for el in numerator,x);
-        op_den = prod(get_op([el-_sage_const_1 ,x]) for el in denominator, get_op([_sage_const_0 ,x]));
+        op_num = prod((get_op([el,x]) for el in numerator),x);
+        op_den = prod((get_op([el-_sage_const_1 ,x]) for el in denominator), get_op([_sage_const_0 ,x]));
         op = op_num - op_den;
         
         f = destiny_ring.element(op);
index be70a16..04d2b1b 100644 (file)
@@ -15,6 +15,8 @@ from sage.rings.polynomial.multi_polynomial_ring import is_MPolynomialRing as is
 from ajpastor.lazy.conversion import ConversionSystem;
 from ajpastor.dd_functions.ddFunction import *;
 
+from ajpastor.misc.matrix import differential_movement;
+
 ####################################################################################################
 ####################################################################################################
 ### ELEMENT CLASS
@@ -352,7 +354,7 @@ class LazyDDRing (UniqueRepresentation, ConversionSystem, IntegralDomain):
                 v = vector(self, v);
                 
                 ## Going to a root with the vector
-                v,dest = self.__pullup_vector(v, current);
+                v,const,dest = self.__pullup_vector(v, self.__poly_ring().zero(), current);
                 
                 ## Returning the appropriate polynomial using the final vector
                 return self.__vector_to_poly(v, dest);
@@ -365,11 +367,16 @@ class LazyDDRing (UniqueRepresentation, ConversionSystem, IntegralDomain):
                 self.__add_function(element, gen=True);
                 self.__r_graph.add_edge((element, root, relation));
                 
-                return self.__map_to_vars[element];        
+                # Removing root as a generator
+                index = self.__gens.index(self.__gen[self.__map_to_vars[root]]);
+                for i in range(self.__trans[root][1].nrows()):
+                    self.__gens.pop(index);
+                
+                return self.__gen[self.__map_to_vars[element]];
             
         ## Otherwise, we add the element to the variables and return it
         self.__add_function(element, gen=True);
-        return self.__map_to_vars[element];
+        return self.__gen[self.__map_to_vars[element]];
         
     ################################################################################################
     ### Other Methods for LazyRing
@@ -393,22 +400,11 @@ class LazyDDRing (UniqueRepresentation, ConversionSystem, IntegralDomain):
         self.__gens = [];
         self.__map_of_derivatives = {};
     
+    def derivative(self, el, times=1):
+        raise NotImplementedError("method derivative not implemented");
+    
     def get_derivative(self, el):
-        if(el in self.__map_of_derivatives):
-            return self.__map_of_derivatives[el];
-            
-        if(el in self.__constants):
-            return _sage_const_0 ;
-        else:
-            try:
-                el = self.poly_ring()(el);
-                if(el in self.poly_ring().gens()):
-                    new_poly = self.to_poly(self.map_of_vars()[str(el)].derivative());
-                    self.__map_of_derivatives[el] = new_poly;
-                    return new_poly;
-            except:
-                pass;
-        raise ValueError("Method 'get_derivative' can only be summoned with variables.\nGot: %s -- %s" %(el, el.parent()));
+        raise NotImplementedError("method get_derivative not implemented");
         
     ################################################################################################
     ### Other Integral Domain methods 
@@ -521,7 +517,35 @@ class LazyDDRing (UniqueRepresentation, ConversionSystem, IntegralDomain):
         
     ################################################################################################
     ### Private methods
-    ################################################################################################   
+    ################################################################################################
+    def __pullup_vector(self, vector, constant, current):
+        if(self.__r_graph.in_degree(current) == 0):
+            return (vector, constant, current);
+            
+        ## Getting all data for this case
+        cR = self.__poly_field;
+        edge = self.__r_graph.incoming_edges(current)[0];
+        C = self.__trans[edge[0]][1];
+        trans_const = self.__trans[edge[0]][0];
+        relation = edge[2];
+        
+        ## Computing the derivatives of current in his father vector space
+        ivectors = [vector(cR, [0 for i in range(relation[0])] + [1] + [0 for i in range(relation[0]+1,self.__trans[current][1].nrows())])];
+        extra_cons = [relation[1][1]];
+        
+        for i in range(len(vector)):
+            extra_cons += [ivectors[-1][-1]*trans_const];
+            ivectors += [differential_movement(C, ivectors[-1], self.derivative)];
+            
+        res_vector = sum([vector(cR,[vector[i]*ivectors[i][j] for j in range(len(ivectors[i]))]) for i in range(len(vector))]);
+        res_constant = sum([vector[i]*extra_cons[i] for i in range(len(vector))], constant);
+        
+        return self.__pollup_vector(res_vector, res_constant, edge[0]);
+        
+    def __vector_to_poly(self, vector, current):
+        gen_index = self.__map_to_vars[current];
+        return sum(vector[i]*self.__gen[gen_index+i] for i in range(len(vector)) if vector[i] != 0);
+            
     def __add_function(self, f, gen=False):
         ## We look for relations with the derivatives of itself
         derivatives = [f.derivative(times=i) for i in range(f.getOrder())];
@@ -559,7 +583,7 @@ class LazyDDRing (UniqueRepresentation, ConversionSystem, IntegralDomain):
             for i in range(order):
                 self.__gens += [self.__gen[self.__used]];
                 self.__map_of_vars[self.__gens[-1]] = current;
-                self.__map_to_vars[current] = self.__gens[-1];
+                self.__map_to_vars[current] = self.__used;
                 self.__used += 1;
                 current = current.derivative();
         
diff --git a/ajpastor/misc/sequence_manipulation.py b/ajpastor/misc/sequence_manipulation.py
new file mode 100644 (file)
index 0000000..ce1b403
--- /dev/null
@@ -0,0 +1,66 @@
+
+################################################################################
+################################################################################
+################################################################################
+## Sequence operations
+def addition(f,g):
+    return lambda n : f(n)+g(n);
+
+def hadamard_product(f,g):
+    return lambda n : f(n)*g(n);
+
+def cauchy_product(f,g):
+    return lambda n : sum(f(m)*g(n-m) for m in range(n+1));
+        
+def composition(f,g):   
+    if(g(0) != 0):                     
+        raise ValueError("Impossible compose with g(0) != 0");
+    def _composition(n):                                     
+        if(n == 0):                                                                
+            return f(0);
+        result = 0; 
+        current = g; 
+        for k in range(1,n+1):
+            result += f(k)*current(n);
+            current = cauchy_product(current, g)
+        return result; 
+    return _composition;
+
+def egf_ogf(f):       
+    '''
+        Method that receives a sequence in the form of a black-box function
+        and return a sequence h(n) such that egf(f) = ogf(h).
+    '''
+    return lambda n: f(n)/factorial(n);
+
+def ogf_egf(f):       
+    '''
+        Method that receives a sequence in the form of a black-box function
+        and return a sequence h(n) such that egf(h) = ogf(f).
+    '''
+    return lambda n: f(n)*factorial(n);
+
+def inv_lagrangian(f):
+    if(f(0) != 0):
+        raise ValueError("Power serie not invertible");
+    if(f(1) == 0):
+        raise NotImplementedError("Case with order higher than 1 not implemented");
+    f = egf_ogf(f);
+    def _inverse(n):
+        if(n == 0):
+            return 0;
+        elif(n == 1):
+            return 1/f(1);
+        else:
+            result = 0;
+            for k in range(1,n):
+                poly = bell_polynomial(n-1,k);
+                #print poly;
+                variables = poly.variables();
+                #print variables;
+                extra = (-1)^k*falling_factorial(n+k-1,k);
+                result += extra*poly(**{str(variables[i]):f(i+1)/((i+1)*f(1)) for i in range(len(v
+ariables))});
+            return (1/((f(1)^n)*factorial(n))) * result;
+    return ogf_egf(_inverse);
+
index eecea87..009625c 100644 (file)
Binary files a/releases/diff_defined_functions__0.6.zip and b/releases/diff_defined_functions__0.6.zip differ
diff --git a/releases/old/diff_defined_functions__0.6__19.01.29_17:02:54.zip b/releases/old/diff_defined_functions__0.6__19.01.29_17:02:54.zip
new file mode 100644 (file)
index 0000000..009625c
Binary files /dev/null and b/releases/old/diff_defined_functions__0.6__19.01.29_17:02:54.zip differ