- Tan
- Sinh
- Cosh
+ - Tanh
- Arcsin
- Arccos
- Arctan
+ - Arcsinh
+ - Arccosh
+ - Arctanh
** EXPONENTIAL FUNCTIONS
- Exp
- Log
required = newOperator.get_jp_fo()+_sage_const_1 ;
init_tan = Tan(x).getInitialValueList(required);
- init_input = [factorial(i)*dR.base().getSequenceElement(g,i) for i in range(required)];
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
newInit = [init_tan[_sage_const_0 ]]+[sum([init_tan[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
return dR.element([-df**_sage_const_3 ,-df2,df],[_sage_const_1 ,_sage_const_0 ,evaluate(df)**_sage_const_2 ], name=DinamicString("cosh(_1)", newName));
@cached_function
+def Tanh(input, ddR = None):
+ '''
+ DD-finite implementation of the Tangent hyperbolic function (tanh(x)).
+
+ References:
+ - http://mathworld.wolfram.com/HyperbolicTangent.html
+ - https://en.wikipedia.org/wiki/Hyperbolic_function
+
+ This functions allows the user to fix the argument. The argument can be:
+ - A symbolic expression: all variables but "x" will be considered as parameters. Must be a polynomial expression with x as a factor.
+ - A polynomial: the first generator of the polynomial ring will be considered the variable to compute derivatives and the rest will be considered as parameters. The polynomial must be divisible by the main variable.
+ - A DDFunction: the composition will be computed. The DDFunction must have initial value 0.
+
+ This function can be converted into symbolic expressions.
+ '''
+ if(is_DDFunction(input)):
+ return Tanh(x)(input);
+ g, dR = __decide_parent(input, ddR,_sage_const_2 );
+
+
+ evaluate = lambda p : dR.getSequenceElement(p,_sage_const_0 );
+ if(evaluate(g) != _sage_const_0 ):
+ raise ValueError("Impossible to compute tan(f) with f(0) != 0");
+
+ dg = dR.base_derivation(g); ddg = dR.base_derivation(dg);
+ a = Cosh(input)**_sage_const_2 ;
+
+ ### First we compute the new linear differential operator
+ newOperator = dR.element([2*dg**3, -ddg*a, dg*a]).equation;
+
+ ### Now, we compute the initial values required
+ if(input == x):
+ newInit = [0,1];
+ else:
+ required = newOperator.get_jp_fo()+_sage_const_1 ;
+
+ init_tanh = Tanh(x).getInitialValueList(required);
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
+
+ newInit = [init_tanh[_sage_const_0 ]]+[sum([init_tanh[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
+
+ result = dR.element(newOperator,newInit);
+
+ newName = repr(input);
+ if(hasattr(input, "_DDFunction__name") and (not(input._DDFunction__name is None))):
+ newName = input._DDFunction__name;
+
+ result._DDFunction__name = DinamicString("tanh(_1)",newName);
+ return result;
+
+@cached_function
def Arcsin(input, ddR = None):
'''
DD-finite implementation of the Arcsine function (arcsin(x)).
required = newOperator.get_jp_fo()+_sage_const_1 ;
init_arcsin = Arcsin(x).getInitialValueList(required);
- init_input = [factorial(i)*dR.base().getSequenceElement(g,i) for i in range(required)];
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
newInit = [init_arcsin[_sage_const_0 ]]+[sum([init_arcsin[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
DD-finite implementation of the Arccosine function (arccos(x)).
References:
- - http://mathworld.wolfram.com/InverseSine.html
+ - http://mathworld.wolfram.com/InverseCosine.html
- https://en.wikipedia.org/wiki/Inverse_trigonometric_functions
This functions allows the user to fix the argument. The argument can be:
required = newOperator.get_jp_fo()+_sage_const_1 ;
init_arccos = Arccos(x).getInitialValueList(required);
- init_input = [factorial(i)*dR.base().getSequenceElement(g,i) for i in range(required)];
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
newInit = [init_arccos[_sage_const_0 ]]+[sum([init_arccos[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
required = newOperator.get_jp_fo()+_sage_const_1 ;
init_arctan = Arctan(x).getInitialValueList(required);
- init_input = [factorial(i)*dR.base().getSequenceElement(g,i) for i in range(required)];
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
newInit = [init_arctan[_sage_const_0 ]]+[sum([init_arctan[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
result._DDFunction__name = DinamicString("arctan(_1)",newName);
return result;
+@cached_function
+def Arcsinh(input, ddR = None):
+ '''
+ DD-finite implementation of the hyperbolic Arcsine function (arcsinh(x)).
+
+ References:
+ - http://mathworld.wolfram.com/InverseHyperbolicSine.html
+ - https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions
+
+ This functions allows the user to fix the argument. The argument can be:
+ - A symbolic expression: all variables but "x" will be considered as parameters. Must be a polynomial expression with x as a factor.
+ - A polynomial: the first generator of the polynomial ring will be considered the variable to compute derivatives and the rest will be considered as parameters. The polynomial must be divisible by the main variable.
+ - A DDFunction: the composition will be computed. The DDFunction must have initial value 0.
+
+ This function can be converted into symbolic expressions.
+ '''
+ if(is_DDFunction(input)):
+ return Arcsinh(x)(input);
+ g, dR = __decide_parent(input, ddR);
+
+ evaluate = lambda p : dR.getSequenceElement(p,_sage_const_0 );
+ if(evaluate(g) != _sage_const_0 ):
+ raise ValueError("Impossible to compute arcsinh(f) with f(0) != 0");
+
+ dg = dR.base_derivation(g); ddg = dR.base_derivation(dg); a = g**2+1
+
+ ### First we compute the new linear differential operator
+ newOperator = dR.element([dR.base().zero(),(g*dg**2 - ddg*a),dg*a]).equation;
+
+ ### Now, we compute the initial values required
+ if(input == x):
+ newInit = [_sage_const_0,_sage_const_1];
+ else:
+ required = newOperator.get_jp_fo()+_sage_const_1 ;
+
+ init_arcsinh = Arcsinh(x).getInitialValueList(required);
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
+
+ newInit = [init_arcsinh[_sage_const_0 ]]+[sum([init_arcsinh[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
+
+ result = dR.element(newOperator,newInit);
+ newName = repr(input);
+ if(hasattr(input, "_DDFunction__name") and (not(input._DDFunction__name is None))):
+ newName = input._DDFunction__name;
+
+ result._DDFunction__name = DinamicString("arcsinh(_1)",newName);
+
+ return result;
+
+@cached_function
+def Arccosh(input, ddR = None):
+ '''
+ DD-finite implementation of the hyperbolic Arccosine function (arccosh(x)).
+
+ References:
+ - http://mathworld.wolfram.com/InverseHyperbolicCosine.html
+ - https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions
+
+ This functions allows the user to fix the argument. The argument can be:
+ - A symbolic expression: all variables but "x" will be considered as parameters. Must be a polynomial expression with x as a factor.
+ - A polynomial: the first generator of the polynomial ring will be considered the variable to compute derivatives and the rest will be considered as parameters. The polynomial must be divisible by the main variable.
+ - A DDFunction: the composition will be computed. The DDFunction must have initial value 0.
+
+ This function can be converted into symbolic expressions.
+ '''
+ if(is_DDFunction(input)):
+ return Arccosh(x)(input);
+ g, dR = __decide_parent(input, ddR);
+ dR = dR.extend_base_field(NumberField(x**2+1, name='I')); I = dR.base_field.gens()[0];
+ dR = ParametrizedDDRing(dR, 'pi'); pi = dR.parameter('pi');
+
+ evaluate = lambda p : dR.getSequenceElement(p,_sage_const_0 );
+ if(evaluate(g) != _sage_const_0 ):
+ raise ValueError("Impossible to compute arccosh(f) with f(0) != 0");
+
+ dg = dR.base_derivation(g); ddg = dR.base_derivation(dg); a = g**2-1
+
+ ### First we compute the new linear differential operator
+ newOperator = dR.element([dR.base().zero(),(g*dg**2 - ddg*a),dg*a]).equation;
+
+ ### Now, we compute the initial values required
+ if(input == x):
+ newInit = [I*pi/2,-I];
+ else:
+ required = newOperator.get_jp_fo()+_sage_const_1 ;
+
+ init_arccosh = Arccosh(x).getInitialValueList(required);
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
+
+ newInit = [init_arccosh[_sage_const_0 ]]+[sum([init_arccosh[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
+
+ result = dR.element(newOperator,newInit);
+ newName = repr(input);
+ if(hasattr(input, "_DDFunction__name") and (not(input._DDFunction__name is None))):
+ newName = input._DDFunction__name;
+
+ result._DDFunction__name = DinamicString("arccosh(_1)",newName);
+
+ return result;
+
+@cached_function
+def Arctanh(input, ddR = None):
+ '''
+ DD-finite implementation of the hyperbolic Arctangent function (arctanh(x)).
+
+ References:
+ - http://mathworld.wolfram.com/InverseHyperbolicTangent.html
+ - https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions
+
+ This functions allows the user to fix the argument. The argument can be:
+ - A symbolic expression: all variables but "x" will be considered as parameters. Must be a polynomial expression with x as a factor.
+ - A polynomial: the first generator of the polynomial ring will be considered the variable to compute derivatives and the rest will be considered as parameters. The polynomial must be divisible by the main variable.
+ - A DDFunction: the composition will be computed. The DDFunction must have initial value 0.
+
+ This function can be converted into symbolic expressions.
+ '''
+ if(is_DDFunction(input)):
+ return Arctanh(x)(input);
+ g, dR = __decide_parent(input, ddR);
+
+ evaluate = lambda p : dR.getSequenceElement(p,_sage_const_0 );
+ if(evaluate(g) != _sage_const_0 ):
+ raise ValueError("Impossible to compute arctanh(f) with f(0) != 0");
+
+ dg = dR.base_derivation(g); ddg = dR.base_derivation(dg); a = 1-g**2;
+
+ ### First we compute the new linear differential operator
+ newOperator = dR.element([dR.base().zero(), -(ddg*a + g*dg**2*2), dg*a]).equation;
+
+ ### Now, we compute the initial values required
+ if(input == x):
+ newInit = [_sage_const_0,_sage_const_1];
+ else:
+ required = newOperator.get_jp_fo()+_sage_const_1 ;
+
+ init_arctanh = Arctanh(x).getInitialValueList(required);
+ init_input = [factorial(i)*dR.getSequenceElement(g,i) for i in range(required)];
+
+ newInit = [init_arctanh[_sage_const_0 ]]+[sum([init_arctanh[j]*bell_polynomial(i,j)(*init_input[_sage_const_1 :i-j+_sage_const_2 ]) for j in range(_sage_const_1 ,i+_sage_const_1 )]) for i in range(_sage_const_1 ,required)]; ## See Faa di Bruno's formula
+
+ result = dR.element(newOperator,newInit);
+
+ newName = repr(input);
+ if(hasattr(input, "_DDFunction__name") and (not(input._DDFunction__name is None))):
+ newName = input._DDFunction__name;
+
+ result._DDFunction__name = DinamicString("arctanh(_1)",newName);
+ return result;
+
##################################################################################
##################################################################################
###
Method to compute a random element in this ring. This method relies in a random generator of the self.base() ring and a generator of
elements of the ring self.base_ring().
This method accepts different named arguments:
- - "min_order": minimal order for the equation we would get (default to 1)
- - "max_order": maximal order for the equation we would get (default to 3)
- - "simple": if True, the leading coefficient will always be one (default True)
- '''
- ## Getting the arguments values
- min_order = kwds.get("min_order", 1);
- max_order = kwds.get("max_order", 3);
- simple = kwds.get("simple", True);
+ - "min_order": minimal order for the equation we would get (default to 1)
+ - "max_order": maximal order for the equation we would get (default to 3)
+ - "simple": if True, the leading coefficient will always be one (default True)
+ '''
+ ## Getting the arguments values
+ min_order = kwds.get("min_order", 1);
+ max_order = kwds.get("max_order", 3);
+ simple = kwds.get("simple", True);
- ## Checking the argument values
- min_order = max(min_order,0); ## Need at least order 1
- max_order = max(min_order, max_order); ## At least the maximal order must be equal to the minimal
- if(simple != True and simple != False):
+ ## Checking the argument values
+ min_order = max(min_order,0); ## Need at least order 1
+ max_order = max(min_order, max_order); ## At least the maximal order must be equal to the minimal
+ if(simple != True and simple != False):
simple = False;
## Computing the list of coefficients
- R = self.base(); S = self.base_field;
+ R = self.base(); S = self.base_field;
coeffs = [R.random_element() for i in range(randint(min_order,max_order)+1)];
-
- init_values = [0];
- while(init_values[0] == 0):
+
+ init_values = [0];
+ while(init_values[0] == 0):
init_values[0] = S.random_element();
- ## If we want simple elements, we can compute the initial values directly
- if(simple):
- coeffs[-1] = R.one();
- init_values += [S.random_element() for i in range(len(coeffs)-2)];
- return self.element(coeffs,init_values);
- ## Otherwise, we need to know the initial value condition
+ ## If we want simple elements, we can compute the initial values directly
+ if(simple):
+ coeffs[-1] = R.one();
+ init_values += [S.random_element() for i in range(len(coeffs)-2)];
+ return self.element(coeffs,init_values);
+ ## Otherwise, we need to know the initial value condition
equation = self.element(coeffs).equation;
warnings.warn("Not-simple random element not implemented. Returning zero", DDFunctionWarning, stacklevel=2);
- return self.zero();
+ return self.zero();
-
-
def characteristic(self):
'''
Method inherited from the Ring SAGE class. It returns the characteristic of the coefficient ring.
def to_depth(self, dest):
return DDRing(self.original_ring(), depth = dest, base_field = self.base_field, invertibility = self.base_inversionCriteria, derivation = self.base_derivation, default_operator = self.default_operator);
+
+ def extend_base_field(self, new_field):
+ return DDRing(pushout(self.original_ring(), new_field), depth = self.depth(), base_field = pushout(self.base_field, new_field), invertibility = self.base_inversionCriteria, derivation = self.base_derivation, default_operator = self.default_operator);
def is_field(self, **kwds):
return False;
# Override to_depth method from DDRing
def to_depth(self, dest):
return ParametrizedDDRing(self.base_ddRing().to_depth(dest), self.parameters(True));
+
+ # Override extend_base_field method from DDRing
+ def extend_base_field(self, new_field):
+ return ParametrizedDDRing(self.base_ddRing().extend_base_field(new_field), self.parameters(True));
# Override eval method from DDRing
def eval(self, element, X=None, **input):