| 
 | 1 | +---  | 
 | 2 | +title: "SPEC 12 — Formatting mathematical expressions"  | 
 | 3 | +number: 12  | 
 | 4 | +date: 2024-06-06  | 
 | 5 | +author:  | 
 | 6 | +  -  "Pamphile Roy <[email protected]>" | 
 | 7 | +discussion: https://discuss.scientific-python.org/t/spec-12-formatting-mathematical-expressions  | 
 | 8 | +endorsed-by:  | 
 | 9 | +---  | 
 | 10 | + | 
 | 11 | +## Description  | 
 | 12 | + | 
 | 13 | +It is known that the PEP8 and other established styling documents are missing  | 
 | 14 | +guidelines about mathematical expressions. This leads to people coming with  | 
 | 15 | +their own interpretation and style. Standardizing the way we represent maths  | 
 | 16 | +would lead to the same benefits seen with "normal" code. It brings consistency  | 
 | 17 | +in the ecosystem improving the collaborative efforts.  | 
 | 18 | + | 
 | 19 | +This SPEC standardize the formatting of mathematical expressions.  | 
 | 20 | + | 
 | 21 | +## Implementation  | 
 | 22 | + | 
 | 23 | +The following rules must be followed.  | 
 | 24 | +These rules respect and complement the PEP8 (relevant sections includes  | 
 | 25 | +[id20](https://www.python.org/dev/peps/pep-0008/#id20) and  | 
 | 26 | +[id20](https://www.python.org/dev/peps/pep-0008/#id28)).  | 
 | 27 | + | 
 | 28 | +We define a _group_ as a collection of operators having the same priority.  | 
 | 29 | +e.g. `a + b + c` is a single group, `a + b * c` is composed of two groups `a`  | 
 | 30 | +and `b * c`. A group is also a collection delimited with parenthesis.  | 
 | 31 | +`(a + b * c)` is a group. And the whole expression by itself is a  | 
 | 32 | +group.   | 
 | 33 | + | 
 | 34 | +- There a space before and after `-` and `+`. Except if  | 
 | 35 | +  the operator is used to define the sign of the number;  | 
 | 36 | + | 
 | 37 | +  ```  | 
 | 38 | +  a + b  | 
 | 39 | +  -a  | 
 | 40 | +  ```  | 
 | 41 | + | 
 | 42 | +- Within a group, if operators with different priorities are used, add whitespace around the operators with the lowest priority(ies).  | 
 | 43 | + | 
 | 44 | +  ```  | 
 | 45 | +  a + b*c  | 
 | 46 | +  ```  | 
 | 47 | + | 
 | 48 | +- There is no space before and after `**`.  | 
 | 49 | + | 
 | 50 | +  ```  | 
 | 51 | +  a**b  | 
 | 52 | +  ```  | 
 | 53 | + | 
 | 54 | +- There is no space before and after operators `*` and `/`. Only exception is if the expression consist of a single operator linking two groups with more than one  | 
 | 55 | + element.  | 
 | 56 | + | 
 | 57 | +  ```  | 
 | 58 | +  a*b  | 
 | 59 | +  (a*b) * (c*d)  | 
 | 60 | +  ```  | 
 | 61 | + | 
 | 62 | +- Operators within a group are ordered from the lowest to the highest priority.  | 
 | 63 | +  If this is technically an issue (e.g. restriction on the AST), add  | 
 | 64 | +  parenthesis or spaces.  | 
 | 65 | + | 
 | 66 | +  ```  | 
 | 67 | +  a/d*b**c  | 
 | 68 | +  a*(b**c)/d  | 
 | 69 | +  a*b**c / d  | 
 | 70 | +  a * b**c / d  | 
 | 71 | +  ```  | 
 | 72 | + | 
 | 73 | +- When splitting an equation, new lines should start with the operator linking  | 
 | 74 | +  the previous and next logical block. Single digit on a line are forbidden.  | 
 | 75 | + | 
 | 76 | +  ```  | 
 | 77 | +  (  | 
 | 78 | +      a/b  | 
 | 79 | +      + c*d  | 
 | 80 | +  )  | 
 | 81 | +  ```  | 
 | 82 | + | 
 | 83 | +### Examples  | 
 | 84 | + | 
 | 85 | +```python  | 
 | 86 | +# good  | 
 | 87 | +i = i + 1  | 
 | 88 | +submitted += 1  | 
 | 89 | +x = x*2 - 1  | 
 | 90 | +hypot2 = x*x + y*y  | 
 | 91 | +c = (a + b) * (a - b)  | 
 | 92 | +dfdx = sign*(-2*x + 2*y + 2)  | 
 | 93 | +result = 2*x**2 + 3*x**(2/3)  | 
 | 94 | +y = 4*x**2 + 2*x + 1  | 
 | 95 | +c_i1j = (  | 
 | 96 | +    1./n**2.  | 
 | 97 | +    *np.prod(  | 
 | 98 | +        0.5*(2. + abs(z_ij[i1, :]) + abs(z_ij) - abs(z_ij[i1, :] - z_ij)), axis=1  | 
 | 99 | +    )  | 
 | 100 | +)  | 
 | 101 | +```  | 
 | 102 | + | 
 | 103 | +```python  | 
 | 104 | +# bad  | 
 | 105 | +i = i + 1  | 
 | 106 | +submitted += 1  | 
 | 107 | +x = x * 2 - 1  | 
 | 108 | +hypot2 = x * x + y * y  | 
 | 109 | +c = (a + b) * (a - b)  | 
 | 110 | +dfdx = sign * (-2 * x + 2 * y + 2)  | 
 | 111 | +result = 2 * x ** 2 + 3 * x ** (2 / 3)  | 
 | 112 | +y = 4 * x ** 2 + 2 * x + 1  | 
 | 113 | +c_i1j = (  | 
 | 114 | +    1.0  | 
 | 115 | +    / n ** 2.0  | 
 | 116 | +    * np.prod(  | 
 | 117 | +        0.5 * (2.0 + abs(z_ij[i1, :]) + abs(z_ij) - abs(z_ij[i1, :] - z_ij)), axis=1  | 
 | 118 | +    )  | 
 | 119 | +)  | 
 | 120 | +```  | 
 | 121 | + | 
 | 122 | +## Notes  | 
 | 123 | + | 
 | 124 | +These formatting rules do not make any consideration in terms of performances  | 
 | 125 | +nor precision. The scope is limited to styling.  | 
0 commit comments