Skip to content

Commit

Permalink
Support list of variables for polynomial coefficient list function
Browse files Browse the repository at this point in the history
  • Loading branch information
benruijl committed May 23, 2024
1 parent 7879d44 commit f2af03c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 60 deletions.
18 changes: 2 additions & 16 deletions .github/workflows/publish_pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ jobs:
macos:
runs-on: ${{ matrix.runner[0] }}
strategy:
fail-fast: false
matrix:
runner: [[macos-latest, x86_64], [macos-14, aarch64]]
runner: [[macos-13, x86_64], [macos-14, aarch64]]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand All @@ -28,18 +29,3 @@ jobs:
with:
name: wheels-macos-${{ matrix.runner[1] }}
path: dist

release:
name: Release
runs-on: ubuntu-latest
if: ${{ startsWith(github.ref, 'refs/tags/') }}
needs: [macos]
steps:
- uses: actions/download-artifact@v4
- name: Publish to PyPI
uses: PyO3/maturin-action@v1
env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*
93 changes: 55 additions & 38 deletions src/api/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,21 @@ impl ConvertibleToPattern {
}
}

#[derive(FromPyObject)]
pub enum OneOrMultiple<T> {
One(T),
Multiple(Vec<T>),
}

impl<T> OneOrMultiple<T> {
pub fn to_iter(&self) -> impl Iterator<Item = &T> {
match self {
OneOrMultiple::One(a) => std::slice::from_ref(a).iter(),
OneOrMultiple::Multiple(m) => m.iter(),
}
}
}

/// Operations that transform an expression.
#[pyclass(name = "Transformer", module = "symbolica")]
#[derive(Clone)]
Expand Down Expand Up @@ -2397,32 +2412,6 @@ impl PythonExpression {
Ok(b.into())
}

pub fn contract(
&self,
metric: PythonExpression,
dimension: PythonExpression,
) -> PyResult<PythonExpression> {
let m = match metric.expr.as_view() {
AtomView::Var(v) => v.get_symbol(),
e => {
return Err(exceptions::PyValueError::new_err(format!(
"Expected variable instead of {}",
e
)));
}
};

let mut b = Atom::new();

Workspace::get_local().with(|ws| {
self.expr
.as_view()
.contract(m, dimension.expr.as_view(), ws, &mut b)
});

Ok(b.into())
}

/// Expand the expression. Optionally, expand in `var` only.
pub fn expand(&self, var: Option<ConvertibleToExpression>) -> PyResult<PythonExpression> {
if let Some(var) = var {
Expand Down Expand Up @@ -4373,7 +4362,7 @@ macro_rules! generate_methods {
Ok(Self { poly: self.poly.constant(self.poly.content())})
}

/// Get the coefficient list in `x`.
/// Get the coefficient list, optionally in the variables `vars`.
///
/// Examples
/// --------
Expand All @@ -4383,18 +4372,46 @@ macro_rules! generate_methods {
/// >>> p = Expression.parse('x*y+2*x+x^2').to_polynomial()
/// >>> for n, pp in p.coefficient_list(x):
/// >>> print(n, pp)
pub fn coefficient_list(&self, var: PythonExpression) -> PyResult<Vec<(usize, Self)>> {
let x = self.poly.get_vars_ref().iter().position(|v| match (v, var.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",
var.__str__()?
)))?;
pub fn coefficient_list(&self, vars: Option<OneOrMultiple<PythonExpression>>) -> PyResult<Vec<(Vec<usize>, Self)>> {
if let Some(vv) = vars {
let mut vars = vec![];

for vvv in vv.to_iter() {
let x = self.poly.get_vars_ref().iter().position(|v| match (v, vvv.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",
vvv.__str__()?
)))?;

vars.push(x);
}

Ok(self.poly.to_univariate_polynomial_list(x).into_iter()
.map(|(f, p)| (p as usize, Self { poly: f })).collect())
if vars.is_empty() {
return Ok(self.poly.into_iter().map(|t| {
(t.exponents.iter().map(|x| *x as usize).collect(), Self { poly: self.poly.constant(t.coefficient.clone()) })
}).collect());
}

if vars.len() == 1 {
return Ok(self.poly.to_univariate_polynomial_list(vars[0]).into_iter()
.map(|(f, p)| (vec![p as usize], Self { poly: f })).collect());
}

// sort the exponents wrt the var map
let mut r: Vec<(Vec<_>, _)> = self.poly.to_multivariate_polynomial_list(&vars, true).into_iter()
.map(|(f, p)| (vars.iter().map(|v| f[*v] as usize).collect(), Self { poly: p })).collect();
r.sort_by(|a, b| a.0.cmp(&b.0));

Ok(r)

} else {
Ok(self.poly.into_iter().map(|t| {
(t.exponents.iter().map(|x| *x as usize).collect(), Self { poly: self.poly.constant(t.coefficient.clone()) })
}).collect())
}
}

/// Replace the variable `x` with a polynomial `v`.
Expand Down
12 changes: 6 additions & 6 deletions symbolica.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1713,8 +1713,8 @@ class Polynomial:
>>> print(p.content())
"""

def coefficient_list(self, x: Expression) -> list[Tuple[int, Polynomial]]:
"""Get the coefficient list in `x`.
def coefficient_list(self, xs: Optional[Expression | Sequence[Expression]]) -> list[Tuple[list[int], Polynomial]]:
"""Get the coefficient list, optionally in the variables `xs`.
Examples
--------
Expand Down Expand Up @@ -1913,8 +1913,8 @@ class IntegerPolynomial:
>>> print(p.content())
"""

def coefficient_list(self, x: Expression) -> list[Tuple[int, IntegerPolynomial]]:
"""Get the coefficient list in `x`.
def coefficient_list(self, xs: Optional[Expression | Sequence[Expression]]) -> list[Tuple[list[int], IntegerPolynomial]]:
"""Get the coefficient list, optionally in the variables `xs`.
Examples
--------
Expand Down Expand Up @@ -2110,8 +2110,8 @@ class FiniteFieldPolynomial:
>>> print(p.content())
"""

def coefficient_list(self, x: Expression) -> list[Tuple[int, FiniteFieldPolynomial]]:
"""Get the coefficient list in `x`.
def coefficient_list(self, xs: Optional[Expression | Sequence[Expression]]) -> list[Tuple[list[int], FiniteFieldPolynomial]]:
"""Get the coefficient list, optionally in the variables `xs`.
Examples
--------
Expand Down

0 comments on commit f2af03c

Please sign in to comment.