Skip to main content

Symbolic evaluation for engineering calculations — renders expression → numbers with units → result as LaTeX

Project description

symeval

Write a sympy expression, fill in pint quantities, and get the full derivation, that is (1) formula, (2) substituted values with units, and (3) the result with unit — rendered as LaTeX in your marimo or Jupyter notebook.

  • Crystal-clear - shows the full derivation: formula, values with units, and result of any expression
  • 🐍 Pure Python - integrate into your interactive notebooks and other Python code, no special syntax, no cell magic, no Domain-Specific Language (DSL)
  • 📏 Unit-aware - pint quantities carry units through every step and convert to your chosen output unit
  • 🧮 Sympy-native - use symbolic math to derive or rearrange your formula first, then evaluate symbolicly
  • 📊 DataFrame-ready - use sympy.Expr.quantity_evalf() on a DataFrame to calculate the values of a new column in a unit-aware manner
pip install symeval

Axial stress under a compressive force

from pint import Quantity
from sympy import Symbol
from symeval import sym_evalf

sigma = sym_evalf(
    expr=Symbol("F") / Symbol("A"),
    subs={Symbol("F"): Quantity(-680, "kN"), Symbol("A"): Quantity(10_580, "mm^2")},
    output_symbol=r"\sigma",
    output_unit="MPa",
    decimals=2,
)

$$\begin{align*} \sigma &= \frac{F}{A} \ &= \frac{\medspace-680\ \mathrm{kN}}{\medspace10580\ \mathrm{mm}^{2}} \ \sigma &= -6.43\times 10^{7}\ \mathrm{Pa} = -64.27\ \mathrm{MPa} \end{align*}$$

You can also build the sympy expression first and call .sym_evalf() as a method — useful when you want to do symbolic math before filling in numbers:

from sympy import Symbol
from pint import Quantity

f_sym = Symbol("F")
a_sym = Symbol("A")
sigma_expr = f_sym / a_sym

f_q = Quantity(-680, "kN")
a_q = Quantity(10_580, "mm^2")

Pass decimals= to control precision and mode= to choose the rendering style. mode="verbose" adds an extra line showing all values converted to SI base units:

sigma_expr.sym_evalf(
    subs={f_sym: f_q, a_sym: a_q},
    output_symbol=r"\sigma",
    output_unit="MPa",
    decimals=2,
    mode="verbose",
)

$$\begin{align*} \sigma &= \frac{F}{A} \ &= \frac{\medspace-680\ \mathrm{kN}}{\medspace10580\ \mathrm{mm}^{2}} \ &= \frac{\medspace-6.800\times 10^{5}\ \mathrm{N}}{\medspace1.058\times 10^{-2}\ \mathrm{m}^{2}} \ \sigma &= -6.43\times 10^{7}\ \mathrm{Pa} = -64.27\ \mathrm{MPa} \end{align*}$$

mode="one_line" collapses the derivation onto a single line:

sigma_expr.sym_evalf(
    subs={f_sym: f_q, a_sym: a_q},
    output_symbol=r"\sigma",
    output_unit="MPa",
    decimals=1,
    mode="one_line",
)

$$\sigma = \frac{F}{A} = \frac{\medspace-680\ \mathrm{kN}}{\medspace10580\ \mathrm{mm}^{2}} = -64.3\ \mathrm{MPa}$$


Ideal Gas Law: Symbolic Rearrangement

Starting from $PV = nRT$, use sympy.solve to rearrange the equation symbolically for any variable, then feed the result straight into sym_evalf:

import sympy
from sympy.physics.units import molar_gas_constant
import sympy.physics.units as spu
from sympy.physics.units.util import convert_to
from pint import Quantity
from symeval import sym_evalf

P, V, n, T, R = sympy.symbols("P V n T R")

# Rearrange symbolically — no hardcoding which variable to solve for
ideal_gas_law = sympy.Eq(P * V, n * R * T)
solution = sympy.solve(ideal_gas_law, P)[0]

# Pull R from sympy — no hardcoded constant
R_si = convert_to(molar_gas_constant, [spu.joule, spu.mol, spu.kelvin])
R_q = Quantity(float(R_si.args[0]), "J/(mol*K)")

solution.sym_evalf(
    subs={R: R_q, V: Quantity(22.4, "L"), n: Quantity(1.0, "mol"), T: Quantity(273.15, "K")},
    output_symbol=P,
    output_unit="kPa",
    decimals=2,
)

Rearranged: $P = \dfrac{R T n}{V}$

$$\begin{align*} P &= \frac{R T n}{V} \ &= \frac{\medspace8.314\ \frac{\mathrm{J}}{\left(\mathrm{K} \cdot \mathrm{mol}\right)} \medspace273.15\ \mathrm{K} \medspace1\ \mathrm{mol}}{\medspace22.4\ \mathrm{l}} \ P &= 1.01\times 10^{5}\ \mathrm{Pa} = 101.39\ \mathrm{kPa} \end{align*}$$

In marimo: add a mo.ui.radio to let the user pick which variable to solve for — the symbolic rearrangement and evaluation both update reactively.


quantity_evalf() on a DataFrame

quantity_evalf is the numeric-only sibling of sym_evalf — same unit-aware evaluation, no LaTeX overhead. It's useful for applying a formula across every row of a DataFrame:

import polars as pl
from pint import Quantity
from sympy import Symbol
from symeval import quantity_evalf

f_sym, a_sym = Symbol("F"), Symbol("A")
sigma_expr = f_sym / a_sym

members = pl.DataFrame({
    "member_type": ["column", "column", "brace", "strut", "tie"],
    "section":     ["W14x90", "HSS8x8x5/8", "HSS6x6x3/8", "L4x4", "C8x11.5"],
    "F_kN":        [-720.0, -680.0, 340.0, -110.0, 250.0],
    "A_mm2":       [17_100.0, 10_580.0, 4_890.0, 1_870.0, 2_168.0],
})

def stress_MPa(row):
    return quantity_evalf(
        sigma_expr,
        subs={f_sym: Quantity(row["F_kN"], "kN"), a_sym: Quantity(row["A_mm2"], "mm^2")},
        output_unit="MPa",
    ).magnitude

members_with_stress = members.with_columns(
    pl.struct(["F_kN", "A_mm2"])
    .map_elements(stress_MPa, return_dtype=pl.Float64)
    .alias("sigma_MPa")
)
member_type section F_kN A_mm2 sigma_MPa
column W14x90 -720.00 17100.00 -42.11
column HSS8x8x5/8 -680.00 10580.00 -64.27
brace HSS6x6x3/8 340.00 4890.00 69.53
strut L4x4 -110.00 1870.00 -58.82
tie C8x11.5 250.00 2168.00 115.31

Then use sym_evalf to show the full derivation for any row you want to inspect:

sigma_expr.sym_evalf(
    subs={f_sym: Quantity(-680, "kN"), a_sym: Quantity(10_580, "mm^2")},
    output_symbol=r"\sigma",
    output_unit="MPa",
    decimals=1,
)

$$\begin{align*} \sigma &= \frac{F}{A} \ &= \frac{\medspace-680\ \mathrm{kN}}{\medspace10580\ \mathrm{mm}^{2}} \ \sigma &= -6.4\times 10^{7}\ \mathrm{Pa} = -64.3\ \mathrm{MPa} \end{align*}$$


Inspiration

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

symeval-0.3.1.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

symeval-0.3.1-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file symeval-0.3.1.tar.gz.

File metadata

  • Download URL: symeval-0.3.1.tar.gz
  • Upload date:
  • Size: 15.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for symeval-0.3.1.tar.gz
Algorithm Hash digest
SHA256 e5cc8894d90ec6ac1a43a491293120c430107771d24d83247a4b99fd232d67ef
MD5 bf8f7855d4885fcb16e5b2196ef416e1
BLAKE2b-256 2069d856ef1033c592cf903737ce66b501a3fba379d3f1553f27b671e68c4264

See more details on using hashes here.

File details

Details for the file symeval-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: symeval-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 13.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.2 {"installer":{"name":"uv","version":"0.10.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for symeval-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 46a9660702c4bf0e4ce362582347a6c78b70d0ca27b14ec9ac07ac74ffe1c6e7
MD5 0d026e83e2e8f918b2dd23b470845ea7
BLAKE2b-256 6f1a5c929cce87b6d8cf3cc2ef4150e8a8185600f42590335a8465341caa7c46

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page