Skip to content

Commit 0d6a679

Browse files
Refactor Equation handling in the uncertainty calculator
Updated the Equation class to use 'latex_name' and 'expression' attributes instead of 'lhs' and 'rhs'. Adjusted related parsing, computation, and rendering logic to accommodate these changes. This refactor enhances clarity in the representation of equations and improves the overall structure of the code. Updated tests to reflect the new attribute names and ensure consistent functionality.
1 parent 94154b5 commit 0d6a679

12 files changed

Lines changed: 49 additions & 40 deletions

File tree

README.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,13 +68,18 @@ The core logic is organized by responsibility:
6868

6969
### 1. Define the Equation
7070

71-
The equation can be defined using the `Equation` class.
71+
The equation can be defined using the `Equation` class. `latex_name` is the
72+
rendered result symbol, while `expression` is the internal symbolic formula
73+
written with variable `name`s.
7274

7375
```python
7476
from uncertainty_calculator import Equation
7577

7678
# Define equation
77-
equation = Equation(lhs=r"\zeta", rhs=r"(K*pi*eta*u*l)/(4*pi*phi*e_0*e_r)")
79+
equation = Equation(
80+
latex_name=r"\zeta",
81+
expression=r"(K*pi*eta*u*l)/(4*pi*phi*e_0*e_r)",
82+
)
7883
```
7984

8085
### 2. Define Variables

src/uncertainty_calculator/compute.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,14 @@ def compute(parse_state: ParseState, digits: Digits) -> ComputeState:
2626
pdv_results: list[tuple[Any, Any, Any]] = []
2727
for symbol in parse_state.symbols:
2828
if parse_state.uncertainty_values[symbol]:
29-
pdv = simplify(diff(parse_state.equation_right, symbol))
29+
pdv = simplify(diff(parse_state.equation_expression, symbol))
3030
num = pdv.subs(parse_state.output_number) # type: ignore
3131
pdv_results.append((symbol, pdv, num))
3232
else:
3333
pdv_results.append((symbol, S.Zero, S.Zero))
3434

3535
result_mu = latex_number(
36-
parse_state.equation_right.evalf(digits.mu, subs=parse_state.output_number) # type: ignore
36+
parse_state.equation_expression.evalf(digits.mu, subs=parse_state.output_number) # type: ignore
3737
)
3838

3939
pdv_nums = [res[2] for res in pdv_results]

src/uncertainty_calculator/parsing.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ class ParseState:
2424
uncertainty_values: Mapping[Symbol, Any]
2525
input_fullunc: list[str]
2626
input_sigma: list[Any]
27-
equation_left: str
28-
equation_right: Any
27+
equation_latex_name: str
28+
equation_expression: Any
2929

3030

3131
def parse_inputs(equation: Equation, variables: Variables) -> ParseState:
@@ -77,8 +77,8 @@ def parse_inputs(equation: Equation, variables: Variables) -> ParseState:
7777
output_value = dict(zip(symbols_parsed + unc_symbols, input_fullmu + input_fullsigma))
7878
uncertainty_values = dict(zip(symbols_parsed, input_sigma))
7979

80-
equation_left = equation.lhs
81-
equation_right = sympify(equation.rhs, locals=symbol_map)
80+
equation_latex_name = equation.latex_name
81+
equation_expression = sympify(equation.expression, locals=symbol_map)
8282

8383
return ParseState(
8484
symbols=symbols_parsed,
@@ -89,6 +89,6 @@ def parse_inputs(equation: Equation, variables: Variables) -> ParseState:
8989
uncertainty_values=uncertainty_values,
9090
input_fullunc=input_fullunc,
9191
input_sigma=input_sigma,
92-
equation_left=equation_left,
93-
equation_right=equation_right,
92+
equation_latex_name=equation_latex_name,
93+
equation_expression=equation_expression,
9494
)

src/uncertainty_calculator/rendering.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,11 @@ def _render_equation_def(
6161
aligned: bool,
6262
) -> None:
6363
separator = "&=" if aligned else "="
64-
printer(parse_state.equation_left, end=separator)
65-
printer(latex_symbol(parse_state.equation_right, parse_state.output_symbol), end="=")
64+
printer(parse_state.equation_latex_name, end=separator)
65+
printer(latex_symbol(parse_state.equation_expression, parse_state.output_symbol), end="=")
6666

6767
if options.insert:
68-
printer(latex_value(parse_state.equation_right, parse_state.output_value), end="=")
68+
printer(latex_value(parse_state.equation_expression, parse_state.output_value), end="=")
6969

7070
res_str = (
7171
compute_state.result_mu
@@ -93,7 +93,7 @@ def _render_pdvs(
9393
continue
9494

9595
lhs = (
96-
f"\\frac{{\\partial {parse_state.equation_left} }}"
96+
f"\\frac{{\\partial {parse_state.equation_latex_name} }}"
9797
f"{{\\partial {parse_state.output_symbol[symbol]} }}"
9898
)
9999
printer(lhs, end=separator)
@@ -110,7 +110,7 @@ def _sigma_symbolic_terms(parse_state: ParseState) -> list[str]:
110110
for symbol, fullunc in zip(parse_state.symbols, parse_state.input_fullunc):
111111
if parse_state.uncertainty_values[symbol]:
112112
terms.append(
113-
f"\\left(\\frac{{\\partial {parse_state.equation_left} }}"
113+
f"\\left(\\frac{{\\partial {parse_state.equation_latex_name} }}"
114114
f"{{\\partial {parse_state.output_symbol[symbol]} }} {fullunc}\\right)^2"
115115
)
116116
return terms
@@ -151,15 +151,17 @@ def _render_sigma(
151151
if options.last_unit is None
152152
else f"{compute_state.result_sigma}\\ {options.last_unit}"
153153
)
154-
printer(f"\\sigma_{{{parse_state.equation_left}}}&=", end="")
154+
printer(f"\\sigma_{{{parse_state.equation_latex_name}}}&=", end="")
155155
if not options.separate:
156156
printer(f"{res_str}\\\\\n\\\\")
157157
else:
158158
printer(res_str)
159159
return
160160

161161
symbolic_terms = _sigma_symbolic_terms(parse_state)
162-
printer(f"\\sigma_{{{parse_state.equation_left}}}&=\\sqrt{{{'+'.join(symbolic_terms)}}}\\\\")
162+
printer(
163+
f"\\sigma_{{{parse_state.equation_latex_name}}}&=\\sqrt{{{'+'.join(symbolic_terms)}}}\\\\"
164+
)
163165

164166
if options.insert:
165167
intermediate_terms = _sigma_intermediate_terms(parse_state, compute_state)
@@ -191,12 +193,12 @@ def _render_result_line(
191193

192194
if options.last_unit is None:
193195
line = (
194-
f"{parse_state.equation_left}{separator}"
196+
f"{parse_state.equation_latex_name}{separator}"
195197
f"{compute_state.result_mu} \\pm {compute_state.result_sigma}"
196198
)
197199
else:
198200
line = (
199-
f"{parse_state.equation_left}{separator}\\left ({compute_state.result_mu} "
201+
f"{parse_state.equation_latex_name}{separator}\\left ({compute_state.result_mu} "
200202
f"\\pm {compute_state.result_sigma} \\right )\\ {options.last_unit}"
201203
)
202204

src/uncertainty_calculator/types.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ class Equation:
1212
"""An equation definition for the uncertainty calculator.
1313
1414
Attributes:
15-
lhs: The left-hand side of the equation (variable name).
16-
rhs: The right-hand side of the equation (expression).
15+
latex_name: The rendered left-hand symbol that appears in the final LaTeX.
16+
expression: The symbolic right-hand-side expression written using
17+
`Variable.name` identifiers. This is only used for computation and
18+
does not appear verbatim in the final rendered output.
1719
1820
"""
1921

20-
lhs: str
21-
rhs: str
22+
latex_name: str
23+
expression: str
2224

2325

2426
@dataclass

src/uncertainty_calculator/validation.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
def validate_inputs(parse_state: ParseState) -> None:
99
"""Ensure all symbols referenced in the equation are defined by variables."""
1010
defined_symbols = set(parse_state.symbols)
11-
free_symbols = parse_state.equation_right.free_symbols
11+
free_symbols = parse_state.equation_expression.free_symbols
1212

1313
for sym in free_symbols:
1414
if sym not in defined_symbols:

tests/input_parsers.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@
1010

1111

1212
def parse_equation(raw_equation: Sequence[str]) -> Equation:
13-
"""Convert a (lhs, rhs) sequence into an Equation dataclass."""
13+
"""Convert a (latex_name, expression) sequence into an Equation dataclass."""
1414
if len(raw_equation) != 2:
15-
msg = "Equation must contain exactly two entries (lhs, rhs)."
15+
msg = "Equation must contain exactly two entries (latex_name, expression)."
1616
raise ValueError(msg)
17-
lhs, rhs = raw_equation
18-
return Equation(lhs=lhs.strip(), rhs=rhs.strip())
17+
latex_name, expression = raw_equation
18+
return Equation(latex_name=latex_name.strip(), expression=expression.strip())
1919

2020

2121
def parse_variables(raw_variables: Iterable[tuple[str, str]]) -> list[Variable]:

tests/test_calculator.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def test_calculator_output_matches_legacy(
2727
):
2828
"""Refactored calculator should match float-normalized legacy rendering."""
2929
expected_output = run_legacy_calculator(
30-
equation=[equation.lhs, equation.rhs],
30+
equation=[equation.latex_name, equation.expression],
3131
variables=_legacy_variables_from_dataclasses(list(variables)),
3232
digits=digits,
3333
last_unit=last_unit,
@@ -60,13 +60,13 @@ def test_run_can_be_called_multiple_times_with_new_inputs():
6060
)
6161

6262
first_output = calc.run(
63-
equation=Equation(lhs="y", rhs="x"),
63+
equation=Equation(latex_name="y", expression="x"),
6464
variables=[Variable(name="x", value=1, uncertainty=0.1, latex_name="x")],
6565
)
6666
assert "\\sigma_{x}" in first_output
6767

6868
second_output = calc.run(
69-
equation=Equation(lhs="y", rhs="m"),
69+
equation=Equation(latex_name="y", expression="m"),
7070
variables=[Variable(name="m", value=2, uncertainty=0.2, latex_name="m")],
7171
)
7272

@@ -89,7 +89,7 @@ def test_constructor_accepts_only_configuration_arguments():
8989

9090
def test_variable_dataclass_input():
9191
"""Calculator should accept dataclass inputs and return a string output."""
92-
equation_obj = Equation(lhs=r"\zeta", rhs=r"K*x")
92+
equation_obj = Equation(latex_name=r"\zeta", expression=r"K*x")
9393
variables_obj = [
9494
Variable(name="K", value=2.0, uncertainty=0.1, latex_name="K"),
9595
Variable(name="x", value=3.0, uncertainty=0.2, latex_name="x"),
@@ -109,7 +109,7 @@ def test_variable_dataclass_input():
109109

110110
def test_mixed_input_types():
111111
"""Numeric values provided as float/int should be accepted."""
112-
equation = Equation(lhs="y", rhs="x")
112+
equation = Equation(latex_name="y", expression="x")
113113
variables = [Variable(name="x", value=10.5, uncertainty=0.5, latex_name="x")]
114114
digits = Digits(mu=2, sigma=2)
115115

tests/test_compute.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212

1313
def _simple_parse_state(value: float, uncertainty: float = 0.1):
14-
equation = Equation(lhs="y", rhs="x")
14+
equation = Equation(latex_name="y", expression="x")
1515
variables = [Variable(name="x", value=value, uncertainty=uncertainty, latex_name="x")]
1616
return parse_inputs(equation, variables)
1717

tests/test_parsing.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ def test_parse_equation_trims_and_builds_dataclass():
1313
"""Whitespace should be stripped when building Equation."""
1414
raw = [" A ", " B + C "]
1515
equation = parse_equation(raw)
16-
assert equation.lhs == "A"
17-
assert equation.rhs == "B + C"
16+
assert equation.latex_name == "A"
17+
assert equation.expression == "B + C"
1818

1919

2020
def test_parse_equation_invalid_length_raises():
@@ -44,7 +44,7 @@ def test_parse_variables_invalid_definition():
4444

4545
def test_parsing_rejects_duplicate_variable_names():
4646
"""Duplicate variable names should raise a ValueError."""
47-
equation = Equation(lhs="y", rhs="x + z")
47+
equation = Equation(latex_name="y", expression="x + z")
4848
variables = [
4949
Variable(name="x", value=1, uncertainty=0.1, latex_name="x"),
5050
Variable(name="x", value=2, uncertainty=0.2, latex_name="x_dup"),

0 commit comments

Comments
 (0)