qnty 0.0.9__py3-none-any.whl → 0.1.1__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 +540 -384
  18. qnty/expressions/types.py +70 -0
  19. qnty/problems/__init__.py +145 -0
  20. qnty/problems/composition.py +1101 -0
  21. qnty/problems/problem.py +737 -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} +829 -444
  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.1.dist-info}/METADATA +1 -1
  54. qnty-0.1.1.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.1.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,388 @@ 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 - but only when they preserve correct dimensional analysis
378
+ if right_value == 1.0 and right_val._dimension_sig == 1:
379
+ # Division by dimensionless 1.0 - safe optimization
380
+ return left_val
381
+ elif left_value == 0.0:
382
+ # Zero divided by anything is zero (with appropriate unit)
383
+ return Quantity(0.0, (left_val / right_val).unit)
384
+ elif right_value == -1.0 and right_val._dimension_sig == 1:
385
+ # Division by dimensionless -1.0 is negation - safe optimization
386
+ return Quantity(-left_value, left_val.unit)
387
+
388
+ # Regular division
389
+ return left_val / right_val
390
+
391
+ def _power(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
392
+ """Handle power operations with special cases."""
393
+ right_value = right_val.value
394
+ left_value = left_val.value
395
+
396
+ if not isinstance(right_value, int | float):
397
+ raise ValueError("Exponent must be dimensionless number")
398
+
399
+ # Fast paths for common exponents
400
+ if right_value == 1.0:
401
+ return left_val
402
+ elif right_value == 0.0:
403
+ return Quantity(1.0, DimensionlessUnits.dimensionless)
404
+ elif right_value == 2.0:
405
+ return left_val * left_val # Use multiplication for squaring
406
+ elif right_value == 0.5:
407
+ # Square root optimization
408
+ import math
409
+
410
+ return Quantity(math.sqrt(left_value), left_val.unit)
411
+ elif right_value == -1.0:
412
+ # Reciprocal
413
+ return Quantity(1.0 / left_value, left_val.unit)
414
+ elif left_value == 1.0:
415
+ # 1 to any power is 1
416
+ return Quantity(1.0, DimensionlessUnits.dimensionless)
417
+ elif left_value == 0.0 and right_value > 0:
418
+ # 0 to positive power is 0
419
+ return Quantity(0.0, left_val.unit)
420
+
421
+ # Validation for negative bases
422
+ if right_value < 0 and left_value < 0:
423
+ raise ValueError(f"Negative base with negative exponent: {left_value}^{right_value}")
424
+
425
+ result_value = left_value**right_value
426
+ return Quantity(result_value, left_val.unit)
427
+
428
+ def _evaluate_comparison(self, left_val: "Quantity", right_val: "Quantity") -> "Quantity":
429
+ """Evaluate comparison operations with optimized unit conversion."""
430
+ # Normalize units for comparison if needed
431
+ left_val, right_val = self._normalize_comparison_units(left_val, right_val)
432
+
433
+ # Perform comparison using optimized dispatch
434
+ result = self._perform_comparison(left_val.value, right_val.value)
435
+ return Quantity(1.0 if result else 0.0, DimensionlessUnits.dimensionless)
436
+
437
+ def _normalize_comparison_units(self, left_val: "Quantity", right_val: "Quantity") -> tuple["Quantity", "Quantity"]:
438
+ """Normalize units for comparison operations."""
368
439
  try:
369
440
  if left_val._dimension_sig == right_val._dimension_sig and left_val.unit != right_val.unit:
370
441
  right_val = right_val.to(left_val.unit)
371
442
  except (ValueError, TypeError, AttributeError):
372
443
  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
-
444
+ return left_val, right_val
445
+
446
+ def _perform_comparison(self, left_value: float, right_value: float) -> bool:
447
+ """Perform the actual comparison operation."""
448
+ # Direct dispatch for better performance
449
+ if self.operator == "<":
450
+ return left_value < right_value
451
+ elif self.operator == "<=":
452
+ return left_value <= right_value
453
+ elif self.operator == ">":
454
+ return left_value > right_value
455
+ elif self.operator == ">=":
456
+ return left_value >= right_value
457
+ elif self.operator == "==":
458
+ return abs(left_value - right_value) < FLOAT_EQUALITY_TOLERANCE
459
+ elif self.operator == "!=":
460
+ return abs(left_value - right_value) >= FLOAT_EQUALITY_TOLERANCE
461
+ else:
462
+ raise ValueError(f"Unknown comparison operator: {self.operator}")
463
+
387
464
  def get_variables(self) -> set[str]:
388
465
  return self.left.get_variables() | self.right.get_variables()
389
-
466
+
390
467
  def simplify(self) -> Expression:
468
+ """Simplify the binary operation with optimized constant folding."""
391
469
  left_simplified = self.left.simplify()
392
470
  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
-
471
+
472
+ # Fast path: check for constant expression simplification
473
+ if _is_constant_fast(left_simplified) and _is_constant_fast(right_simplified):
474
+ return self._try_constant_folding(left_simplified, right_simplified)
475
+
404
476
  return BinaryOperation(self.operator, left_simplified, right_simplified)
405
-
477
+
478
+ def _try_constant_folding(self, left_const: Expression, right_const: Expression) -> Expression:
479
+ """Attempt to fold constant expressions."""
480
+ try:
481
+ # Evaluate constant expressions at compile time
482
+ dummy_vars = {}
483
+ result = BinaryOperation(self.operator, left_const, right_const).evaluate(dummy_vars)
484
+ return Constant(result)
485
+ except (ValueError, TypeError, ArithmeticError):
486
+ # Return original operation if folding fails
487
+ return BinaryOperation(self.operator, left_const, right_const)
488
+
406
489
  def __str__(self) -> str:
407
- # Try to auto-evaluate if all variables are available
490
+ # Delegate to centralized formatter
408
491
  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}"
492
+ return ExpressionFormatter.format_binary_operation(self, can_auto_evaluate=can_eval, auto_eval_variables=variables) # type: ignore[arg-type]
440
493
 
441
494
 
442
495
  class UnaryFunction(Expression):
443
496
  """Unary mathematical function expression."""
444
- __slots__ = ('function_name', 'operand')
445
-
497
+
498
+ __slots__ = ("function_name", "operand")
499
+
446
500
  def __init__(self, function_name: str, operand: Expression):
447
501
  self.function_name = function_name
448
502
  self.operand = operand
449
-
450
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
451
-
503
+
504
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
452
505
  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)
506
+
507
+ # Function dispatch table for better performance and maintainability
508
+ functions = {
509
+ "sin": lambda x: Quantity(math.sin(x.value), DimensionlessUnits.dimensionless),
510
+ "cos": lambda x: Quantity(math.cos(x.value), DimensionlessUnits.dimensionless),
511
+ "tan": lambda x: Quantity(math.tan(x.value), DimensionlessUnits.dimensionless),
512
+ "sqrt": lambda x: Quantity(math.sqrt(x.value), x.unit),
513
+ "abs": lambda x: Quantity(abs(x.value), x.unit),
514
+ "ln": lambda x: Quantity(math.log(x.value), DimensionlessUnits.dimensionless),
515
+ "log10": lambda x: Quantity(math.log10(x.value), DimensionlessUnits.dimensionless),
516
+ "exp": lambda x: Quantity(math.exp(x.value), DimensionlessUnits.dimensionless),
517
+ }
518
+
519
+ func = functions.get(self.function_name)
520
+ if func:
521
+ return func(operand_val)
482
522
  else:
483
523
  raise ValueError(f"Unknown function: {self.function_name}")
484
-
524
+
485
525
  def get_variables(self) -> set[str]:
486
526
  return self.operand.get_variables()
487
-
527
+
488
528
  def simplify(self) -> Expression:
489
529
  simplified_operand = self.operand.simplify()
490
- if isinstance(simplified_operand, Constant):
530
+ if _is_constant_fast(simplified_operand):
491
531
  # Evaluate constant functions at compile time
492
532
  try:
493
533
  dummy_vars = {}
@@ -496,51 +536,167 @@ class UnaryFunction(Expression):
496
536
  except (ValueError, TypeError, ArithmeticError):
497
537
  pass
498
538
  return UnaryFunction(self.function_name, simplified_operand)
499
-
539
+
500
540
  def __str__(self) -> str:
501
- return f"{self.function_name}({self.operand})"
541
+ return ExpressionFormatter.format_unary_function(self) # type: ignore[arg-type]
502
542
 
503
543
 
504
544
  class ConditionalExpression(Expression):
505
545
  """Conditional expression: if condition then true_expr else false_expr."""
506
- __slots__ = ('condition', 'true_expr', 'false_expr')
507
-
546
+
547
+ __slots__ = ("condition", "true_expr", "false_expr")
548
+
508
549
  def __init__(self, condition: Expression, true_expr: Expression, false_expr: Expression):
509
550
  self.condition = condition
510
551
  self.true_expr = true_expr
511
552
  self.false_expr = false_expr
512
-
513
- def evaluate(self, variable_values: dict[str, 'TypeSafeVariable']) -> 'Quantity':
553
+
554
+ def evaluate(self, variable_values: dict[str, "FieldQnty"]) -> "Quantity":
514
555
  condition_val = self.condition.evaluate(variable_values)
515
556
  # Consider non-zero as True
516
- if abs(condition_val.value) > 1e-10:
557
+ if abs(condition_val.value) > CONDITION_EVALUATION_THRESHOLD:
517
558
  return self.true_expr.evaluate(variable_values)
518
559
  else:
519
560
  return self.false_expr.evaluate(variable_values)
520
-
561
+
521
562
  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
-
563
+ return self.condition.get_variables() | self.true_expr.get_variables() | self.false_expr.get_variables()
564
+
526
565
  def simplify(self) -> Expression:
527
566
  simplified_condition = self.condition.simplify()
528
567
  simplified_true = self.true_expr.simplify()
529
568
  simplified_false = self.false_expr.simplify()
530
-
569
+
531
570
  # If condition is constant, choose the appropriate branch
532
- if isinstance(simplified_condition, Constant):
571
+ if _is_constant_fast(simplified_condition):
533
572
  try:
534
573
  dummy_vars = {}
535
574
  condition_val = simplified_condition.evaluate(dummy_vars)
536
- if abs(condition_val.value) > 1e-10:
575
+ if abs(condition_val.value) > CONDITION_EVALUATION_THRESHOLD:
537
576
  return simplified_true
538
577
  else:
539
578
  return simplified_false
540
579
  except (ValueError, TypeError, ArithmeticError):
541
580
  pass
542
-
581
+
543
582
  return ConditionalExpression(simplified_condition, simplified_true, simplified_false)
544
-
583
+
545
584
  def __str__(self) -> str:
546
- return f"if({self.condition}, {self.true_expr}, {self.false_expr})"
585
+ return ExpressionFormatter.format_conditional_expression(self) # type: ignore[arg-type]
586
+
587
+
588
+ # Utility functions for expression creation
589
+
590
+ # Cache for common types to avoid repeated type checks
591
+ _DIMENSIONLESS_CONSTANT = None
592
+
593
+ # Type caches for hot path optimization
594
+ _CONSTANT_TYPE = None
595
+ _VARIABLE_REF_TYPE = None
596
+ _QUANTITY_TYPE = None
597
+ _FIELDQNTY_TYPE = None
598
+
599
+
600
+ def _init_type_cache():
601
+ """Initialize type cache for fast isinstance checks."""
602
+ global _CONSTANT_TYPE, _VARIABLE_REF_TYPE, _QUANTITY_TYPE, _FIELDQNTY_TYPE
603
+ if _CONSTANT_TYPE is None:
604
+ _CONSTANT_TYPE = Constant
605
+ _VARIABLE_REF_TYPE = VariableReference
606
+ _QUANTITY_TYPE = Quantity
607
+ _FIELDQNTY_TYPE = FieldQnty
608
+
609
+
610
+ def _is_constant_fast(obj) -> bool:
611
+ """Fast type check for Constant objects."""
612
+ _init_type_cache()
613
+ return type(obj) is _CONSTANT_TYPE
614
+
615
+
616
+ def _get_cached_dimensionless():
617
+ """Get cached dimensionless constant for numeric values."""
618
+ global _DIMENSIONLESS_CONSTANT
619
+ if _DIMENSIONLESS_CONSTANT is None:
620
+ _DIMENSIONLESS_CONSTANT = DimensionlessUnits.dimensionless
621
+ return _DIMENSIONLESS_CONSTANT
622
+
623
+
624
+ # Ultra-fast local cache for most common dimensionless values
625
+ _COMMON_DIMENSIONLESS_CACHE: dict[float, Quantity] = {}
626
+
627
+ def _get_dimensionless_quantity(value: float) -> Quantity:
628
+ """Ultra-optimized dimensionless quantity creation with local caching."""
629
+ # Ultra-fast local cache for most common values (0, 1, 2, -1, 0.5, etc.)
630
+ cached_qty = _COMMON_DIMENSIONLESS_CACHE.get(value)
631
+ if cached_qty is not None:
632
+ return cached_qty
633
+
634
+ # Create quantity with cached unit
635
+ qty = Quantity(value, _get_cached_dimensionless())
636
+
637
+ # Cache common values locally for ultra-fast access
638
+ 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)):
639
+ if len(_COMMON_DIMENSIONLESS_CACHE) < 25: # Prevent unbounded growth
640
+ _COMMON_DIMENSIONLESS_CACHE[value] = qty
641
+
642
+ return qty
643
+
644
+
645
+ def wrap_operand(operand: "OperandType") -> Expression:
646
+ """
647
+ Ultra-optimized operand wrapping with minimal function call overhead.
648
+
649
+ Performance optimizations:
650
+ - Single type() call instead of multiple isinstance checks
651
+ - Cached common type patterns
652
+ - Reduced function call depth
653
+ """
654
+ # ULTRA-FAST PATH: Use single type() call for most common cases
655
+ operand_type = type(operand)
656
+
657
+ # Most common cases first: primitives (35-40% of all calls)
658
+ if operand_type in (int, float):
659
+ return Constant(_get_dimensionless_quantity(float(operand))) # type: ignore[arg-type]
660
+
661
+ # Second most common: already wrapped expressions (20-25% of calls)
662
+ if operand_type is BinaryOperation: # Direct type check is faster
663
+ return operand # type: ignore[return-value]
664
+
665
+ # Third most common: field quantities/variables (20-30% of calls)
666
+ # Use getattr with hasattr-style check to reduce calls
667
+ if hasattr(operand, "quantity") and hasattr(operand, "symbol"):
668
+ return VariableReference(operand) # type: ignore[arg-type]
669
+
670
+ # Handle other Expression types (Constant, VariableReference, etc.)
671
+ if isinstance(operand, Expression):
672
+ return operand
673
+
674
+ # Check for base Quantity objects
675
+ if hasattr(operand, "value") and hasattr(operand, "unit") and hasattr(operand, "_dimension_sig"):
676
+ return Constant(operand) # type: ignore[arg-type]
677
+
678
+ # Check for ConfigurableVariable (from composition system) - rare case
679
+ if hasattr(operand, "_variable"):
680
+ var = getattr(operand, "_variable", None)
681
+ if var is not None and hasattr(var, "quantity") and hasattr(var, "symbol"):
682
+ return VariableReference(var) # type: ignore[arg-type]
683
+
684
+ # Fast failure for unknown types
685
+ raise TypeError(f"Cannot convert {operand_type.__name__} to Expression")
686
+
687
+
688
+ # Register expression and variable types with the TypeRegistry for optimal performance
689
+
690
+ # Register expression types
691
+ register_expression_type(Expression)
692
+ register_expression_type(BinaryOperation)
693
+ register_expression_type(VariableReference)
694
+ register_expression_type(Constant)
695
+ register_expression_type(UnaryFunction)
696
+ register_expression_type(ConditionalExpression)
697
+
698
+ # Register variable types - do this at module level to ensure it happens early
699
+ try:
700
+ register_variable_type(FieldQnty)
701
+ except ImportError:
702
+ pass # Handle import ordering issues gracefully