0
\$\begingroup\$

Function

Calculates values for user defined equations. Just a concept right now. I plan to add many more equations.

Equations in code

Density:

$$ p = \frac{m}{v} $$

Speed:

$$ s = u + a \cdot t $$


class Equations:
    def __init__(self) -> None:
       self.p = lambda m, v: m / v
       self.m = lambda p, v: m * v
       self.v = lambda p, m: m / p
       self.s = lambda u, a, t: u + a * t
    
    
def calculate() -> None:
    density = Equations()
    answer = density.p(1.23, 1.66)
    print(f'density: {answer:.2f}')

    speed = Equations()
    answer = speed.s(3, 4, 5)
    print(f'speed: {answer:.2f}')
   

if __name__ == '__main__':
    calculate()

Output:

density: 0.74

speed: 23.00

Notes

  • I am a beginner so I’m definitely doing things wrong here, suggestions welcome.

  • Is this OOP and classes done right?

Background

I asked a similar question like this and the answer I got was from a very kind user and was very elegant, however it works for 1 equation, and this users suggestion to make it work for multiple equations went over my head:

Other question

https://codereview.stackexchange.com/questions/276177/class-to-calculate-values-of-equation-ρ-m-v/276181?noredirect=1#comment547477_276181

\$\endgroup\$
3
  • \$\begingroup\$ so the reason I had to write this code was because I didn’t understand how to move solve to an abstract class, I looked up abstract classes, you import ABC and pass that in but I just don’t know how to implement it, I really wanted to use your code as it rearranges equations by itself and only allows real numbers, the only problem is I can’t find material which would enable me to do as you said, any resources or tips you can recommend? \$\endgroup\$
    – Nickotine
    Commented Aug 14, 2022 at 21:27
  • \$\begingroup\$ do you mean for this question or shall we continue this in the original question? sure this is meant to contain many equations , I’ll update \$\endgroup\$
    – Nickotine
    Commented Aug 14, 2022 at 22:09
  • \$\begingroup\$ updated for you @reinderien \$\endgroup\$
    – Nickotine
    Commented Aug 14, 2022 at 22:18

1 Answer 1

2
\$\begingroup\$

Your use case is quite simple. You said that you wanted to use Sympy, but you're not sure how to generalise to multiple equations. You also want real number assumptions in Sympy (mind you this is different from validation). Your existing class doesn't offer much - it's basically a collection of functions saved as members, which you should not do. Instead consider a class that parses expressions for the sides of an equation; one instance per equation.

Suggested

import sympy
from sympy import Equality, solve, Symbol, Expr


def parse_real(expr_str: str) -> tuple[Expr, dict[str, Symbol]]:
    symbols_expr = sympy.S(expr_str)

    symbols = {
        s.name: Symbol(
            s.name, real=True, finite=True, nonnegative=True,
        )
        for s in symbols_expr.free_symbols
    }

    expr = sympy.parse_expr(expr_str, symbols)
    return expr, symbols


class EqnSystem:
    def __init__(self, left: str, right: str) -> None:
        left_expr, left_syms = parse_real(left)
        right_expr, right_syms = parse_real(right)
        self.equation = Equality(left_expr, right_expr)
        self.symbols = left_syms | right_syms

    def solve(self, **kwargs: float) -> float:
        unknown, = self.symbols.keys() - kwargs.keys()
        solved, = solve(self.equation, self.symbols[unknown])
        value = solved.subs({
            self.symbols[k]: known
            for k, known in kwargs.items()
        })
        return float(value)


DENSITY = EqnSystem('p', 'm/v')
SPEED = EqnSystem('s', 'u + a*t')


def test() -> None:
    p = DENSITY.solve(m=1.23, v=1.66)
    print(f'density: {p:.2f}')

    s = SPEED.solve(u=3, a=4, t=5)
    print(f'speed: {s:.2f}')


if __name__ == '__main__':
    test()
\$\endgroup\$
9
  • 1
    \$\begingroup\$ thanks a lot my friend, I’m going to study this very properly over the next few days and come back to you with questions, I want to completely understand everything this time, learning resources on the web are very shallow, and I know I don’t have to say this as you have proven time and time again that you are willing to teach me but please bear with me, I appreciate your kindness very much \$\endgroup\$
    – Nickotine
    Commented Aug 15, 2022 at 8:16
  • \$\begingroup\$ the 1st question I have is what is this left and right about? \$\endgroup\$
    – Nickotine
    Commented Aug 15, 2022 at 8:35
  • \$\begingroup\$ The left and right sides of an equation \$\endgroup\$
    – Reinderien
    Commented Aug 15, 2022 at 12:22
  • \$\begingroup\$ How do you find libraries while not knowing what it is what you might want? Do you read the docs to get the methods/properties for the libraries or use your IDE? self.symbols = left_syms | right_syms what is the purpose of this pipe? def parse_real(expr_str: str) -> tuple[Expr, dict[str, Symbol]] expr_str: str so how does it return a tuple and a dict? Apart from these things I think I understand everything else. \$\endgroup\$
    – Nickotine
    Commented Aug 17, 2022 at 0:33
  • 1
    \$\begingroup\$ Experience, Google, StackOverflow, pypi. \$\endgroup\$
    – Reinderien
    Commented Aug 17, 2022 at 11:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.