Skip to content

Commit 62df654

Browse files
Brought up to par with main
1 parent 6da9111 commit 62df654

17 files changed

+798
-295
lines changed

app/context/physical_quantity.py

Lines changed: 79 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# IMPORTS
33
# -------
44

5+
import re
56
from copy import deepcopy
67
from ..utility.physical_quantity_utilities import (
78
SLR_quantity_parser,
@@ -19,6 +20,10 @@
1920
units_sets_dictionary,
2021
set_of_SI_prefixes,
2122
set_of_SI_base_unit_dimensions,
23+
set_of_derived_SI_units_in_SI_base_units,
24+
set_of_common_units_in_SI,
25+
set_of_very_common_units_in_SI,
26+
set_of_imperial_units,
2227
)
2328
from ..utility.slr_parsing_utilities import create_node, infix, operate, catch_undefined, SLR_Parser
2429
from sympy import Symbol
@@ -67,22 +72,6 @@ def generate_criteria_parser(reserved_expressions):
6772
end_symbol = "END"
6873
null_symbol = "NULL"
6974

70-
def compare(comparison):
71-
comparison_dict = {
72-
"=": lambda inputs: bool((inputs[0] - inputs[1]).cancel().simplify().simplify() == 0),
73-
"<=": lambda inputs: bool((inputs[0] - inputs[1]).cancel().simplify().simplify() <= 0),
74-
">=": lambda inputs: bool((inputs[0] - inputs[1]).cancel().simplify().simplify() >= 0),
75-
"<": lambda inputs: bool((inputs[0] - inputs[1]).cancel().simplify().simplify() < 0),
76-
">": lambda inputs: bool((inputs[0] - inputs[1]).cancel().simplify().simplify() > 0),
77-
}
78-
79-
def wrap(inputs):
80-
if inputs[0] is not None and inputs[1] is not None:
81-
return comparison_dict[comparison](inputs)
82-
else:
83-
return False
84-
return wrap
85-
8675
criteria_operations = {
8776
"matches",
8877
"dimension",
@@ -487,7 +476,70 @@ def feedback_procedure_generator(parameters_dict):
487476
return graphs
488477

489478

490-
def expression_preprocess(expr, name, parameters):
479+
def expression_preprocess(name, expr, parameters):
480+
if parameters.get("strictness", "natural") == "legacy":
481+
prefix_data = {(p[0], p[1], tuple(), p[3]) for p in set_of_SI_prefixes}
482+
prefixes = []
483+
for prefix in prefix_data:
484+
prefixes = prefixes+[prefix[0]] + list(prefix[-1])
485+
prefix_short_forms = [prefix[1] for prefix in prefix_data]
486+
unit_data = set_of_SI_base_unit_dimensions \
487+
| set_of_derived_SI_units_in_SI_base_units \
488+
| set_of_common_units_in_SI \
489+
| set_of_very_common_units_in_SI \
490+
| set_of_imperial_units
491+
unit_long_forms = prefixes
492+
for unit in unit_data:
493+
unit_long_forms = unit_long_forms+[unit[0]] + list(unit[-2]) + list(unit[-1])
494+
unit_long_forms = "("+"|".join(unit_long_forms)+")"
495+
# Rewrite any expression on the form "*UNIT" (but not "**UNIT") as " UNIT"
496+
# Example: "newton*metre" ---> "newton metre"
497+
search_string = r"(?<!\*)\* *"+unit_long_forms
498+
match_content = re.search(search_string, expr[1:])
499+
while match_content is not None:
500+
expr = expr[0:match_content.span()[0]+1]+match_content.group().replace("*", " ")+expr[match_content.span()[1]+1:]
501+
match_content = re.search(search_string, expr[1:])
502+
prefixes = "("+"|".join(prefixes)+")"
503+
# Rewrite any expression on the form "PREFIX UNIT" as "PREFIXUNIT"
504+
# Example: "kilo metre" ---> "kilometre"
505+
search_string = prefixes+" "+unit_long_forms
506+
match_content = re.search(search_string, expr)
507+
while match_content is not None:
508+
expr = expr[0:match_content.span()[0]]+" "+"".join(match_content.group().split())+expr[match_content.span()[1]:]
509+
match_content = re.search(search_string, expr)
510+
unit_short_forms = [u[1] for u in unit_data]
511+
short_forms = "("+"|".join(list(set(prefix_short_forms+unit_short_forms)))+")"
512+
# Add space before short forms of prefixes or unit names if they are preceded by numbers or multiplication
513+
# Example: "100Pa" ---> "100 Pa"
514+
search_string = r"[0-9\*\(\)]"+short_forms
515+
match_content = re.search(search_string, expr)
516+
while match_content is not None:
517+
expr = expr[0:match_content.span()[0]+1]+" "+expr[match_content.span()[0]+1:]
518+
match_content = re.search(search_string, expr)
519+
# Remove space after prefix short forms if they are preceded by numbers, multiplication or space
520+
# Example: "100 m Pa" ---> "100 mPa"
521+
prefix_short_forms = "("+"|".join(prefix_short_forms)+")"
522+
search_string = r"[0-9\*\(\) ]"+prefix_short_forms+" "
523+
match_content = re.search(search_string, expr)
524+
while match_content is not None:
525+
expr = expr[0:match_content.span()[0]+1]+match_content.group()[0:-1]+expr[match_content.span()[1]:]
526+
match_content = re.search(search_string, expr)
527+
# Remove multiplication and space after prefix short forms if they are preceded by numbers, multiplication or space
528+
# Example: "100 m* Pa" ---> "100 mPa"
529+
search_string = r"[0-9\*\(\) ]"+prefix_short_forms+"\* "
530+
match_content = re.search(search_string, expr)
531+
while match_content is not None:
532+
expr = expr[0:match_content.span()[0]+1]+match_content.group()[0:-2]+expr[match_content.span()[1]:]
533+
match_content = re.search(search_string, expr)
534+
# Replace multiplication followed by space before unit short forms with only spaces if they are preceded by numbers or space
535+
# Example: "100* Pa" ---> "100 Pa"
536+
unit_short_forms = "("+"|".join(unit_short_forms)+")"
537+
search_string = r"[0-9\(\) ]\* "+unit_short_forms
538+
match_content = re.search(search_string, expr)
539+
while match_content is not None:
540+
expr = expr[0:match_content.span()[0]]+match_content.group().replace("*"," ")+expr[match_content.span()[1]:]
541+
match_content = re.search(search_string, expr)
542+
491543
prefixes = set(x[0] for x in set_of_SI_prefixes)
492544
fundamental_units = set(x[0] for x in set_of_SI_base_unit_dimensions)
493545
units_string = parameters.get("units_string", "SI common imperial")
@@ -499,7 +551,7 @@ def expression_preprocess(expr, name, parameters):
499551
dimensions = set(x[2] for x in set_of_SI_base_unit_dimensions)
500552
unsplittable_symbols = list(prefixes | fundamental_units | valid_units | dimensions)
501553
preprocess_parameters = deepcopy(parameters)
502-
# TODO: find better way to add reserved keywords for physical quantity criteria added to prevent preprocessing to mangle them
554+
# TODO: find better way to prevent preprocessing from mangling reserved keywords for physical quantity criteria
503555
preprocess_parameters.update({"reserved_keywords": preprocess_parameters.get("reserved_keywords", [])+unsplittable_symbols+['matches']})
504556
expr = substitute_input_symbols(expr.strip(), preprocess_parameters)[0]
505557
success = True
@@ -516,6 +568,14 @@ def feedback_string_generator(tags, graph, parameters_dict):
516568
return
517569

518570

571+
def parsing_parameters_generator(params, unsplittable_symbols=tuple(), symbol_assumptions=tuple()):
572+
parsing_parameters = create_sympy_parsing_params(params)
573+
parsing_parameters.update({
574+
"strictness": params.get("strictness", "natural")
575+
})
576+
return parsing_parameters
577+
578+
519579
context = {
520580
"expression_preview": preview_function,
521581
"generate_criteria_parser": generate_criteria_parser,
@@ -524,5 +584,5 @@ def feedback_string_generator(tags, graph, parameters_dict):
524584
"default_criteria": {"response matches answer"},
525585
"feedback_procedure_generator": feedback_procedure_generator,
526586
"feedback_string_generator": feedback_string_generator,
527-
"parsing_parameters_generator": create_sympy_parsing_params,
587+
"parsing_parameters_generator": parsing_parameters_generator,
528588
}

0 commit comments

Comments
 (0)