laddu-compile 0.21.3

Amplitude analysis tools for Rust
Documentation
use laddu_expr::{BinaryOp, ExprId, ExprMetadata, ExprNode, ExprSourceKind, UnaryOp};

use crate::CompileResult;

use super::super::{ConjugationRule, NormSqrExpansionRule, Rewrite, RewriteContext, RewriteRule};

use super::add_mul::ReplacementFragment;

impl RewriteRule for NormSqrExpansionRule {
    fn name(&self) -> &'static str {
        "norm-sqr-expansion"
    }

    fn rewrite(
        &self,
        node: &ExprNode,
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> CompileResult<Rewrite> {
        let ExprNode::Unary {
            op: UnaryOp::NormSqr,
            input,
        } = node
        else {
            return Ok(Rewrite::Keep);
        };
        let mut builder = ReplacementFragment::new(context);
        let conj = builder.push(
            ExprNode::Unary {
                op: UnaryOp::Conj,
                input: *input,
            },
            ExprMetadata::new(ExprSourceKind::Unary),
        );
        builder.push(
            ExprNode::NaryMul {
                factors: vec![*input, conj],
            },
            metadata.clone(),
        );
        Ok(builder.into_rewrite())
    }
}

impl RewriteRule for ConjugationRule {
    fn name(&self) -> &'static str {
        "conjugation"
    }

    fn rewrite(
        &self,
        node: &ExprNode,
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> CompileResult<Rewrite> {
        let ExprNode::Unary {
            op: UnaryOp::Conj,
            input,
        } = node
        else {
            return Ok(Rewrite::Keep);
        };
        Ok(match context.node(*input) {
            Some(ExprNode::NaryMul { factors }) => {
                self.push_conjugated_product(factors, metadata, context)
            }
            Some(ExprNode::Binary {
                op: BinaryOp::Mul,
                lhs,
                rhs,
            }) => self.push_conjugated_product(&[*lhs, *rhs], metadata, context),
            Some(ExprNode::NaryAdd { terms }) => self.push_conjugated_sum(terms, metadata, context),
            Some(ExprNode::Binary {
                op: BinaryOp::Add,
                lhs,
                rhs,
            }) => self.push_conjugated_sum(&[*lhs, *rhs], metadata, context),
            Some(ExprNode::Unary {
                op: UnaryOp::Exp,
                input,
            }) => self.push_conjugated_exp(*input, metadata, context),
            Some(ExprNode::Unary {
                op: UnaryOp::Neg,
                input,
            }) => self.push_conjugated_neg(*input, metadata, context),
            _ => Rewrite::Keep,
        })
    }
}

impl ConjugationRule {
    fn push_conjugated_product(
        &self,
        factors: &[ExprId],
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> Rewrite {
        let mut builder = ReplacementFragment::new(context);
        let factors = factors
            .iter()
            .map(|factor| builder.conjugated_term(*factor))
            .collect();
        builder.push(ExprNode::NaryMul { factors }, metadata.clone());
        builder.into_rewrite()
    }

    fn push_conjugated_sum(
        &self,
        terms: &[ExprId],
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> Rewrite {
        let mut builder = ReplacementFragment::new(context);
        let terms = terms
            .iter()
            .map(|term| builder.conjugated_term(*term))
            .collect();
        builder.push(ExprNode::NaryAdd { terms }, metadata.clone());
        builder.into_rewrite()
    }

    fn push_conjugated_exp(
        &self,
        input: ExprId,
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> Rewrite {
        let mut builder = ReplacementFragment::new(context);
        let input = builder.conjugated_term(input);
        builder.push(
            ExprNode::Unary {
                op: UnaryOp::Exp,
                input,
            },
            metadata.clone(),
        );
        builder.into_rewrite()
    }

    fn push_conjugated_neg(
        &self,
        input: ExprId,
        metadata: &ExprMetadata,
        context: &RewriteContext<'_>,
    ) -> Rewrite {
        let mut builder = ReplacementFragment::new(context);
        let input = builder.conjugated_term(input);
        builder.push(
            ExprNode::Unary {
                op: UnaryOp::Neg,
                input,
            },
            metadata.clone(),
        );
        builder.into_rewrite()
    }
}