Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully-featured math expression parser and calculator #2026

Open
Keavon opened this issue Oct 9, 2024 · 5 comments · May be fixed by #2033
Open

Fully-featured math expression parser and calculator #2026

Keavon opened this issue Oct 9, 2024 · 5 comments · May be fixed by #2033
Labels
Feature New feature or request Good First Issue Good for newcomers Help Wanted Extra attention is needed Rust Involves Rust programming for the backend

Comments

@Keavon
Copy link
Member

Keavon commented Oct 9, 2024

This should be built as a library (in our /libraries directory) that uses a parsing framework such as nom or pest that takes a string at runtime and calculates its result, including units and dimensional analysis.

This would make a great solo contribution for somebody interested in developing a robust solution for this problem without needing to learn any of Graphite's code base. It would also make a good university team/solo "capstone" project, which our organization can serve as an "industry sponsor" for.

Here's the spec:

Operators

  • Infix operators:
    • Addition: +
    • Subtraction: -
    • Multiplication: *
    • Division: /
    • Modulo: %
    • Exponentiation: ^
  • Prefix operators:
    • Unary Plus: +
    • Unary Minus: -
    • Square root:
  • Postfix operators:
    • Factorial: !
  • Grouping operators:
    • Parentheses: ( and )

Constants

  • Infinity: inf, INF, infinity, INFINITY,
  • Imaginary unit: i, I
  • Pi: pi, PI, π
  • Tau: tau, TAU, τ
  • Euler's Number: e
  • Golden Ratio: phi, PHI, φ
  • Earth's gravitational acceleration: G

Variables

  • Single-letter variables (examples: x, y, z)
  • Multi-letter variables (examples: theta, alpha, beta, gamma)
  • Non-Latin letters and symbols (examples: λ, , 👍)

Functions

  • Trig:
    • sin(), cos(), tan()
    • csc(), sec(), cot()
  • Inverse trig (aliases: ar- and arc- prefixes):
    • asin(), acos(), atan(), atan2()
    • acsc(), asec(), acot()
  • Hyperbolic:
    • sinh(), cosh(), tanh()
    • csch(), sech(), coth()
  • Inverse hyperbolic (aliases: ar- and arc- prefixes):
    • asinh(), acosh(), atanh()
    • acsch(), asech(), acoth()
  • Logarithm:
    • Natural log: ln()
    • Logarithm base 10: log()
    • Logarithm base 2: log2()
    • Logarithm base N: logN() (alias: log_N())
      • Examples: log5(), log3.25(), log_8()
    • Logarithm with variable base: log(x, b)
  • Exponential:
    • e^x: exp()
    • 2^x: exp2()
  • Roots:
    • Square root: sqrt() (alias: root(), root2(), root_2())
    • Cube root: cbrt() (alias: root3(), root_3())
    • Nth root: rootN() (alias: root_N())
      • Examples: root3(), root5.237(), root_27.72()
    • Root with variable degree: root(n, x)
      • Example: root(27, 3) is equivalent to cbrt(27)
  • Geometry:
    Hypotenuse equation sqrt(a^2 + b^2): hypot()
  • Mapping:
    • Absolute value: abs() (magnitude of a real or complex number)
    • Floor: floor()
    • Ceiling: ceil()
    • Round: round()
    • Clamp: clamp(x, min, max)
    • Lerp: lerp(a, b, t)
    • Truncate: trunc()
    • Fractional part: frac()
    • Sign: sign()
  • Logical
    • Is NaN: isnan() (returns 1 if the operand is NaN, 0 otherwise)
    • Equality: eq() (returns 1 if both operands and units are equal, 0 otherwise)
    • Greater than: greater() (returns 1 if the left operand is greater than the right operand and units are equal, 0 otherwise)
    • Greater-or-equal: greatereq() (returns 1 if the left operand is greater than or equal to the right operand and units are equal, 0 otherwise)
    • Less than: lesser() (returns 1 if the left operand is less than the right operand and units are equal, 0 otherwise)
    • Less-or-equal: lessereq() (returns 1 if the left operand is less than or equal to the right operand and units are equal, 0 otherwise)
    • Not: not() (returns 1 if the operand is zero, 0 otherwise)
    • And: and() (returns 1 if both operands are non-zero, 0 otherwise)
    • Or: or() (returns 1 if either operand is non-zero, 0 otherwise)
    • Xor: xor() (returns 1 if exactly one operand is non-zero, 0 otherwise)
    • If: if(cond, a, b) (returns a if cond is non-zero, b otherwise)
      • A potential alternative to nonzeroness in these logical functions could be using true and false as units with either no value, a value of 0, or a value of 1
  • Complex numbers:
    • Real part: real()
    • Imaginary part: imag()
    • Angle: arg() (alias: angle())

Number representations

  • Integers (examples: 0, 42, -42)
  • Decimals (examples: 0.5, 3.14159, -2.71828)
  • Scientific notation (examples: 1e-6, 2.5E3)
  • Imaginary numbers (examples: 3i, -2.5i, 1.5e-3i, 2.5e3 + 2.1e-2i)
  • Units (examples: 5m, 5 m, 3.5kg, 3.5 kg, 2.5m/s^2, 2.5 m/s^2)

Units

  • In addition to the unit abbreviations, full unit names can be used in either singular or plural form
  • Math expressions perform dimensional analysis
    • The scalar part is simplified while the unit part is kept as a fraction if it cannot be simplified
    • Units should only be combined if they are mixed with other units in either the numerator or denominator, defaulting to the unit that would best avoid loss of precision
      • Example: 5m + 3m -> 8m
      • Example: 5ft + 3ft -> 8ft
      • Example: 5m + 3ft -> 5.9144m (meters are chosen because 1ft = 0.3048m exactly, while its inverse can't be represented exactly)
  • Values can always be requested for conversion to a specific unit in the API

Unit list

  • Unitless
  • Pixels:
    • px
  • Length:
    • Meter m and its prefixes
    • thou, pc, pt, in/", ft/', yd, mi, nmi
  • Area:
    • length^2
    • acre, are, hectare
  • Volume:
    • length^3, area * length
    • Paper sizes: A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10
    • floz, cup, pint, qt, gal
    • l and its prefixes
  • Mass:
    • Kilogram kg and its prefixes
    • gr, oz, lb, ton, tonne
  • Time:
    • Second s and its prefixes
    • min, hr, day
  • Angle:
    • Degrees: deg/°
    • Radians: rad (unitless is not an angle)
    • Turns: turn
  • Velocity:
    • length / time
    • m/s, km/h, mph, knot
  • Acceleration:
    • velocity / time, length / time^2
    • m/s^2, ft/s^2, g
  • Angular velocity:
    • angle / time
    • deg/s, rad/s, rpm, rps
  • Angular acceleration:
    • angular velocity / time, angle / time^2
    • deg/s^2, rad/s^2
  • Illumination
    • TODO: Research and lay out what these are, like candela, nits, etc.

Unit metric prefixes

  • Nano (n)
  • Micro (µ, u)
  • Milli (m)
  • Centi (c)
  • Deci (d)
  • Deca (da)
  • Hecto (h)
  • Kilo (k)
  • Mega (M)
  • Giga (G)
  • Tera (T)

Implicit multiplication

  • Automatically handle multiplication without explicit * operator
    • Between numbers and variables/constants (examples: 3x, 2pi)
    • Between numbers and functions (example: 4sin(90deg))
    • Between adjacent variables/constants (examples: xy, pi r^2)

API features

  • Syntax highlighting
  • Setting the result of one expression to a variable for use in subsequent expressions
  • Parsing/construction separate from evaluation so the same expression can be run repeatedly with different variables without wasted performance
  • Custom supplied units, unit symbols, functions, and constants
@Keavon Keavon added Feature New feature or request Help Wanted Extra attention is needed Good First Issue Good for newcomers Rust Involves Rust programming for the backend labels Oct 9, 2024
@abueno19
Copy link

abueno19 commented Oct 9, 2024

I'm interested in this issue. I'm a bit new, but I hope to do my best and make progress in this field.

@Keavon
Copy link
Member Author

Keavon commented Oct 9, 2024

@abueno19 that would be great, thanks for volunteering! We'd ideally like to get a reasonably functional version of this working in the next month or so, with progress towards the full functionality outlined here over the next couple months. My plan was to post this issue on /r/rust to find interested collaborators. Multiple people could probably work on it together, like writing tests, figuring out the correct formal grammar, handling the AST, working with the dimensional analysis, calculating the values, implementing the functions, etc. What's your level of experience with software engineering or computer science in general, and grammar parsing in particular, and would you like to work with others on this?

@abueno19
Copy link

@Keavon

Hello,
I have 2 years of experience working with IoT in .NET, and I’ve been working with Rust for 3 months on my own mini-projects.

As for grammar analysis, I don’t think I’d have any issues with parsing.

Regarding your question about working with others, I would love to!

What I’m looking to gain from this is learning how to structure code, work in a community, and learn new methodologies.

Just let me know, and I’ll start with the basics (character parsing system).
By the way, how will the data be passed around?

@urisinger
Copy link

urisinger commented Oct 10, 2024

This issue seems interesting, I'm working on a parser for desmos expressions and the syntax is very similar, so maybe some of the code can be reused.

@Keavon
Copy link
Member Author

Keavon commented Oct 12, 2024

Thanks for the introduction, @abueno19! Could you join our Discord (https://discord.graphite.rs) and work with @urisinger in the new channel I created for this library project, which I've tentatively called #🧮math-expr-calc? Easier to communicate there by chatting compared to here. See you there!

@urisinger urisinger linked a pull request Oct 12, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature New feature or request Good First Issue Good for newcomers Help Wanted Extra attention is needed Rust Involves Rust programming for the backend
Projects
Status: Short-Term
Development

Successfully merging a pull request may close this issue.

4 participants
@Keavon @urisinger @abueno19 and others