use super::{
AnnotationSet, BinaryOp, Direction, InequalityOp, IntegralBounds, LogicalOp, MathConstant,
MathFloat, MultipleBounds, NumberSet, RelationOp, SetOp, SetRelation, TensorIndex, UnaryOp,
VectorNotation,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", content = "value"))]
pub enum ExprKind {
Integer(i64),
Float(MathFloat),
Rational {
numerator: Box<Expression>,
denominator: Box<Expression>,
},
Complex {
real: Box<Expression>,
imaginary: Box<Expression>,
},
Quaternion {
real: Box<Expression>,
i: Box<Expression>,
j: Box<Expression>,
k: Box<Expression>,
},
Variable(String),
Constant(MathConstant),
Binary {
op: BinaryOp,
left: Box<Expression>,
right: Box<Expression>,
},
Unary {
op: UnaryOp,
operand: Box<Expression>,
},
Function {
name: String,
args: Vec<Expression>,
},
Derivative {
expr: Box<Expression>,
var: String,
order: u32,
},
PartialDerivative {
expr: Box<Expression>,
var: String,
order: u32,
},
Integral {
integrand: Box<Expression>,
var: String,
bounds: Option<IntegralBounds>,
},
MultipleIntegral {
dimension: u8,
integrand: Box<Expression>,
bounds: Option<MultipleBounds>,
vars: Vec<String>,
},
ClosedIntegral {
dimension: u8,
integrand: Box<Expression>,
surface: Option<String>,
var: String,
},
Limit {
expr: Box<Expression>,
var: String,
to: Box<Expression>,
direction: Direction,
},
Sum {
index: String,
lower: Box<Expression>,
upper: Box<Expression>,
body: Box<Expression>,
},
Product {
index: String,
lower: Box<Expression>,
upper: Box<Expression>,
body: Box<Expression>,
},
Vector(Vec<Expression>),
Matrix(Vec<Vec<Expression>>),
Equation {
left: Box<Expression>,
right: Box<Expression>,
},
Inequality {
op: InequalityOp,
left: Box<Expression>,
right: Box<Expression>,
},
ForAll {
variable: String,
domain: Option<Box<Expression>>,
body: Box<Expression>,
},
Exists {
variable: String,
domain: Option<Box<Expression>>,
body: Box<Expression>,
unique: bool,
},
Logical {
op: LogicalOp,
operands: Vec<Expression>,
},
MarkedVector {
name: String,
notation: VectorNotation,
},
DotProduct {
left: Box<Expression>,
right: Box<Expression>,
},
CrossProduct {
left: Box<Expression>,
right: Box<Expression>,
},
OuterProduct {
left: Box<Expression>,
right: Box<Expression>,
},
Gradient {
expr: Box<Expression>,
},
Divergence {
field: Box<Expression>,
},
Curl {
field: Box<Expression>,
},
Laplacian {
expr: Box<Expression>,
},
Nabla,
Determinant {
matrix: Box<Expression>,
},
Trace {
matrix: Box<Expression>,
},
Rank {
matrix: Box<Expression>,
},
ConjugateTranspose {
matrix: Box<Expression>,
},
MatrixInverse {
matrix: Box<Expression>,
},
NumberSetExpr(NumberSet),
SetOperation {
op: SetOp,
left: Box<Expression>,
right: Box<Expression>,
},
SetRelationExpr {
relation: SetRelation,
element: Box<Expression>,
set: Box<Expression>,
},
SetBuilder {
variable: String,
domain: Option<Box<Expression>>,
predicate: Box<Expression>,
},
EmptySet,
PowerSet {
set: Box<Expression>,
},
Tensor {
name: String,
indices: Vec<TensorIndex>,
},
KroneckerDelta {
indices: Vec<TensorIndex>,
},
LeviCivita {
indices: Vec<TensorIndex>,
},
FunctionSignature {
name: String,
domain: Box<Expression>,
codomain: Box<Expression>,
},
Composition {
outer: Box<Expression>,
inner: Box<Expression>,
},
Differential {
var: String,
},
WedgeProduct {
left: Box<Expression>,
right: Box<Expression>,
},
Relation {
op: RelationOp,
left: Box<Expression>,
right: Box<Expression>,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Expression {
pub kind: ExprKind,
pub annotations: AnnotationSet,
}
impl Expression {
pub fn new(kind: ExprKind) -> Self {
Self {
kind,
annotations: AnnotationSet::default(),
}
}
pub fn with_annotations(kind: ExprKind, annotations: AnnotationSet) -> Self {
Self { kind, annotations }
}
pub fn integer(v: i64) -> Self {
Self::new(ExprKind::Integer(v))
}
pub fn float(v: MathFloat) -> Self {
Self::new(ExprKind::Float(v))
}
pub fn variable(name: impl Into<String>) -> Self {
Self::new(ExprKind::Variable(name.into()))
}
pub fn constant(c: MathConstant) -> Self {
Self::new(ExprKind::Constant(c))
}
pub fn vector(elements: Vec<Expression>) -> Self {
Self::new(ExprKind::Vector(elements))
}
pub fn matrix(rows: Vec<Vec<Expression>>) -> Self {
Self::new(ExprKind::Matrix(rows))
}
pub fn number_set(s: NumberSet) -> Self {
Self::new(ExprKind::NumberSetExpr(s))
}
pub fn nabla() -> Self {
Self::new(ExprKind::Nabla)
}
pub fn empty_set() -> Self {
Self::new(ExprKind::EmptySet)
}
}
impl From<ExprKind> for Expression {
fn from(kind: ExprKind) -> Self {
Self::new(kind)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for Expression {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
use serde::ser::{Error, SerializeMap};
let kind_value = serde_json::to_value(&self.kind).map_err(Error::custom)?;
let obj = kind_value
.as_object()
.ok_or_else(|| Error::custom("ExprKind did not serialize to a JSON object"))?;
let extra = if self.annotations.is_empty() { 0 } else { 1 };
let mut map = serializer.serialize_map(Some(obj.len() + extra))?;
for (k, v) in obj {
map.serialize_entry(k, v)?;
}
if !self.annotations.is_empty() {
map.serialize_entry("annotations", &self.annotations)?;
}
map.end()
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Expression {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
use serde::de::Error;
let mut value: serde_json::Value = serde::Deserialize::deserialize(deserializer)?;
let annotations = match value.as_object_mut() {
Some(obj) => match obj.remove("annotations") {
Some(ann) => serde_json::from_value(ann).map_err(Error::custom)?,
None => AnnotationSet::default(),
},
None => AnnotationSet::default(),
};
let kind: ExprKind = serde_json::from_value(value).map_err(Error::custom)?;
Ok(Expression { kind, annotations })
}
}