Handcalcs.jl - For more readable calculations

Hello Julia community!

I am excited to announce my first registered package Handcalcs.jl! This package is inspired by the handcalcs.py package in python.

It is designed to be used in either jupyter or pluto. It will render your algebraic equations in latex. It will also evaluate them! See example below:

Here are the docs for it: Handcalc.jl docs

I am new to Julia so the doc(stable) button isn’t working. If someone could help with that, I would greatly appreciate it.

81 Likes

Oh wow:

Future plans are to integrate the package with Unitful.jl, be able to render the algebraic expressions within a function, and many other things. This package is an extension of Latexify.jl.

This is fantastic! Great work @co1emi11er! I’ll give it a whirl one of these days for some of my literate documents I write with Weave.jl and Quarto!

3 Likes

This already looks amazing.


Regarding your future plans:

A macro that will generate LaTeX for a function that was called. The generated
LaTeX would be the algebraic equations within the function.

My ultimate wish for this type of functionality is to be able to pull simple equation sets from different sources and use them together showing my work at the destination:

using Handcalcs, Smith1993, Jefferson2020
a=3
b=4
@handcalcs y = Smith1993.y(a)     # show LaTeX for y equation defined in package
@handcalcs z = Jefferson2020.z(b) # show LaTeX for z equation defined in package
@handcalcs c = y + z              # just show simple LaTeX addition

I structure my code like this now because:

  1. I can keep a master copy of my reference equations separately from all the reports that will use them. This avoids a lot of boilerplate and copy-paste errors.
  2. I can easily update or swap reference equations for all future reports with a dependency change.
  3. It makes clear in the report where I am coming up with my equations.

I use @latexrun when defining the equations in my dependency packages and then compare a weaved PDF in the dependency package to the reference text for verification that I transcribed them correctly. However, it would be wonderful if I could show the reference equation substitutions in the report itself!

Thanks!

Yes this is exactly the goal of the function functionality! I do believe it is possible. The CodeTracking.jl package allows me to pull the function head and body info from a function.

The code is there to do the latex substitution. I just need to figure out how I will parse the args and kwargs of the function!

2 Likes

This looks very cool. My main use of Pluto is for exactly this sort of calculation with Unitful, so I’ll try it out sometime.

Incredible! It looks like handcalcs.py integrates nicely with SymPy. Does Handcalcs.jl have plans to similarly integrate with Symbolics.jl in the future? And what might that look like if so?

This is an amazing package btw!!

1 Like

Cool! Yeah that one exponent issue is the only thing I know of currently for unitful stuff. The back end is Latexify.jl so you can provide kwargs at the end of the handcalc macro to pass those through to latexify.

You can type for example:

a = 0.25u"ft"
b = 4u"inch"
@handcalcs c = sqrt(a^2+b^2) post = u"inch"

with Pluto you want to use begin and end statements though to get rid of the assignment callout in the top left of the output cell. Like so:

@handcalcs begin
  c = sqrt(a^2+b^2) 
  end post = u"inch"

CleanShot 2024-02-07 at 23.06.07@2x

You can see the exponent not rendering properly in the numeric substitution part. This is probably at the top of my list to get fixed. It actually breaks when you have a unit that has an exponent that is then under an exponent. But it should hopefully work smoothly after this fix. I want to get it fixed on the latexify side though, since it is broken on that end too.

Thanks!

I would say top priorities are getting unitful bug fixed, and functions integrated with the package. After that I can look at Symbolics.jl.

I haven’t ever used the Symbolics.jl package so it may take some time, but I see the benefit it could bring!

1 Like

Oh man this is amazing. I would have killed for this in school.

My natural reading of this is that a^2 is 0.25 ft^2 rather than Edit: (0.25 ft)^2. The MathCad 14 equivalent follows.

image

Also note the use of the assignment operator (:=)

4 Likes

Correct. This is what I want to get fixed in Latexify. See my pull request here. This pull request fixes the issue on the latexify side. I haven’t received any responses though.

2 Likes

Out of curiosity, and tangential to your awesome package announcement, would it be possible to have the latex formatting on the “grey boxes”?

In the sense that the output you show here, which is awesome, could that be how “the code looked” when one wrote it?

It might seem like a bit of a crazy idea, but for me being able to exactly recognize the equation and have it look like the code, is amazing :slight_smile:

Congratulations on the package!

Kind regards

Hi Nathan,

I just wanted to provide an update on the progress here, because I will be unable to work on this for a couple weeks. I have a rough working macro that does this in my handfunc branch! See example below!

Some function defined in another package

function calc_Ix(b, h) 
    d = if b > 4
        b * 5
    else
        b + 5
    end; "test if statement";
    c = h + 6; "test equation";
    Ix = b*h^3/12
    
end

using @handfunc (you don’t need to use begin end here but can)

@handfunc begin Ix = calc_Ix(5, 15) end

or can be a non exported function

@handfunc Ix = Handcalcs.calc_Ix(5, 15) 

And yes Ix is evaluated!! Ix being the variable assigned in the @handfunc part (variables within function are not defined in the global name space). If you assign it to a different variable then that will be the variable defined (although you will still see it as Ix in the latex portion)

The current limitations are:

  1. You can’t have return statements in the function (I plan to filter these out before passing to be latexified.)
  2. The names of the variables you pass to the function as parameters can not be the same name as the parameters in the actual function or any variable names defined in the function. (There is some macro hygiene I need to do).
  3. you must pass numbers or symbols (not fields of objects). This is also a current limitation of the @handcalcs macro.
  4. For whatever reason things work in jupyter and the repl but not pluto (I am unsure what to do here).
  5. I believe the function needs to be defined in another package. The @code_expr macro from CodeTracking.jl does not see functions in Main for some reason.
7 Likes

There is also an issue with negative exponents in units:

julia> using Unitful, Handcalcs

julia> v = 10u"m/s"
10 m s^-1

julia> A = 2u"m^2"
2 m^2

julia> ρ = 1.2u"kg/m^3"
1.2 kg m^-3

julia> @handcalc mdot = ρ * v * A
L"$\begin{align}
mdot &= \rho \cdot v \cdot A = 1.2 kg m^-3 \cdot 10 m s^-1 \cdot 2 m^2 = 24.0 kg s^-1
\end{align}$

I assume that need a fix on the handcalcs side since the whole negative exponent would need to go into {}

Sorry. What is the issue here? I am getting:
image

I am not super familiar with LaTeX. I have just been going off visual and I would be fine with this.

Interesting. that’s not what I get on my system. You are right, that’s how it should look like.

If you look at my Latex output that has m^-3 in it while yours looks like m^{-3}

What’s the Latex output you get? Am I missing a dependency/setting for Latexify?

oh yes. See what happens when you use UnitfulLatexify.jl.

So do:

julia> using Unitful, Handcalcs, UnitfulLatexify

julia> v = 10u"m/s"
10 m s^-1

julia> A = 2u"m^2"
2 m^2

julia> ρ = 1.2u"kg/m^3"
1.2 kg m^-3

julia> @handcalcs mdot = ρ * v * A
L"$\begin{align}
mdot &= \rho \cdot v \cdot A = 1.2\;\mathrm{kg}\,\mathrm{m}^{-3} \cdot 10\;\mathrm{m}\,\mathrm{s}^{-1} \cdot 2\;\mathrm{m}^{2} = 24\;\mathrm{kg}\,\mathrm{s}^{-1}
\end{align}$"

Thanks. That’s what I was missing. Awesome.

1 Like