open_vaf/hir_lowering/derivatives/
mod.rs

1/*
2 * ******************************************************************************************
3 * Copyright (c) 2019 Pascal Kuthe. This file is part of the OpenVAF project.
4 * It is subject to the license terms in the LICENSE file found in the top-level directory
5 *  of this distribution and at  https://gitlab.com/DSPOM/OpenVAF/blob/master/LICENSE.
6 *  No part of OpenVAF, including this file, may be copied, modified, propagated, or
7 *  distributed except according to the terms contained in the LICENSE file.
8 * *****************************************************************************************
9*/
10
11use 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                                ) //lhs'*rhs + lhs*rhs'
107                            }
108
109                            RealBinaryOperator::Divide => {
110                                // (lhs'*rhs-lhs * rhs') / (rhs*rhs)
111                                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                                // (rhs/lhs * lhs' + ln (lhs) * rhs')*expr
144                                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                                // (ln (lhs) * rhs') * expr
209                                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                                // -lhs * rhs' / (rhs*rhs)
231
232                                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                            } // rhs is just a scalar (x/c->x'/c)
272
273                            RealBinaryOperator::Exponent => {
274                                // (rhs/lhs*lhs') * expr
275                                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(_) /* Whether this is a limexp or exp doesnt affect how the derivative is calculated*/ => RealExpression::BinaryOperator(
354                        inner_derivative,
355                        self.mir[expr].clone_as(RealBinaryOperator::Multiply),
356                        expr,
357                    ),
358
359                    BuiltInFunctionCall1p::Sqrt => {
360                        // f'/(2*sqrt(f))
361                        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                        // (f'/f)*log10_e
378                        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                    // Undefined for integers. 0 rest of the time. Your problem if you are stupid enough to derive that we are just going to treat it like 0
419                    // TODO warn ( or error?)
420                    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                        // f'*(1+tan^2(f))
451                        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                        // f' / sqrt(1-f^2)
476                        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                        // - f' / sqrt(1-f^2)
509                        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                        //  f' / ( 1 + f*f )
548                        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                        //  f' / ( 1 + f*f )
574                        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                        //  f' / sqrt( f*f - 1 )
600                        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                        //  f' / ( f*f - 1 )
633                        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                        // (rhs/lhs * lhs' + ln (lhs) * rhs')*expr
731                        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                        // (arg1'arg2 - arg2'*arg1)/(arg1*arg1+arg2*arg2)
804
805                        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                        // (  arg1 * arg1' +  arg2 * arg2' ) /  expr
862                        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            } //TODO other system function calls
910
911            RealExpression::Vt(None) if Unknown::Temperature == derive_by => {
912                //TODO add a way to customize constants
913                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                //TODO add a way to customize constants
924                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            //TODO branch temperature dependence
943            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                        // the other way around because the node being low potential means current flows in
969                        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                                ) //lhs'*rhs + lhs*rhs'
1068                            }
1069
1070                            IntegerBinaryOperator::Divide => {
1071                                // (lhs'*rhs-lhs * rhs') / (rhs*rhs)
1072                                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                                // (rhs/lhs * lhs' + ln (lhs) * rhs')*expr
1109                                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                                // ( lhs'+ln(2)*lhs*rhs' )* 2 ** rhs
1172                                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                                // ( lhs' - ln(2)*lhs*rhs' ) * 2 ** (- rhs)
1218                                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                                // (ln (lhs) * rhs') * expr
1294                                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                                // - lhs * rhs' / (rhs*rhs)
1316
1317                                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                                // ln(2)*rhs' * expr
1359                                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                                // ( - ln(2)*rhs' ) * expr
1378                                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                            ), // rhs is just a scalar (x/c->x'/c)
1426
1427                            IntegerBinaryOperator::Exponent => {
1428                                // (rhs/lhs*lhs') * expr
1429                                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                                //  lhs'* 2 ** rhs
1466
1467                                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                                // ( lhs'  * 2 ** (- rhs)
1487                                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            // rounding undefined at 0.5 + n for any integer n rest is zero TODO warn (or error?)
1673            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        //TODO warning
1743        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}