1use crate::ast::UnaryOperator;
12use crate::hir::Branch;
13use crate::hir::DisciplineAccess;
14use crate::hir_lowering::error::{Error, Type, Warning, WarningType};
15use crate::hir_lowering::HirToMirFold;
16use crate::ir::mir::{
17 ComparisonOperator, IntegerBinaryOperator, RealExpression, Variable, VariableType,
18};
19use crate::ir::{
20 AttributeNode, Attributes, BranchId, BuiltInFunctionCall1p, BuiltInFunctionCall2p,
21 IntegerExpressionId, NetId, Node, ParameterId, RealExpressionId, VariableId,
22};
23
24use crate::mir::{IntegerExpression, Mir, RealBinaryOperator};
25use crate::symbol::{Ident, Symbol};
26use crate::ControlFlowGraph;
27use rustc_hash::{FxHashMap, FxHashSet};
28
29mod solver;
30
31pub(super) type PartialDerivativeMap = FxHashMap<Unknown, VariableId>;
32
33pub(super) type DerivativeMap = FxHashMap<VariableId, PartialDerivativeMap>;
34
35#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
36pub enum Unknown {
37 Parameter(ParameterId),
38 NodePotential(NetId),
39 PortFlow(NetId),
40 Flow(BranchId),
41 Temperature,
42 Time,
43}
44
45impl<'lt> HirToMirFold<'lt> {
46 pub(super) fn generate_derivatives(&mut self, cfg: &mut ControlFlowGraph) {
47 self.solve(cfg)
48 }
49
50 pub fn derivative_of_reference(
51 &mut self,
52 reference: VariableId,
53 derive_by: Unknown,
54 ) -> VariableId {
55 let mir = &mut self.mir;
56 *self
57 .variable_to_differentiate
58 .entry(reference)
59 .or_insert_with(|| FxHashMap::with_capacity_and_hasher(2, Default::default()))
60 .entry(derive_by)
61 .or_insert_with(|| mir.declare_partial_derivative_variable(reference, derive_by))
62 }
63
64 pub fn partial_derivative_read_only(
65 &mut self,
66 expr: RealExpressionId,
67 derive_by: Unknown,
68 ) -> Option<RealExpressionId> {
69 self.partial_derivative(expr, derive_by, &mut |fold, var| {
70 fold.derivative_of_reference(var, derive_by)
71 })
72 }
73
74 pub fn partial_derivative(
75 &mut self,
76 expr: RealExpressionId,
77 derive_by: Unknown,
78 reference_derivative: &mut impl FnMut(&mut Self, VariableId) -> VariableId,
79 ) -> Option<RealExpressionId> {
80 let res = match self.mir[expr].contents {
81 RealExpression::VariableReference(variable) => {
82 RealExpression::VariableReference(reference_derivative(self, variable))
83 }
84
85 RealExpression::BinaryOperator(lhs, op, rhs) => {
86 let lhs_derived = self.partial_derivative(lhs, derive_by, reference_derivative);
87 let rhs_derived = self.partial_derivative(rhs, derive_by, reference_derivative);
88 match (lhs_derived, rhs_derived) {
89 (None, None) => return None,
90 (Some(lhs_derived), Some(rhs_derived)) => {
91 match op.contents {
92 RealBinaryOperator::Sum | RealBinaryOperator::Subtract => {
93 RealExpression::BinaryOperator(lhs_derived, op, rhs_derived)
94 }
95 RealBinaryOperator::Multiply => {
96 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
97 RealExpression::BinaryOperator(lhs_derived, op, rhs),
98 ));
99 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
100 RealExpression::BinaryOperator(lhs, op, rhs_derived),
101 ));
102 RealExpression::BinaryOperator(
103 sum1,
104 op.copy_as(RealBinaryOperator::Sum),
105 sum2,
106 ) }
108
109 RealBinaryOperator::Divide => {
110 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
112 RealExpression::BinaryOperator(
113 lhs_derived,
114 op.copy_as(RealBinaryOperator::Multiply),
115 rhs,
116 ),
117 ));
118 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
119 RealExpression::BinaryOperator(
120 lhs,
121 op.copy_as(RealBinaryOperator::Multiply),
122 rhs_derived,
123 ),
124 ));
125 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
126 RealExpression::BinaryOperator(
127 sum1,
128 op.copy_as(RealBinaryOperator::Subtract),
129 sum2,
130 ),
131 ));
132 let bottom = self.mir.real_expressions.push(
133 self.mir[expr].clone_as(RealExpression::BinaryOperator(
134 rhs,
135 op.copy_as(RealBinaryOperator::Multiply),
136 rhs,
137 )),
138 );
139 RealExpression::BinaryOperator(top, op, bottom)
140 }
141
142 RealBinaryOperator::Exponent => {
143 let ratio = self.mir.real_expressions.push(
145 self.mir[expr].clone_as(RealExpression::BinaryOperator(
146 rhs,
147 op.copy_as(RealBinaryOperator::Divide),
148 lhs,
149 )),
150 );
151 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
152 RealExpression::BinaryOperator(
153 ratio,
154 op.copy_as(RealBinaryOperator::Multiply),
155 lhs_derived,
156 ),
157 ));
158
159 let ln_lhs = self.mir.real_expressions.push(
160 self.mir[expr].clone_as(RealExpression::BuiltInFunctionCall1p(
161 BuiltInFunctionCall1p::Ln,
162 lhs,
163 )),
164 );
165 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
166 RealExpression::BinaryOperator(
167 ln_lhs,
168 op.copy_as(RealBinaryOperator::Multiply),
169 rhs_derived,
170 ),
171 ));
172
173 let inner_derivative = self.mir.real_expressions.push(
174 self.mir[expr].clone_as(RealExpression::BinaryOperator(
175 sum1,
176 op.copy_as(RealBinaryOperator::Sum),
177 sum2,
178 )),
179 );
180
181 RealExpression::BinaryOperator(
182 inner_derivative,
183 op.copy_as(RealBinaryOperator::Multiply),
184 expr,
185 )
186 }
187
188 RealBinaryOperator::Modulus => {
189 self.errors.push(Error {
190 error_type: Type::DerivativeNotDefined,
191 source: self.mir[expr].source,
192 });
193 return None;
194 }
195 }
196 }
197
198 (None, Some(rhs_derived)) => {
199 match op.contents {
200 RealBinaryOperator::Sum => return Some(rhs_derived),
201 RealBinaryOperator::Subtract => {
202 RealExpression::Negate(op.source, rhs_derived)
203 }
204 RealBinaryOperator::Multiply => {
205 RealExpression::BinaryOperator(lhs, op, rhs_derived)
206 }
207 RealBinaryOperator::Exponent => {
208 let ln_lhs = self.mir.real_expressions.push(
210 self.mir[expr].clone_as(RealExpression::BuiltInFunctionCall1p(
211 BuiltInFunctionCall1p::Ln,
212 lhs,
213 )),
214 );
215 let inner_derivative = self.mir.real_expressions.push(
216 self.mir[expr].clone_as(RealExpression::BinaryOperator(
217 ln_lhs,
218 op.copy_as(RealBinaryOperator::Multiply),
219 rhs_derived,
220 )),
221 );
222
223 RealExpression::BinaryOperator(
224 inner_derivative,
225 op.copy_as(RealBinaryOperator::Multiply),
226 expr,
227 )
228 }
229 RealBinaryOperator::Divide => {
230 let product = self.mir.real_expressions.push(self.mir[expr].clone_as(
233 RealExpression::BinaryOperator(
234 lhs,
235 op.copy_as(RealBinaryOperator::Multiply),
236 rhs_derived,
237 ),
238 ));
239
240 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
241 RealExpression::Negate(op.source,product)
242 ));
243
244 let bottom = self.mir.real_expressions.push(
245 self.mir[expr].clone_as(RealExpression::BinaryOperator(
246 rhs,
247 op.copy_as(RealBinaryOperator::Multiply),
248 rhs,
249 )),
250 );
251
252 RealExpression::BinaryOperator(top, op, bottom)
253 }
254 RealBinaryOperator::Modulus => {
255 self.errors.push(Error {
256 error_type: Type::DerivativeNotDefined,
257 source: self.mir[expr].source,
258 });
259 return None;
260 }
261 }
262 }
263 (Some(lhs_derived), None) => {
264 match op.contents {
265 RealBinaryOperator::Sum | RealBinaryOperator::Subtract => {
266 return Some(lhs_derived)
267 }
268
269 RealBinaryOperator::Multiply | RealBinaryOperator::Divide => {
270 RealExpression::BinaryOperator(lhs_derived, op, rhs)
271 } RealBinaryOperator::Exponent => {
274 let ratio = self.mir.real_expressions.push(
276 self.mir[expr].clone_as(RealExpression::BinaryOperator(
277 rhs,
278 op.copy_as(RealBinaryOperator::Divide),
279 lhs,
280 )),
281 );
282 let inner_derivative = self.mir.real_expressions.push(
283 self.mir[expr].clone_as(RealExpression::BinaryOperator(
284 ratio,
285 op.copy_as(RealBinaryOperator::Multiply),
286 lhs_derived,
287 )),
288 );
289 RealExpression::BinaryOperator(
290 inner_derivative,
291 op.copy_as(RealBinaryOperator::Multiply),
292 expr,
293 )
294 }
295
296 RealBinaryOperator::Modulus => {
297 self.errors.push(Error {
298 error_type: Type::DerivativeNotDefined,
299 source: self.mir[expr].source,
300 });
301 return None;
302 }
303 }
304 }
305 }
306 }
307
308 RealExpression::Noise(_, _) => {
309 self.errors.push(Error {
310 error_type: Type::DerivativeNotDefined,
311 source: self.mir[expr].source,
312 });
313 return None;
314 }
315
316 RealExpression::Negate(span, expr) => RealExpression::Negate(
317 span,
318 self.partial_derivative(expr, derive_by, reference_derivative)?,
319 ),
320
321 RealExpression::Condition(cond, question_span, true_val, colon_span, else_val) => {
322 let true_val = self.partial_derivative(true_val, derive_by, reference_derivative);
323 let else_val = self.partial_derivative(else_val, derive_by, reference_derivative);
324 if true_val.is_none() && else_val.is_none() {
325 return None;
326 }
327 let else_val = else_val.unwrap_or_else(|| {
328 self.mir
329 .real_expressions
330 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
331 });
332
333 let true_val = true_val.unwrap_or_else(|| {
334 self.mir
335 .real_expressions
336 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
337 });
338
339 RealExpression::Condition(cond, question_span, true_val, colon_span, else_val)
340 }
341
342 RealExpression::BuiltInFunctionCall1p(call, arg) => {
343 let inner_derivative =
344 self.partial_derivative(arg, derive_by, reference_derivative)?;
345
346 match call {
347 BuiltInFunctionCall1p::Ln => RealExpression::BinaryOperator(
348 inner_derivative,
349 self.mir[expr].clone_as(RealBinaryOperator::Divide),
350 arg,
351 ),
352
353 BuiltInFunctionCall1p::Exp(_) => RealExpression::BinaryOperator(
354 inner_derivative,
355 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
356 expr,
357 ),
358
359 BuiltInFunctionCall1p::Sqrt => {
360 let two = self
362 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(2.0)));
363 let bottom =
364 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
365 two,
366 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
367 expr,
368 )));
369 RealExpression::BinaryOperator(
370 inner_derivative,
371 self.mir[expr].clone_as(RealBinaryOperator::Divide),
372 bottom,
373 )
374 }
375
376 BuiltInFunctionCall1p::Log => {
377 let log10_e =
379 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(
380 std::f64::consts::E.log10(),
381 )));
382
383 let outer =
384 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
385 log10_e,
386 self.mir[expr].clone_as(RealBinaryOperator::Divide),
387 expr,
388 )));
389
390 RealExpression::BinaryOperator(
391 inner_derivative,
392 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
393 outer,
394 )
395 }
396
397 BuiltInFunctionCall1p::Abs => {
398 let literal_0 = self
399 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)));
400 RealExpression::Condition(
401 self.mir.integer_expressions.push(self.mir[expr].clone_as(
402 IntegerExpression::RealComparison(
403 arg,
404 self.mir[expr].clone_as(ComparisonOperator::GreaterThen),
405 literal_0,
406 ),
407 )),
408 self.mir[expr].source,
409 inner_derivative,
410 self.mir[expr].source,
411 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Negate(
412 self.mir[expr].source,
413 inner_derivative,
414 ))),
415 )
416 }
417
418 BuiltInFunctionCall1p::Floor | BuiltInFunctionCall1p::Ceil => return None,
421
422 BuiltInFunctionCall1p::Sin => {
423 let outer_derivative = self.mir.real_expressions.push(self.mir[expr].clone_as(
424 RealExpression::BuiltInFunctionCall1p(BuiltInFunctionCall1p::Cos, arg),
425 ));
426 RealExpression::BinaryOperator(
427 inner_derivative,
428 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
429 outer_derivative,
430 )
431 }
432
433 BuiltInFunctionCall1p::Cos => {
434 let sin = self.mir.real_expressions.push(self.mir[expr].clone_as(
435 RealExpression::BuiltInFunctionCall1p(BuiltInFunctionCall1p::Sin, arg),
436 ));
437 let neg_sin = self.mir.real_expressions.push(
438 self.mir[expr]
439 .clone_as(RealExpression::Negate(self.mir[expr].source, sin)),
440 );
441
442 RealExpression::BinaryOperator(
443 inner_derivative,
444 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
445 neg_sin,
446 )
447 }
448
449 BuiltInFunctionCall1p::Tan => {
450 let squared =
452 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
453 expr,
454 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
455 expr,
456 )));
457 let one = self
458 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
459
460 let outer =
461 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
462 one,
463 self.mir[expr].clone_as(RealBinaryOperator::Sum),
464 squared,
465 )));
466
467 RealExpression::BinaryOperator(
468 inner_derivative,
469 self.mir[expr].clone_as(RealBinaryOperator::Divide),
470 outer,
471 )
472 }
473
474 BuiltInFunctionCall1p::ArcSin => {
475 let one = self
477 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
478
479 let squared =
480 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
481 arg,
482 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
483 arg,
484 )));
485
486 let diff =
487 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
488 one,
489 self.mir[expr].clone_as(RealBinaryOperator::Subtract),
490 squared,
491 )));
492
493 let root = self.mir.real_expressions.push(self.mir[expr].clone_as(
494 RealExpression::BuiltInFunctionCall1p(
495 BuiltInFunctionCall1p::Sqrt,
496 diff,
497 ),
498 ));
499
500 RealExpression::BinaryOperator(
501 inner_derivative,
502 self.mir[expr].clone_as(RealBinaryOperator::Divide),
503 root,
504 )
505 }
506
507 BuiltInFunctionCall1p::ArcCos => {
508 let one = self
510 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
511
512 let squared =
513 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
514 arg,
515 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
516 arg,
517 )));
518
519 let diff =
520 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
521 one,
522 self.mir[expr].clone_as(RealBinaryOperator::Subtract),
523 squared,
524 )));
525
526 let root = self.mir.real_expressions.push(self.mir[expr].clone_as(
527 RealExpression::BuiltInFunctionCall1p(
528 BuiltInFunctionCall1p::Sqrt,
529 diff,
530 ),
531 ));
532
533 let top = self
534 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Negate(
535 self.mir[expr].source,
536 inner_derivative,
537 )));
538
539 RealExpression::BinaryOperator(
540 top,
541 self.mir[expr].clone_as(RealBinaryOperator::Divide),
542 root,
543 )
544 }
545
546 BuiltInFunctionCall1p::ArcTan => {
547 let one = self
549 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
550
551 let squared =
552 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
553 arg,
554 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
555 arg,
556 )));
557
558 let bottom =
559 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
560 one,
561 self.mir[expr].clone_as(RealBinaryOperator::Sum),
562 squared,
563 )));
564
565 RealExpression::BinaryOperator(
566 inner_derivative,
567 self.mir[expr].clone_as(RealBinaryOperator::Divide),
568 bottom,
569 )
570 }
571
572 BuiltInFunctionCall1p::ArcSinH => {
573 let one = self
575 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
576
577 let squared =
578 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
579 arg,
580 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
581 arg,
582 )));
583
584 let bottom =
585 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
586 one,
587 self.mir[expr].clone_as(RealBinaryOperator::Sum),
588 squared,
589 )));
590
591 RealExpression::BinaryOperator(
592 inner_derivative,
593 self.mir[expr].clone_as(RealBinaryOperator::Divide),
594 bottom,
595 )
596 }
597
598 BuiltInFunctionCall1p::ArcCosH => {
599 let one = self
601 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
602
603 let squared =
604 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
605 arg,
606 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
607 arg,
608 )));
609
610 let bottom =
611 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
612 squared,
613 self.mir[expr].clone_as(RealBinaryOperator::Subtract),
614 one,
615 )));
616
617 let root = self.mir.real_expressions.push(self.mir[expr].clone_as(
618 RealExpression::BuiltInFunctionCall1p(
619 BuiltInFunctionCall1p::Sqrt,
620 bottom,
621 ),
622 ));
623
624 RealExpression::BinaryOperator(
625 inner_derivative,
626 self.mir[expr].clone_as(RealBinaryOperator::Divide),
627 root,
628 )
629 }
630
631 BuiltInFunctionCall1p::ArcTanH => {
632 let one = self
634 .mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::Literal(1.0)));
635
636 let squared =
637 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
638 arg,
639 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
640 arg,
641 )));
642
643 let bottom =
644 self.mir.real_expressions .push(self.mir[expr].clone_as(RealExpression::BinaryOperator(
645 one,
646 self.mir[expr].clone_as(RealBinaryOperator::Subtract),
647 squared,
648 )));
649
650 RealExpression::BinaryOperator(
651 inner_derivative,
652 self.mir[expr].clone_as(RealBinaryOperator::Divide),
653 bottom,
654 )
655 }
656
657 BuiltInFunctionCall1p::SinH => {
658 let outer = self.mir.real_expressions.push(self.mir[expr].clone_as(
659 RealExpression::BuiltInFunctionCall1p(BuiltInFunctionCall1p::CosH, arg),
660 ));
661
662 RealExpression::BinaryOperator(
663 outer,
664 self.mir[arg].clone_as(RealBinaryOperator::Multiply),
665 inner_derivative,
666 )
667 }
668
669 BuiltInFunctionCall1p::CosH => {
670 let outer = self.mir.real_expressions.push(self.mir[arg].clone_as(
671 RealExpression::BuiltInFunctionCall1p(BuiltInFunctionCall1p::SinH, arg),
672 ));
673
674 RealExpression::BinaryOperator(
675 outer,
676 self.mir[arg].clone_as(RealBinaryOperator::Multiply),
677 inner_derivative,
678 )
679 }
680
681 BuiltInFunctionCall1p::TanH => {
682 let one = self
683 .mir.real_expressions .push(self.mir[arg].clone_as(RealExpression::Literal(1.0)));
684
685 let squared =
686 self.mir.real_expressions .push(self.mir[arg].clone_as(RealExpression::BinaryOperator(
687 arg,
688 self.mir[arg].clone_as(RealBinaryOperator::Multiply),
689 arg,
690 )));
691
692 let outer =
693 self.mir.real_expressions .push(self.mir[arg].clone_as(RealExpression::BinaryOperator(
694 one,
695 self.mir[arg].clone_as(RealBinaryOperator::Subtract),
696 squared,
697 )));
698
699 RealExpression::BinaryOperator(
700 inner_derivative,
701 self.mir[arg].clone_as(RealBinaryOperator::Multiply),
702 outer,
703 )
704 }
705 }
706 }
707
708 RealExpression::BuiltInFunctionCall2p(call, arg1, arg2) => {
709 let arg1_derivative =
710 self.partial_derivative(arg1, derive_by, reference_derivative);
711 let arg2_derivative =
712 self.partial_derivative(arg2, derive_by, reference_derivative);
713
714 if arg1_derivative.is_none() && arg2_derivative.is_none() {
715 return None;
716 }
717 let arg1_derivative = arg1_derivative.unwrap_or_else(|| {
718 self.mir
719 .real_expressions
720 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
721 });
722 let arg2_derivative = arg2_derivative.unwrap_or_else(|| {
723 self.mir
724 .real_expressions
725 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
726 });
727
728 match call {
729 BuiltInFunctionCall2p::Pow => {
730 let ratio = self.mir.real_expressions.push(self.mir[expr].clone_as(
732 RealExpression::BinaryOperator(
733 arg2,
734 self.mir[expr].clone_as(RealBinaryOperator::Divide),
735 arg1,
736 ),
737 ));
738
739 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
740 RealExpression::BinaryOperator(
741 ratio,
742 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
743 arg1_derivative,
744 ),
745 ));
746
747 let ln_lhs = self.mir.real_expressions.push(self.mir[expr].clone_as(
748 RealExpression::BuiltInFunctionCall1p(BuiltInFunctionCall1p::Ln, arg1),
749 ));
750
751 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
752 RealExpression::BinaryOperator(
753 ln_lhs,
754 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
755 arg2_derivative,
756 ),
757 ));
758
759 let inner_derivative = self.mir.real_expressions.push(
760 self.mir[expr].clone_as(RealExpression::BinaryOperator(
761 sum1,
762 self.mir[expr].clone_as(RealBinaryOperator::Sum),
763 sum2,
764 )),
765 );
766
767 RealExpression::BinaryOperator(
768 inner_derivative,
769 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
770 expr,
771 )
772 }
773
774 BuiltInFunctionCall2p::Min => RealExpression::Condition(
775 self.mir.integer_expressions.push(self.mir[expr].clone_as(
776 IntegerExpression::RealComparison(
777 arg1,
778 self.mir[expr].clone_as(ComparisonOperator::LessThen),
779 arg2,
780 ),
781 )),
782 self.mir[expr].source,
783 arg1_derivative,
784 self.mir[expr].source,
785 arg2_derivative,
786 ),
787
788 BuiltInFunctionCall2p::Max => RealExpression::Condition(
789 self.mir.integer_expressions.push(self.mir[expr].clone_as(
790 IntegerExpression::RealComparison(
791 arg1,
792 self.mir[expr].clone_as(ComparisonOperator::GreaterThen),
793 arg2,
794 ),
795 )),
796 self.mir[expr].source,
797 arg1_derivative,
798 self.mir[expr].source,
799 arg2_derivative,
800 ),
801
802 BuiltInFunctionCall2p::ArcTan2 => {
803 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
806 RealExpression::BinaryOperator(
807 arg1_derivative,
808 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
809 arg2,
810 ),
811 ));
812
813 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
814 RealExpression::BinaryOperator(
815 arg2_derivative,
816 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
817 arg1,
818 ),
819 ));
820
821 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
822 RealExpression::BinaryOperator(
823 sum1,
824 self.mir[expr].clone_as(RealBinaryOperator::Subtract),
825 sum2,
826 ),
827 ));
828
829 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
830 RealExpression::BinaryOperator(
831 arg1_derivative,
832 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
833 arg2,
834 ),
835 ));
836
837 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
838 RealExpression::BinaryOperator(
839 arg2_derivative,
840 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
841 arg1,
842 ),
843 ));
844
845 let bottom = self.mir.real_expressions.push(self.mir[expr].clone_as(
846 RealExpression::BinaryOperator(
847 sum1,
848 self.mir[expr].clone_as(RealBinaryOperator::Sum),
849 sum2,
850 ),
851 ));
852
853 RealExpression::BinaryOperator(
854 top,
855 self.mir[expr].clone_as(RealBinaryOperator::Divide),
856 bottom,
857 )
858 }
859
860 BuiltInFunctionCall2p::Hypot => {
861 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
863 RealExpression::BinaryOperator(
864 arg1_derivative,
865 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
866 arg1,
867 ),
868 ));
869
870 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
871 RealExpression::BinaryOperator(
872 arg2_derivative,
873 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
874 arg2,
875 ),
876 ));
877
878 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
879 RealExpression::BinaryOperator(
880 sum1,
881 self.mir[expr].clone_as(RealBinaryOperator::Sum),
882 sum2,
883 ),
884 ));
885
886 RealExpression::BinaryOperator(
887 top,
888 self.mir[expr].clone_as(RealBinaryOperator::Divide),
889 expr,
890 )
891 }
892 }
893 }
894
895 RealExpression::IntegerConversion(expr) => {
896 return self.partial_derivative_of_integer_expression(
897 expr,
898 derive_by,
899 reference_derivative,
900 )
901 }
902
903 RealExpression::ParameterReference(param) if Unknown::Parameter(param) == derive_by => {
904 RealExpression::Literal(1.0)
905 }
906
907 RealExpression::Temperature if Unknown::Temperature == derive_by => {
908 RealExpression::Literal(1.0)
909 } RealExpression::Vt(None) if Unknown::Temperature == derive_by => {
912 self.warnings.push(Warning {
914 error_type: WarningType::StandardNatureConstants(
915 "Derivative of '$vt' by temperature encountered",
916 ),
917 source: self.mir[expr].source,
918 });
919 RealExpression::Literal(1.3806488e-23 / 1.602176565e-19)
920 }
921
922 RealExpression::Vt(Some(temp)) => {
923 self.warnings.push(Warning {
925 error_type: WarningType::StandardNatureConstants(
926 "Derivative of '$vt(T)' encountered",
927 ),
928 source: self.mir[expr].source,
929 });
930 let derivatve_temp = self.partial_derivative(temp, derive_by, reference_derivative)?;
931 let p_q_p_k = self.mir.real_expressions.push(
932 self.mir[expr]
933 .clone_as(RealExpression::Literal(1.3806488e-23 / 1.602176565e-19)),
934 );
935 RealExpression::BinaryOperator(
936 p_q_p_k,
937 self.mir[expr].clone_as(RealBinaryOperator::Multiply),
938 derivatve_temp,
939 )
940 }
941
942 RealExpression::BranchAccess(DisciplineAccess::Potential, branch, 0) => {
944 if let Unknown::NodePotential(net) = derive_by {
945 match self.mir[branch].contents.branch {
946 Branch::Nets(high, _) if high == net => RealExpression::Literal(1.0),
947 Branch::Nets(_, low) if low == net => RealExpression::Literal(-1.0),
948 _ => return None,
949 }
950 } else {
951 return None;
952 }
953 }
954
955 RealExpression::BranchAccess(DisciplineAccess::Flow, branch, 0)
956 if Unknown::Flow(branch) == derive_by =>
957 {
958 RealExpression::Literal(1.0)
959 }
960
961 RealExpression::BranchAccess(access, branch, order) if Unknown::Time == derive_by => {
962 RealExpression::BranchAccess(access, branch, order + 1)
963 }
964
965 RealExpression::BranchAccess(DisciplineAccess::Flow, branch, 0) => {
966 if let Unknown::PortFlow(net) = derive_by {
967 match self.mir[branch].contents.branch {
968 Branch::Nets(high, _) if high == net => RealExpression::Literal(-1.0),
970 Branch::Nets(_, low) if low == net => RealExpression::Literal(1.0),
971 _ => return None,
972 }
973 } else {
974 return None;
975 }
976 }
977
978 RealExpression::Literal(_)
979 | RealExpression::ParameterReference(_)
980 | RealExpression::SimParam(_, _)
981 | RealExpression::Temperature
982 | RealExpression::Vt(None) => return None,
983
984 RealExpression::BranchAccess(_, _, _) => {
985 self.errors.push(Error {
986 error_type: Type::PartialDerivativeOfTimeDerivative,
987 source: self.mir[expr].source,
988 });
989 return None;
990 }
991 };
992 Some(self.mir.real_expressions.push(self.mir[expr].clone_as(res)))
993 }
994
995 pub fn partial_derivative_of_integer_expression(
996 &mut self,
997 expr: IntegerExpressionId,
998 derive_by: Unknown,
999 reference_derivative: &mut impl FnMut(&mut Self, VariableId) -> VariableId,
1000 ) -> Option<RealExpressionId> {
1001 let res = match self.mir[expr].contents {
1002 IntegerExpression::VariableReference(variable) => {
1003 RealExpression::VariableReference(reference_derivative(self, variable))
1004 }
1005
1006 IntegerExpression::ParameterReference(param)
1007 if Unknown::Parameter(param) == derive_by =>
1008 {
1009 RealExpression::Literal(1.0)
1010 }
1011
1012 IntegerExpression::BinaryOperator(lhs, op, rhs) => {
1013 let lhs_derived = self.partial_derivative_of_integer_expression(
1014 lhs,
1015 derive_by,
1016 reference_derivative,
1017 );
1018 let rhs_derived = self.partial_derivative_of_integer_expression(
1019 rhs,
1020 derive_by,
1021 reference_derivative,
1022 );
1023 match (lhs_derived, rhs_derived) {
1024 (None, None) => return None,
1025 (Some(lhs_derived), Some(rhs_derived)) => {
1026 let lhs = self
1027 .mir
1028 .real_expressions
1029 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(lhs)));
1030 let rhs = self
1031 .mir
1032 .real_expressions
1033 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(rhs)));
1034
1035 match op.contents {
1036 IntegerBinaryOperator::Sum => RealExpression::BinaryOperator(
1037 lhs_derived,
1038 op.copy_as(RealBinaryOperator::Sum),
1039 rhs_derived,
1040 ),
1041
1042 IntegerBinaryOperator::Subtract => RealExpression::BinaryOperator(
1043 lhs_derived,
1044 op.copy_as(RealBinaryOperator::Subtract),
1045 rhs_derived,
1046 ),
1047
1048 IntegerBinaryOperator::Multiply => {
1049 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1050 RealExpression::BinaryOperator(
1051 lhs_derived,
1052 op.copy_as(RealBinaryOperator::Multiply),
1053 rhs,
1054 ),
1055 ));
1056 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1057 RealExpression::BinaryOperator(
1058 lhs,
1059 op.copy_as(RealBinaryOperator::Multiply),
1060 rhs_derived,
1061 ),
1062 ));
1063 RealExpression::BinaryOperator(
1064 sum1,
1065 op.copy_as(RealBinaryOperator::Sum),
1066 sum2,
1067 ) }
1069
1070 IntegerBinaryOperator::Divide => {
1071 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1073 RealExpression::BinaryOperator(
1074 lhs_derived,
1075 op.copy_as(RealBinaryOperator::Multiply),
1076 rhs,
1077 ),
1078 ));
1079 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1080 RealExpression::BinaryOperator(
1081 lhs,
1082 op.copy_as(RealBinaryOperator::Multiply),
1083 rhs_derived,
1084 ),
1085 ));
1086 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
1087 RealExpression::BinaryOperator(
1088 sum1,
1089 op.copy_as(RealBinaryOperator::Subtract),
1090 sum2,
1091 ),
1092 ));
1093 let bottom = self.mir.real_expressions.push(
1094 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1095 rhs,
1096 op.copy_as(RealBinaryOperator::Multiply),
1097 rhs,
1098 )),
1099 );
1100 RealExpression::BinaryOperator(
1101 top,
1102 op.copy_as(RealBinaryOperator::Divide),
1103 bottom,
1104 )
1105 }
1106
1107 IntegerBinaryOperator::Exponent => {
1108 let ratio = self.mir.real_expressions.push(
1110 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1111 rhs,
1112 op.copy_as(RealBinaryOperator::Divide),
1113 lhs,
1114 )),
1115 );
1116 let sum1 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1117 RealExpression::BinaryOperator(
1118 ratio,
1119 op.copy_as(RealBinaryOperator::Multiply),
1120 lhs_derived,
1121 ),
1122 ));
1123
1124 let ln_lhs = self.mir.real_expressions.push(
1125 self.mir[expr].clone_as(RealExpression::BuiltInFunctionCall1p(
1126 BuiltInFunctionCall1p::Ln,
1127 lhs,
1128 )),
1129 );
1130 let sum2 = self.mir.real_expressions.push(self.mir[expr].clone_as(
1131 RealExpression::BinaryOperator(
1132 ln_lhs,
1133 op.copy_as(RealBinaryOperator::Multiply),
1134 rhs_derived,
1135 ),
1136 ));
1137
1138 let inner_derivative = self.mir.real_expressions.push(
1139 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1140 sum1,
1141 op.copy_as(RealBinaryOperator::Sum),
1142 sum2,
1143 )),
1144 );
1145
1146 RealExpression::BinaryOperator(
1147 inner_derivative,
1148 op.copy_as(RealBinaryOperator::Multiply),
1149 self.mir.real_expressions.push(
1150 self.mir[expr]
1151 .clone_as(RealExpression::IntegerConversion(expr)),
1152 ),
1153 )
1154 }
1155
1156 IntegerBinaryOperator::Modulus
1157 | IntegerBinaryOperator::Xor
1158 | IntegerBinaryOperator::NXor
1159 | IntegerBinaryOperator::And
1160 | IntegerBinaryOperator::Or
1161 | IntegerBinaryOperator::LogicOr
1162 | IntegerBinaryOperator::LogicAnd => {
1163 self.errors.push(Error {
1164 error_type: Type::DerivativeNotDefined,
1165 source: self.mir[expr].source,
1166 });
1167 return None;
1168 }
1169
1170 IntegerBinaryOperator::ShiftLeft => {
1171 let ln2 = self.mir.real_expressions.push(
1173 self.mir[expr].clone_as(RealExpression::Literal(2f64.ln())),
1174 );
1175 let ln2_lhs = self.mir.real_expressions.push(
1176 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1177 ln2,
1178 op.copy_as(RealBinaryOperator::Multiply),
1179 lhs,
1180 )),
1181 );
1182 let product = self.mir.real_expressions.push(
1183 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1184 ln2_lhs,
1185 op.copy_as(RealBinaryOperator::Multiply),
1186 rhs_derived,
1187 )),
1188 );
1189
1190 let sum = self.mir.real_expressions.push(self.mir[expr].clone_as(
1191 RealExpression::BinaryOperator(
1192 product,
1193 op.copy_as(RealBinaryOperator::Sum),
1194 lhs_derived,
1195 ),
1196 ));
1197
1198 let literal2 = self
1199 .mir
1200 .real_expressions
1201 .push(self.mir[expr].clone_as(RealExpression::Literal(2_f64)));
1202 let pow = self.mir.real_expressions.push(self.mir[expr].clone_as(
1203 RealExpression::BuiltInFunctionCall2p(
1204 BuiltInFunctionCall2p::Pow,
1205 literal2,
1206 rhs,
1207 ),
1208 ));
1209
1210 RealExpression::BinaryOperator(
1211 sum,
1212 op.copy_as(RealBinaryOperator::Multiply),
1213 pow,
1214 )
1215 }
1216 IntegerBinaryOperator::ShiftRight => {
1217 let ln2 = self.mir.real_expressions.push(
1219 self.mir[expr].clone_as(RealExpression::Literal(2f64.ln())),
1220 );
1221 let ln2_lhs = self.mir.real_expressions.push(
1222 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1223 ln2,
1224 op.copy_as(RealBinaryOperator::Multiply),
1225 lhs,
1226 )),
1227 );
1228 let product = self.mir.real_expressions.push(
1229 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1230 ln2_lhs,
1231 op.copy_as(RealBinaryOperator::Multiply),
1232 rhs_derived,
1233 )),
1234 );
1235
1236 let sum = self.mir.real_expressions.push(self.mir[expr].clone_as(
1237 RealExpression::BinaryOperator(
1238 lhs_derived,
1239 op.copy_as(RealBinaryOperator::Subtract),
1240 product,
1241 ),
1242 ));
1243
1244 let literal2 = self
1245 .mir
1246 .real_expressions
1247 .push(self.mir[expr].clone_as(RealExpression::Literal(2f64)));
1248 let neg_rhs = self.mir.real_expressions.push(
1249 self.mir[expr].clone_as(RealExpression::Negate(op.source, rhs)),
1250 );
1251 let pow = self.mir.real_expressions.push(self.mir[expr].clone_as(
1252 RealExpression::BuiltInFunctionCall2p(
1253 BuiltInFunctionCall2p::Pow,
1254 literal2,
1255 neg_rhs,
1256 ),
1257 ));
1258
1259 RealExpression::BinaryOperator(
1260 sum,
1261 op.copy_as(RealBinaryOperator::Multiply),
1262 pow,
1263 )
1264 }
1265 }
1266 }
1267
1268 (None, Some(rhs_derived)) => {
1269 let lhs = self
1270 .mir
1271 .real_expressions
1272 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(lhs)));
1273 let rhs = self
1274 .mir
1275 .real_expressions
1276 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(rhs)));
1277 let expr_as_real = self
1278 .mir
1279 .real_expressions
1280 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(expr)));
1281
1282 match op.contents {
1283 IntegerBinaryOperator::Sum => return Some(rhs_derived),
1284 IntegerBinaryOperator::Subtract => {
1285 RealExpression::Negate(op.source, rhs_derived)
1286 }
1287 IntegerBinaryOperator::Multiply => RealExpression::BinaryOperator(
1288 lhs,
1289 op.copy_as(RealBinaryOperator::Multiply),
1290 rhs_derived,
1291 ),
1292 IntegerBinaryOperator::Exponent => {
1293 let ln_lhs = self.mir.real_expressions.push(
1295 self.mir[expr].clone_as(RealExpression::BuiltInFunctionCall1p(
1296 BuiltInFunctionCall1p::Ln,
1297 lhs,
1298 )),
1299 );
1300 let inner_derivative = self.mir.real_expressions.push(
1301 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1302 ln_lhs,
1303 op.copy_as(RealBinaryOperator::Multiply),
1304 rhs_derived,
1305 )),
1306 );
1307
1308 RealExpression::BinaryOperator(
1309 inner_derivative,
1310 op.copy_as(RealBinaryOperator::Multiply),
1311 expr_as_real,
1312 )
1313 }
1314 IntegerBinaryOperator::Divide => {
1315 let product = self.mir.real_expressions.push(self.mir[expr].clone_as(
1318 RealExpression::BinaryOperator(
1319 lhs,
1320 op.copy_as(RealBinaryOperator::Multiply),
1321 rhs_derived,
1322 ),
1323 ));
1324
1325 let top = self.mir.real_expressions.push(self.mir[expr].clone_as(
1326 RealExpression::Negate(op.source,product)
1327 ));
1328
1329 let bottom = self.mir.real_expressions.push(
1330 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1331 rhs,
1332 op.copy_as(RealBinaryOperator::Multiply),
1333 rhs,
1334 )),
1335 );
1336
1337 RealExpression::BinaryOperator(
1338 top,
1339 op.copy_as(RealBinaryOperator::Divide),
1340 bottom,
1341 )
1342 }
1343 IntegerBinaryOperator::Modulus
1344 | IntegerBinaryOperator::Xor
1345 | IntegerBinaryOperator::NXor
1346 | IntegerBinaryOperator::And
1347 | IntegerBinaryOperator::Or
1348 | IntegerBinaryOperator::LogicOr
1349 | IntegerBinaryOperator::LogicAnd => {
1350 self.errors.push(Error {
1351 error_type: Type::DerivativeNotDefined,
1352 source: self.mir[expr].source,
1353 });
1354 return None;
1355 }
1356
1357 IntegerBinaryOperator::ShiftLeft => {
1358 let ln2 = self.mir.real_expressions.push(
1360 self.mir[expr].clone_as(RealExpression::Literal(2f64.ln())),
1361 );
1362 let ln2_drhs = self.mir.real_expressions.push(
1363 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1364 ln2,
1365 op.copy_as(RealBinaryOperator::Multiply),
1366 rhs_derived,
1367 )),
1368 );
1369
1370 RealExpression::BinaryOperator(
1371 ln2_drhs,
1372 op.copy_as(RealBinaryOperator::Multiply),
1373 expr_as_real,
1374 )
1375 }
1376 IntegerBinaryOperator::ShiftRight => {
1377 let neg_ln2 = self.mir.real_expressions.push(
1379 self.mir[expr].clone_as(RealExpression::Literal(-(2f64.ln()))),
1380 );
1381 let ln2_drhs = self.mir.real_expressions.push(
1382 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1383 neg_ln2,
1384 op.copy_as(RealBinaryOperator::Multiply),
1385 rhs_derived,
1386 )),
1387 );
1388
1389 RealExpression::BinaryOperator(
1390 ln2_drhs,
1391 op.copy_as(RealBinaryOperator::Multiply),
1392 expr_as_real,
1393 )
1394 }
1395 }
1396 }
1397 (Some(lhs_derived), None) => {
1398 let lhs = self
1399 .mir
1400 .real_expressions
1401 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(lhs)));
1402 let rhs = self
1403 .mir
1404 .real_expressions
1405 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(rhs)));
1406 let expr_as_real = self
1407 .mir
1408 .real_expressions
1409 .push(self.mir[lhs].clone_as(RealExpression::IntegerConversion(expr)));
1410
1411 match op.contents {
1412 IntegerBinaryOperator::Sum | IntegerBinaryOperator::Subtract => {
1413 return Some(lhs_derived)
1414 }
1415
1416 IntegerBinaryOperator::Multiply => RealExpression::BinaryOperator(
1417 lhs_derived,
1418 op.copy_as(RealBinaryOperator::Multiply),
1419 rhs,
1420 ),
1421 IntegerBinaryOperator::Divide => RealExpression::BinaryOperator(
1422 lhs_derived,
1423 op.copy_as(RealBinaryOperator::Divide),
1424 rhs,
1425 ), IntegerBinaryOperator::Exponent => {
1428 let ratio = self.mir.real_expressions.push(
1430 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1431 rhs,
1432 op.copy_as(RealBinaryOperator::Divide),
1433 lhs,
1434 )),
1435 );
1436 let inner_derivative = self.mir.real_expressions.push(
1437 self.mir[expr].clone_as(RealExpression::BinaryOperator(
1438 ratio,
1439 op.copy_as(RealBinaryOperator::Multiply),
1440 lhs_derived,
1441 )),
1442 );
1443 RealExpression::BinaryOperator(
1444 inner_derivative,
1445 op.copy_as(RealBinaryOperator::Multiply),
1446 expr_as_real,
1447 )
1448 }
1449
1450 IntegerBinaryOperator::Modulus
1451 | IntegerBinaryOperator::Xor
1452 | IntegerBinaryOperator::NXor
1453 | IntegerBinaryOperator::And
1454 | IntegerBinaryOperator::Or
1455 | IntegerBinaryOperator::LogicOr
1456 | IntegerBinaryOperator::LogicAnd => {
1457 self.errors.push(Error {
1458 error_type: Type::DerivativeNotDefined,
1459 source: self.mir[expr].source,
1460 });
1461 return None;
1462 }
1463
1464 IntegerBinaryOperator::ShiftLeft => {
1465 let literal2 = self
1468 .mir
1469 .real_expressions
1470 .push(self.mir[expr].clone_as(RealExpression::Literal(2f64)));
1471 let pow = self.mir.real_expressions.push(self.mir[expr].clone_as(
1472 RealExpression::BuiltInFunctionCall2p(
1473 BuiltInFunctionCall2p::Pow,
1474 literal2,
1475 rhs,
1476 ),
1477 ));
1478
1479 RealExpression::BinaryOperator(
1480 lhs_derived,
1481 op.copy_as(RealBinaryOperator::Multiply),
1482 pow,
1483 )
1484 }
1485 IntegerBinaryOperator::ShiftRight => {
1486 let literal2 = self
1488 .mir
1489 .real_expressions
1490 .push(self.mir[expr].clone_as(RealExpression::Literal(2f64)));
1491 let neg_rhs = self.mir.real_expressions.push(
1492 self.mir[expr].clone_as(RealExpression::Negate(op.source, rhs)),
1493 );
1494 let pow = self.mir.real_expressions.push(self.mir[expr].clone_as(
1495 RealExpression::BuiltInFunctionCall2p(
1496 BuiltInFunctionCall2p::Pow,
1497 literal2,
1498 neg_rhs,
1499 ),
1500 ));
1501
1502 RealExpression::BinaryOperator(
1503 lhs_derived,
1504 op.copy_as(RealBinaryOperator::Multiply),
1505 pow,
1506 )
1507 }
1508 }
1509 }
1510 }
1511 }
1512
1513 IntegerExpression::UnaryOperator(
1514 Node {
1515 source,
1516 contents: UnaryOperator::ArithmeticNegate,
1517 },
1518 expr,
1519 ) => RealExpression::Negate(
1520 source,
1521 self.partial_derivative_of_integer_expression(
1522 expr,
1523 derive_by,
1524 reference_derivative,
1525 )?,
1526 ),
1527
1528 IntegerExpression::Condition(cond, question_span, true_val, colon_span, else_val) => {
1529 let true_val = self.partial_derivative_of_integer_expression(
1530 true_val,
1531 derive_by,
1532 reference_derivative,
1533 );
1534 let else_val = self.partial_derivative_of_integer_expression(
1535 else_val,
1536 derive_by,
1537 reference_derivative,
1538 );
1539 if true_val.is_none() && else_val.is_none() {
1540 return None;
1541 }
1542 let else_val = else_val.unwrap_or_else(|| {
1543 self.mir
1544 .real_expressions
1545 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1546 });
1547
1548 let true_val = true_val.unwrap_or_else(|| {
1549 self.mir
1550 .real_expressions
1551 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1552 });
1553
1554 RealExpression::Condition(cond, question_span, true_val, colon_span, else_val)
1555 }
1556
1557 IntegerExpression::Min(arg1, arg2) => {
1558 let arg1_derivative = self.partial_derivative_of_integer_expression(
1559 arg1,
1560 derive_by,
1561 reference_derivative,
1562 );
1563 let arg2_derivative = self.partial_derivative_of_integer_expression(
1564 arg2,
1565 derive_by,
1566 reference_derivative,
1567 );
1568
1569 if arg1_derivative.is_none() && arg2_derivative.is_none() {
1570 return None;
1571 }
1572 let arg1_derivative = arg1_derivative.unwrap_or_else(|| {
1573 self.mir
1574 .real_expressions
1575 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1576 });
1577 let arg2_derivative = arg2_derivative.unwrap_or_else(|| {
1578 self.mir
1579 .real_expressions
1580 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1581 });
1582
1583 RealExpression::Condition(
1584 self.mir.integer_expressions.push(self.mir[expr].clone_as(
1585 IntegerExpression::IntegerComparison(
1586 arg1,
1587 self.mir[expr].clone_as(ComparisonOperator::LessThen),
1588 arg2,
1589 ),
1590 )),
1591 self.mir[expr].source,
1592 arg1_derivative,
1593 self.mir[expr].source,
1594 arg2_derivative,
1595 )
1596 }
1597
1598 IntegerExpression::Max(arg1, arg2) => {
1599 let arg1_derivative = self.partial_derivative_of_integer_expression(
1600 arg1,
1601 derive_by,
1602 reference_derivative,
1603 );
1604 let arg2_derivative = self.partial_derivative_of_integer_expression(
1605 arg2,
1606 derive_by,
1607 reference_derivative,
1608 );
1609
1610 if arg1_derivative.is_none() && arg2_derivative.is_none() {
1611 return None;
1612 }
1613 let arg1_derivative = arg1_derivative.unwrap_or_else(|| {
1614 self.mir
1615 .real_expressions
1616 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1617 });
1618 let arg2_derivative = arg2_derivative.unwrap_or_else(|| {
1619 self.mir
1620 .real_expressions
1621 .push(self.mir[expr].clone_as(RealExpression::Literal(0.0)))
1622 });
1623
1624 RealExpression::Condition(
1625 self.mir.integer_expressions.push(self.mir[expr].clone_as(
1626 IntegerExpression::IntegerComparison(
1627 arg1,
1628 self.mir[expr].clone_as(ComparisonOperator::GreaterThen),
1629 arg2,
1630 ),
1631 )),
1632 self.mir[expr].source,
1633 arg1_derivative,
1634 self.mir[expr].source,
1635 arg2_derivative,
1636 )
1637 }
1638
1639 IntegerExpression::Abs(arg) => {
1640 let arg_derived = self.partial_derivative_of_integer_expression(
1641 arg,
1642 derive_by,
1643 reference_derivative,
1644 )?;
1645 let literal_0 = self
1646 .mir
1647 .integer_expressions
1648 .push(self.mir[expr].clone_as(IntegerExpression::Literal(0)));
1649
1650 RealExpression::Condition(
1651 self.mir.integer_expressions.push(self.mir[expr].clone_as(
1652 IntegerExpression::IntegerComparison(
1653 arg,
1654 self.mir[expr].clone_as(ComparisonOperator::GreaterThen),
1655 literal_0,
1656 ),
1657 )),
1658 self.mir[expr].source,
1659 arg_derived,
1660 self.mir[expr].source,
1661 self.mir.real_expressions.push(
1662 self.mir[expr]
1663 .clone_as(RealExpression::Negate(self.mir[expr].source, arg_derived)),
1664 ),
1665 )
1666 }
1667
1668 IntegerExpression::Literal(_) | IntegerExpression::ParameterReference(_) => {
1669 return None
1670 }
1671
1672 IntegerExpression::RealCast(_) => return None,
1674
1675 IntegerExpression::FunctionCall(_, _) => todo!("Function calls"),
1676 IntegerExpression::NetReference(_) | IntegerExpression::PortReference(_) => {
1677 todo!("Digital")
1678 }
1679
1680 IntegerExpression::IntegerComparison(_, _, _)
1681 | IntegerExpression::RealComparison(_, _, _)
1682 | IntegerExpression::StringEq(_, _)
1683 | IntegerExpression::UnaryOperator(_, _)
1684 | IntegerExpression::StringNEq(_, _) => {
1685 self.errors.push(Error {
1686 error_type: Type::DerivativeNotDefined,
1687 source: self.mir[expr].source,
1688 });
1689 return None;
1690 }
1691
1692 IntegerExpression::PortConnected(_) | IntegerExpression::ParamGiven(_) => return None,
1693 };
1694 Some(self.mir.real_expressions.push(self.mir[expr].clone_as(res)))
1695 }
1696
1697 pub fn or_for_derivative(
1698 &mut self,
1699 expr: IntegerExpressionId,
1700 delta_name: Symbol,
1701 derivatives_inside_loop: &FxHashSet<VariableId>,
1702 ) -> IntegerExpressionId {
1703 for derived_variable in derivatives_inside_loop.iter().copied() {
1704 if self.mir[derived_variable].contents.name.name == delta_name {
1705 if let Some(partial_derivatives) =
1706 self.variable_to_differentiate.get(&derived_variable)
1707 {
1708 let mut res = expr;
1709
1710 for derive_by in partial_derivatives.keys() {
1711 let mut replacements = FxHashMap::with_capacity_and_hasher(
1712 derivatives_inside_loop.len(),
1713 Default::default(),
1714 );
1715
1716 for (variable, partial_derivatives) in &self.variable_to_differentiate {
1717 if derivatives_inside_loop.contains(variable) {
1718 if let Some(&derivative) = partial_derivatives.get(derive_by) {
1719 replacements.insert(*variable, derivative);
1720 }
1721 }
1722 }
1723
1724 if let Some(derived_condition) = self.mir.map_int_expr(expr, &replacements)
1725 {
1726 let span = self.mir[expr].source;
1727 res = self.mir.integer_expressions.push(Node::new(
1728 IntegerExpression::BinaryOperator(
1729 res,
1730 Node::new(IntegerBinaryOperator::LogicOr, span),
1731 derived_condition,
1732 ),
1733 span,
1734 ))
1735 }
1736 }
1737
1738 return res;
1739 }
1740 }
1741 }
1742 expr
1744 }
1745}
1746impl Mir {
1747 pub fn declare_partial_derivative_variable(
1748 &mut self,
1749 variable: VariableId,
1750 derive_by: Unknown,
1751 ) -> VariableId {
1752 let derive_by = match derive_by {
1753 Unknown::Parameter(parameter) => self[parameter].contents.name.to_string(),
1754 Unknown::NodePotential(net) => format!("pot({})", self[net].contents.name),
1755 Unknown::Flow(branch) => format!("flow({})", self[branch].contents.name),
1756 Unknown::PortFlow(net) => format!("flow(<{}>)", self[net].contents.name),
1757 Unknown::Temperature => "Temp".to_string(),
1758 Unknown::Time => "t".to_string(),
1759 };
1760 let name =
1761 Ident::from_str(format!("∂{}/∂{}", self[variable].contents.name, derive_by).as_str());
1762 let res = self.variables.push(AttributeNode {
1763 attributes: Attributes::empty(),
1764 source: self[variable].source,
1765 contents: Variable {
1766 name,
1767 variable_type: VariableType::Real(None),
1768 },
1769 });
1770 debug_assert!(&self[self[res].attributes.as_range()].is_empty());
1771 res
1772 }
1773}