qnty 0.0.1__py3-none-any.whl → 0.0.2__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.
qnty/variable.py CHANGED
@@ -2,21 +2,36 @@
2
2
  High-Performance Quantity and Variables
3
3
  ========================================
4
4
 
5
- FastQuantity class and type-safe variables optimized for engineering calculations
5
+ FastQuantity class and type-safe variables optimized for engineering calculations
6
6
  with dimensional safety.
7
7
  """
8
8
 
9
- from typing import Union, Optional, TypeVar, Generic, TYPE_CHECKING
10
- from .dimension import DimensionSignature, DIMENSIONLESS, LENGTH, PRESSURE, AREA, VOLUME, FORCE, ENERGY
9
+ from __future__ import annotations
10
+
11
+ from typing import Generic, Self, TypeVar
12
+
13
+ from .dimension import AREA, DIMENSIONLESS, ENERGY, FORCE, LENGTH, PRESSURE, VOLUME, DimensionSignature
11
14
  from .unit import UnitConstant, UnitDefinition, registry
12
15
  from .units import DimensionlessUnits, LengthUnits, PressureUnits
13
16
 
14
- if TYPE_CHECKING:
15
- from .setters import TypeSafeSetter, LengthSetter, PressureSetter
17
+ # TypeVar for generic dimensional types
18
+ DimensionType = TypeVar('DimensionType', bound='FastQuantity')
16
19
 
17
20
 
18
- DimensionType = TypeVar('DimensionType', bound='FastQuantity')
19
- SetterType = TypeVar('SetterType')
21
+ class TypeSafeSetter:
22
+ """Basic type-safe setter that accepts compatible units."""
23
+
24
+ def __init__(self, variable: TypeSafeVariable, value: float):
25
+ self.variable = variable
26
+ self.value = value
27
+
28
+ def with_unit(self, unit: UnitConstant) -> TypeSafeVariable:
29
+ """Set with type-safe unit constant."""
30
+ if not self.variable.expected_dimension.is_compatible(unit.dimension):
31
+ raise TypeError(f"Unit {unit.name} incompatible with expected dimension")
32
+
33
+ self.variable.quantity = FastQuantity(self.value, unit)
34
+ return self.variable
20
35
 
21
36
 
22
37
  class FastQuantity:
@@ -39,7 +54,7 @@ class FastQuantity:
39
54
  return f"FastQuantity({self.value}, {self.unit.name})"
40
55
 
41
56
  # Ultra-fast arithmetic with dimensional checking
42
- def __add__(self, other: 'FastQuantity') -> 'FastQuantity':
57
+ def __add__(self, other: FastQuantity) -> FastQuantity:
43
58
  # Fast dimension compatibility check using cached signatures
44
59
  if self._dimension_sig != other._dimension_sig:
45
60
  raise ValueError(f"Cannot add {self.unit.name} and {other.unit.name}")
@@ -52,7 +67,7 @@ class FastQuantity:
52
67
  other_value = other.value * other._si_factor / self._si_factor
53
68
  return FastQuantity(self.value + other_value, self.unit)
54
69
 
55
- def __sub__(self, other: 'FastQuantity') -> 'FastQuantity':
70
+ def __sub__(self, other: FastQuantity) -> FastQuantity:
56
71
  # Fast dimension compatibility check using cached signatures
57
72
  if self._dimension_sig != other._dimension_sig:
58
73
  raise ValueError(f"Cannot subtract {other.unit.name} from {self.unit.name}")
@@ -65,8 +80,8 @@ class FastQuantity:
65
80
  other_value = other.value * other._si_factor / self._si_factor
66
81
  return FastQuantity(self.value - other_value, self.unit)
67
82
 
68
- def __mul__(self, other: Union['FastQuantity', float, int]) -> 'FastQuantity':
69
- if isinstance(other, (int, float)):
83
+ def __mul__(self, other: FastQuantity | float | int) -> FastQuantity:
84
+ if isinstance(other, int | float):
70
85
  return FastQuantity(self.value * other, self.unit)
71
86
 
72
87
  # Fast dimensional analysis using cached signatures
@@ -83,14 +98,14 @@ class FastQuantity:
83
98
 
84
99
  return FastQuantity(result_value, result_unit)
85
100
 
86
- def __rmul__(self, other: Union[float, int]) -> 'FastQuantity':
101
+ def __rmul__(self, other: float | int) -> FastQuantity:
87
102
  """Reverse multiplication for cases like 2 * quantity."""
88
- if isinstance(other, (int, float)):
103
+ if isinstance(other, int | float):
89
104
  return FastQuantity(other * self.value, self.unit)
90
105
  return NotImplemented
91
106
 
92
- def __truediv__(self, other: Union['FastQuantity', float, int]) -> 'FastQuantity':
93
- if isinstance(other, (int, float)):
107
+ def __truediv__(self, other: FastQuantity | float | int) -> FastQuantity:
108
+ if isinstance(other, int | float):
94
109
  return FastQuantity(self.value / other, self.unit)
95
110
 
96
111
  # Fast dimensional analysis using cached signatures
@@ -107,8 +122,8 @@ class FastQuantity:
107
122
 
108
123
  return FastQuantity(result_value, result_unit)
109
124
 
110
- def _find_result_unit_fast(self, result_dimension_sig: int,
111
- left_qty: 'FastQuantity', right_qty: 'FastQuantity') -> UnitConstant:
125
+ def _find_result_unit_fast(self, result_dimension_sig: int,
126
+ left_qty: FastQuantity, right_qty: FastQuantity) -> UnitConstant:
112
127
  """Ultra-fast unit finding using cached dimension signatures."""
113
128
 
114
129
  # Initialize dimension cache if empty
@@ -130,7 +145,7 @@ class FastQuantity:
130
145
  # For rare combined dimensions, create temporary unit
131
146
  temp_unit = UnitDefinition(
132
147
  name=f"combined_{result_dimension_sig}",
133
- symbol="combined",
148
+ symbol="combined",
134
149
  dimension=DimensionSignature(result_dimension_sig),
135
150
  si_factor=1.0
136
151
  )
@@ -140,13 +155,13 @@ class FastQuantity:
140
155
  registry._dimension_cache[result_dimension_sig] = result_unit
141
156
  return result_unit
142
157
 
143
- def _find_result_unit(self, result_dimension: DimensionSignature,
144
- left_qty: 'FastQuantity', right_qty: 'FastQuantity') -> UnitConstant:
158
+ def _find_result_unit(self, result_dimension: DimensionSignature,
159
+ left_qty: FastQuantity, right_qty: FastQuantity) -> UnitConstant:
145
160
  """Legacy method - kept for compatibility."""
146
161
  return self._find_result_unit_fast(result_dimension._signature, left_qty, right_qty)
147
162
 
148
163
  # Ultra-fast comparisons
149
- def __lt__(self, other: 'FastQuantity') -> bool:
164
+ def __lt__(self, other: FastQuantity) -> bool:
150
165
  if self._dimension_sig != other._dimension_sig:
151
166
  raise ValueError("Cannot compare incompatible dimensions")
152
167
 
@@ -172,7 +187,7 @@ class FastQuantity:
172
187
  other_value = other.value * other._si_factor / self._si_factor
173
188
  return abs(self.value - other_value) < 1e-10
174
189
 
175
- def to(self, target_unit: UnitConstant) -> 'FastQuantity':
190
+ def to(self, target_unit: UnitConstant) -> FastQuantity:
176
191
  """Ultra-fast unit conversion."""
177
192
  if self.unit == target_unit:
178
193
  return FastQuantity(self.value, target_unit)
@@ -183,16 +198,40 @@ class FastQuantity:
183
198
 
184
199
 
185
200
  class TypeSafeVariable(Generic[DimensionType]):
186
- """Type-safe variable with compile-time dimensional checking."""
201
+ """
202
+ Base class for type-safe variables with dimensional checking.
187
203
 
188
- def __init__(self, name: str, expected_dimension: DimensionSignature):
204
+ This is a simple data container without dependencies on expressions or equations.
205
+ Mathematical operations are added by subclasses or mixins.
206
+ """
207
+
208
+ # Class attribute defining which setter to use - subclasses can override
209
+ _setter_class = TypeSafeSetter
210
+
211
+ def __init__(self, name: str, expected_dimension, is_known: bool = True):
189
212
  self.name = name
213
+ self.symbol: str | None = None # Will be set by EngineeringProblem to attribute name
190
214
  self.expected_dimension = expected_dimension
191
- self.quantity: Optional[FastQuantity] = None
215
+ self.quantity: FastQuantity | None = None
216
+ self.is_known = is_known
217
+
218
+ def set(self, value: float):
219
+ """Create a setter for this variable using the class-specific setter type."""
220
+ return self._setter_class(self, value)
192
221
 
193
- def set(self, value: float) -> Union['TypeSafeSetter', 'LengthSetter', 'PressureSetter']:
194
- from .setters import TypeSafeSetter
195
- return TypeSafeSetter(self, value)
222
+ @property
223
+ def unknown(self) -> Self:
224
+ """Mark this variable as unknown using fluent API."""
225
+ self.is_known = False
226
+ return self
227
+
228
+ @property
229
+ def known(self) -> Self:
230
+ """Mark this variable as known using fluent API."""
231
+ self.is_known = True
232
+ return self
196
233
 
197
234
  def __str__(self):
198
- return f"{self.name}: {self.quantity}" if self.quantity else f"{self.name}: unset"
235
+ return f"{self.name}: {self.quantity}" if self.quantity else f"{self.name}: unset"
236
+
237
+
qnty/variables.py CHANGED
@@ -1,31 +1,229 @@
1
1
  """
2
- Specialized Variables
3
- =====================
2
+ Specialized Variables and Setters
3
+ ==================================
4
4
 
5
- Dimension-specific variable classes with type safety.
5
+ Dimension-specific variable classes with type safety, fluent API setters,
6
+ and mathematical operations for expressions and equations.
6
7
  """
7
8
 
8
- from .dimension import LENGTH, PRESSURE
9
- from .variable import TypeSafeVariable
10
- from .setters import LengthSetter, PressureSetter
9
+ from __future__ import annotations
11
10
 
11
+ from typing import cast
12
12
 
13
- # Specialized variable types
14
- class Length(TypeSafeVariable):
15
- """Type-safe length variable."""
13
+ from .dimension import DIMENSIONLESS, LENGTH, PRESSURE
14
+ from .equation import Equation
15
+ from .expression import Expression, wrap_operand
16
+ from .units import DimensionlessUnits, LengthUnits, PressureUnits
17
+ from .variable import FastQuantity, TypeSafeSetter, TypeSafeVariable
18
+
19
+
20
+ class ExpressionVariable(TypeSafeVariable):
21
+ """
22
+ TypeSafeVariable extended with expression and equation capabilities.
23
+
24
+ This adds mathematical operations that create expressions and equations,
25
+ keeping the base TypeSafeVariable free of these dependencies.
26
+ """
27
+
28
+ def equals(self, expression: Expression | TypeSafeVariable | FastQuantity | int | float):
29
+ """Create an equation: self = expression."""
30
+ # Wrap the expression in proper Expression type
31
+ rhs_expr = wrap_operand(expression)
32
+ return Equation(f"{self.name}_eq", self, rhs_expr)
33
+
34
+ def __add__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
35
+ """Add this variable to another operand, returning an Expression."""
36
+ return wrap_operand(self) + wrap_operand(other)
37
+
38
+ def __radd__(self, other: FastQuantity | int | float) -> Expression:
39
+ """Reverse add for this variable."""
40
+ return wrap_operand(other) + wrap_operand(self)
41
+
42
+ def __sub__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
43
+ """Subtract another operand from this variable, returning an Expression."""
44
+ return wrap_operand(self) - wrap_operand(other)
45
+
46
+ def __rsub__(self, other: FastQuantity | int | float) -> Expression:
47
+ """Reverse subtract for this variable."""
48
+ return wrap_operand(other) - wrap_operand(self)
49
+
50
+ def __mul__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
51
+ """Multiply this variable by another operand, returning an Expression."""
52
+ return wrap_operand(self) * wrap_operand(other)
53
+
54
+ def __rmul__(self, other: FastQuantity | int | float) -> Expression:
55
+ """Reverse multiply for this variable."""
56
+ return wrap_operand(other) * wrap_operand(self)
16
57
 
17
- def __init__(self, name: str):
18
- super().__init__(name, LENGTH)
58
+ def __truediv__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
59
+ """Divide this variable by another operand, returning an Expression."""
60
+ return wrap_operand(self) / wrap_operand(other)
61
+
62
+ def __rtruediv__(self, other: FastQuantity | int | float) -> Expression:
63
+ """Reverse divide for this variable."""
64
+ return wrap_operand(other) / wrap_operand(self)
65
+
66
+ def __pow__(self, other: TypeSafeVariable | FastQuantity | int | float) -> Expression:
67
+ """Raise this variable to a power, returning an Expression."""
68
+ return wrap_operand(self) ** wrap_operand(other)
69
+
70
+ def __rpow__(self, other: FastQuantity | int | float) -> Expression:
71
+ """Reverse power for this variable."""
72
+ return wrap_operand(other) ** wrap_operand(self)
73
+
74
+
75
+ # Specialized setter classes
76
+ class LengthSetter(TypeSafeSetter):
77
+ """Length-specific setter with only length units."""
19
78
 
20
- def set(self, value: float) -> 'LengthSetter':
21
- return LengthSetter(self, value)
79
+ def __init__(self, variable: Length, value: float):
80
+ super().__init__(variable, value)
81
+
82
+ # Only length units available - compile-time safe!
83
+ @property
84
+ def meters(self) -> Length:
85
+ self.variable.quantity = FastQuantity(self.value, LengthUnits.meter)
86
+ return cast(Length, self.variable)
87
+
88
+ @property
89
+ def millimeters(self) -> Length:
90
+ self.variable.quantity = FastQuantity(self.value, LengthUnits.millimeter)
91
+ return cast(Length, self.variable)
92
+
93
+ @property
94
+ def inches(self) -> Length:
95
+ self.variable.quantity = FastQuantity(self.value, LengthUnits.inch)
96
+ return cast(Length, self.variable)
97
+
98
+ @property
99
+ def feet(self) -> Length:
100
+ self.variable.quantity = FastQuantity(self.value, LengthUnits.foot)
101
+ return cast(Length, self.variable)
22
102
 
23
103
 
24
- class Pressure(TypeSafeVariable):
25
- """Type-safe pressure variable."""
104
+ class PressureSetter(TypeSafeSetter):
105
+ """Pressure-specific setter with only pressure units."""
106
+
107
+ def __init__(self, variable: Pressure, value: float):
108
+ super().__init__(variable, value)
26
109
 
27
- def __init__(self, name: str):
28
- super().__init__(name, PRESSURE)
110
+ # Only pressure units available - compile-time safe!
111
+ @property
112
+ def psi(self) -> Pressure:
113
+ self.variable.quantity = FastQuantity(self.value, PressureUnits.psi)
114
+ return cast(Pressure, self.variable)
29
115
 
30
- def set(self, value: float) -> 'PressureSetter':
31
- return PressureSetter(self, value)
116
+ @property
117
+ def kPa(self) -> Pressure:
118
+ self.variable.quantity = FastQuantity(self.value, PressureUnits.kilopascal)
119
+ return cast(Pressure, self.variable)
120
+
121
+ @property
122
+ def MPa(self) -> Pressure:
123
+ self.variable.quantity = FastQuantity(self.value, PressureUnits.megapascal)
124
+ return cast(Pressure, self.variable)
125
+
126
+ @property
127
+ def bar(self) -> Pressure:
128
+ self.variable.quantity = FastQuantity(self.value, PressureUnits.bar)
129
+ return cast(Pressure, self.variable)
130
+
131
+
132
+ class DimensionlessSetter(TypeSafeSetter):
133
+ """Dimensionless-specific setter with only dimensionless units."""
134
+
135
+ def __init__(self, variable: Dimensionless, value: float):
136
+ super().__init__(variable, value)
137
+
138
+ # Dimensionless units
139
+ @property
140
+ def dimensionless(self) -> Dimensionless:
141
+ self.variable.quantity = FastQuantity(self.value, DimensionlessUnits.dimensionless)
142
+ return cast(Dimensionless, self.variable)
143
+
144
+ # Common alias for no units
145
+ @property
146
+ def unitless(self) -> Dimensionless:
147
+ self.variable.quantity = FastQuantity(self.value, DimensionlessUnits.dimensionless)
148
+ return cast(Dimensionless, self.variable)
149
+
150
+
151
+ # Specialized variable types that users interact with
152
+ class Length(ExpressionVariable):
153
+ """Type-safe length variable with expression capabilities."""
154
+
155
+ _setter_class = LengthSetter
156
+
157
+ def __init__(self, *args, is_known: bool = True):
158
+ if len(args) == 1:
159
+ # Length("name") - original syntax
160
+ super().__init__(args[0], LENGTH, is_known=is_known)
161
+ elif len(args) == 3:
162
+ # Length(value, "unit", "name") - new syntax
163
+ value, unit, name = args
164
+ super().__init__(name, LENGTH, is_known=is_known)
165
+ # Auto-set the value with the specified unit
166
+ setter = LengthSetter(self, value)
167
+ # Get the unit setter method dynamically
168
+ if unit == "in": # Handle "in" alias for inches
169
+ setter.inches
170
+ elif hasattr(setter, unit):
171
+ getattr(setter, unit)
172
+ elif hasattr(setter, unit + 's'): # Handle singular/plural
173
+ getattr(setter, unit + 's')
174
+ else:
175
+ # Default to meters if unit not recognized
176
+ setter.meters
177
+ else:
178
+ raise ValueError("Length expects either 1 argument (name) or 3 arguments (value, unit, name)")
179
+
180
+
181
+ class Pressure(ExpressionVariable):
182
+ """Type-safe pressure variable with expression capabilities."""
183
+
184
+ _setter_class = PressureSetter
185
+
186
+ def __init__(self, *args, is_known: bool = True):
187
+ if len(args) == 1:
188
+ # Pressure("name") - original syntax
189
+ super().__init__(args[0], PRESSURE, is_known=is_known)
190
+ elif len(args) == 3:
191
+ # Pressure(value, "unit", "name") - new syntax
192
+ value, unit, name = args
193
+ super().__init__(name, PRESSURE, is_known=is_known)
194
+ # Auto-set the value with the specified unit
195
+ setter = PressureSetter(self, value)
196
+ # Get the unit setter method dynamically
197
+ if unit == "psi":
198
+ setter.psi
199
+ elif unit == "kPa":
200
+ setter.kPa
201
+ elif unit == "MPa":
202
+ setter.MPa
203
+ elif unit == "bar":
204
+ setter.bar
205
+ else:
206
+ # Default to psi if unit not recognized
207
+ setter.psi
208
+ else:
209
+ raise ValueError("Pressure expects either 1 argument (name) or 3 arguments (value, unit, name)")
210
+
211
+
212
+ class Dimensionless(ExpressionVariable):
213
+ """Type-safe dimensionless variable with expression capabilities."""
214
+
215
+ _setter_class = DimensionlessSetter
216
+
217
+ def __init__(self, *args, is_known: bool = True):
218
+ if len(args) == 1:
219
+ # Dimensionless("name") - original syntax
220
+ super().__init__(args[0], DIMENSIONLESS, is_known=is_known)
221
+ elif len(args) == 2:
222
+ # Dimensionless(value, "name") - new syntax
223
+ value, name = args
224
+ super().__init__(name, DIMENSIONLESS, is_known=is_known)
225
+ # Auto-set the value as dimensionless
226
+ setter = DimensionlessSetter(self, value)
227
+ setter.dimensionless
228
+ else:
229
+ raise ValueError("Dimensionless expects either 1 argument (name) or 2 arguments (value, name)")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: qnty
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: High-performance unit system library for Python with dimensional safety and fast unit conversions
5
5
  License: Apache-2.0
6
6
  Keywords: units,dimensional analysis,engineering,physics,quantities,measurements
@@ -33,7 +33,7 @@ Description-Content-Type: text/markdown
33
33
 
34
34
  **High-performance unit system library for Python with dimensional safety and fast unit conversions for engineering calculations.**
35
35
 
36
- [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
36
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
37
37
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
38
38
  [![Development Status](https://img.shields.io/badge/status-beta-orange.svg)](https://pypi.org/project/qnty/)
39
39
 
@@ -43,7 +43,7 @@ Description-Content-Type: text/markdown
43
43
 
44
44
  **📐 Accuracy Notice**: The authors are not responsible or liable for incorrect results, calculation errors, or any consequences arising from the use of this library. Always validate calculations independently using established engineering tools and practices.
45
45
 
46
- **🚀 Learn from History**: Remember, even NASA's Mars Climate Orbiter had a $327 million oops moment due to unit conversion errors between metric and imperial systems. Don't let your project become the next cautionary tale - double-check everything!
46
+ **🚀 Learn from History**: Remember, even NASA's Mars Climate Orbiter had a $327 million oops moment due to unit conversion errors between metric and imperial systems. Don't let your project become the next cautionary tale - double-check everything!
47
47
 
48
48
  *Use Qnty to help prevent unit errors, but always verify critical calculations through multiple methods.*
49
49
 
@@ -58,7 +58,9 @@ Qnty is designed around **type safety** and **performance optimization** using c
58
58
  - **⚡ Zero-Cost Abstractions**: Optimized operations with `__slots__` and caching
59
59
  - **🔗 Fluent API**: Intuitive method chaining for readable code
60
60
  - **🧮 Engineering-Focused**: Built for real-world engineering calculations
61
- - **📊 Comprehensive Testing**: 400+ tests with performance benchmarks
61
+ - **🧬 Mathematical System**: Built-in equation solving and expression trees
62
+ - **📊 Comprehensive Testing**: 457 tests with performance benchmarks
63
+ - **🏗️ Clean Architecture**: Circular import-free design with strict dependency hierarchy
62
64
 
63
65
  ## 🚀 Quick Start
64
66
 
@@ -73,7 +75,7 @@ poetry add qnty
73
75
  ### Basic Usage
74
76
 
75
77
  ```python
76
- from qnty.variables import Length, Pressure
78
+ from qnty import Length, Pressure, Dimensionless
77
79
  from qnty.variable import FastQuantity
78
80
  from qnty.units import LengthUnits, PressureUnits
79
81
 
@@ -95,7 +97,7 @@ force = pressure * area # Automatic dimensional analysis
95
97
  ### Engineering Example
96
98
 
97
99
  ```python
98
- from qnty.variables import Length, Pressure
100
+ from qnty import Length, Pressure
99
101
 
100
102
  # ASME pressure vessel calculation with mixed units
101
103
  pressure = Pressure("internal_pressure")
@@ -112,47 +114,90 @@ thickness = (pressure.quantity * diameter.quantity) / (2 * stress.quantity)
112
114
  print(f"Required thickness: {thickness}") # Automatically in correct units
113
115
  ```
114
116
 
117
+ ### Mathematical Equations & Solving
118
+
119
+ ```python
120
+ from qnty import Length, Pressure, Dimensionless
121
+
122
+ # Define engineering variables
123
+ T = Length("Wall Thickness", is_known=False) # Unknown to solve for
124
+ T_bar = Length(0.147, "inches", "Nominal Wall Thickness")
125
+ U_m = Dimensionless(0.125, "Mill Undertolerance")
126
+
127
+ # Create equation using fluent API: T = T_bar * (1 - U_m)
128
+ equation = T.equals(T_bar * (1 - U_m))
129
+
130
+ # Solve automatically
131
+ known_vars = {"T_bar": T_bar, "U_m": U_m}
132
+ result = equation.solve_for("T", known_vars)
133
+ print(f"Solved thickness: {result.quantity}") # 0.128625 inches
134
+
135
+ # Verify equation is satisfied
136
+ assert equation.check_residual(known_vars) is True
137
+ ```
138
+
115
139
  ## 🏗️ Architecture
116
140
 
141
+ ### Clean Dependency Design
142
+
143
+ Qnty features a carefully designed architecture that eliminates circular imports through a strict dependency hierarchy:
144
+
145
+ ```python
146
+ variable → variables → expression → equation
147
+ ```
148
+
149
+ This ensures clean type checking, maintainable code, and optimal performance throughout the system.
150
+
117
151
  ### Core Components
118
152
 
119
- **🔢 Dimensional System**
153
+ ### 🔢 Dimensional System
154
+
120
155
  - Prime number encoding for ultra-fast dimensional compatibility checks
121
156
  - Zero-cost dimensional analysis at compile time
122
157
  - Immutable dimension signatures for thread safety
123
158
 
124
- **⚙️ High-Performance Quantities**
159
+ ### ⚙️ High-Performance Quantities
160
+
125
161
  - `FastQuantity`: Optimized for engineering calculations with `__slots__`
126
162
  - Cached SI factors and dimension signatures
127
163
  - Fast-path optimizations for same-unit operations
128
164
 
129
- **🎯 Type-Safe Variables**
130
- - `Length`, `Pressure`: Domain-specific variables with compile-time safety
165
+ ### 🎯 Type-Safe Variables
166
+
167
+ - `Length`, `Pressure`, `Dimensionless`: Domain-specific variables with compile-time safety
131
168
  - Fluent API with specialized setters
132
169
  - Prevents dimensional errors at the type level
133
170
 
134
- **🔄 Smart Unit System**
171
+ ### 🔄 Smart Unit System
172
+
135
173
  - Pre-computed conversion tables
136
174
  - Automatic unit resolution for calculations
137
175
  - Support for mixed-unit operations
138
176
 
177
+ ### 🧬 Mathematical System
178
+
179
+ - Built-in equation solving with symbolic manipulation
180
+ - Expression trees for complex mathematical operations
181
+ - Automatic residual checking and validation
182
+ - Engineering equation support (ASME, pressure vessels, etc.)
183
+
139
184
  ## 📊 Performance
140
185
 
141
- Qnty significantly outperforms other unit libraries with **23.7x average speedup** over Pint:
186
+ Qnty significantly outperforms other unit libraries with **18.9x average speedup** over Pint:
142
187
 
143
188
  ### Real Benchmark Results (μs per operation)
144
189
 
145
190
  | Operation | Qnty | Pint | **Speedup** |
146
191
  |-----------|------|------|-------------|
147
- | Unit Conversion (m → mm) | 0.60 | 14.03 | **23.5x** |
148
- | Mixed Unit Addition (mm + in) | 1.14 | 31.80 | **28.0x** |
149
- | Multiplication (m × m) | 0.91 | 14.13 | **15.5x** |
150
- | Division (psi ÷ mm) | 1.01 | 16.29 | **16.1x** |
151
- | Complex ASME Equation | 5.46 | 180.95 | **33.1x** 🚀 |
152
- | Type-Safe Variables | 1.08 | 24.80 | **23.0x** |
153
- | Chained Operations | 3.93 | 88.94 | **22.6x** |
154
- | Loop (10 additions) | 6.49 | 118.21 | **18.2x** |
155
- | **AVERAGE** | **2.58** | **61.14** | **23.7x** 🏆 |
192
+ | Unit Conversion (m → mm) | 0.50 | 9.72 | **19.5x** |
193
+ | Mixed Unit Addition (mm + in) | 0.76 | 17.52 | **23.1x** |
194
+ | Multiplication (m × m) | 0.82 | 10.64 | **12.9x** |
195
+ | Division (psi ÷ mm) | 0.87 | 11.23 | **12.9x** |
196
+ | Complex ASME Equation | 4.07 | 106.17 | **26.1x** 🚀 |
197
+ | Type-Safe Variables | 0.98 | 9.65 | **9.8x** |
198
+ | Chained Operations | 1.83 | 42.22 | **23.1x** |
199
+ | Loop (10 additions) | 5.32 | 79.48 | **14.9x** |
200
+ | **AVERAGE** | **1.89** | **35.83** | **18.9x** 🏆 |
156
201
 
157
202
  *Benchmarks performed on typical engineering calculations. Run `pytest tests/test_benchmark.py -v -s` to verify on your system.*
158
203
 
@@ -197,6 +242,44 @@ area = width.quantity * height.quantity
197
242
  perimeter = 2 * (width.quantity + height.quantity)
198
243
  ```
199
244
 
245
+ ### Equation Solving System
246
+
247
+ ```python
248
+ from qnty import Length, Pressure, Dimensionless
249
+
250
+ # Multi-variable engineering equations
251
+ P = Pressure(90, "psi", "P") # Known
252
+ D = Length(0.84, "inches", "D") # Known
253
+ t = Length("t", is_known=False) # Unknown - solve for this
254
+ S = Pressure(20000, "psi", "S") # Known
255
+
256
+ # ASME pressure vessel equation: P = (S * t) / ((D/2) + 0.6*t)
257
+ # Rearranged to solve for t
258
+ equation = t.equals((P * D) / (2 * S - 1.2 * P))
259
+
260
+ # Solve automatically
261
+ known_variables = {"P": P, "D": D, "S": S}
262
+ thickness_result = equation.solve_for("t", known_variables)
263
+ print(f"Required thickness: {thickness_result.quantity}")
264
+
265
+ # Verify solution
266
+ assert equation.check_residual(known_variables) is True
267
+ ```
268
+
269
+ ### Import Strategy
270
+
271
+ Qnty provides a clean, minimal public API:
272
+
273
+ ```python
274
+ # Preferred import style - clean public API
275
+ from qnty import Length, Pressure, Dimensionless
276
+
277
+ # Internal imports when needed for advanced usage
278
+ from qnty.variable import FastQuantity, TypeSafeVariable
279
+ from qnty.expression import Expression
280
+ from qnty.equation import Equation, EquationSystem
281
+ ```
282
+
200
283
  ## 🔧 Development
201
284
 
202
285
  ### Setup Development Environment
@@ -221,6 +304,7 @@ python tests/test_benchmark.py
221
304
  ```bash
222
305
  # Linting with ruff (200 character line length)
223
306
  ruff check src/ tests/
307
+ ruff format src/ tests/
224
308
 
225
309
  # Type checking
226
310
  mypy src/qnty/
@@ -232,7 +316,9 @@ mypy src/qnty/
232
316
 
233
317
  - **`FastQuantity`**: High-performance quantity with value and unit
234
318
  - **`TypeSafeVariable`**: Base class for dimension-specific variables
235
- - **`Length`**, **`Pressure`**: Specialized variables with fluent setters
319
+ - **`Length`**, **`Pressure`**, **`Dimensionless`**: Specialized variables with fluent setters
320
+ - **`Equation`**: Mathematical equations with solving capabilities
321
+ - **`Expression`**: Abstract base for mathematical expression trees
236
322
  - **`DimensionSignature`**: Immutable dimension encoding system
237
323
  - **`UnitConstant`**: Type-safe unit definitions
238
324
 
@@ -266,3 +352,4 @@ This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENS
266
352
  ---
267
353
 
268
354
  **Ready to supercharge your engineering calculations?** Install Qnty today and experience the power of type-safe, high-performance unit handling! 🚀
355
+
@@ -0,0 +1,11 @@
1
+ qnty/__init__.py,sha256=wzFXh3bgSbjHzg1tHYRwEcEO25mijhsdohHUQDibVu4,106
2
+ qnty/dimension.py,sha256=X9v4_-8IhLcUsXzYgC6rXaGZ-Y6tqB8MPZgN9re_lx8,2781
3
+ qnty/equation.py,sha256=XgzM91jn__GomKbgslncoFJWPDJiMb4_VKD-8sdcFXc,9096
4
+ qnty/expression.py,sha256=UM0hCqOVD1gK_O5-Rsq7BWIPDTEL_kFORprV6LIqGcU,20890
5
+ qnty/unit.py,sha256=dgJX6rcbeAv6NFyQtrT-Zp7m93X39GlU9jkcRYBKic4,4187
6
+ qnty/units.py,sha256=uazbYoC3sFE6MKd46f2BrysmgJ-r0v7BvKGsvw8a2W0,1367
7
+ qnty/variable.py,sha256=6Z-QmLE3ke2fdw-d6hNR7OSC7aAhE02htHY5XTN7zgI,9808
8
+ qnty/variables.py,sha256=_dchFWFOedWkGDMC4AhZ_kHEM6VVH7iqANksVyfHoLc,9039
9
+ qnty-0.0.2.dist-info/METADATA,sha256=90UoHneLF5m66UFkdjV84C5KohJVBxMy0wzx1LN8rD0,12113
10
+ qnty-0.0.2.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
11
+ qnty-0.0.2.dist-info/RECORD,,