1#[cfg(feature = "symbolic")]
8pub use quantrs2_symengine::{Expression as SymEngine, SymEngineError, SymEngineResult};
9
10use crate::error::{QuantRS2Error, QuantRS2Result};
11use scirs2_core::num_traits::{One, Zero}; use scirs2_core::Complex64;
13use std::collections::HashMap;
14use std::fmt;
15
16#[derive(Debug, Clone, PartialEq)]
18pub enum SymbolicExpression {
19 Constant(f64),
21
22 ComplexConstant(Complex64),
24
25 Variable(String),
27
28 #[cfg(feature = "symbolic")]
30 SymEngine(SymEngine),
31
32 #[cfg(not(feature = "symbolic"))]
34 Simple(SimpleExpression),
35}
36
37#[cfg(not(feature = "symbolic"))]
39#[derive(Debug, Clone, PartialEq)]
40pub enum SimpleExpression {
41 Add(Box<SymbolicExpression>, Box<SymbolicExpression>),
42 Sub(Box<SymbolicExpression>, Box<SymbolicExpression>),
43 Mul(Box<SymbolicExpression>, Box<SymbolicExpression>),
44 Div(Box<SymbolicExpression>, Box<SymbolicExpression>),
45 Pow(Box<SymbolicExpression>, Box<SymbolicExpression>),
46 Sin(Box<SymbolicExpression>),
47 Cos(Box<SymbolicExpression>),
48 Exp(Box<SymbolicExpression>),
49 Log(Box<SymbolicExpression>),
50}
51
52impl SymbolicExpression {
53 pub fn constant(value: f64) -> Self {
55 SymbolicExpression::Constant(value)
56 }
57
58 pub fn zero() -> Self {
59 SymbolicExpression::Constant(0.0)
60 }
61
62 pub fn complex_constant(value: Complex64) -> Self {
64 SymbolicExpression::ComplexConstant(value)
65 }
66
67 pub fn variable(name: &str) -> Self {
69 SymbolicExpression::Variable(name.to_string())
70 }
71
72 #[cfg(feature = "symbolic")]
74 pub fn from_symengine(expr: SymEngine) -> Self {
75 SymbolicExpression::SymEngine(expr)
76 }
77
78 pub fn parse(expr: &str) -> QuantRS2Result<Self> {
80 #[cfg(feature = "symbolic")]
81 {
82 match SymEngine::try_new(expr) {
83 Ok(sym_expr) => Ok(SymbolicExpression::SymEngine(sym_expr)),
84 Err(_) => {
85 Self::parse_simple(expr)
87 }
88 }
89 }
90
91 #[cfg(not(feature = "symbolic"))]
92 {
93 Self::parse_simple(expr)
94 }
95 }
96
97 fn parse_simple(expr: &str) -> QuantRS2Result<Self> {
99 let trimmed = expr.trim();
100
101 if let Ok(value) = trimmed.parse::<f64>() {
103 return Ok(SymbolicExpression::Constant(value));
104 }
105
106 Ok(SymbolicExpression::Variable(trimmed.to_string()))
108 }
109
110 pub fn evaluate(&self, variables: &HashMap<String, f64>) -> QuantRS2Result<f64> {
112 match self {
113 SymbolicExpression::Constant(value) => Ok(*value),
114 SymbolicExpression::ComplexConstant(value) => {
115 if value.im.abs() < 1e-12 {
116 Ok(value.re)
117 } else {
118 Err(QuantRS2Error::InvalidInput(
119 "Cannot evaluate complex expression to real number".to_string(),
120 ))
121 }
122 }
123 SymbolicExpression::Variable(name) => variables.get(name).copied().ok_or_else(|| {
124 QuantRS2Error::InvalidInput(format!("Variable '{}' not found", name))
125 }),
126
127 #[cfg(feature = "symbolic")]
128 SymbolicExpression::SymEngine(expr) => {
129 if let Ok(value) = expr.to_string().parse::<f64>() {
132 Ok(value)
133 } else {
134 Err(QuantRS2Error::UnsupportedOperation(
135 "SymEngine evaluation not yet implemented".to_string(),
136 ))
137 }
138 }
139
140 #[cfg(not(feature = "symbolic"))]
141 SymbolicExpression::Simple(simple_expr) => {
142 Self::evaluate_simple(simple_expr, variables)
143 }
144 }
145 }
146
147 pub fn evaluate_complex(
149 &self,
150 variables: &HashMap<String, Complex64>,
151 ) -> QuantRS2Result<Complex64> {
152 match self {
153 SymbolicExpression::Constant(value) => Ok(Complex64::new(*value, 0.0)),
154 SymbolicExpression::ComplexConstant(value) => Ok(*value),
155 SymbolicExpression::Variable(name) => variables.get(name).copied().ok_or_else(|| {
156 QuantRS2Error::InvalidInput(format!("Variable '{}' not found", name))
157 }),
158
159 #[cfg(feature = "symbolic")]
160 SymbolicExpression::SymEngine(_) => Err(QuantRS2Error::UnsupportedOperation(
161 "Complex SymEngine evaluation not yet implemented".to_string(),
162 )),
163
164 #[cfg(not(feature = "symbolic"))]
165 SymbolicExpression::Simple(simple_expr) => {
166 Self::evaluate_simple_complex(simple_expr, variables)
167 }
168 }
169 }
170
171 #[cfg(not(feature = "symbolic"))]
172 fn evaluate_simple(
173 expr: &SimpleExpression,
174 variables: &HashMap<String, f64>,
175 ) -> QuantRS2Result<f64> {
176 match expr {
177 SimpleExpression::Add(a, b) => Ok(a.evaluate(variables)? + b.evaluate(variables)?),
178 SimpleExpression::Sub(a, b) => Ok(a.evaluate(variables)? - b.evaluate(variables)?),
179 SimpleExpression::Mul(a, b) => Ok(a.evaluate(variables)? * b.evaluate(variables)?),
180 SimpleExpression::Div(a, b) => {
181 let b_val = b.evaluate(variables)?;
182 if b_val.abs() < 1e-12 {
183 Err(QuantRS2Error::DivisionByZero)
184 } else {
185 Ok(a.evaluate(variables)? / b_val)
186 }
187 }
188 SimpleExpression::Pow(a, b) => Ok(a.evaluate(variables)?.powf(b.evaluate(variables)?)),
189 SimpleExpression::Sin(a) => Ok(a.evaluate(variables)?.sin()),
190 SimpleExpression::Cos(a) => Ok(a.evaluate(variables)?.cos()),
191 SimpleExpression::Exp(a) => Ok(a.evaluate(variables)?.exp()),
192 SimpleExpression::Log(a) => {
193 let a_val = a.evaluate(variables)?;
194 if a_val <= 0.0 {
195 Err(QuantRS2Error::InvalidInput(
196 "Logarithm of non-positive number".to_string(),
197 ))
198 } else {
199 Ok(a_val.ln())
200 }
201 }
202 }
203 }
204
205 #[cfg(not(feature = "symbolic"))]
206 fn evaluate_simple_complex(
207 expr: &SimpleExpression,
208 variables: &HashMap<String, Complex64>,
209 ) -> QuantRS2Result<Complex64> {
210 let real_vars: HashMap<String, f64> = variables
212 .iter()
213 .filter_map(|(k, v)| {
214 if v.im.abs() < 1e-12 {
215 Some((k.clone(), v.re))
216 } else {
217 None
218 }
219 })
220 .collect();
221
222 let real_result = Self::evaluate_simple(expr, &real_vars)?;
223 Ok(Complex64::new(real_result, 0.0))
224 }
225
226 pub fn variables(&self) -> Vec<String> {
228 match self {
229 SymbolicExpression::Constant(_) | SymbolicExpression::ComplexConstant(_) => Vec::new(),
230 SymbolicExpression::Variable(name) => vec![name.clone()],
231
232 #[cfg(feature = "symbolic")]
233 SymbolicExpression::SymEngine(_) => {
234 Vec::new()
236 }
237
238 #[cfg(not(feature = "symbolic"))]
239 SymbolicExpression::Simple(simple_expr) => Self::variables_simple(simple_expr),
240 }
241 }
242
243 #[cfg(not(feature = "symbolic"))]
244 fn variables_simple(expr: &SimpleExpression) -> Vec<String> {
245 match expr {
246 SimpleExpression::Add(a, b)
247 | SimpleExpression::Sub(a, b)
248 | SimpleExpression::Mul(a, b)
249 | SimpleExpression::Div(a, b)
250 | SimpleExpression::Pow(a, b) => {
251 let mut vars = a.variables();
252 vars.extend(b.variables());
253 vars.sort();
254 vars.dedup();
255 vars
256 }
257 SimpleExpression::Sin(a)
258 | SimpleExpression::Cos(a)
259 | SimpleExpression::Exp(a)
260 | SimpleExpression::Log(a) => a.variables(),
261 }
262 }
263
264 pub fn is_constant(&self) -> bool {
266 match self {
267 SymbolicExpression::Constant(_) | SymbolicExpression::ComplexConstant(_) => true,
268 SymbolicExpression::Variable(_) => false,
269
270 #[cfg(feature = "symbolic")]
271 SymbolicExpression::SymEngine(_) => {
272 false
274 }
275
276 #[cfg(not(feature = "symbolic"))]
277 SymbolicExpression::Simple(_) => false,
278 }
279 }
280
281 pub fn substitute(
283 &self,
284 substitutions: &HashMap<String, SymbolicExpression>,
285 ) -> QuantRS2Result<Self> {
286 match self {
287 SymbolicExpression::Constant(_) | SymbolicExpression::ComplexConstant(_) => {
288 Ok(self.clone())
289 }
290 SymbolicExpression::Variable(name) => Ok(substitutions
291 .get(name)
292 .cloned()
293 .unwrap_or_else(|| self.clone())),
294
295 #[cfg(feature = "symbolic")]
296 SymbolicExpression::SymEngine(_) => {
297 Err(QuantRS2Error::UnsupportedOperation(
299 "SymEngine substitution not yet implemented".to_string(),
300 ))
301 }
302
303 #[cfg(not(feature = "symbolic"))]
304 SymbolicExpression::Simple(_) => {
305 Err(QuantRS2Error::UnsupportedOperation(
307 "Simple expression substitution not yet implemented".to_string(),
308 ))
309 }
310 }
311 }
312}
313
314impl std::ops::Add for SymbolicExpression {
316 type Output = Self;
317
318 fn add(self, rhs: Self) -> Self::Output {
319 #[cfg(feature = "symbolic")]
320 {
321 match (self, rhs) {
322 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
324 SymbolicExpression::Constant(a + b)
325 }
326 (SymbolicExpression::SymEngine(a), SymbolicExpression::SymEngine(b)) => {
327 SymbolicExpression::SymEngine(a + b)
328 }
329 (a, b) => {
330 let a_sym = match a {
332 SymbolicExpression::Constant(val) => SymEngine::from(val),
333 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
334 SymbolicExpression::SymEngine(expr) => expr,
335 _ => return SymbolicExpression::Constant(0.0), };
337 let b_sym = match b {
338 SymbolicExpression::Constant(val) => SymEngine::from(val),
339 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
340 SymbolicExpression::SymEngine(expr) => expr,
341 _ => return SymbolicExpression::Constant(0.0), };
343 SymbolicExpression::SymEngine(a_sym + b_sym)
344 }
345 }
346 }
347
348 #[cfg(not(feature = "symbolic"))]
349 {
350 match (self, rhs) {
351 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
352 SymbolicExpression::Constant(a + b)
353 }
354 (a, b) => {
355 SymbolicExpression::Simple(SimpleExpression::Add(Box::new(a), Box::new(b)))
356 }
357 }
358 }
359 }
360}
361
362impl std::ops::Sub for SymbolicExpression {
363 type Output = Self;
364
365 fn sub(self, rhs: Self) -> Self::Output {
366 #[cfg(feature = "symbolic")]
367 {
368 match (self, rhs) {
369 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
371 SymbolicExpression::Constant(a - b)
372 }
373 (SymbolicExpression::SymEngine(a), SymbolicExpression::SymEngine(b)) => {
374 SymbolicExpression::SymEngine(a - b)
375 }
376 (a, b) => {
377 let a_sym = match a {
378 SymbolicExpression::Constant(val) => SymEngine::from(val),
379 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
380 SymbolicExpression::SymEngine(expr) => expr,
381 _ => return SymbolicExpression::Constant(0.0),
382 };
383 let b_sym = match b {
384 SymbolicExpression::Constant(val) => SymEngine::from(val),
385 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
386 SymbolicExpression::SymEngine(expr) => expr,
387 _ => return SymbolicExpression::Constant(0.0),
388 };
389 SymbolicExpression::SymEngine(a_sym - b_sym)
390 }
391 }
392 }
393
394 #[cfg(not(feature = "symbolic"))]
395 {
396 match (self, rhs) {
397 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
398 SymbolicExpression::Constant(a - b)
399 }
400 (a, b) => {
401 SymbolicExpression::Simple(SimpleExpression::Sub(Box::new(a), Box::new(b)))
402 }
403 }
404 }
405 }
406}
407
408impl std::ops::Mul for SymbolicExpression {
409 type Output = Self;
410
411 fn mul(self, rhs: Self) -> Self::Output {
412 #[cfg(feature = "symbolic")]
413 {
414 match (self, rhs) {
415 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
417 SymbolicExpression::Constant(a * b)
418 }
419 (SymbolicExpression::SymEngine(a), SymbolicExpression::SymEngine(b)) => {
420 SymbolicExpression::SymEngine(a * b)
421 }
422 (a, b) => {
423 let a_sym = match a {
424 SymbolicExpression::Constant(val) => SymEngine::from(val),
425 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
426 SymbolicExpression::SymEngine(expr) => expr,
427 _ => return SymbolicExpression::Constant(0.0),
428 };
429 let b_sym = match b {
430 SymbolicExpression::Constant(val) => SymEngine::from(val),
431 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
432 SymbolicExpression::SymEngine(expr) => expr,
433 _ => return SymbolicExpression::Constant(0.0),
434 };
435 SymbolicExpression::SymEngine(a_sym * b_sym)
436 }
437 }
438 }
439
440 #[cfg(not(feature = "symbolic"))]
441 {
442 match (self, rhs) {
443 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
444 SymbolicExpression::Constant(a * b)
445 }
446 (a, b) => {
447 SymbolicExpression::Simple(SimpleExpression::Mul(Box::new(a), Box::new(b)))
448 }
449 }
450 }
451 }
452}
453
454impl std::ops::Div for SymbolicExpression {
455 type Output = Self;
456
457 fn div(self, rhs: Self) -> Self::Output {
458 #[cfg(feature = "symbolic")]
459 {
460 match (self, rhs) {
461 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
463 if b.abs() < 1e-12 {
464 SymbolicExpression::Constant(f64::INFINITY)
465 } else {
466 SymbolicExpression::Constant(a / b)
467 }
468 }
469 (SymbolicExpression::SymEngine(a), SymbolicExpression::SymEngine(b)) => {
470 SymbolicExpression::SymEngine(a / b)
471 }
472 (a, b) => {
473 let a_sym = match a {
474 SymbolicExpression::Constant(val) => SymEngine::from(val),
475 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
476 SymbolicExpression::SymEngine(expr) => expr,
477 _ => return SymbolicExpression::Constant(0.0),
478 };
479 let b_sym = match b {
480 SymbolicExpression::Constant(val) => SymEngine::from(val),
481 SymbolicExpression::Variable(name) => SymEngine::symbol(name),
482 SymbolicExpression::SymEngine(expr) => expr,
483 _ => return SymbolicExpression::Constant(1.0),
484 };
485 SymbolicExpression::SymEngine(a_sym / b_sym)
486 }
487 }
488 }
489
490 #[cfg(not(feature = "symbolic"))]
491 {
492 match (self, rhs) {
493 (SymbolicExpression::Constant(a), SymbolicExpression::Constant(b)) => {
494 if b.abs() < 1e-12 {
495 SymbolicExpression::Constant(f64::INFINITY)
496 } else {
497 SymbolicExpression::Constant(a / b)
498 }
499 }
500 (a, b) => {
501 SymbolicExpression::Simple(SimpleExpression::Div(Box::new(a), Box::new(b)))
502 }
503 }
504 }
505 }
506}
507
508impl fmt::Display for SymbolicExpression {
509 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
510 match self {
511 SymbolicExpression::Constant(value) => write!(f, "{}", value),
512 SymbolicExpression::ComplexConstant(value) => {
513 if value.im == 0.0 {
514 write!(f, "{}", value.re)
515 } else if value.re == 0.0 {
516 write!(f, "{}*I", value.im)
517 } else {
518 write!(f, "{} + {}*I", value.re, value.im)
519 }
520 }
521 SymbolicExpression::Variable(name) => write!(f, "{}", name),
522
523 #[cfg(feature = "symbolic")]
524 SymbolicExpression::SymEngine(expr) => write!(f, "{}", expr),
525
526 #[cfg(not(feature = "symbolic"))]
527 SymbolicExpression::Simple(expr) => Self::display_simple(expr, f),
528 }
529 }
530}
531
532#[cfg(not(feature = "symbolic"))]
533impl SymbolicExpression {
534 fn display_simple(expr: &SimpleExpression, f: &mut fmt::Formatter<'_>) -> fmt::Result {
535 match expr {
536 SimpleExpression::Add(a, b) => write!(f, "({} + {})", a, b),
537 SimpleExpression::Sub(a, b) => write!(f, "({} - {})", a, b),
538 SimpleExpression::Mul(a, b) => write!(f, "({} * {})", a, b),
539 SimpleExpression::Div(a, b) => write!(f, "({} / {})", a, b),
540 SimpleExpression::Pow(a, b) => write!(f, "({} ^ {})", a, b),
541 SimpleExpression::Sin(a) => write!(f, "sin({})", a),
542 SimpleExpression::Cos(a) => write!(f, "cos({})", a),
543 SimpleExpression::Exp(a) => write!(f, "exp({})", a),
544 SimpleExpression::Log(a) => write!(f, "log({})", a),
545 }
546 }
547}
548
549impl From<f64> for SymbolicExpression {
550 fn from(value: f64) -> Self {
551 SymbolicExpression::Constant(value)
552 }
553}
554
555impl From<Complex64> for SymbolicExpression {
556 fn from(value: Complex64) -> Self {
557 if value.im == 0.0 {
558 SymbolicExpression::Constant(value.re)
559 } else {
560 SymbolicExpression::ComplexConstant(value)
561 }
562 }
563}
564
565impl From<&str> for SymbolicExpression {
566 fn from(name: &str) -> Self {
567 SymbolicExpression::Variable(name.to_string())
568 }
569}
570
571impl Zero for SymbolicExpression {
572 fn zero() -> Self {
573 SymbolicExpression::Constant(0.0)
574 }
575
576 fn is_zero(&self) -> bool {
577 match self {
578 SymbolicExpression::Constant(val) => *val == 0.0,
579 SymbolicExpression::ComplexConstant(val) => val.is_zero(),
580 _ => false,
581 }
582 }
583}
584
585impl One for SymbolicExpression {
586 fn one() -> Self {
587 SymbolicExpression::Constant(1.0)
588 }
589
590 fn is_one(&self) -> bool {
591 match self {
592 SymbolicExpression::Constant(val) => *val == 1.0,
593 SymbolicExpression::ComplexConstant(val) => val.is_one(),
594 _ => false,
595 }
596 }
597}
598
599#[cfg(feature = "symbolic")]
601pub mod calculus {
602 use super::*;
603 use quantrs2_symengine::ops::calculus;
604
605 pub fn diff(expr: &SymbolicExpression, var: &str) -> QuantRS2Result<SymbolicExpression> {
607 match expr {
608 SymbolicExpression::SymEngine(sym_expr) => {
609 let var_expr = SymEngine::symbol(var);
610 match calculus::diff(sym_expr, &var_expr) {
611 Ok(result) => Ok(SymbolicExpression::SymEngine(result)),
612 Err(e) => Err(QuantRS2Error::ComputationError(format!(
613 "Differentiation failed: {}",
614 e
615 ))),
616 }
617 }
618 _ => Err(QuantRS2Error::UnsupportedOperation(
619 "Differentiation requires SymEngine expressions".to_string(),
620 )),
621 }
622 }
623
624 pub fn integrate(expr: &SymbolicExpression, var: &str) -> QuantRS2Result<SymbolicExpression> {
626 match expr {
627 SymbolicExpression::SymEngine(sym_expr) => {
628 let var_expr = SymEngine::symbol(var);
629 match calculus::integrate(sym_expr, &var_expr) {
630 Ok(result) => Ok(SymbolicExpression::SymEngine(result)),
631 Err(e) => Err(QuantRS2Error::ComputationError(format!(
632 "Integration failed: {}",
633 e
634 ))),
635 }
636 }
637 _ => Err(QuantRS2Error::UnsupportedOperation(
638 "Integration requires SymEngine expressions".to_string(),
639 )),
640 }
641 }
642
643 pub fn limit(
645 expr: &SymbolicExpression,
646 var: &str,
647 value: f64,
648 ) -> QuantRS2Result<SymbolicExpression> {
649 match expr {
650 SymbolicExpression::SymEngine(sym_expr) => {
651 let var_expr = SymEngine::symbol(var);
652 let value_expr = SymEngine::from(value);
653 match calculus::limit(sym_expr, &var_expr, &value_expr) {
654 Ok(result) => Ok(SymbolicExpression::SymEngine(result)),
655 Err(e) => Err(QuantRS2Error::ComputationError(format!(
656 "Limit computation failed: {}",
657 e
658 ))),
659 }
660 }
661 _ => Err(QuantRS2Error::UnsupportedOperation(
662 "Limit computation requires SymEngine expressions".to_string(),
663 )),
664 }
665 }
666
667 pub fn expand(expr: &SymbolicExpression) -> QuantRS2Result<SymbolicExpression> {
669 match expr {
670 SymbolicExpression::SymEngine(sym_expr) => {
671 Ok(SymbolicExpression::SymEngine(sym_expr.expand()))
672 }
673 _ => Ok(expr.clone()), }
675 }
676
677 pub fn simplify(expr: &SymbolicExpression) -> QuantRS2Result<SymbolicExpression> {
679 match expr {
680 SymbolicExpression::SymEngine(sym_expr) => {
681 Ok(SymbolicExpression::SymEngine(sym_expr.expand()))
683 }
684 _ => Ok(expr.clone()),
685 }
686 }
687}
688
689pub mod matrix {
691 use super::*;
692 use scirs2_core::ndarray::Array2;
693
694 #[derive(Debug, Clone)]
696 pub struct SymbolicMatrix {
697 pub rows: usize,
698 pub cols: usize,
699 pub elements: Vec<Vec<SymbolicExpression>>,
700 }
701
702 impl SymbolicMatrix {
703 pub fn new(rows: usize, cols: usize) -> Self {
705 let elements = vec![vec![SymbolicExpression::zero(); cols]; rows];
706 SymbolicMatrix {
707 rows,
708 cols,
709 elements,
710 }
711 }
712
713 pub fn identity(size: usize) -> Self {
715 let mut matrix = Self::new(size, size);
716 for i in 0..size {
717 matrix.elements[i][i] = SymbolicExpression::one();
718 }
719 matrix
720 }
721
722 #[allow(unused_variables)]
724 pub fn rotation_x(theta: SymbolicExpression) -> Self {
725 let mut matrix = Self::new(2, 2);
726
727 #[cfg(feature = "symbolic")]
728 {
729 let half_theta = theta.clone() / SymbolicExpression::constant(2.0);
730 let cos_expr = SymbolicExpression::SymEngine(
731 quantrs2_symengine::ops::trig::cos(&match &half_theta {
732 SymbolicExpression::SymEngine(expr) => expr.clone(),
733 _ => return matrix,
734 })
735 .unwrap_or_else(|_| quantrs2_symengine::Expression::from(1.0)),
736 );
737 let sin_expr = SymbolicExpression::SymEngine(
738 quantrs2_symengine::ops::trig::sin(&match &half_theta {
739 SymbolicExpression::SymEngine(expr) => expr.clone(),
740 _ => return matrix,
741 })
742 .unwrap_or_else(|_| quantrs2_symengine::Expression::from(0.0)),
743 );
744
745 matrix.elements[0][0] = cos_expr.clone();
746 matrix.elements[0][1] =
747 SymbolicExpression::complex_constant(Complex64::new(0.0, -1.0))
748 * sin_expr.clone();
749 matrix.elements[1][0] =
750 SymbolicExpression::complex_constant(Complex64::new(0.0, -1.0)) * sin_expr;
751 matrix.elements[1][1] = cos_expr;
752 }
753
754 #[cfg(not(feature = "symbolic"))]
755 {
756 matrix.elements[0][0] = SymbolicExpression::parse("cos(theta/2)")
758 .unwrap_or_else(|_| SymbolicExpression::one());
759 matrix.elements[0][1] = SymbolicExpression::parse("-i*sin(theta/2)")
760 .unwrap_or_else(|_| SymbolicExpression::zero());
761 matrix.elements[1][0] = SymbolicExpression::parse("-i*sin(theta/2)")
762 .unwrap_or_else(|_| SymbolicExpression::zero());
763 matrix.elements[1][1] = SymbolicExpression::parse("cos(theta/2)")
764 .unwrap_or_else(|_| SymbolicExpression::one());
765 }
766
767 matrix
768 }
769
770 pub fn evaluate(
772 &self,
773 variables: &HashMap<String, f64>,
774 ) -> QuantRS2Result<Array2<Complex64>> {
775 let mut result = Array2::<Complex64>::zeros((self.rows, self.cols));
776
777 for i in 0..self.rows {
778 for j in 0..self.cols {
779 let complex_vars: HashMap<String, Complex64> = variables
780 .iter()
781 .map(|(k, v)| (k.clone(), Complex64::new(*v, 0.0)))
782 .collect();
783
784 let value = self.elements[i][j].evaluate_complex(&complex_vars)?;
785 result[[i, j]] = value;
786 }
787 }
788
789 Ok(result)
790 }
791
792 pub fn multiply(&self, other: &SymbolicMatrix) -> QuantRS2Result<SymbolicMatrix> {
794 if self.cols != other.rows {
795 return Err(QuantRS2Error::InvalidInput(
796 "Matrix dimensions don't match for multiplication".to_string(),
797 ));
798 }
799
800 let mut result = SymbolicMatrix::new(self.rows, other.cols);
801
802 for i in 0..self.rows {
803 for j in 0..other.cols {
804 let mut sum = SymbolicExpression::zero();
805 for k in 0..self.cols {
806 let product = self.elements[i][k].clone() * other.elements[k][j].clone();
807 sum = sum + product;
808 }
809 result.elements[i][j] = sum;
810 }
811 }
812
813 Ok(result)
814 }
815 }
816
817 impl fmt::Display for SymbolicMatrix {
818 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819 writeln!(f, "SymbolicMatrix[{}x{}]:", self.rows, self.cols)?;
820 for row in &self.elements {
821 write!(f, "[")?;
822 for (j, elem) in row.iter().enumerate() {
823 if j > 0 {
824 write!(f, ", ")?;
825 }
826 write!(f, "{}", elem)?;
827 }
828 writeln!(f, "]")?;
829 }
830 Ok(())
831 }
832 }
833}
834
835#[cfg(test)]
836mod tests {
837 use super::*;
838
839 #[test]
840 fn test_symbolic_expression_creation() {
841 let const_expr = SymbolicExpression::constant(std::f64::consts::PI);
842 assert!(const_expr.is_constant());
843
844 let var_expr = SymbolicExpression::variable("x");
845 assert!(!var_expr.is_constant());
846 assert_eq!(var_expr.variables(), vec!["x"]);
847 }
848
849 #[test]
850 fn test_symbolic_arithmetic() {
851 let a = SymbolicExpression::constant(2.0);
852 let b = SymbolicExpression::constant(3.0);
853 let sum = a + b;
854
855 match sum {
856 SymbolicExpression::Constant(value) => assert_eq!(value, 5.0),
857 _ => panic!("Expected constant result"),
858 }
859 }
860
861 #[test]
862 fn test_symbolic_evaluation() {
863 let mut vars = HashMap::new();
864 vars.insert("x".to_string(), 2.0);
865
866 let var_expr = SymbolicExpression::variable("x");
867 let result = var_expr
868 .evaluate(&vars)
869 .expect("Failed to evaluate expression in test_symbolic_evaluation");
870 assert_eq!(result, 2.0);
871 }
872
873 #[test]
874 fn test_symbolic_matrix() {
875 let matrix = matrix::SymbolicMatrix::identity(2);
876 assert_eq!(matrix.rows, 2);
877 assert_eq!(matrix.cols, 2);
878 assert!(matrix.elements[0][0].is_one());
879 assert!(matrix.elements[1][1].is_one());
880 assert!(matrix.elements[0][1].is_zero());
881 }
882
883 #[cfg(feature = "symbolic")]
884 #[test]
885 fn test_symengine_integration() {
886 let expr = SymbolicExpression::parse("x^2")
887 .expect("Failed to parse expression in test_symengine_integration");
888 match expr {
889 SymbolicExpression::SymEngine(_) => {
890 assert!(!expr.is_constant());
892 }
893 _ => {
894 assert!(!expr.is_constant());
896 }
897 }
898 }
899}