Multiplication needs extra processing to reorder coefficient and variable
Casper-Guo opened this issue · 7 comments
Environment
If you used latexify in your own environment, fill at least the following items.
Feel free to add other items if you think they are useful.
- OS: Windows 10
- Python: 3.8
- Package manager: pip 22.2.1
- Latexify version: current dev branch
Description
The current implementation of visit_BinOp
doesn't change the ordering of the operands. This is desirable or acceptable for most operations with multiplication being the exception. Numeric coefficients should always precede variable names. That is a*2
and 2*a
should both produce 2a
.
latexify_py/src/latexify/codegen/function_codegen.py
Lines 473 to 479 in 3b1b05b
Reproduction
@latexify.function
def solve(a, b, c):
return (-b + math.sqrt(b**2 - 4*a*c)) / (a*2)
print(solve(1, 4, 3))
print(solve)
solve
produces
\mathrm{solve}(a, b, c) = \frac{-b + \sqrt{b^{{2}} - {4} a c}}{a {2}}
Expected behavior
The above should produce:
\mathrm{solve}(a, b, c) = \frac{-b + \sqrt{b^{{2}} - {4} a c}}{{2} a}
To be clear: this reordering should be applicable only when the targeted node represents the exact number.
The algorithm can be implemented as a new transformer I think. We should also provide a boolean option to switch the behavior.
What about in more complicated cases?
def solve(x):
return 2 * x * 4
It's probably desirable to bubble constant numbers to the front of each product expression somehow, e.g. 2 * x * 4 + a * 3 -> 2 * 4 * x + 3 * a
.
I think we need to handle #89 before this issue. Adding \cdot
( \cdot
, all expressions should be fine without any modification of AST (but the appearance becomes redundant)
Now that #139 is done, the only times where \cdot
shouldn't be used are between a number and a single-character variable or between two single-character variables. The ordering of these variables can be handled using default Python string ordering (e.g "2" < "a" = True
)
What about in more complicated cases?
def solve(x): return 2 * x * 4It's probably desirable to bubble constant numbers to the front of each product expression somehow, e.g.
2 * x * 4 + a * 3 -> 2 * 4 * x + 3 * a
.
In such cases we can implement a simplification procedure similar to #115 and combine all the constant coefficients.
I'm not sure combining constant coeff is always desirable. It may be nice to keep separate for things like 4 * 3.14 / 3 r^3
.
If the user wants them combined they can do it themselves, or maybe it can be introduced as a config option, defaulting to False
.
Good point, it should be configurable
On a related note, operations with brackets, such as (3*a)*(2*b)
also shouldn't be modified. If IIRC, this is the default behavior anyways
The ordering of these variables can be handled using default Python string ordering (e.g "2" < "a" = True)
Yeah that's true, but somewhat tricky. It looks it is desirable to check it in more declarative manner.
I'm not sure combining constant coeff is always desirable
It is generally good to keep the original syntax as-is. It would be good to make every option normally off if it is too intelligent (the good example is reduce_assignments
: this is quite useful IMO, but may confuse users if it is enabled by default)