-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split out example parsers into separate modules in the examples direc…
…tory.
- Loading branch information
Showing
11 changed files
with
224 additions
and
203 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# | ||
# business_arithmetic_parser.py | ||
# | ||
# Copyright 2021, Paul McGuire | ||
# | ||
from plusminus import BaseArithmeticParser, safe_pow | ||
|
||
|
||
class BusinessArithmeticParser(BaseArithmeticParser): | ||
""" | ||
A parser for evaluating common financial and retail calculations: | ||
50% of 20 | ||
20 * (1-20%) | ||
(100-20)% of 20 | ||
5 / 20% | ||
FV(20000, 3%, 30) | ||
FV(20000, 3%/12, 30*12) | ||
Functions: | ||
FV(present_value, rate_per_period, number_of_periods) | ||
future value of an amount, n periods in the future, at an interest rate per period | ||
PV(future_value, rate_per_period, number_of_periods) | ||
present value of a future amount, n periods in the future, at an interest rate per period | ||
PP(present_value, rate_per_period, number_of_periods) | ||
periodic value of n amounts, one per period, for n periods, at an interest rate per period | ||
""" | ||
|
||
def customize(self): | ||
def pv(future_value, rate, n_periods): | ||
return future_value / safe_pow(1 + rate, n_periods) | ||
|
||
def fv(present_value, rate, n_periods): | ||
return present_value * safe_pow(1 + rate, n_periods) | ||
|
||
def pp(present_value, rate, n_periods): | ||
return rate * present_value / (1 - safe_pow(1 + rate, -n_periods)) | ||
|
||
super().customize() | ||
self.add_operator("of", 2, BaseArithmeticParser.LEFT, lambda a, b: a * b) | ||
self.add_operator("%", 1, BaseArithmeticParser.LEFT, lambda a: a / 100) | ||
|
||
self.add_function("PV", 3, pv) | ||
self.add_function("FV", 3, fv) | ||
self.add_function("PP", 3, pp) | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
parser = BusinessArithmeticParser() | ||
parser.runTests( | ||
"""\ | ||
25% | ||
20 * 50% | ||
50% of 20 | ||
20 * (1-20%) | ||
(100-20)% of 20 | ||
5 / 20% | ||
FV(20000, 3%, 30) | ||
FV(20000, 3%/12, 30*12) | ||
""", | ||
postParse=lambda _, result: result[0].evaluate(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# | ||
# combinatorics_arithmetic_parser.py | ||
# | ||
# Copyright 2021, Paul McGuire | ||
# | ||
from plusminus import BaseArithmeticParser, ArithmeticParser, constrained_factorial | ||
|
||
|
||
class CombinatoricsArithmeticParser(BaseArithmeticParser): | ||
""" | ||
Parser for evaluating expressions of combinatorics problems, for numbers of | ||
permutations (nPm) and combinations (nCm): | ||
nPm = n! / (n-m)! | ||
8P4 = number of (ordered) permutations of selecting 4 items from a collection of 8 | ||
nCm = n! / m!(n-m)! | ||
8C4 = number of (unordered) combinations of selecting 4 items from a collection of 8 | ||
""" | ||
|
||
def customize(self): | ||
super().customize() | ||
# fmt: off | ||
self.add_operator("P", 2, BaseArithmeticParser.LEFT, | ||
lambda a, b: int(constrained_factorial(a) / constrained_factorial(a - b))) | ||
self.add_operator("C", 2, BaseArithmeticParser.LEFT, | ||
lambda a, b: int(constrained_factorial(a) | ||
/ constrained_factorial(b) | ||
/ constrained_factorial(a - b))) | ||
self.add_operator(*ArithmeticParser.Operators.FACTORIAL) | ||
# fmt: on | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
parser = CombinatoricsArithmeticParser() | ||
parser.runTests( | ||
"""\ | ||
3! | ||
-3! | ||
3!! | ||
6! / (6-2)! | ||
6 P 2 | ||
6! / (2!*(6-2)!) | ||
6 C 2 | ||
6P6 | ||
6C6 | ||
""", | ||
postParse=lambda _, result: result[0].evaluate(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# | ||
# date_time_arithmetic_parser.py | ||
# | ||
# Copyright 2021, Paul McGuire | ||
# | ||
from plusminus import BaseArithmeticParser | ||
|
||
|
||
class DateTimeArithmeticParser(BaseArithmeticParser): | ||
""" | ||
Parser for evaluating expressions in dates and times, using operators d, h, m, and s | ||
to define terms for amounts of days, hours, minutes, and seconds: | ||
now() | ||
today() | ||
now() + 10s | ||
now() + 24h | ||
All numeric expressions will be treated as UTC integer timestamps. To display | ||
timestamps as ISO strings, use str(): | ||
str(now()) | ||
str(today() + 3d) | ||
""" | ||
|
||
SECONDS_PER_MINUTE = 60 | ||
SECONDS_PER_HOUR = SECONDS_PER_MINUTE * 60 | ||
SECONDS_PER_DAY = SECONDS_PER_HOUR * 24 | ||
|
||
def customize(self): | ||
from datetime import datetime | ||
|
||
# fmt: off | ||
self.add_operator("d", 1, BaseArithmeticParser.LEFT, lambda t: t * DateTimeArithmeticParser.SECONDS_PER_DAY) | ||
self.add_operator("h", 1, BaseArithmeticParser.LEFT, lambda t: t * DateTimeArithmeticParser.SECONDS_PER_HOUR) | ||
self.add_operator("m", 1, BaseArithmeticParser.LEFT, lambda t: t * DateTimeArithmeticParser.SECONDS_PER_MINUTE) | ||
self.add_operator("s", 1, BaseArithmeticParser.LEFT, lambda t: t) | ||
|
||
self.add_function("now", 0, lambda: datetime.utcnow().timestamp()) | ||
self.add_function("today", 0, | ||
lambda: datetime.utcnow().replace(hour=0, minute=0, second=0, microsecond=0).timestamp()) | ||
self.add_function("str", 1, lambda dt: str(datetime.fromtimestamp(dt))) | ||
# fmt: on | ||
|
||
|
||
if __name__ == "__main__": | ||
|
||
parser = DateTimeArithmeticParser() | ||
parser.runTests( | ||
"""\ | ||
now() | ||
str(now()) | ||
str(today()) | ||
"A day from now: " + str(now() + 1d) | ||
"A day and an hour from now: " + str(now() + 1d + 1h) | ||
str(now() + 3*(1d + 1h)) | ||
""", | ||
postParse=lambda _, result: result[0].evaluate(), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# | ||
# dice_roll_parser.py | ||
# | ||
# Copyright 2021, Paul McGuire | ||
# | ||
from plusminus import BaseArithmeticParser | ||
|
||
|
||
class DiceRollParser(BaseArithmeticParser): | ||
""" | ||
Parser for evaluating expressions representing rolls of dice, as used in many board and | ||
role-playing games, such as: | ||
d20 | ||
3d20 | ||
5d6 + d20 | ||
""" | ||
|
||
def customize(self): | ||
import random | ||
|
||
# fmt: off | ||
self.add_operator("d", 1, BaseArithmeticParser.RIGHT, lambda a: random.randint(1, a)) | ||
self.add_operator("d", 2, BaseArithmeticParser.LEFT, | ||
lambda a, b: sum(random.randint(1, b) for _ in range(a))) | ||
# fmt: on | ||
|
||
|
||
if __name__ == '__main__': | ||
|
||
parser = DiceRollParser() | ||
parser.runTests( | ||
"""\ | ||
d20 | ||
3d6 | ||
d20+3d4 | ||
2d100 | ||
""", | ||
postParse=lambda _, result: result[0].evaluate(), | ||
) |
Oops, something went wrong.