Skip to content

Commit

Permalink
Add derivative method for rational polynomials
Browse files Browse the repository at this point in the history
- Fix ncols() in Python API
  • Loading branch information
benruijl committed Jul 19, 2024
1 parent b2fec19 commit 9533f21
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 1 deletion.
62 changes: 61 additions & 1 deletion src/api/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8082,6 +8082,36 @@ impl PythonRationalPolynomial {
}
}

/// Take a derivative in `x`.
///
/// Examples
/// --------
///
/// >>> from symbolica import Expression
/// >>> x = Expression.symbol('x')
/// >>> p = Expression.parse('1/((x+y)*(x^2+x*y+1)(x+1))').to_rational_polynomial()
/// >>> print(p.derivative(x))
pub fn derivative(&self, x: PythonExpression) -> PyResult<Self> {
let x = self
.poly
.numerator
.get_vars_ref()
.iter()
.position(|v| match (v, x.expr.as_view()) {
(Variable::Symbol(y), AtomView::Var(vv)) => *y == vv.get_symbol(),
(Variable::Function(_, f) | Variable::Other(f), a) => f.as_view() == a,
_ => false,
})
.ok_or(exceptions::PyValueError::new_err(format!(
"Variable {} not found in polynomial",
x.__str__()?
)))?;

Ok(Self {
poly: self.poly.derivative(x),
})
}

/// Compute the partial fraction decomposition in `x`.
///
/// Examples
Expand Down Expand Up @@ -8366,6 +8396,36 @@ impl PythonFiniteFieldRationalPolynomial {
}
}

/// Take a derivative in `x`.
///
/// Examples
/// --------
///
/// >>> from symbolica import Expression
/// >>> x = Expression.symbol('x')
/// >>> p = Expression.parse('1/((x+y)*(x^2+x*y+1)(x+1))').to_rational_polynomial()
/// >>> print(p.derivative(x))
pub fn derivative(&self, x: PythonExpression) -> PyResult<Self> {
let x = self
.poly
.numerator
.get_vars_ref()
.iter()
.position(|v| match (v, x.expr.as_view()) {
(Variable::Symbol(y), AtomView::Var(vv)) => *y == vv.get_symbol(),
(Variable::Function(_, f) | Variable::Other(f), a) => f.as_view() == a,
_ => false,
})
.ok_or(exceptions::PyValueError::new_err(format!(
"Variable {} not found in polynomial",
x.__str__()?
)))?;

Ok(Self {
poly: self.poly.derivative(x),
})
}

/// Compute the partial fraction decomposition in `x`.
///
/// Examples
Expand Down Expand Up @@ -8718,7 +8778,7 @@ impl PythonMatrix {

/// Return the number of columns.
pub fn ncols(&self) -> usize {
self.matrix.nrows()
self.matrix.ncols()
}

/// Return true iff every entry in the matrix is zero.
Expand Down
33 changes: 33 additions & 0 deletions src/domains/rational_polynomial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,39 @@ where
}
}

impl<R: EuclideanDomain + PolynomialGCD<E>, E: Exponent> RationalPolynomial<R, E>
where
RationalPolynomial<R, E>: FromNumeratorAndDenominator<R, R, E>,
{
/// Compute the derivative of the rational polynomial in `var`.
pub fn derivative(&self, var: usize) -> Self {
if self.numerator.degree(var) == E::zero() && self.denominator.degree(var) == E::zero() {
return RationalPolynomial {
numerator: self.numerator.zero(),
denominator: self.denominator.one(),
};
}

let dn = self.numerator.derivative(var);
let dd = self.denominator.derivative(var);

let a = RationalPolynomial::from_num_den(
dn,
self.denominator.clone(),
&self.numerator.field,
false,
);
let b = RationalPolynomial::from_num_den(
&self.numerator * &dd,
&self.denominator * &self.denominator,
&self.numerator.field,
false,
);

&a - &b
}
}

impl<R: EuclideanDomain + PolynomialGCD<E>, E: Exponent> RationalPolynomial<R, E>
where
RationalPolynomial<R, E>: FromNumeratorAndDenominator<R, R, E>,
Expand Down
24 changes: 24 additions & 0 deletions symbolica.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -2561,6 +2561,18 @@ class RationalPolynomial:
>>> print((e - p.to_expression()).expand())
"""

def derivative(self, x: Expression) -> RationalPolynomial:
"""Take a derivative in `x`.
Examples
--------
>>> from symbolica import Expression
>>> x = Expression.symbol('x')
>>> p = Expression.parse('1/((x+y)*(x^2+x*y+1)(x+1))').to_rational_polynomial()
>>> print(p.derivative(x))
"""

def apart(self, x: Expression) -> List[RationalPolynomial]:
"""Compute the partial fraction decomposition in `x`.
Expand Down Expand Up @@ -2629,6 +2641,18 @@ class FiniteFieldRationalPolynomial:
def gcd(self, rhs: FiniteFieldRationalPolynomial) -> FiniteFieldRationalPolynomial:
"""Compute the greatest common divisor (GCD) of two rational polynomials."""

def derivative(self, x: Expression) -> RationalPolynomial:
"""Take a derivative in `x`.
Examples
--------
>>> from symbolica import Expression
>>> x = Expression.symbol('x')
>>> p = Expression.parse('1/((x+y)*(x^2+x*y+1)(x+1))').to_rational_polynomial()
>>> print(p.derivative(x))
"""

def apart(self, x: Expression) -> List[FiniteFieldRationalPolynomial]:
"""Compute the partial fraction decomposition in `x`.
Expand Down

0 comments on commit 9533f21

Please sign in to comment.