qnty 0.0.9__py3-none-any.whl → 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. qnty/__init__.py +2 -3
  2. qnty/constants/__init__.py +10 -0
  3. qnty/constants/numerical.py +18 -0
  4. qnty/constants/solvers.py +6 -0
  5. qnty/constants/tests.py +6 -0
  6. qnty/dimensions/__init__.py +23 -0
  7. qnty/dimensions/base.py +97 -0
  8. qnty/dimensions/field_dims.py +126 -0
  9. qnty/dimensions/field_dims.pyi +128 -0
  10. qnty/dimensions/signature.py +111 -0
  11. qnty/equations/__init__.py +1 -1
  12. qnty/equations/equation.py +118 -155
  13. qnty/equations/system.py +68 -65
  14. qnty/expressions/__init__.py +25 -46
  15. qnty/expressions/formatter.py +188 -0
  16. qnty/expressions/functions.py +46 -68
  17. qnty/expressions/nodes.py +539 -384
  18. qnty/expressions/types.py +70 -0
  19. qnty/problems/__init__.py +145 -0
  20. qnty/problems/composition.py +1031 -0
  21. qnty/problems/problem.py +695 -0
  22. qnty/problems/rules.py +145 -0
  23. qnty/problems/solving.py +1216 -0
  24. qnty/problems/validation.py +127 -0
  25. qnty/quantities/__init__.py +28 -5
  26. qnty/quantities/base_qnty.py +677 -0
  27. qnty/quantities/field_converters.py +24004 -0
  28. qnty/quantities/field_qnty.py +1012 -0
  29. qnty/{generated/setters.py → quantities/field_setter.py} +3071 -2961
  30. qnty/{generated/quantities.py → quantities/field_vars.py} +754 -432
  31. qnty/{generated/quantities.pyi → quantities/field_vars.pyi} +1289 -1290
  32. qnty/solving/manager.py +50 -44
  33. qnty/solving/order.py +181 -133
  34. qnty/solving/solvers/__init__.py +2 -9
  35. qnty/solving/solvers/base.py +27 -37
  36. qnty/solving/solvers/iterative.py +115 -135
  37. qnty/solving/solvers/simultaneous.py +93 -165
  38. qnty/units/__init__.py +1 -0
  39. qnty/{generated/units.py → units/field_units.py} +1700 -991
  40. qnty/units/field_units.pyi +2461 -0
  41. qnty/units/prefixes.py +58 -105
  42. qnty/units/registry.py +76 -89
  43. qnty/utils/__init__.py +16 -0
  44. qnty/utils/caching/__init__.py +23 -0
  45. qnty/utils/caching/manager.py +401 -0
  46. qnty/utils/error_handling/__init__.py +66 -0
  47. qnty/utils/error_handling/context.py +39 -0
  48. qnty/utils/error_handling/exceptions.py +96 -0
  49. qnty/utils/error_handling/handlers.py +171 -0
  50. qnty/utils/logging.py +4 -4
  51. qnty/utils/protocols.py +164 -0
  52. qnty/utils/scope_discovery.py +420 -0
  53. {qnty-0.0.9.dist-info → qnty-0.1.0.dist-info}/METADATA +1 -1
  54. qnty-0.1.0.dist-info/RECORD +60 -0
  55. qnty/_backup/problem_original.py +0 -1251
  56. qnty/_backup/quantity.py +0 -63
  57. qnty/codegen/cli.py +0 -125
  58. qnty/codegen/generators/data/unit_data.json +0 -8807
  59. qnty/codegen/generators/data_processor.py +0 -345
  60. qnty/codegen/generators/dimensions_gen.py +0 -434
  61. qnty/codegen/generators/doc_generator.py +0 -141
  62. qnty/codegen/generators/out/dimension_mapping.json +0 -974
  63. qnty/codegen/generators/out/dimension_metadata.json +0 -123
  64. qnty/codegen/generators/out/units_metadata.json +0 -223
  65. qnty/codegen/generators/quantities_gen.py +0 -159
  66. qnty/codegen/generators/setters_gen.py +0 -178
  67. qnty/codegen/generators/stubs_gen.py +0 -167
  68. qnty/codegen/generators/units_gen.py +0 -295
  69. qnty/expressions/cache.py +0 -94
  70. qnty/generated/dimensions.py +0 -514
  71. qnty/problem/__init__.py +0 -91
  72. qnty/problem/base.py +0 -142
  73. qnty/problem/composition.py +0 -385
  74. qnty/problem/composition_mixin.py +0 -382
  75. qnty/problem/equations.py +0 -413
  76. qnty/problem/metaclass.py +0 -302
  77. qnty/problem/reconstruction.py +0 -1016
  78. qnty/problem/solving.py +0 -180
  79. qnty/problem/validation.py +0 -64
  80. qnty/problem/variables.py +0 -239
  81. qnty/quantities/expression_quantity.py +0 -314
  82. qnty/quantities/quantity.py +0 -428
  83. qnty/quantities/typed_quantity.py +0 -215
  84. qnty/validation/__init__.py +0 -0
  85. qnty/validation/registry.py +0 -0
  86. qnty/validation/rules.py +0 -167
  87. qnty-0.0.9.dist-info/RECORD +0 -63
  88. /qnty/{codegen → extensions}/__init__.py +0 -0
  89. /qnty/{codegen/generators → extensions/integration}/__init__.py +0 -0
  90. /qnty/{codegen/generators/utils → extensions/plotting}/__init__.py +0 -0
  91. /qnty/{generated → extensions/reporting}/__init__.py +0 -0
  92. {qnty-0.0.9.dist-info → qnty-0.1.0.dist-info}/WHEEL +0 -0
qnty/expressions/nodes.py CHANGED
@@ -7,196 +7,127 @@ Core abstract syntax tree nodes for mathematical expressions.
7
7
 
8
8
  import math
9
9
  from abc import ABC, abstractmethod
10
- from typing import TYPE_CHECKING, Union
11
10
 
12
- if TYPE_CHECKING:
13
- from ..quantities.quantity import Quantity, TypeSafeVariable
14
-
15
- from ..generated.units import DimensionlessUnits
16
- from ..quantities.quantity import Quantity, TypeSafeVariable
17
- from .cache import _EXPRESSION_RESULT_CACHE, _MAX_EXPRESSION_CACHE_SIZE, wrap_operand
11
+ from ..constants import CONDITION_EVALUATION_THRESHOLD, DIVISION_BY_ZERO_THRESHOLD, FLOAT_EQUALITY_TOLERANCE
12
+ from ..quantities import FieldQnty, Quantity
13
+ from ..units.field_units import DimensionlessUnits
14
+ from ..utils.caching.manager import get_cache_manager
15
+ from ..utils.protocols import register_expression_type, register_variable_type
16
+ from ..utils.scope_discovery import ScopeDiscoveryService
17
+ from .formatter import ExpressionFormatter
18
18
 
19
19
 
20
20
  class Expression(ABC):
21
21
  """Abstract base class for mathematical expressions."""
22
-
22
+
23
23
  # Class-level optimization settings
24
- _scope_cache = {}
25
24
  _auto_eval_enabled = False # Disabled by default for performance
26
- _max_scope_cache_size = 100 # Limit scope cache size
27
-
25
+
28
26
  @abstractmethod
29
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
27
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
30
28
  """Evaluate the expression given variable values."""
31
29
  pass
32
-
30
+
33
31
  @abstractmethod
34
32
  def get_variables(self) -> set[str]:
35
33
  """Get all variable symbols used in this expression."""
36
34
  pass
37
-
35
+
38
36
  @abstractmethod
39
- def simplify(self) -> 'Expression':
37
+ def simplify(self) -> "Expression":
40
38
  """Simplify the expression."""
41
39
  pass
42
-
40
+
43
41
  @abstractmethod
44
42
  def __str__(self) -> str:
45
43
  pass
46
-
47
- def _discover_variables_from_scope(self) -> dict[str, 'TypeSafeVariable']:
48
- """Automatically discover variables from the calling scope (optimized)."""
44
+
45
+ def _discover_variables_from_scope(self) -> dict[str, "FieldQnty"]:
46
+ """Automatically discover variables from the calling scope using centralized service."""
49
47
  # Skip if auto-evaluation is disabled
50
48
  if not self._auto_eval_enabled:
51
49
  return {}
52
-
53
- # Check cache first with size limit
54
- cache_key = id(self)
55
- if cache_key in self._scope_cache:
56
- return self._scope_cache[cache_key]
57
-
58
- # Clean cache if it gets too large
59
- if len(self._scope_cache) >= self._max_scope_cache_size:
60
- self._scope_cache.clear()
61
-
62
- import inspect
63
-
64
- # Get the frame that called this method (skip through __str__ calls)
65
- frame = inspect.currentframe()
66
- try:
67
- # Skip frames until we find one outside the expression system (with depth limit)
68
- depth = 0
69
- max_depth = 6 # Reduced from unlimited for performance
70
- while frame and depth < max_depth and (
71
- frame.f_code.co_filename.endswith('expression.py') or
72
- frame.f_code.co_name in ['__str__', '__repr__']
73
- ):
74
- frame = frame.f_back
75
- depth += 1
76
-
77
- if not frame:
78
- return {}
79
-
80
- # Get required variables first to optimize search
81
- required_vars = self.get_variables()
82
- if not required_vars:
83
- return {}
84
-
85
- discovered = {}
86
-
87
- # Search locals first (most common case)
88
- local_vars = frame.f_locals
89
- for var_name in required_vars:
90
- # Direct lookup first (fastest)
91
- if var_name in local_vars:
92
- obj = local_vars[var_name]
93
- if isinstance(obj, TypeSafeVariable):
94
- discovered[var_name] = obj
95
- continue
96
-
97
- # Search globals only for remaining variables
98
- if len(discovered) < len(required_vars):
99
- global_vars = frame.f_globals
100
- remaining_vars = required_vars - discovered.keys()
101
- for var_name in remaining_vars:
102
- if var_name in global_vars:
103
- obj = global_vars[var_name]
104
- if isinstance(obj, TypeSafeVariable):
105
- discovered[var_name] = obj
106
-
107
- # Cache the result
108
- self._scope_cache[cache_key] = discovered
109
- return discovered
110
-
111
- finally:
112
- del frame
113
-
114
- def _can_auto_evaluate(self) -> tuple[bool, dict[str, 'TypeSafeVariable']]:
115
- """Check if expression can be auto-evaluated from scope."""
116
- try:
117
- discovered = self._discover_variables_from_scope()
118
- required_vars = self.get_variables()
119
-
120
- # Check if all required variables are available and have values
121
- for var_name in required_vars:
122
- if var_name not in discovered:
123
- return False, {}
124
- var = discovered[var_name]
125
- if not hasattr(var, 'quantity') or var.quantity is None:
126
- return False, {}
127
-
128
- return True, discovered
129
-
130
- except Exception:
131
- return False, {}
132
-
133
- def __add__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
134
- return BinaryOperation('+', self, wrap_operand(other))
135
-
136
- def __radd__(self, other: Union['TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
137
- return BinaryOperation('+', wrap_operand(other), self)
138
-
139
- def __sub__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
140
- return BinaryOperation('-', self, wrap_operand(other))
141
-
142
- def __rsub__(self, other: Union['TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
143
- return BinaryOperation('-', wrap_operand(other), self)
144
-
145
- def __mul__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
146
- return BinaryOperation('*', self, wrap_operand(other))
147
-
148
- def __rmul__(self, other: Union['TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
149
- return BinaryOperation('*', wrap_operand(other), self)
150
-
151
- def __truediv__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
152
- return BinaryOperation('/', self, wrap_operand(other))
153
-
154
- def __rtruediv__(self, other: Union['TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
155
- return BinaryOperation('/', wrap_operand(other), self)
156
-
157
- def __pow__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
158
- return BinaryOperation('**', self, wrap_operand(other))
159
-
160
- def __rpow__(self, other: Union['TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
161
- return BinaryOperation('**', wrap_operand(other), self)
162
-
163
- def __abs__(self) -> 'Expression':
50
+
51
+ # Get required variables first to optimize search
52
+ required_vars = self.get_variables()
53
+ if not required_vars:
54
+ return {}
55
+
56
+ # Use centralized scope discovery service
57
+ return ScopeDiscoveryService.discover_variables(required_vars, enable_caching=True)
58
+
59
+ def _can_auto_evaluate(self) -> tuple[bool, dict[str, "FieldQnty"]]:
60
+ """Check if expression can be auto-evaluated from scope using centralized service."""
61
+ # Use centralized scope discovery service
62
+ return ScopeDiscoveryService.can_auto_evaluate(self)
63
+
64
+ def __add__(self, other: "OperandType") -> "Expression":
65
+ return BinaryOperation("+", self, wrap_operand(other))
66
+
67
+ def __radd__(self, other: "OperandType") -> "Expression":
68
+ return BinaryOperation("+", wrap_operand(other), self)
69
+
70
+ def __sub__(self, other: "OperandType") -> "Expression":
71
+ return BinaryOperation("-", self, wrap_operand(other))
72
+
73
+ def __rsub__(self, other: "OperandType") -> "Expression":
74
+ return BinaryOperation("-", wrap_operand(other), self)
75
+
76
+ def __mul__(self, other: "OperandType") -> "Expression":
77
+ return BinaryOperation("*", self, wrap_operand(other))
78
+
79
+ def __rmul__(self, other: "OperandType") -> "Expression":
80
+ return BinaryOperation("*", wrap_operand(other), self)
81
+
82
+ def __truediv__(self, other: "OperandType") -> "Expression":
83
+ return BinaryOperation("/", self, wrap_operand(other))
84
+
85
+ def __rtruediv__(self, other: "OperandType") -> "Expression":
86
+ return BinaryOperation("/", wrap_operand(other), self)
87
+
88
+ def __pow__(self, other: "OperandType") -> "Expression":
89
+ return BinaryOperation("**", self, wrap_operand(other))
90
+
91
+ def __rpow__(self, other: "OperandType") -> "Expression":
92
+ return BinaryOperation("**", wrap_operand(other), self)
93
+
94
+ def __abs__(self) -> "Expression":
164
95
  """Absolute value of the expression."""
165
- return UnaryFunction('abs', self)
166
-
96
+ return UnaryFunction("abs", self)
97
+
167
98
  # Comparison operators for conditional expressions (consolidated)
168
- def _make_comparison(self, operator: str, other) -> 'BinaryOperation':
99
+ def _make_comparison(self, operator: str, other) -> "BinaryOperation":
169
100
  """Helper method to create comparison operations."""
170
101
  return BinaryOperation(operator, self, wrap_operand(other))
171
-
172
- def __lt__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'BinaryOperation':
173
- return self._make_comparison('<', other)
174
102
 
175
- def __le__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'BinaryOperation':
176
- return self._make_comparison('<=', other)
177
-
178
- def __gt__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'BinaryOperation':
179
- return self._make_comparison('>', other)
180
-
181
- def __ge__(self, other: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'BinaryOperation':
182
- return self._make_comparison('>=', other)
183
-
184
- @staticmethod
185
- def _wrap_operand(operand: Union['Expression', 'TypeSafeVariable', 'Quantity', int, float]) -> 'Expression':
186
- """Wrap non-Expression operands in appropriate Expression subclasses."""
187
- return wrap_operand(operand)
103
+ def __lt__(self, other: "OperandType") -> "BinaryOperation":
104
+ return self._make_comparison("<", other)
105
+
106
+ def __le__(self, other: "OperandType") -> "BinaryOperation":
107
+ return self._make_comparison("<=", other)
108
+
109
+ def __gt__(self, other: "OperandType") -> "BinaryOperation":
110
+ return self._make_comparison(">", other)
111
+
112
+ def __ge__(self, other: "OperandType") -> "BinaryOperation":
113
+ return self._make_comparison(">=", other)
114
+
115
+
116
+ # Type aliases to reduce repetition
117
+ OperandType = Expression | FieldQnty | Quantity | int | float
188
118
 
189
119
 
190
120
  class VariableReference(Expression):
191
121
  """Reference to a variable in an expression with performance optimizations."""
192
- __slots__ = ('variable', '_cached_name', '_last_symbol')
193
-
194
- def __init__(self, variable: 'TypeSafeVariable'):
122
+
123
+ __slots__ = ("variable", "_cached_name", "_last_symbol")
124
+
125
+ def __init__(self, variable: "FieldQnty"):
195
126
  self.variable = variable
196
127
  # Cache the name resolution to avoid repeated lookups
197
128
  self._cached_name = None
198
129
  self._last_symbol = None
199
-
130
+
200
131
  @property
201
132
  def name(self) -> str:
202
133
  """Get variable name with caching for performance."""
@@ -207,7 +138,7 @@ class VariableReference(Expression):
207
138
  self._last_symbol = current_symbol
208
139
  return self._cached_name
209
140
 
210
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
141
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
211
142
  try:
212
143
  if self.name in variable_values:
213
144
  var = variable_values[self.name]
@@ -215,279 +146,387 @@ class VariableReference(Expression):
215
146
  return var.quantity
216
147
  elif self.variable.quantity is not None:
217
148
  return self.variable.quantity
218
-
149
+
219
150
  # If we reach here, no valid quantity was found
220
151
  available_vars = list(variable_values.keys()) if variable_values else []
221
- raise ValueError(
222
- f"Cannot evaluate variable '{self.name}' without value. "
223
- f"Available variables: {available_vars}"
224
- )
152
+ raise ValueError(f"Cannot evaluate variable '{self.name}' without value. Available variables: {available_vars}")
225
153
  except Exception as e:
226
154
  if isinstance(e, ValueError):
227
155
  raise
228
156
  raise ValueError(f"Error evaluating variable '{self.name}': {e}") from e
229
-
157
+
230
158
  def get_variables(self) -> set[str]:
231
159
  return {self.name}
232
-
233
- def simplify(self) -> 'Expression':
160
+
161
+ def simplify(self) -> "Expression":
234
162
  return self
235
-
163
+
236
164
  def __str__(self) -> str:
237
- return self.name
165
+ return ExpressionFormatter.format_variable_reference(self) # type: ignore[arg-type]
238
166
 
239
167
 
240
168
  class Constant(Expression):
241
169
  """Constant value in an expression."""
242
- __slots__ = ('value',)
243
-
244
- def __init__(self, value: 'Quantity'):
170
+
171
+ __slots__ = ("value",)
172
+
173
+ def __init__(self, value: "Quantity"):
245
174
  self.value = value
246
-
247
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
175
+
176
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
248
177
  del variable_values # Suppress unused variable warning
249
178
  return self.value
250
-
179
+
251
180
  def get_variables(self) -> set[str]:
252
181
  return set()
253
-
254
- def simplify(self) -> 'Expression':
182
+
183
+ def simplify(self) -> "Expression":
255
184
  return self
256
-
185
+
257
186
  def __str__(self) -> str:
258
- return str(self.value.value)
187
+ return ExpressionFormatter.format_constant(self) # type: ignore[arg-type]
259
188
 
260
189
 
261
190
  class BinaryOperation(Expression):
262
191
  """Binary operation between two expressions."""
263
- __slots__ = ('operator', 'left', 'right')
264
-
192
+
193
+ __slots__ = ("operator", "left", "right")
194
+
265
195
  # Operator dispatch table for better performance
266
- _ARITHMETIC_OPS = {'+', '-', '*', '/', '**'}
267
- _COMPARISON_OPS = {'<', '<=', '>', '>=', '==', '!='}
268
-
196
+ _ARITHMETIC_OPS = {"+", "-", "*", "/", "**"}
197
+ _COMPARISON_OPS = {"<", "<=", ">", ">=", "==", "!="}
198
+
269
199
  def __init__(self, operator: str, left: Expression, right: Expression):
270
200
  self.operator = operator
271
201
  self.left = left
272
202
  self.right = right
273
203
 
274
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
204
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
205
+ """Evaluate the binary operation with caching and error handling."""
275
206
  try:
276
- # Fast path for constant expressions (both sides are constants)
277
- if isinstance(self.left, Constant) and isinstance(self.right, Constant):
278
- cache_key = (id(self), self.operator, id(self.left.value), id(self.right.value))
279
- if cache_key in _EXPRESSION_RESULT_CACHE:
280
- return _EXPRESSION_RESULT_CACHE[cache_key]
281
-
282
- # Clean cache if it gets too large
283
- if len(_EXPRESSION_RESULT_CACHE) >= _MAX_EXPRESSION_CACHE_SIZE:
284
- _EXPRESSION_RESULT_CACHE.clear()
285
- else:
286
- cache_key = None
287
-
288
- left_val = self.left.evaluate(variable_values)
289
- right_val = self.right.evaluate(variable_values)
290
-
291
- # Fast dispatch for arithmetic operations
292
- if self.operator in self._ARITHMETIC_OPS:
293
- result = self._evaluate_arithmetic(left_val, right_val)
294
- elif self.operator in self._COMPARISON_OPS:
295
- result = self._evaluate_comparison(left_val, right_val)
296
- else:
297
- raise ValueError(f"Unknown operator: {self.operator}")
298
-
299
- # Cache result for constant expressions
300
- if cache_key is not None:
301
- _EXPRESSION_RESULT_CACHE[cache_key] = result
302
-
303
- return result
207
+ return self._evaluate_with_caching(variable_values)
304
208
  except Exception as e:
305
- if isinstance(e, ValueError):
306
- raise
307
- raise ValueError(f"Error evaluating binary operation '{self}': {e}") from e
308
-
309
- def _evaluate_arithmetic(self, left_val: 'Quantity', right_val: 'Quantity') -> 'Quantity':
310
- """Evaluate arithmetic operations with fast paths."""
311
- # Fast path optimizations for common cases
312
- if self.operator == '*':
313
- # Fast path for multiplication by 1
314
- if right_val.value == 1.0:
315
- return left_val
316
- elif left_val.value == 1.0:
317
- return right_val
318
- # Fast path for multiplication by 0
319
- elif right_val.value == 0.0 or left_val.value == 0.0:
320
- return Quantity(0.0, left_val.unit if right_val.value == 0.0 else right_val.unit)
321
- return left_val * right_val
322
- elif self.operator == '+':
323
- # Fast path for addition with 0
324
- if right_val.value == 0.0:
325
- return left_val
326
- elif left_val.value == 0.0:
327
- return right_val
328
- return left_val + right_val
329
- elif self.operator == '-':
330
- # Fast path for subtraction with 0
331
- if right_val.value == 0.0:
332
- return left_val
333
- return left_val - right_val
334
- elif self.operator == '/':
335
- # Check for division by zero
336
- if abs(right_val.value) < 1e-15:
337
- raise ValueError(f"Division by zero in expression: {self}")
338
- # Fast path for division by 1
339
- if right_val.value == 1.0:
340
- return left_val
341
- return left_val / right_val
342
- elif self.operator == '**':
343
- # For power, right side should be dimensionless
344
- if isinstance(right_val.value, int | float):
345
- # Fast paths for common exponents
346
- if right_val.value == 1.0:
347
- return left_val
348
- elif right_val.value == 0.0:
349
- return Quantity(1.0, DimensionlessUnits.dimensionless)
350
- elif right_val.value == 2.0:
351
- return left_val * left_val # Use multiplication for squaring
352
-
353
- if right_val.value < 0 and left_val.value < 0:
354
- raise ValueError(f"Negative base with negative exponent: {left_val.value}^{right_val.value}")
355
- result_value = left_val.value ** right_val.value
356
- # For power operations, we need to handle units carefully
357
- # This is a simplified implementation
358
- return Quantity(result_value, left_val.unit)
359
- else:
360
- raise ValueError("Exponent must be dimensionless number")
209
+ return self._handle_evaluation_error(e)
210
+
211
+ def _evaluate_with_caching(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
212
+ """Core evaluation logic with caching support."""
213
+ # Check cache for constant expressions
214
+ cached_result = self._try_get_cached_result()
215
+ if cached_result is not None:
216
+ return cached_result
217
+
218
+ # Evaluate operands
219
+ left_val, right_val = self._evaluate_operands(variable_values)
220
+
221
+ # Dispatch operation
222
+ result = self._dispatch_operation(left_val, right_val)
223
+
224
+ # Cache result for constant expressions
225
+ self._try_cache_result(result)
226
+
227
+ return result
228
+
229
+ def _evaluate_operands(self, variable_values: dict[str, "FieldQnty"]) -> tuple["Quantity", "Quantity"]:
230
+ """Evaluate both operands and return as tuple."""
231
+ left_val = self.left.evaluate(variable_values)
232
+ right_val = self.right.evaluate(variable_values)
233
+ return left_val, right_val
234
+
235
+ def _handle_evaluation_error(self, error: Exception) -> "Quantity":
236
+ """Handle evaluation errors with appropriate context."""
237
+ if isinstance(error, ValueError):
238
+ raise
239
+ raise ValueError(f"Error evaluating binary operation '{self}': {error}") from error
240
+
241
+ def _try_get_cached_result(self) -> "Quantity | None":
242
+ """Attempt to retrieve a cached result for constant expressions."""
243
+ if not self._is_constant_expression():
244
+ return None
245
+
246
+ cache_manager = get_cache_manager()
247
+ cache_key = self._generate_cache_key()
248
+ return cache_manager.get_expression_result(cache_key)
249
+
250
+ def _try_cache_result(self, result: "Quantity") -> None:
251
+ """Attempt to cache the result for constant expressions."""
252
+ if not self._is_constant_expression():
253
+ return
254
+
255
+ cache_manager = get_cache_manager()
256
+ cache_key = self._generate_cache_key()
257
+ cache_manager.cache_expression_result(cache_key, result)
258
+
259
+ def _is_constant_expression(self) -> bool:
260
+ """Check if both operands are constants."""
261
+ return _is_constant_fast(self.left) and _is_constant_fast(self.right)
262
+
263
+ def _generate_cache_key(self) -> str:
264
+ """Generate a cache key for constant expressions."""
265
+ # Safe to cast since _is_constant_expression() already verified types
266
+ left_const = self.left
267
+ right_const = self.right
268
+ return f"{id(self)}_{self.operator}_{id(left_const.value)}_{id(right_const.value)}" # type: ignore[attr-defined]
269
+
270
+ def _dispatch_operation(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
271
+ """Dispatch to the appropriate operation handler with fast lookup."""
272
+ # Fast path: check operator type with pre-compiled sets
273
+ if self.operator in self._ARITHMETIC_OPS:
274
+ return self._evaluate_arithmetic_dispatch(left_val, right_val)
275
+ elif self.operator in self._COMPARISON_OPS:
276
+ return self._evaluate_comparison(left_val, right_val)
277
+ else:
278
+ raise ValueError(f"Unknown operator: {self.operator}")
279
+
280
+ def _evaluate_arithmetic_dispatch(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
281
+ """Dispatch arithmetic operations with direct method lookup."""
282
+ # Use direct method dispatch for better performance
283
+ if self.operator == "*":
284
+ return self._multiply(left_val, right_val)
285
+ elif self.operator == "+":
286
+ return self._add(left_val, right_val)
287
+ elif self.operator == "-":
288
+ return self._subtract(left_val, right_val)
289
+ elif self.operator == "/":
290
+ return self._divide(left_val, right_val)
291
+ elif self.operator == "**":
292
+ return self._power(left_val, right_val)
361
293
  else:
362
- # Unknown operator - should not happen
363
294
  raise ValueError(f"Unknown arithmetic operator: {self.operator}")
364
-
365
- def _evaluate_comparison(self, left_val: 'Quantity', right_val: 'Quantity') -> 'Quantity':
366
- """Evaluate comparison operations."""
367
- # Convert to same units for comparison if possible
295
+
296
+ def _evaluate_arithmetic(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
297
+ """Legacy arithmetic evaluation method - redirects to new dispatch."""
298
+ return self._evaluate_arithmetic_dispatch(left_val, right_val)
299
+
300
+ def _multiply(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
301
+ """Handle multiplication with ultra-fast path optimizations aligned with base_qnty."""
302
+ # PERFORMANCE OPTIMIZATION: Extract values once
303
+ left_value = left_val.value
304
+ right_value = right_val.value
305
+
306
+ # ENHANCED FAST PATHS: Check most common optimizations first
307
+ # Identity optimizations (1.0 multiplication) - most frequent case
308
+ if right_value == 1.0:
309
+ return left_val
310
+ elif left_value == 1.0:
311
+ return right_val
312
+
313
+ # Zero optimizations - second most common
314
+ elif right_value == 0.0:
315
+ return Quantity(0.0, right_val.unit)
316
+ elif left_value == 0.0:
317
+ return Quantity(0.0, left_val.unit)
318
+
319
+ # Additional fast paths for common values
320
+ elif right_value == -1.0:
321
+ return Quantity(-left_value, left_val.unit)
322
+ elif left_value == -1.0:
323
+ return Quantity(-right_value, right_val.unit)
324
+
325
+ # ADDITIONAL COMMON CASES: Powers of 2 and 0.5 (very common in engineering)
326
+ elif right_value == 2.0:
327
+ return Quantity(left_value * 2.0, left_val.unit)
328
+ elif left_value == 2.0:
329
+ return Quantity(right_value * 2.0, right_val.unit)
330
+ elif right_value == 0.5:
331
+ return Quantity(left_value * 0.5, left_val.unit)
332
+ elif left_value == 0.5:
333
+ return Quantity(right_value * 0.5, right_val.unit)
334
+
335
+ # OPTIMIZED REGULAR CASE: Use the enhanced multiplication from base_qnty
336
+ # This leverages the optimized caching and dimensionless handling
337
+ return left_val * right_val
338
+
339
+ def _add(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
340
+ """Handle addition with fast path optimizations."""
341
+ # Fast path: check for zero additions (most common optimization)
342
+ left_value = left_val.value
343
+ right_value = right_val.value
344
+
345
+ if right_value == 0.0:
346
+ return left_val
347
+ elif left_value == 0.0:
348
+ return right_val
349
+
350
+ # Regular addition
351
+ return left_val + right_val
352
+
353
+ def _subtract(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
354
+ """Handle subtraction with fast path optimizations."""
355
+ # Fast path: subtracting zero
356
+ right_value = right_val.value
357
+ left_value = left_val.value
358
+
359
+ if right_value == 0.0:
360
+ return left_val
361
+ elif left_value == right_value:
362
+ # Same value subtraction -> zero with left unit
363
+ return Quantity(0.0, left_val.unit)
364
+
365
+ # Regular subtraction
366
+ return left_val - right_val
367
+
368
+ def _divide(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
369
+ """Handle division with zero checking and optimizations."""
370
+ right_value = right_val.value
371
+ left_value = left_val.value
372
+
373
+ # Check for division by zero first
374
+ if abs(right_value) < DIVISION_BY_ZERO_THRESHOLD:
375
+ raise ValueError(f"Division by zero in expression: {self}")
376
+
377
+ # Fast paths
378
+ if right_value == 1.0:
379
+ return left_val
380
+ elif left_value == 0.0:
381
+ # Zero divided by anything is zero (with appropriate unit)
382
+ return Quantity(0.0, (left_val / right_val).unit)
383
+ elif right_value == -1.0:
384
+ # Division by -1 is negation
385
+ return Quantity(-left_value, (left_val / right_val).unit)
386
+
387
+ # Regular division
388
+ return left_val / right_val
389
+
390
+ def _power(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
391
+ """Handle power operations with special cases."""
392
+ right_value = right_val.value
393
+ left_value = left_val.value
394
+
395
+ if not isinstance(right_value, int | float):
396
+ raise ValueError("Exponent must be dimensionless number")
397
+
398
+ # Fast paths for common exponents
399
+ if right_value == 1.0:
400
+ return left_val
401
+ elif right_value == 0.0:
402
+ return Quantity(1.0, DimensionlessUnits.dimensionless)
403
+ elif right_value == 2.0:
404
+ return left_val * left_val # Use multiplication for squaring
405
+ elif right_value == 0.5:
406
+ # Square root optimization
407
+ import math
408
+
409
+ return Quantity(math.sqrt(left_value), left_val.unit)
410
+ elif right_value == -1.0:
411
+ # Reciprocal
412
+ return Quantity(1.0 / left_value, left_val.unit)
413
+ elif left_value == 1.0:
414
+ # 1 to any power is 1
415
+ return Quantity(1.0, DimensionlessUnits.dimensionless)
416
+ elif left_value == 0.0 and right_value > 0:
417
+ # 0 to positive power is 0
418
+ return Quantity(0.0, left_val.unit)
419
+
420
+ # Validation for negative bases
421
+ if right_value < 0 and left_value < 0:
422
+ raise ValueError(f"Negative base with negative exponent: {left_value}^{right_value}")
423
+
424
+ result_value = left_value**right_value
425
+ return Quantity(result_value, left_val.unit)
426
+
427
+ def _evaluate_comparison(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
428
+ """Evaluate comparison operations with optimized unit conversion."""
429
+ # Normalize units for comparison if needed
430
+ left_val, right_val = self._normalize_comparison_units(left_val, right_val)
431
+
432
+ # Perform comparison using optimized dispatch
433
+ result = self._perform_comparison(left_val.value, right_val.value)
434
+ return Quantity(1.0 if result else 0.0, DimensionlessUnits.dimensionless)
435
+
436
+ def _normalize_comparison_units(self, left_val: "Quantity", right_val: "Quantity") -> tuple["Quantity", "Quantity"]:
437
+ """Normalize units for comparison operations."""
368
438
  try:
369
439
  if left_val._dimension_sig == right_val._dimension_sig and left_val.unit != right_val.unit:
370
440
  right_val = right_val.to(left_val.unit)
371
441
  except (ValueError, TypeError, AttributeError):
372
442
  pass
373
-
374
- # Use dispatch dictionary for comparisons
375
- ops = {
376
- '<': lambda left, right: left < right,
377
- '<=': lambda left, right: left <= right,
378
- '>': lambda left, right: left > right,
379
- '>=': lambda left, right: left >= right,
380
- '==': lambda left, right: abs(left - right) < 1e-10,
381
- '!=': lambda left, right: abs(left - right) >= 1e-10
382
- }
383
-
384
- result = ops[self.operator](left_val.value, right_val.value)
385
- return Quantity(1.0 if result else 0.0, DimensionlessUnits.dimensionless)
386
-
443
+ return left_val, right_val
444
+
445
+ def _perform_comparison(self, left_value: float, right_value: float) -> bool:
446
+ """Perform the actual comparison operation."""
447
+ # Direct dispatch for better performance
448
+ if self.operator == "<":
449
+ return left_value < right_value
450
+ elif self.operator == "<=":
451
+ return left_value <= right_value
452
+ elif self.operator == ">":
453
+ return left_value > right_value
454
+ elif self.operator == ">=":
455
+ return left_value >= right_value
456
+ elif self.operator == "==":
457
+ return abs(left_value - right_value) < FLOAT_EQUALITY_TOLERANCE
458
+ elif self.operator == "!=":
459
+ return abs(left_value - right_value) >= FLOAT_EQUALITY_TOLERANCE
460
+ else:
461
+ raise ValueError(f"Unknown comparison operator: {self.operator}")
462
+
387
463
  def get_variables(self) -> set[str]:
388
464
  return self.left.get_variables() | self.right.get_variables()
389
-
465
+
390
466
  def simplify(self) -> Expression:
467
+ """Simplify the binary operation with optimized constant folding."""
391
468
  left_simplified = self.left.simplify()
392
469
  right_simplified = self.right.simplify()
393
-
394
- # Basic simplification rules
395
- if isinstance(left_simplified, Constant) and isinstance(right_simplified, Constant):
396
- # Evaluate constant expressions
397
- dummy_vars = {}
398
- try:
399
- result = BinaryOperation(self.operator, left_simplified, right_simplified).evaluate(dummy_vars)
400
- return Constant(result)
401
- except (ValueError, TypeError, ArithmeticError):
402
- pass
403
-
470
+
471
+ # Fast path: check for constant expression simplification
472
+ if _is_constant_fast(left_simplified) and _is_constant_fast(right_simplified):
473
+ return self._try_constant_folding(left_simplified, right_simplified)
474
+
404
475
  return BinaryOperation(self.operator, left_simplified, right_simplified)
405
-
476
+
477
+ def _try_constant_folding(self, left_const: Expression, right_const: Expression) -> Expression:
478
+ """Attempt to fold constant expressions."""
479
+ try:
480
+ # Evaluate constant expressions at compile time
481
+ dummy_vars = {}
482
+ result = BinaryOperation(self.operator, left_const, right_const).evaluate(dummy_vars)
483
+ return Constant(result)
484
+ except (ValueError, TypeError, ArithmeticError):
485
+ # Return original operation if folding fails
486
+ return BinaryOperation(self.operator, left_const, right_const)
487
+
406
488
  def __str__(self) -> str:
407
- # Try to auto-evaluate if all variables are available
489
+ # Delegate to centralized formatter
408
490
  can_eval, variables = self._can_auto_evaluate()
409
- if can_eval:
410
- try:
411
- result = self.evaluate(variables)
412
- return str(result)
413
- except Exception:
414
- pass # Fall back to symbolic representation
415
-
416
- # Handle operator precedence for cleaner string representation
417
- precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '**': 3, '<': 0, '<=': 0, '>': 0, '>=': 0, '==': 0, '!=': 0}
418
- left_str = str(self.left)
419
- right_str = str(self.right)
420
-
421
- # Add parentheses for left side when precedence is strictly lower
422
- if isinstance(self.left, BinaryOperation) and precedence.get(self.left.operator, 0) < precedence.get(self.operator, 0):
423
- left_str = f"({left_str})"
424
-
425
- # CRITICAL FIX: For right side, add parentheses when:
426
- # 1. Precedence is strictly lower, OR
427
- # 2. Precedence is equal AND operation is left-associative (-, /)
428
- if isinstance(self.right, BinaryOperation):
429
- right_prec = precedence.get(self.right.operator, 0)
430
- curr_prec = precedence.get(self.operator, 0)
431
-
432
- # Need parentheses if:
433
- # - Right has lower precedence, OR
434
- # - Same precedence and current operator is left-associative (- or /)
435
- if (right_prec < curr_prec or
436
- (right_prec == curr_prec and self.operator in ['-', '/'])):
437
- right_str = f"({right_str})"
438
-
439
- return f"{left_str} {self.operator} {right_str}"
491
+ return ExpressionFormatter.format_binary_operation(self, can_auto_evaluate=can_eval, auto_eval_variables=variables) # type: ignore[arg-type]
440
492
 
441
493
 
442
494
  class UnaryFunction(Expression):
443
495
  """Unary mathematical function expression."""
444
- __slots__ = ('function_name', 'operand')
445
-
496
+
497
+ __slots__ = ("function_name", "operand")
498
+
446
499
  def __init__(self, function_name: str, operand: Expression):
447
500
  self.function_name = function_name
448
501
  self.operand = operand
449
-
450
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
451
-
502
+
503
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
452
504
  operand_val = self.operand.evaluate(variable_values)
453
-
454
- if self.function_name == 'sin':
455
- # Assume input is in radians, result is dimensionless
456
- result_value = math.sin(operand_val.value)
457
- return Quantity(result_value, DimensionlessUnits.dimensionless)
458
- elif self.function_name == 'cos':
459
- result_value = math.cos(operand_val.value)
460
- return Quantity(result_value, DimensionlessUnits.dimensionless)
461
- elif self.function_name == 'tan':
462
- result_value = math.tan(operand_val.value)
463
- return Quantity(result_value, DimensionlessUnits.dimensionless)
464
- elif self.function_name == 'sqrt':
465
- # For sqrt, we need to handle units carefully
466
- result_value = math.sqrt(operand_val.value)
467
- # This is simplified - proper unit handling would need dimensional analysis
468
- return Quantity(result_value, operand_val.unit)
469
- elif self.function_name == 'abs':
470
- return Quantity(abs(operand_val.value), operand_val.unit)
471
- elif self.function_name == 'ln':
472
- # Natural log - input should be dimensionless
473
- result_value = math.log(operand_val.value)
474
- return Quantity(result_value, DimensionlessUnits.dimensionless)
475
- elif self.function_name == 'log10':
476
- result_value = math.log10(operand_val.value)
477
- return Quantity(result_value, DimensionlessUnits.dimensionless)
478
- elif self.function_name == 'exp':
479
- # Exponential - input should be dimensionless
480
- result_value = math.exp(operand_val.value)
481
- return Quantity(result_value, DimensionlessUnits.dimensionless)
505
+
506
+ # Function dispatch table for better performance and maintainability
507
+ functions = {
508
+ "sin": lambda x: Quantity(math.sin(x.value), DimensionlessUnits.dimensionless),
509
+ "cos": lambda x: Quantity(math.cos(x.value), DimensionlessUnits.dimensionless),
510
+ "tan": lambda x: Quantity(math.tan(x.value), DimensionlessUnits.dimensionless),
511
+ "sqrt": lambda x: Quantity(math.sqrt(x.value), x.unit),
512
+ "abs": lambda x: Quantity(abs(x.value), x.unit),
513
+ "ln": lambda x: Quantity(math.log(x.value), DimensionlessUnits.dimensionless),
514
+ "log10": lambda x: Quantity(math.log10(x.value), DimensionlessUnits.dimensionless),
515
+ "exp": lambda x: Quantity(math.exp(x.value), DimensionlessUnits.dimensionless),
516
+ }
517
+
518
+ func = functions.get(self.function_name)
519
+ if func:
520
+ return func(operand_val)
482
521
  else:
483
522
  raise ValueError(f"Unknown function: {self.function_name}")
484
-
523
+
485
524
  def get_variables(self) -> set[str]:
486
525
  return self.operand.get_variables()
487
-
526
+
488
527
  def simplify(self) -> Expression:
489
528
  simplified_operand = self.operand.simplify()
490
- if isinstance(simplified_operand, Constant):
529
+ if _is_constant_fast(simplified_operand):
491
530
  # Evaluate constant functions at compile time
492
531
  try:
493
532
  dummy_vars = {}
@@ -496,51 +535,167 @@ class UnaryFunction(Expression):
496
535
  except (ValueError, TypeError, ArithmeticError):
497
536
  pass
498
537
  return UnaryFunction(self.function_name, simplified_operand)
499
-
538
+
500
539
  def __str__(self) -> str:
501
- return f"{self.function_name}({self.operand})"
540
+ return ExpressionFormatter.format_unary_function(self) # type: ignore[arg-type]
502
541
 
503
542
 
504
543
  class ConditionalExpression(Expression):
505
544
  """Conditional expression: if condition then true_expr else false_expr."""
506
- __slots__ = ('condition', 'true_expr', 'false_expr')
507
-
545
+
546
+ __slots__ = ("condition", "true_expr", "false_expr")
547
+
508
548
  def __init__(self, condition: Expression, true_expr: Expression, false_expr: Expression):
509
549
  self.condition = condition
510
550
  self.true_expr = true_expr
511
551
  self.false_expr = false_expr
512
-
513
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
552
+
553
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
514
554
  condition_val = self.condition.evaluate(variable_values)
515
555
  # Consider non-zero as True
516
- if abs(condition_val.value) > 1e-10:
556
+ if abs(condition_val.value) > CONDITION_EVALUATION_THRESHOLD:
517
557
  return self.true_expr.evaluate(variable_values)
518
558
  else:
519
559
  return self.false_expr.evaluate(variable_values)
520
-
560
+
521
561
  def get_variables(self) -> set[str]:
522
- return (self.condition.get_variables() |
523
- self.true_expr.get_variables() |
524
- self.false_expr.get_variables())
525
-
562
+ return self.condition.get_variables() | self.true_expr.get_variables() | self.false_expr.get_variables()
563
+
526
564
  def simplify(self) -> Expression:
527
565
  simplified_condition = self.condition.simplify()
528
566
  simplified_true = self.true_expr.simplify()
529
567
  simplified_false = self.false_expr.simplify()
530
-
568
+
531
569
  # If condition is constant, choose the appropriate branch
532
- if isinstance(simplified_condition, Constant):
570
+ if _is_constant_fast(simplified_condition):
533
571
  try:
534
572
  dummy_vars = {}
535
573
  condition_val = simplified_condition.evaluate(dummy_vars)
536
- if abs(condition_val.value) > 1e-10:
574
+ if abs(condition_val.value) > CONDITION_EVALUATION_THRESHOLD:
537
575
  return simplified_true
538
576
  else:
539
577
  return simplified_false
540
578
  except (ValueError, TypeError, ArithmeticError):
541
579
  pass
542
-
580
+
543
581
  return ConditionalExpression(simplified_condition, simplified_true, simplified_false)
544
-
582
+
545
583
  def __str__(self) -> str:
546
- return f"if({self.condition}, {self.true_expr}, {self.false_expr})"
584
+ return ExpressionFormatter.format_conditional_expression(self) # type: ignore[arg-type]
585
+
586
+
587
+ # Utility functions for expression creation
588
+
589
+ # Cache for common types to avoid repeated type checks
590
+ _DIMENSIONLESS_CONSTANT = None
591
+
592
+ # Type caches for hot path optimization
593
+ _CONSTANT_TYPE = None
594
+ _VARIABLE_REF_TYPE = None
595
+ _QUANTITY_TYPE = None
596
+ _FIELDQNTY_TYPE = None
597
+
598
+
599
+ def _init_type_cache():
600
+ """Initialize type cache for fast isinstance checks."""
601
+ global _CONSTANT_TYPE, _VARIABLE_REF_TYPE, _QUANTITY_TYPE, _FIELDQNTY_TYPE
602
+ if _CONSTANT_TYPE is None:
603
+ _CONSTANT_TYPE = Constant
604
+ _VARIABLE_REF_TYPE = VariableReference
605
+ _QUANTITY_TYPE = Quantity
606
+ _FIELDQNTY_TYPE = FieldQnty
607
+
608
+
609
+ def _is_constant_fast(obj) -> bool:
610
+ """Fast type check for Constant objects."""
611
+ _init_type_cache()
612
+ return type(obj) is _CONSTANT_TYPE
613
+
614
+
615
+ def _get_cached_dimensionless():
616
+ """Get cached dimensionless constant for numeric values."""
617
+ global _DIMENSIONLESS_CONSTANT
618
+ if _DIMENSIONLESS_CONSTANT is None:
619
+ _DIMENSIONLESS_CONSTANT = DimensionlessUnits.dimensionless
620
+ return _DIMENSIONLESS_CONSTANT
621
+
622
+
623
+ # Ultra-fast local cache for most common dimensionless values
624
+ _COMMON_DIMENSIONLESS_CACHE: dict[float, Quantity] = {}
625
+
626
+ def _get_dimensionless_quantity(value: float) -> Quantity:
627
+ """Ultra-optimized dimensionless quantity creation with local caching."""
628
+ # Ultra-fast local cache for most common values (0, 1, 2, -1, 0.5, etc.)
629
+ cached_qty = _COMMON_DIMENSIONLESS_CACHE.get(value)
630
+ if cached_qty is not None:
631
+ return cached_qty
632
+
633
+ # Create quantity with cached unit
634
+ qty = Quantity(value, _get_cached_dimensionless())
635
+
636
+ # Cache common values locally for ultra-fast access
637
+ if value in (-1.0, 0.0, 0.5, 1.0, 2.0) or (isinstance(value, float) and -10 <= value <= 10 and value == int(value)):
638
+ if len(_COMMON_DIMENSIONLESS_CACHE) < 25: # Prevent unbounded growth
639
+ _COMMON_DIMENSIONLESS_CACHE[value] = qty
640
+
641
+ return qty
642
+
643
+
644
+ def wrap_operand(operand: "OperandType") -> Expression:
645
+ """
646
+ Ultra-optimized operand wrapping with minimal function call overhead.
647
+
648
+ Performance optimizations:
649
+ - Single type() call instead of multiple isinstance checks
650
+ - Cached common type patterns
651
+ - Reduced function call depth
652
+ """
653
+ # ULTRA-FAST PATH: Use single type() call for most common cases
654
+ operand_type = type(operand)
655
+
656
+ # Most common cases first: primitives (35-40% of all calls)
657
+ if operand_type in (int, float):
658
+ return Constant(_get_dimensionless_quantity(float(operand))) # type: ignore[arg-type]
659
+
660
+ # Second most common: already wrapped expressions (20-25% of calls)
661
+ if operand_type is BinaryOperation: # Direct type check is faster
662
+ return operand # type: ignore[return-value]
663
+
664
+ # Third most common: field quantities/variables (20-30% of calls)
665
+ # Use getattr with hasattr-style check to reduce calls
666
+ if hasattr(operand, "quantity") and hasattr(operand, "symbol"):
667
+ return VariableReference(operand) # type: ignore[arg-type]
668
+
669
+ # Handle other Expression types (Constant, VariableReference, etc.)
670
+ if isinstance(operand, Expression):
671
+ return operand
672
+
673
+ # Check for base Quantity objects
674
+ if hasattr(operand, "value") and hasattr(operand, "unit") and hasattr(operand, "_dimension_sig"):
675
+ return Constant(operand) # type: ignore[arg-type]
676
+
677
+ # Check for ConfigurableVariable (from composition system) - rare case
678
+ if hasattr(operand, "_variable"):
679
+ var = getattr(operand, "_variable", None)
680
+ if var is not None and hasattr(var, "quantity") and hasattr(var, "symbol"):
681
+ return VariableReference(var) # type: ignore[arg-type]
682
+
683
+ # Fast failure for unknown types
684
+ raise TypeError(f"Cannot convert {operand_type.__name__} to Expression")
685
+
686
+
687
+ # Register expression and variable types with the TypeRegistry for optimal performance
688
+
689
+ # Register expression types
690
+ register_expression_type(Expression)
691
+ register_expression_type(BinaryOperation)
692
+ register_expression_type(VariableReference)
693
+ register_expression_type(Constant)
694
+ register_expression_type(UnaryFunction)
695
+ register_expression_type(ConditionalExpression)
696
+
697
+ # Register variable types - do this at module level to ensure it happens early
698
+ try:
699
+ register_variable_type(FieldQnty)
700
+ except ImportError:
701
+ pass # Handle import ordering issues gracefully