quantrs2_symengine_pure/scirs2_bridge/
ndarray.rs

1//! Ndarray integration with SciRS2.
2//!
3//! This module provides conversion between symbolic matrices and
4//! SciRS2's ndarray types.
5
6use std::fmt::Write;
7
8use scirs2_core::ndarray::{Array1, Array2};
9use scirs2_core::Complex64;
10
11use crate::error::{SymEngineError, SymEngineResult};
12use crate::expr::Expression;
13
14/// Convert a symbolic matrix expression to a numeric `Array2<Complex64>`.
15///
16/// # Arguments
17/// * `expr` - The matrix expression
18/// * `values` - Variable values for evaluation
19///
20/// # Errors
21/// Returns an error if the expression is not a matrix or evaluation fails.
22pub fn to_array2(
23    expr: &Expression,
24    values: &std::collections::HashMap<String, f64>,
25) -> SymEngineResult<Array2<Complex64>> {
26    // TODO: Implement proper matrix parsing and evaluation
27    Err(SymEngineError::not_impl(
28        "Matrix to Array2 conversion not yet implemented",
29    ))
30}
31
32/// Convert a numeric `Array2<Complex64>` to a symbolic matrix expression.
33pub fn from_array2(arr: &Array2<Complex64>) -> Expression {
34    let (rows, cols) = arr.dim();
35
36    let mut matrix_str = String::from("Matrix([");
37
38    for i in 0..rows {
39        matrix_str.push('[');
40        for j in 0..cols {
41            let c = arr[[i, j]];
42            if c.im.abs() < 1e-15 {
43                let _ = write!(matrix_str, "{}", c.re);
44            } else if c.re.abs() < 1e-15 {
45                let _ = write!(matrix_str, "{}*I", c.im);
46            } else {
47                let _ = write!(matrix_str, "({}+{}*I)", c.re, c.im);
48            }
49            if j < cols - 1 {
50                matrix_str.push_str(", ");
51            }
52        }
53        matrix_str.push(']');
54        if i < rows - 1 {
55            matrix_str.push_str(", ");
56        }
57    }
58
59    matrix_str.push_str("])");
60
61    Expression::new(matrix_str)
62}
63
64/// Convert a symbolic vector expression to a numeric `Array1<Complex64>`.
65///
66/// # Errors
67/// Returns an error if conversion fails.
68pub fn to_array1(
69    expr: &Expression,
70    values: &std::collections::HashMap<String, f64>,
71) -> SymEngineResult<Array1<Complex64>> {
72    // TODO: Implement proper vector parsing and evaluation
73    Err(SymEngineError::not_impl(
74        "Vector to Array1 conversion not yet implemented",
75    ))
76}
77
78/// Convert a numeric `Array1<Complex64>` to a symbolic column vector expression.
79pub fn from_array1(arr: &Array1<Complex64>) -> Expression {
80    let n = arr.len();
81
82    let mut matrix_str = String::from("Matrix([");
83
84    for (i, c) in arr.iter().enumerate() {
85        matrix_str.push('[');
86        if c.im.abs() < 1e-15 {
87            let _ = write!(matrix_str, "{}", c.re);
88        } else if c.re.abs() < 1e-15 {
89            let _ = write!(matrix_str, "{}*I", c.im);
90        } else {
91            let _ = write!(matrix_str, "({}+{}*I)", c.re, c.im);
92        }
93        matrix_str.push(']');
94        if i < n - 1 {
95            matrix_str.push_str(", ");
96        }
97    }
98
99    matrix_str.push_str("])");
100
101    Expression::new(matrix_str)
102}
103
104/// Compute the gradient at given values as an `Array1<f64>`.
105///
106/// This is useful for integration with SciRS2 optimization routines.
107pub fn gradient_array(
108    expr: &Expression,
109    params: &[Expression],
110    values: &std::collections::HashMap<String, f64>,
111) -> SymEngineResult<Array1<f64>> {
112    let grad_vec = crate::optimization::gradient_at(expr, params, values)?;
113    Ok(Array1::from_vec(grad_vec))
114}
115
116/// Compute the Hessian at given values as an `Array2<f64>`.
117///
118/// This is useful for integration with SciRS2 optimization routines.
119pub fn hessian_array(
120    expr: &Expression,
121    params: &[Expression],
122    values: &std::collections::HashMap<String, f64>,
123) -> SymEngineResult<Array2<f64>> {
124    let hess_vec = crate::optimization::hessian_at(expr, params, values)?;
125    let n = params.len();
126    let mut arr = Array2::zeros((n, n));
127
128    for (i, row) in hess_vec.iter().enumerate() {
129        for (j, &val) in row.iter().enumerate() {
130            arr[[i, j]] = val;
131        }
132    }
133
134    Ok(arr)
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140    use scirs2_core::ndarray::array;
141
142    #[test]
143    fn test_from_array2() {
144        let arr: Array2<Complex64> = array![
145            [Complex64::new(1.0, 0.0), Complex64::new(0.0, 1.0)],
146            [Complex64::new(0.0, -1.0), Complex64::new(1.0, 0.0)],
147        ];
148
149        let expr = from_array2(&arr);
150        // Matrix expressions are stored as symbolic strings
151        assert!(expr.to_string().contains("Matrix"));
152    }
153
154    #[test]
155    fn test_from_array1() {
156        let arr: Array1<Complex64> = array![Complex64::new(1.0, 0.0), Complex64::new(0.0, 1.0),];
157
158        let expr = from_array1(&arr);
159        // Vector expressions are stored as symbolic matrix strings
160        assert!(expr.to_string().contains("Matrix"));
161    }
162
163    #[test]
164    fn test_gradient_array() {
165        let x = Expression::symbol("x");
166        let expr = x.clone() * x.clone(); // x^2
167        let params = vec![x];
168
169        let mut values = std::collections::HashMap::new();
170        values.insert("x".to_string(), 3.0);
171
172        let grad = gradient_array(&expr, &params, &values).expect("should compute");
173        assert!((grad[0] - 6.0).abs() < 1e-6); // d/dx(x^2) = 2x = 6 at x=3
174    }
175}