Expand description
The crate provides manipulation, calculation and evaluation of integer polynomials.
The central struct of the crate is Polynomial<I, C, P>
. The three generic arguments
specify the types of three internal parts:
I: Id
- the type which uniquely identifies a single variable variable, e.g. if we have a^x ,
then a: Id
. Note that this does not mean that it is an Integer
, but rather it is a type
which can uniquely defined variables. For instance one can use a String
by naming each
variable. Importantly, the ordering of I
defines the total ordering of the monomials
which is used to define the ordering of the polynomials as well -
Wikipedia.
C: Coefficient
- the variable Integer
type of the internal coefficients for each monomial.
The Polynomial<C, I, P>
will have implemented standard operators for interacting with type C
.
Whenever you evaluate a polynomial, the output would be of this type.
P: Power
- the Integer
type of the power values of each monomial, e.g. if we have a^x ,
then x: Power
. Note that it is required that P
is an Unsigned
type.
The choice of C
and P
should depend on the problem you are using the library for. If you
do not expect too high power values setting P
to u8
or u16
should suffice.
In all of the tests Polynomial<String, i64, u8>
is used.
§Examples
use std::collections::HashMap;
extern crate symbolic_polynomials;
use symbolic_polynomials::*;
type SymInt = Polynomial<String, i64, u8>;
pub fn main() {
// Create symbolic variables
let a: SymInt = variable("a".into());
let b: SymInt = variable("b".into());
let c: SymInt = variable("c".into());
// Build polynomials
// 5b + 2
let poly1 = &(&b * 5) + 2;
// ab
let poly2 = &a * &b;
// ab + ac + b + c
let poly3 = &(&b + &c) * &(&a + 1);
// a^2 - ab + 12
let poly4 = &(&(&a * &a) - &(&a * &b)) + 12;
// ac^2 + 3a + bc^2 + 3b + c^2 + 3
let poly5 = &(&(&a + &b) + 1) * &(&(&c * 2) + 3);
// floor(a^2, b^2)
let poly6 = floor(&(&b * &b), &(&a * &a));
// ceil(a^2, b^2)
let poly7 = ceil(&(&b * &b), &(&a * &a));
// min(ab + 12, ab + a)
let poly8 = min(&(&(&a * &b) + 12), &(&(&a * &b) + &a));
// max (ab + 12, ab + a)
let poly9 = max(&(&(&a * &b) + 12), &(&(&a * &b) + &a));
// max(floor(a^2, b) - 4, ceil(c, b) + 1)
let poly10 = max(&(&floor(&(&a *&a), &b) - 2), &(&ceil(&c, &b) + 1));
// Polynomial printing
println!("{}", (0..50).map(|_| "=").collect::<String>());
println!("{}", (0..50).map(|_| "=").collect::<String>());
println!("Displaying polynomials (string representation = code representation):");
println!("{} = {}", poly1, poly1.to_code(&|x: String| x));
println!("{} = {}", poly2, poly2.to_code(&|x: String| x));
println!("{} = {}", poly3, poly3.to_code(&|x: String| x));
println!("{} = {}", poly4, poly4.to_code(&|x: String| x));
println!("{} = {}", poly5, poly5.to_code(&|x: String| x));
println!("{} = {}", poly6, poly6.to_code(&|x: String| x));
println!("{} = {}", poly7, poly7.to_code(&|x: String| x));
println!("{} = {}", poly8, poly8.to_code(&|x: String| x));
println!("{} = {}", poly9, poly9.to_code(&|x: String| x));
println!("{} = {}", poly10, poly10.to_code(&|x: String| x));
println!("{}", (0..50).map(|_| "=").collect::<String>());
// Polynomial evaluation
let mut values = HashMap::<String, i64>::new();
values.insert("a".into(), 3);
values.insert("b".into(), 2);
values.insert("c".into(), 5);
println!("Evaluating for a = 3, b = 2, c = 5.");
println!("{} = {} [Expected 12]", poly1, poly1.eval(&values).unwrap());
println!("{} = {} [Expected 6]", poly2, poly2.eval(&values).unwrap());
println!("{} = {} [Expected 28]", poly3, poly3.eval(&values).unwrap());
println!("{} = {} [Expected 15]", poly4, poly4.eval(&values).unwrap());
println!("{} = {} [Expected 78]", poly5, poly5.eval(&values).unwrap());
println!("{} = {} [Expected 0]", poly6, poly6.eval(&values).unwrap());
println!("{} = {} [Expected 1]", poly7, poly7.eval(&values).unwrap());
println!("{} = {} [Expected 9]", poly8, poly8.eval(&values).unwrap());
println!("{} = {} [Expected 18]", poly9, poly9.eval(&values).unwrap());
println!("{} = {} [Expected 4]", poly10, poly10.eval(&values).unwrap());
println!("{}", (0..50).map(|_| "=").collect::<String>());
// Variable deduction
values.insert("a".into(), 5);
values.insert("b".into(), 3);
values.insert("c".into(), 8);
let implicit_values = vec![(poly1.clone(), poly1.eval(&values).unwrap()),
(poly2.clone(), poly2.eval(&values).unwrap()),
(poly3.clone(), poly3.eval(&values).unwrap())];
let deduced_values = deduce_values(&implicit_values).unwrap();
println!("Deduced values:");
println!("a = {} [Expected 5]", deduced_values["a"]);
println!("b = {} [Expected 3]", deduced_values["b"]);
println!("c = {} [Expected 8]", deduced_values["c"]);
println!("{}", (0..50).map(|_| "=").collect::<String>());
}
The polynomials are used in Metadiff
for modeling the shapes of tensors.
A small example of how this can be achieved is shown
here.
Structs§
- A symbolic monomial represented as C * a_1^p_1 * a_2^p_2 * … * a_n^p_n.
- A symbolic polynomial represented as m_1 + m_2 + … + m_n.
Enums§
- A composite expression (tagged union) of a variable or an irreducible function (floor, ceil, max, min)
Traits§
- A trait specifying all the bounds a
Coefficient
type should meet. - A trait specifying all the bounds an
Id
type should meet. - A trait specifying all the bounds a
Power
type should meet.
Functions§
- Computes a symbolic
ceil
between two polynomials. - Automatically deduces the individual variable assignments based on the system of equations specified by the mapping of
Polynomial
to a constant value. - Computes a symbolic
floor
between two polynomials. - Computes a symbolic
max
between two polynomials. - Computes a symbolic
min
between two polynomials. - Reduces the polynomial, given the variable assignments provided.
- Reduces the monomial, given the variable assignments provided.
- Returns a polynomial representing 1 * x^1 + 0, where ‘x’ is a variable uniquely identifiable by the provided
id
.