From: Antonio Jimenez Pastor Date: Mon, 21 Jan 2019 08:55:55 +0000 (+0100) Subject: Started new implementation of diff_to_diffalg using the algorithm X-Git-Url: http://git.risc.jku.at/gitweb/?a=commitdiff_plain;h=808ada2c8d465678d6a50547be370362dc44713f;p=ajpastor%2Fdiff_defined_functions.git Started new implementation of diff_to_diffalg using the algorithm described in the last paper. Not yet finished --- diff --git a/ajpastor/dd_functions/toDiffAlgebraic.py b/ajpastor/dd_functions/toDiffAlgebraic.py index d2d906a..cf44b8b 100644 --- a/ajpastor/dd_functions/toDiffAlgebraic.py +++ b/ajpastor/dd_functions/toDiffAlgebraic.py @@ -146,6 +146,260 @@ def fromFinitePolynomial_toInfinitePolynomial(poly): ### Methods for computing Diff. Algebraic equations with simpler coefficients ### ################################################################################ +def diffalg_reduction(poly, _infinite=False, _debug=False): + ''' + Method that recieves a polynomial 'poly' with variables y_0,...,y_m with coefficients in some ring DD(R) and reduce it to a polynomial + 'result' with coefficients in R where, for any function f(x) such that poly(f) == 0, result(f) == 0. + + The algorithm works as follows: + 1 - Collect all the coefficients and their derivatives + 2 - Perform the simplification to each pair of coefficients + 3 - Perform the simplification for the last derivatives of the remaining coefficients --> gens + 4 - Build the final derivation matrix for 'gens' + 5 - Create a vector v for represent 'poly' w.r.t. 'gens' + 6 - Build a square matrix --> M = (v | v' | ... | v^(n)) + 7 - Return det(M) + + INPUT: + - poly: a polynomial with variables y_0,...,y_m. Also an infinite polynomial with variable y_* is valid. + - _infinite: if True the result polynomial will be an infinite polynomial. Otherwise, a finite variable polynomial will be returned. + - _debug: if True, the steps of the algorithm will be printed. + ''' + ## Processing the input _infinite + if(_infinite): + r_method = fromFinitePolynomial_toInfinitePolynomial; + else: + r_method = fromInfinityPolynomial_toFinitePolynomial; + + ### Preprocessing the input poly + parent, poly, dR = __check_input(poly, _debug); + + if(not is_DDRing(dR)): + raise TypeError("diffalg_reduction: polynomial is not over a DDRing"); + + R = dR.base(); + + ## Step 1: collecting function and derivatives + __dprint("---- DEBUGGING PRINTING FOR diffalg_reduction", _debug); + __dprint("poly: %s" %poly, _debug); + __dprint("R: %s" %R, _debug); + __dprint("-- Starting step 1", _debug); + coeffs = poly.coefficients(); # List of original coefficients + ocoeffs = coeffs; # Extra variable with the same list + monomials = poly.monomials(); # List of monomials + l_of_derivatives = [[f.derivative(times=i) for i in range(f.getOrder())] for f in coeffs]; # List of derivatives for each coefficient + + ## Step 2: simplification of coefficients + __dprint("-- Starting step 2", _debug); + poset, relation = __simplify_coefficients(R, coeffs, l_of_derivatives, _debug); + maximal_elements = poset.maximal_elements(); + + ## Detecting case: all coefficients are already simpler + if(len(maximal_elements) == 1 and maximal_elements[0] == -1): + __dprint("Detected simplicity: returning the same polynomial over the basic ring"); + return r_method(InfinitePolynomialRing(R, names=["y"])(poly)); + + # Reducing the considered coefficients + coeffs = [coeffs[i] for i in maximal_elements if i != (-1)]; + l_of_derivatives = [l_of_derivatives[i] for i in maximal_elements if i != (-1)]; + + ## Step 3: simplification with the derivatives + __dprint("-- Starting step 3", _debug); + drelation = __simplify_derivatives(l_of_derivatives, _debug); + + ## Building the vector of final generators + gens = []; + if(-1 in poset): + gens = [1]; + gens = sum([l_of_derivatives[:drelation[i]] for i in range(len(coeffs))], gens); + S = len(gens); + __dprint("Resulting vector of generators: %s" %gens, _debug); + + ## Step 4: build the derivation matrix + __dprint("-- Starting step 4", _debug); + C = __build_derivation_matrix(coeffs, drelation, _debug); + + ## Step 5: build the vector v + __dprint("-- Starting step 5", _debug); + v = __build_vector(ocoeffs, monomials, poset, relation, drelation, _debug); + + ## Step 6: build the square matrix M = (v, v',...) + __dprint("-- Starting step 6", _debug); + derivative = None; # TODO: set this derivation + M = matrix_of_dMovement(C, v, derivative, S); + + return r_method(M.determinant()); + +################################################################################ +################################################################################ +### Some private methods for diffalg_reduction +################################################################################ +################################################################################ + +def __check_input(poly, _debug=False): + ''' + Method that check and cast the polynomial input accordingly to our standards. + + The element 'poly' must be a polynomial with variables y_0,...,y_m with coefficients in some ring + ''' + parent = poly.parent(); + if(not is_InfinitePolynomialRing(parent)): + if(not is_MPolynomialRing(parent)): + if(not is_PolynomialRing(parent)): + raise TypeError("__check_input: the input is not a valid polynomial. Obtained something in %s" %parent); + if(not str(parent.gens()[0]).startswith("y_")): + raise TypeError("The input is not a valid polynomial. Obtained %s but wanted something with variables y_*" %poly); + parent = InfinitePolynomialRing(parent.base(), "y"); + else: + gens = list(parent.gens()); + to_delete = []; + for gen in gens: + if(str(gen).startswith("y_")): + to_delete += [gen]; + if(len(to_delete) == 0): + raise TypeError("__check_input: the input is not a valid polynomial. Obtained %s but wanted something with variables y_*" %poly); + for gen in to_delete: + gens.remove(gen); + parent = InfinitePolynomialRing(PolynomialRing(parent.base(), gens), "y"); + else: + if(parent.ngens() > 1 or repr(parent.gen()) != "y_*"): + raise TypeError("__check_input: the input is not a valid polynomial. Obtained %s but wanted something with variables y_*" %poly); + + poly = parent(poly); + dR = parent.base(); + + return (parent, poly, dR); + +def __simplify_coefficients(R, coeffs, derivatives, _debug=False): + ''' + Method that get the relations for the coefficients within their derivatives. The list 'coeffs' is the list to simplify + and ;derivatives' is a list of lists with the derivatives of each element of 'coeffs' that we will consider. + + It returns a pair (poset, relations) where: + - poset: the Partially Oriented Set of the indices + - relations: a dictionary which tells for each i < j, how the ith coefficient is related with the jth coefficient + (see __find_relation to know how that relation is expressed). + ''' + # Checking the input + n = len(coeffs); + if(len(derivatives) < n): + raise ValueError("__simplify_coefficients: error in size of the input 'derivatives'"); + + E = range(n); + R = []; + + # Checking the simplest cases (coeff[i] in R) + for i in range(n): + if(coeffs[i] in R): + if((-1) not in E): + E += [-1]; + R += [(i,-1)]; + + # Starting the comparison + relations = {}; + for i in range(n): + for j in range(i+1, n): + # Checking (j,i) + rel = __find_relation(coeffs[j], derivatives[i], _debug); + if(not(rel is None)): + R += [(j,i)]; + relations[(j,i)] = rel; + continue; + # Checking (i,j) + rel = __find_relation(coeffs[i], derivatives[j], _debug); + if(not(rel is None)): + R += [(i,j)]; + relations[(i,j)] = rel; + + # Checking if the basic case will be used because of the relations + if((-1) not in E and any(rel[1][1] != 0 for rel in relations.values())): + E += [-1]; + + # Building the poset and returning + __dprint("All relations: %s" %R, _debug); + poset = Poset((E,R)); + + return (poset, relations); + +def __simplify_derivatives(derivatives, _debug=False): + ''' + Method to get the relations for the derivatives of the coefficients. The argument 'derivatives' contains a list of lists for which + one we will see if the last elements have relations with the firsts. + + It returns a list of tuples 'res' where 'res[i][0] = k' if the kth fucntion in 'derivatives[i]' is the first element on the list + with relations with the previous elements and 'res[i][1]' is the relation found. + If no relation is found, a tuple (None,None) is added to the list. + ''' + res = []; + for i in range(len(derivatives)): + for k in range(len(derivatives[i])-1,0,-1): + relation = __find_relation(derivatives[i][k], derivatives[i][:k-1], _debug); + if(not (relation is None)): + res += [(k,relation)]; + break; + res += [(None,None)]; + + __dprint("Found relations with derivatives: %s" %res, _debug); + return res; + +def __find_relation(g,df, _debug=False): + ''' + Method that get the relation between g and the list df. + + It returns a tuple (k,res) where: + - k: the first index which we found a relation + - res: the relation (see __find_linear_relation to see how such relation is expressed). + ''' + for k in range(len(derivatives)): + res = __find_linear_relation(df[k], g); + if(not (res is None)): + __dprint("Found relation:\n\t(%s) == [%s]*(%s) + [%s]" %(repr(g),repr(res[0]), repr(res[1]), repr(df[k]), _debug); + return (k,res); + + return None; + +def __find_linear_relation(f,g): + ''' + This method receives two DDFunctions and return two constants (c,d) such that f = cg+d. + None is return if those constants do not exist. + ''' + if(not (is_DDFunction(f) and is_DDFunction(g))): + raise TypeError("find_linear_relation: The functions are not DDFunctions"); + + try: + of = 1; while(f.getSequenceElement(of) == 0): of += 1; + og = 1; while(g.getSequenceElement(og) == 0): og += 1; + + if(of == og): + c = f.getSequenceElement(of)/g.getSequenceElement(og); + d = f(0) - c*g(0); + + if(f == c*g + d): + return (c,d); + except Exception: + pass; + + return None; + + ## Simplest case: some of the functions are constants is a constant + if(f.is_constant): + return (f.parent().zero(), f(0)); + elif(g.is_constant): + return None; + +def __build_derivation_matrix(coeffs, drelations, _debug=False): + ## TODO: Implement this + raise NotImplementedError("__build_derivation_matrix: method not implemented"); + +def __build_vector(coeffs, monomials, poset, relation, drelation, _debug=False): + ## TODO: Implement this + raise NotImplementedError("__build_vector: method not implemented"); + + +################################################################################ +################################################################################ +################################################################################ + def toDifferentiallyAlgebraic_Below(poly, _infinite=False, _debug=False): ''' Method that receives a polynomial with variables y_0,...,y_m with coefficients in some ring DD(R) and reduce it to a polynomial @@ -629,7 +883,34 @@ def Exponential_polynomials(n, parent): prev = Exponential_polynomials(n-1,parent); return infinite_derivative(prev) + y[0]*prev; +################################################################################################### +### Private functions +################################################################################################### +def __dprint(obj, _debug): + if(_debug): print obj; + #################################################################################################### #### PACKAGE ENVIRONMENT VARIABLES #################################################################################################### __all__ = ["is_InfinitePolynomialRing", "get_InfinitePolynomialRingGen", "get_InfinitePolynomialRingVaribale", "infinite_derivative", "toDifferentiallyAlgebraic_Below", "diff_to_diffalg", "inverse_DA", "func_inverse_DA", "guess_DA_DDfinite", "guess_homogeneous_DNfinite", "FaaDiBruno_polynomials", "Exponential_polynomials"]; + + +def simplify_coefficients(R, coeffs, derivatives, _debug=True): + return __simplify_coefficients(R,coeffs,derivatives,_debug); + +def simplify_derivatives(derivatives, _debug=True): + return __simplify_derivatives(derivatives, _debug) + +def find_relation(g,df, _debug=True): + return __find_relation(g,df,_debug); + +def find_linear_relation(f,g): + return __find_linear_relation(g,df); + +def build_derivation_matrix(coeffs, drelations, _debug=True): + return __build_derivation_matrix(coeffs, drelations, _debug); + +def build_vector(coeffs, monomials, poset, relation, drelation, _debug=True): + return __build_vector(coeffs, monomials, poset, relation, drelation, _debug); +# Extra functions for debuggin +__all__ += ["simplify_coefficients", "simplify_derivatives", "find_relation", "find_linear_relation", "build_derivation_matrix", "build_vector"]; diff --git a/releases/diff_defined_functions__0.6.zip b/releases/diff_defined_functions__0.6.zip index 91790ed..1555c6d 100644 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.09_11:12:08.zip b/releases/old/diff_defined_functions__0.6__19.01.09_11:12:08.zip new file mode 100644 index 0000000..f3ca4bd Binary files /dev/null and b/releases/old/diff_defined_functions__0.6__19.01.09_11:12:08.zip differ diff --git a/releases/old/diff_defined_functions__0.6__19.01.17_09:44:41.zip b/releases/old/diff_defined_functions__0.6__19.01.17_09:44:41.zip new file mode 100644 index 0000000..014f486 Binary files /dev/null and b/releases/old/diff_defined_functions__0.6__19.01.17_09:44:41.zip differ diff --git a/releases/old/diff_defined_functions__0.6__19.01.21_09:55:55.zip b/releases/old/diff_defined_functions__0.6__19.01.21_09:55:55.zip new file mode 100644 index 0000000..1555c6d Binary files /dev/null and b/releases/old/diff_defined_functions__0.6__19.01.21_09:55:55.zip differ