# Code Generation Using Sympy

**URL:** <https://fortran-lang.discourse.group/t/code-generation-using-sympy/321>\
**Category:** Tutorials\
**Created:** [September 28, 2020, 12:42pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321 "2020-09-28T12:42:30Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [September 28, 2020, 12:42pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/1 "2020-09-28T12:42:30Z")

</div>

I would like to share a short Python snippet I’ve been using very often to generate Fortran code through symbolic simplification and common sub-expression elimination:

```auto
# Copyright (c) 2020 Ivan Pribec. All rights reserved.
#
# This work is licensed under the terms of the MIT license.  
# For a copy, see <https://opensource.org/licenses/MIT>.

import sympy as sp
from sympy.printing.fcode import print_fcode

def apply_cse_and_print_fcode(expr,assign_to,source_format='free',standard=95):
    """Apply common subexpression simplification and print Fortran code
    
    Input:
    expr - a list of expressions we would like to evaluate
    assign_to - the symbols we would like to assign them to (either a tuple of strings or sp.symbols)
    
    Output:
        The expressions will be printed to the standard output.
    """
    
    rvar, rexpr = sp.cse(sp.simplify(expr))
    
    print("! Reduced variables")
    for var, var_expr in rvar:
        print_fcode(var_expr,assign_to=var,source_format=source_format,standard=standard)
    
    print("! Reduced expressions")
    for var, var_expr in zip(assign_to,rexpr):
        print_fcode(var_expr,assign_to=var,source_format=source_format,standard=standard)

```

As an example I will be computing the [water activity](https://en.wikipedia.org/wiki/Water_activity) of a wet material, a\_w, which is a function of moisture content X and temperature T, according to the Oswin model equation:

a\_w(X,T)=\frac{\left(\frac{X}{a}\right)^{1/b}}{1+\left(\frac{X}{a}\right)^{1/b}},\quad a=a\_1+a\_2 T,\quad b=b\_1+b\_2 T

where the parameters (a\_1,a\_2,b\_1,b\_2) are empiricial fitting coefficients. In some applications we might also be interested in the derivative of a\_w with respect to the variables X and T. Using SymPy we can easily find these using the following snippet (you can run this in a Jupyter notebook):

```auto
# Create symbols
X, T, a1, a2, b1, b2 = sp.symbols('X T a1 a2 b1 b2')
# Define symbolic expression
a = a1 + a2*T
b = b1 + b2*T
aw = (X/a)**(1/b)/(1 + (X/a)**(1/b)) 
# Find symbolic derivatives
daw_dX = sp.diff(aw,X)
daw_dT = sp.diff(aw,T)

```

To generate Fortran code for the expression and derivatives all I need to do now is run the following code:

```auto
output = (aw,daw_dX,daw_dT)
output_var = ('aw','daw_dX','daw_dT')
apply_cse_and_print_fcode(output,output_var)

```

which will print the reduced variables and expressions to standard output:

```auto
! Reduced variables
x0 = T*a2 + a1
x1 = 1d0/x0
x2 = X*x1
x3 = T*b2 + b1
x4 = 1d0/x3
x5 = x2**x4
x6 = x5 + 1
x7 = x5/x6**2
! Reduced expressions
aw = x5/x6
daw_dX = x4*x7/X
daw_dT = -x1*x7*(a2*x3 + b2*x0*log(x2))/x3**2

```

I can now wrap this output into a subroutine block, specifying the precise interface and applying any further changes (i.e. replace the `d0` format specifier to my desired precision):

```auto
subroutine oswin_model(X,T,a1,a2,b1,b2,aw,daw_dX,daw_dT)
  real(wp), intent(in) :: X, T
  real(wp), intent(in) :: a1, a2, b1, b2,
  real(wp), intent(out) :: aw, daw_dX, daw_dT

  real(wp) :: x0,x1,x2,x3,x4,x5,x6,x7

  ! Reduced variables
  x0 = T*a2 + a1
  x1 = 1.0_wp/x0
  x2 = X*x1
  x3 = T*b2 + b1
  x4 = 1.0_wp/x3
  x5 = x2**x4
  x6 = x5 + 1
  x7 = x5/x6**2
  ! Reduced expressions
  aw = x5/x6
  daw_dX = x4*x7/X
  daw_dT = -x1*x7*(a2*x3 + b2*x0*log(x2))/x3**2
end subroutine

```

As a second example, say you want to evaluate the Jacobian of a system of ordinary differential equations. I will use the [Lorenz attractor](https://en.wikipedia.org/wiki/Lorenz_system) as a trivial example:

\frac{dx}{dt} = \sigma(y-x) \\ \frac{dy}{dt} = x (\rho - z) - y \\ \frac{dz}{dt} = xy - \beta z

First we define the symbolic system of differential equations:

```auto
x,y,z = sp.symbols('x y z')
s,r,b = sp.symbols('sigma rho beta')

dx_dt = s*(y-x)
dy_dt = x*(r - z) - y
dz_dt = x*y - b*z

system = sp.Matrix([dx_dt,dy_dt,dz_dt])

```

The SymPy Matrix object has a built-in Jacobian function, that can be called as `system.jacobian((x,y,z))` to produce the output:

\left[\begin{matrix}- \sigma & \sigma & 0\\ \rho - z & -1 & - x\\ y & x & - \beta\end{matrix}\right]

To output the Fortran code we again use the function defined above,

```auto
output = (system,system.jacobian((x,y,z)))
output_vars = ('F','J')
apply_cse_and_print_fcode(output,output_vars)

```

which generates the output:

```auto
! Reduced variables
x0 = -x
x1 = rho - z
! Reduced expressions
F(1, 1) = sigma*(x0 + y)
F(2, 1) = x*x1 - y
F(3, 1) = -beta*z + x*y
J(1, 1) = -sigma
J(2, 1) = x1
J(3, 1) = y
J(1, 2) = sigma
J(2, 2) = -1
J(3, 2) = x
J(1, 3) = 0
J(2, 3) = x0
J(3, 3) = -beta

```

We can see in this case, there is not much need to introduce temporary variables. Nevertheless, the symbolic route is much easier than writing the Jacobian by hand. In principle, it is possible to fine-tune the format of the output arrays by passing additional arguments to the Fortran printer in SymPy. Personally, for short functions, I prefer to do it manually using a good text editor.

If you are interested in learning more about code generation using Sympy, I suggest reading the tutorial [“Automatic Code Generation with SymPy”](https://www.sympy.org/scipy-2017-codegen-tutorial/). For those who have a MATLAB license, a [similar tool](https://de.mathworks.com/help/symbolic/fortran.html) is available in the [Symbolic Math Toolbox](https://de.mathworks.com/products/symbolic.html).

Hopefully, someone will find this useful.

---

<div class="post-metadata">

**Author:** ![gardhor](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/gardhor/32/88_2.png) [@gardhor](https://fortran-lang.discourse.group/u/gardhor)\
**Post date:** [September 28, 2020, 2:17pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/2 "2020-09-28T14:17:34Z")

</div>

Thanks for sharing your code, this can be very useful.  
You can use also Mathematica to simplify and export some mathematical expression to fortran.

Another, comment about your applications, if you don’t need the analytical expressions (you just need to be able to compute some values), you can use some automatic differentiation libraries (see [http://www.autodiff.org](http://www.autodiff.org)). Some libraries are in fortran:

- [http://www.autodiff.org/?module=Tools&tool=AUTO\_DERIV](http://www.autodiff.org/?module=Tools&tool=AUTO_DERIV)
- [https://github.com/lauvergn/QuantumModelLib/tree/OOP\_branch/SRC/dnSLib](https://github.com/lauvergn/QuantumModelLib/tree/OOP_branch/SRC/dnSLib) (this one is hidden in one of my codes)

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 28, 2020, 2:54pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/3 "2020-09-28T14:54:04Z")

</div>

@ivanpribec thanks for sharing that. I have several additional thoughts:

- I think it could be sometimes helpful to keep the original expression in Fortran, then extract it into SymPy via LFortran, do some manipulation of it in SymPy, and generate Fortran code out of it. We have a prototype for that in LFortran.

- For autodifferentiation, one route is the previous bullet point or your post. Another route is directly via a compiler ([https://gitlab.com/lfortran/lfortran/-/issues/97](https://gitlab.com/lfortran/lfortran/-/issues/97)).

- There are initial Fortran wrappers for SymEngine (a reimplementation of SymPy in C++), I started them here: [https://github.com/symengine/symengine.f90](https://github.com/symengine/symengine.f90). That would allow to do such symbolic manipulations in Fortran itself. It might open many possibilities. Essentially, just like Matlab can do symbolics in Matlab itself (see the link you posted above), we should be able to do this in Fortran. If anybody is interested in brainstorming this, designing this, or helping out, please let me know.

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [September 28, 2020, 4:17pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/4 "2020-09-28T16:17:35Z")

</div>

> [@certik](#):
>
> There are initial Fortran wrappers for SymEngine (a reimplementation of SymPy in C++), I started them here: [GitHub - symengine/symengine.f90: Fortran wrappers of SymEngine](https://github.com/symengine/symengine.f90). That would allow to do such symbolic manipulations in Fortran itself. It might open many possibilities. Essentially, just like Matlab can do symbolics in Matlab itself (see the link you posted above), we should be able to do this in Fortran. If anybody is interested in brainstorming this, designing this, or helping out, please let me know.

I’ve looked at SymEngine a few times but lack the time to get my hands dirty. Probably the low-level C interface could be lifted back up in Fortan to an OO-style interface so users could just write their symbolic expressions normally using operator overloading. As a next step you could use the [delayed evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation) technique described by @Arjen Markus in “Modern Fortran in Practice” (page 31). It was also shown in his presentation at FortranCon 2020 - [“Experimental Programming in Fortran”](https://tcevents.chem.uzh.ch/event/12/contributions/54/attachments/19/81/experimental_programming_online.pdf).

With LFortran run dynamically from a Jupyter Notebook, I guess it would be interesting to have equivalents of `sympify` and `lambdify` to convert between textual representation, symbolic expressions, and Fortran code.

For static compilation however, with existing tools, I don’t really see how I could get a symbolic block replaced with Fortran. I guess it is possible to write a _fypp_ macro to read a Fortran expression into a symbolic representation, perform symbolic differentation or simplification, and then get replaced with Fortran code. But I am not sure what is the advantage compared to doing it separately in a Jupyter notebook (apart from having the code in a single file).

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 28, 2020, 4:34pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/5 "2020-09-28T16:34:43Z")

</div>

> I’ve looked at SymEngine a few times but lack the time to get my hands dirty. Probably the low-level C interface could be lifted back up in Fortan to an OO-style interface so users could just write their symbolic expressions normally using operator overloading. As a next step you could use the [delayed evaluation](https://en.wikipedia.org/wiki/Lazy_evaluation) technique described by @Arjen Markus in “Modern Fortran in Practice” (page 31). It was also shown in his presentation at FortranCon 2020 - [“Experimental Programming in Fortran”](https://tcevents.chem.uzh.ch/event/12/contributions/54/attachments/19/81/experimental_programming_online.pdf).

> With LFortran run dynamically from a Jupyter Notebook, I guess it would be interesting to have equivalents of `sympify` and `lambdify` to convert between textual representation, symbolic expressions, and Fortran code.

Great ideas!

> For static compilation however, with existing tools, I don’t really see how I could get a symbolic block replaced with Fortran. I guess it is possible to write a _fypp_ macro to read a Fortran expression into a symbolic representation, perform symbolic differentation or simplification, and then get replaced with Fortran code. But I am not sure what is the advantage compared to doing it separately in a Jupyter notebook (apart from having the code in a single file).

This has to be implemented, but you would call it exactly as you do it now (whether from a Jupyter notebook, or a standalone `.py` file), except that you will use Fortran instead of Python. So you either write a `.f90` program (a “script”) that gets compiled (with any Fortran compiler) and executed; or you call it from a Jupyter notebook via LFortran. This “script” will then call SymEngine to do whatever manipulation you want and generate Fortran code.

The overall idea is that in Matlab you don’t need to switch to another language (Python or Mathematica) to do symbolics, you simply use Matlab for everything: numerics, plotting, symbolics and code generation. In the same way, we could use Fortran down the road for all these tasks also. Until we do it, I can’t of course guarantee that it will be easy to use and natural, but if Matlab can do it, then I think Fortran (as a language) can do it too, as easily. (If Matlab couldn’t do it, then that would be different.)

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [September 28, 2020, 5:27pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/6 "2020-09-28T17:27:07Z")

</div>

In MATLAB, one can convert a symbolic expression to a numeric function handle for immediate use as follows:

```auto
syms x y
f(x,y) = x^3 + y^3;
ht = matlabFunction(f)

```

It is also possible to put this into a script which generates a separate function file, i.e.

```auto
syms x
f = x^2 + log(x^2);
matlabFunction(f,'File','myfile');

```

produces the output:

```auto
function f = myfile(x)
%MYFILE
% F = MYFILE(X)

% This function was generated by the Symbolic Math Toolbox version 8.4.
% 01-Sep-2019 00:00:00

t2 = x.^2;
f = t2+log(t2);

```

Note the creation of a temporary variable. I copied both examples from the MATLAB documentation: [https://de.mathworks.com/help/symbolic/matlabfunction.html](https://de.mathworks.com/help/symbolic/matlabfunction.html)

Carrying this concept over to Fortran would mean having a driver script along the lines of:

```auto
use symengine

type(sym_t) :: x, y
type(expr_t) :: f

call f%set([x,y], x **2 + y** 2)
call fortran_function(f,'File','myfile')
end

```

In the most simple setting this would produce the file `myfile.f90` containing something like

```auto
elemental function myfile(x,y)
  real(sp) :: myfile
  real(sp), intent(in) :: x, y
  myfile = x*x + y*y
end function

```

One of the challenges would be how to extend the interface to arbitrary precision and simultaneously provide a common interface block. And second, how to make such kind of symbolic meta-programming tools available inside of a module.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [September 28, 2020, 6:33pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/7 "2020-09-28T18:33:04Z")

</div>

@ivanpribec perfect, that is exactly what I had in mind. I opened [https://github.com/symengine/symengine.f90/issues/4](https://github.com/symengine/symengine.f90/issues/4) for some of the details.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [September 30, 2020, 1:51am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/8 "2020-09-30T01:51:54Z")

</div>

> [@ivanpribec](#):
>
> One of the challenges would be how to extend the interface to arbitrary precision …

@ivanpribec, @certik, et al.

I’m inclined to make a close connection with this challenge mentioned above @ivanpribec with the other big challenge with Fortran 202Y which is whether a sufficiently full-featured GENERIC programming facility can be incorporated in it. Any investigation by you all with `code generation` along the lines of this thread and the findings can really help become good use case(s) for generics in Fortran 202Y.

In the meantime, integrating some preprocessing into the mix, say [FYPP](https://github.com/aradi/fypp), might be an option for the generated code to work with any of the supported floating-point kinds in a modern Fortran processor?

---

<div class="post-metadata">

**Author:** ![themos](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/themos/32/521_2.png) [@themos](https://fortran-lang.discourse.group/u/themos)\
**Post date:** [March 31, 2021, 9:59am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/9 "2021-03-31T09:59:03Z")

</div>

Some users might be more interested in the most numerically stable transformation of an algebraic expression.

This is a good place to put a link to [Herbie](https://herbie.uwplse.org/doc/latest/tutorial.html).

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [March 31, 2021, 10:44am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/10 "2021-03-31T10:44:47Z")

</div>

Indeed, another idea is to integrate something like Herbie with a Fortran compiler:

> **[SymPy integration (#71) · Issues · lfortran / lfortran](https://gitlab.com/lfortran/lfortran/-/issues/71)**
>
> There are two fundamental projects: Use LFortran for SymPy's code generation. SymPy will target the LFortran's ASR, and LFortran can both generate...

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [September 28, 2021, 2:27am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/11 "2021-09-28T02:27:35Z")

</div>

Minor correction in @ivanpribec 's post of 28 Sep 2020: in your TeX formatted Oswin model equation, only X is raised to the power (1/b), whereas in your code (X/a) is raised to the power (1/b). In other words, you need to add parentheses around (X/a) in two places, or introduce a new variable for X/a.

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [September 28, 2021, 10:10am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/12 "2021-09-28T10:10:25Z")

</div>

Thanks @mecej4 for catching this. Indeed, the TeX formatted model equation should have parentheses around (X/a). I am not able to edit the post any more, I’m not sure if the moderators (ping @lkedward) are able to do it?

---

<div class="post-metadata">

**Author:** ![Beliavsky](https://avatars.discourse-cdn.com/v4/letter/b/ba8739/32.png) [@Beliavsky](https://fortran-lang.discourse.group/u/Beliavsky)\
**Post date:** [September 28, 2021, 11:57am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/13 "2021-09-28T11:57:31Z")

</div>

> [@ivanpribec](#):
>
> Thanks @mecej4 for catching this. Indeed, the TeX formatted model equation should have parentheses around (X/a). I am not able to edit the post any more, I’m not sure if the moderators (ping @lkedward) are able to do it?

I think it is fixed now.

---

<div class="post-metadata">

**Author:** ![oyvind](https://avatars.discourse-cdn.com/v4/letter/o/e68b1a/32.png) [@oyvind](https://fortran-lang.discourse.group/u/oyvind)\
**Post date:** [March 10, 2023, 2:14pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/14 "2023-03-10T14:14:25Z")

</div>

Thanks for sharing this! Do you know if there is a way to have Sympy produce expressions like x\*\*(n-1) instead of x\*\*n/x, avoiding a NaN for x=0?

I am currently experimenting with generating function overloads for hyper-dual numbers (dual numbers extended to 2nd derivatives) based on the generic overload rules described here: [https://arxiv.org/pdf/1801.03614.pdf](https://arxiv.org/pdf/1801.03614.pdf)

But there seems there is no way around manual inspection to catch these kind of things!

---

<div class="post-metadata">

**Author:** ![msz59](https://avatars.discourse-cdn.com/v4/letter/m/3d9bf3/32.png) [@msz59](https://fortran-lang.discourse.group/u/msz59)\
**Post date:** [March 10, 2023, 4:18pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/15 "2023-03-10T16:18:19Z")

</div>

On MacOS 12.6.3 Monterey, with Python 3.10.9 and sympy 1.11.1 I get

```plaintext
>>> import sympy as sp
>>> from sympy.printing.fcode import print_fcode
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'sympy.printing.fcode'

```

☹  
Not aliasing `sympy` as `sp` (just `import sympy`) does not help.

---

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [March 10, 2023, 4:23pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/16 "2023-03-10T16:23:16Z")

</div>

It looks like the module has been renamed to [`sympy.printing.fortran`](https://docs.sympy.org/latest/modules/printing.html#sympy.printing.fortran.print_fcode).

---

<div class="post-metadata">

**Author:** ![gardhor](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/gardhor/32/88_2.png) [@gardhor](https://fortran-lang.discourse.group/u/gardhor)\
**Post date:** [March 11, 2023, 9:29am UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/17 "2023-03-11T09:29:22Z")

</div>

> [@oyvind](#):
>
> I am currently experimenting with generating function overloads for hyper-dual numbers (dual numbers extended to 2nd derivatives) based on the generic overload rules described here: [https://arxiv.org/pdf/1801.03614.pdf](https://arxiv.org/pdf/1801.03614.pdf)

It is not related directly to the topic of the post, but I’ve developed a library, [AD\_dnSVM](https://github.com/lauvergn/AD_dnSVM), to deal up to third order derivatives. All intrinsic Fortran 2003 functions are overloaded (including, dot\_product, matmul and order matrix operations).

---

<div class="post-metadata">

**Author:** ![oyvind](https://avatars.discourse-cdn.com/v4/letter/o/e68b1a/32.png) [@oyvind](https://fortran-lang.discourse.group/u/oyvind)\
**Post date:** [March 11, 2023, 3:46pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/18 "2023-03-11T15:46:53Z")

</div>

Thanks for sharing! Here is [my approach](https://github.com/oyvindyr/dnad).

It is a fork of joddlehod´s DNAD repository. I have refactored it into fypp macros that can “inject” interfaces and function overloads directly into the module where they are used. See for instance example/example\_hdual\_mod.fypp. One advantage of this approach is that functions are likely to be inlined without having to resort to interprocedural optimizations. I also like to think about the dual type in the macro as a kind of “meta-type” where each generated type have a particular meaning - representing derivatives with respect to particular physical variables. Lately I have also introduced a hyper-dual type where the overloaded functions are automatically generated by src/fortran\_gen.py.

---

<div class="post-metadata">

**Author:** ![oyvind](https://avatars.discourse-cdn.com/v4/letter/o/e68b1a/32.png) [@oyvind](https://fortran-lang.discourse.group/u/oyvind)\
**Post date:** [March 11, 2023, 4:56pm UTC](https://fortran-lang.discourse.group/t/code-generation-using-sympy/321/19 "2023-03-11T16:56:27Z")

</div>

Python/Sympy here generates fypp Macros, so it is actually meta-meta-programming😀
