qnty 0.0.8__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.
- qnty/__init__.py +140 -59
- qnty/constants/__init__.py +10 -0
- qnty/constants/numerical.py +18 -0
- qnty/constants/solvers.py +6 -0
- qnty/constants/tests.py +6 -0
- qnty/dimensions/__init__.py +23 -0
- qnty/dimensions/base.py +97 -0
- qnty/dimensions/field_dims.py +126 -0
- qnty/dimensions/field_dims.pyi +128 -0
- qnty/dimensions/signature.py +111 -0
- qnty/equations/__init__.py +4 -0
- qnty/equations/equation.py +220 -0
- qnty/equations/system.py +130 -0
- qnty/expressions/__init__.py +40 -0
- qnty/expressions/formatter.py +188 -0
- qnty/expressions/functions.py +74 -0
- qnty/expressions/nodes.py +701 -0
- qnty/expressions/types.py +70 -0
- qnty/extensions/plotting/__init__.py +0 -0
- qnty/extensions/reporting/__init__.py +0 -0
- qnty/problems/__init__.py +145 -0
- qnty/problems/composition.py +1031 -0
- qnty/problems/problem.py +695 -0
- qnty/problems/rules.py +145 -0
- qnty/problems/solving.py +1216 -0
- qnty/problems/validation.py +127 -0
- qnty/quantities/__init__.py +29 -0
- qnty/quantities/base_qnty.py +677 -0
- qnty/quantities/field_converters.py +24004 -0
- qnty/quantities/field_qnty.py +1012 -0
- qnty/quantities/field_setter.py +12320 -0
- qnty/quantities/field_vars.py +6325 -0
- qnty/quantities/field_vars.pyi +4191 -0
- qnty/solving/__init__.py +0 -0
- qnty/solving/manager.py +96 -0
- qnty/solving/order.py +403 -0
- qnty/solving/solvers/__init__.py +13 -0
- qnty/solving/solvers/base.py +82 -0
- qnty/solving/solvers/iterative.py +165 -0
- qnty/solving/solvers/simultaneous.py +475 -0
- qnty/units/__init__.py +1 -0
- qnty/units/field_units.py +10507 -0
- qnty/units/field_units.pyi +2461 -0
- qnty/units/prefixes.py +203 -0
- qnty/{unit.py → units/registry.py} +89 -61
- qnty/utils/__init__.py +16 -0
- qnty/utils/caching/__init__.py +23 -0
- qnty/utils/caching/manager.py +401 -0
- qnty/utils/error_handling/__init__.py +66 -0
- qnty/utils/error_handling/context.py +39 -0
- qnty/utils/error_handling/exceptions.py +96 -0
- qnty/utils/error_handling/handlers.py +171 -0
- qnty/utils/logging.py +40 -0
- qnty/utils/protocols.py +164 -0
- qnty/utils/scope_discovery.py +420 -0
- qnty-0.1.0.dist-info/METADATA +199 -0
- qnty-0.1.0.dist-info/RECORD +60 -0
- qnty/dimension.py +0 -186
- qnty/equation.py +0 -297
- qnty/expression.py +0 -553
- qnty/prefixes.py +0 -229
- qnty/unit_types/base.py +0 -47
- qnty/units.py +0 -8113
- qnty/variable.py +0 -300
- qnty/variable_types/base.py +0 -58
- qnty/variable_types/expression_variable.py +0 -106
- qnty/variable_types/typed_variable.py +0 -87
- qnty/variables.py +0 -2298
- qnty/variables.pyi +0 -6148
- qnty-0.0.8.dist-info/METADATA +0 -355
- qnty-0.0.8.dist-info/RECORD +0 -19
- /qnty/{unit_types → extensions}/__init__.py +0 -0
- /qnty/{variable_types → extensions/integration}/__init__.py +0 -0
- {qnty-0.0.8.dist-info → qnty-0.1.0.dist-info}/WHEEL +0 -0
qnty/units/prefixes.py
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
"""
|
2
|
+
SI Prefix System
|
3
|
+
================
|
4
|
+
|
5
|
+
Standard SI prefixes for unit multiplication/division.
|
6
|
+
Provides systematic handling of metric prefixes like kilo-, milli-, micro-, etc.
|
7
|
+
"""
|
8
|
+
|
9
|
+
from dataclasses import dataclass
|
10
|
+
from enum import Enum
|
11
|
+
|
12
|
+
from ..constants.numerical import PREFIX_LOOKUP_MIN_TOLERANCE, PREFIX_LOOKUP_TOLERANCE
|
13
|
+
|
14
|
+
|
15
|
+
@dataclass(frozen=True, slots=True)
|
16
|
+
class SIPrefix:
|
17
|
+
"""
|
18
|
+
Standard SI prefix definition.
|
19
|
+
|
20
|
+
Attributes:
|
21
|
+
name: Full prefix name (e.g., "kilo", "milli")
|
22
|
+
symbol: Standard symbol (e.g., "k", "m")
|
23
|
+
factor: Multiplication factor relative to base unit (e.g., 1000, 0.001)
|
24
|
+
"""
|
25
|
+
|
26
|
+
name: str
|
27
|
+
symbol: str
|
28
|
+
factor: float
|
29
|
+
|
30
|
+
def apply_to_name(self, base_name: str) -> str:
|
31
|
+
"""Apply prefix to a base unit name."""
|
32
|
+
return self.name + base_name if self.name else base_name
|
33
|
+
|
34
|
+
def apply_to_symbol(self, base_symbol: str) -> str:
|
35
|
+
"""Apply prefix to a base unit symbol."""
|
36
|
+
return self.symbol + base_symbol if self.symbol else base_symbol
|
37
|
+
|
38
|
+
|
39
|
+
class StandardPrefixes(Enum):
|
40
|
+
"""
|
41
|
+
Standard SI prefixes with their multiplication factors.
|
42
|
+
|
43
|
+
From yotta (10^24) to yocto (10^-24).
|
44
|
+
"""
|
45
|
+
|
46
|
+
# Larger prefixes (10^3 to 10^24)
|
47
|
+
YOTTA = SIPrefix("yotta", "Y", 1e24)
|
48
|
+
ZETTA = SIPrefix("zetta", "Z", 1e21)
|
49
|
+
EXA = SIPrefix("exa", "E", 1e18)
|
50
|
+
PETA = SIPrefix("peta", "P", 1e15)
|
51
|
+
TERA = SIPrefix("tera", "T", 1e12)
|
52
|
+
GIGA = SIPrefix("giga", "G", 1e9)
|
53
|
+
MEGA = SIPrefix("mega", "M", 1e6)
|
54
|
+
KILO = SIPrefix("kilo", "k", 1e3)
|
55
|
+
HECTO = SIPrefix("hecto", "h", 1e2)
|
56
|
+
DECA = SIPrefix("deca", "da", 1e1)
|
57
|
+
|
58
|
+
# Base (no prefix)
|
59
|
+
NONE = SIPrefix("", "", 1.0)
|
60
|
+
|
61
|
+
# Smaller prefixes (10^-1 to 10^-24)
|
62
|
+
DECI = SIPrefix("deci", "d", 1e-1)
|
63
|
+
CENTI = SIPrefix("centi", "c", 1e-2)
|
64
|
+
MILLI = SIPrefix("milli", "m", 1e-3)
|
65
|
+
MICRO = SIPrefix("micro", "μ", 1e-6)
|
66
|
+
NANO = SIPrefix("nano", "n", 1e-9)
|
67
|
+
PICO = SIPrefix("pico", "p", 1e-12)
|
68
|
+
FEMTO = SIPrefix("femto", "f", 1e-15)
|
69
|
+
ATTO = SIPrefix("atto", "a", 1e-18)
|
70
|
+
ZEPTO = SIPrefix("zepto", "z", 1e-21)
|
71
|
+
YOCTO = SIPrefix("yocto", "y", 1e-24)
|
72
|
+
|
73
|
+
|
74
|
+
# Common prefix groups for different unit types
|
75
|
+
COMMON_LENGTH_PREFIXES: list[StandardPrefixes] = [
|
76
|
+
StandardPrefixes.KILO,
|
77
|
+
StandardPrefixes.CENTI,
|
78
|
+
StandardPrefixes.MILLI,
|
79
|
+
StandardPrefixes.MICRO,
|
80
|
+
StandardPrefixes.NANO,
|
81
|
+
]
|
82
|
+
|
83
|
+
COMMON_MASS_PREFIXES: list[StandardPrefixes] = [
|
84
|
+
StandardPrefixes.KILO, # Note: kilogram is the SI base unit
|
85
|
+
StandardPrefixes.MILLI,
|
86
|
+
StandardPrefixes.MICRO,
|
87
|
+
]
|
88
|
+
|
89
|
+
COMMON_TIME_PREFIXES: list[StandardPrefixes] = [
|
90
|
+
StandardPrefixes.MILLI,
|
91
|
+
StandardPrefixes.MICRO,
|
92
|
+
StandardPrefixes.NANO,
|
93
|
+
StandardPrefixes.PICO,
|
94
|
+
]
|
95
|
+
|
96
|
+
COMMON_ELECTRIC_PREFIXES: list[StandardPrefixes] = [
|
97
|
+
StandardPrefixes.KILO,
|
98
|
+
StandardPrefixes.MILLI,
|
99
|
+
StandardPrefixes.MICRO,
|
100
|
+
StandardPrefixes.NANO,
|
101
|
+
StandardPrefixes.PICO,
|
102
|
+
]
|
103
|
+
|
104
|
+
COMMON_ENERGY_PREFIXES: list[StandardPrefixes] = [
|
105
|
+
StandardPrefixes.KILO,
|
106
|
+
StandardPrefixes.MEGA,
|
107
|
+
StandardPrefixes.GIGA,
|
108
|
+
]
|
109
|
+
|
110
|
+
COMMON_POWER_PREFIXES: list[StandardPrefixes] = [
|
111
|
+
StandardPrefixes.KILO,
|
112
|
+
StandardPrefixes.MEGA,
|
113
|
+
StandardPrefixes.GIGA,
|
114
|
+
StandardPrefixes.MILLI,
|
115
|
+
StandardPrefixes.MICRO,
|
116
|
+
]
|
117
|
+
|
118
|
+
COMMON_PRESSURE_PREFIXES: list[StandardPrefixes] = [
|
119
|
+
StandardPrefixes.KILO,
|
120
|
+
StandardPrefixes.MEGA,
|
121
|
+
StandardPrefixes.GIGA,
|
122
|
+
]
|
123
|
+
|
124
|
+
|
125
|
+
# Lookup dictionaries for fast prefix searches
|
126
|
+
_NAME_TO_PREFIX: dict[str, SIPrefix] = {}
|
127
|
+
_SYMBOL_TO_PREFIX: dict[str, SIPrefix] = {}
|
128
|
+
_FACTOR_TO_PREFIX: dict[float, SIPrefix] = {}
|
129
|
+
|
130
|
+
|
131
|
+
def _initialize_lookup_caches() -> None:
|
132
|
+
"""Initialize lookup caches for fast prefix lookups."""
|
133
|
+
for prefix_enum in StandardPrefixes:
|
134
|
+
prefix = prefix_enum.value
|
135
|
+
_NAME_TO_PREFIX[prefix.name] = prefix
|
136
|
+
_SYMBOL_TO_PREFIX[prefix.symbol] = prefix
|
137
|
+
_FACTOR_TO_PREFIX[prefix.factor] = prefix
|
138
|
+
|
139
|
+
|
140
|
+
def get_prefix_by_name(name: str) -> SIPrefix | None:
|
141
|
+
"""Get a prefix by its name (e.g., 'kilo', 'milli')."""
|
142
|
+
return _NAME_TO_PREFIX.get(name)
|
143
|
+
|
144
|
+
|
145
|
+
def get_prefix_by_symbol(symbol: str) -> SIPrefix | None:
|
146
|
+
"""Get a prefix by its symbol (e.g., 'k', 'm')."""
|
147
|
+
return _SYMBOL_TO_PREFIX.get(symbol)
|
148
|
+
|
149
|
+
|
150
|
+
def get_prefix_by_factor(factor: float, tolerance: float = PREFIX_LOOKUP_TOLERANCE) -> SIPrefix | None:
|
151
|
+
"""Get a prefix by its multiplication factor."""
|
152
|
+
# Check for exact match first
|
153
|
+
if factor in _FACTOR_TO_PREFIX:
|
154
|
+
return _FACTOR_TO_PREFIX[factor]
|
155
|
+
|
156
|
+
# Search with tolerance if meaningful
|
157
|
+
if tolerance > PREFIX_LOOKUP_MIN_TOLERANCE:
|
158
|
+
for cached_factor, prefix in _FACTOR_TO_PREFIX.items():
|
159
|
+
if abs(cached_factor - factor) < tolerance:
|
160
|
+
return prefix
|
161
|
+
return None
|
162
|
+
|
163
|
+
|
164
|
+
def extract_prefix_values(prefix_enums: list[StandardPrefixes]) -> list[SIPrefix]:
|
165
|
+
"""Extract SIPrefix values from StandardPrefixes enums."""
|
166
|
+
return [prefix_enum.value for prefix_enum in prefix_enums]
|
167
|
+
|
168
|
+
|
169
|
+
# Units that should get automatic prefixes
|
170
|
+
PREFIXABLE_UNITS: dict[str, list[StandardPrefixes]] = {
|
171
|
+
# Base SI units
|
172
|
+
"meter": COMMON_LENGTH_PREFIXES,
|
173
|
+
"gram": COMMON_MASS_PREFIXES,
|
174
|
+
"second": COMMON_TIME_PREFIXES,
|
175
|
+
"ampere": COMMON_ELECTRIC_PREFIXES,
|
176
|
+
"kelvin": [], # Temperature usually doesn't use prefixes
|
177
|
+
"mole": [StandardPrefixes.MILLI, StandardPrefixes.MICRO],
|
178
|
+
"candela": [], # Luminous intensity rarely uses prefixes
|
179
|
+
# Derived SI units
|
180
|
+
"pascal": COMMON_PRESSURE_PREFIXES,
|
181
|
+
"joule": COMMON_ENERGY_PREFIXES,
|
182
|
+
"watt": COMMON_POWER_PREFIXES,
|
183
|
+
"coulomb": COMMON_ELECTRIC_PREFIXES,
|
184
|
+
"volt": COMMON_ELECTRIC_PREFIXES,
|
185
|
+
"farad": [StandardPrefixes.MILLI, StandardPrefixes.MICRO, StandardPrefixes.NANO, StandardPrefixes.PICO],
|
186
|
+
"ohm": [StandardPrefixes.KILO, StandardPrefixes.MEGA, StandardPrefixes.MILLI],
|
187
|
+
"siemens": [StandardPrefixes.MILLI, StandardPrefixes.MICRO],
|
188
|
+
"weber": [StandardPrefixes.MILLI, StandardPrefixes.MICRO],
|
189
|
+
"tesla": [StandardPrefixes.MILLI, StandardPrefixes.MICRO, StandardPrefixes.NANO],
|
190
|
+
"henry": [StandardPrefixes.MILLI, StandardPrefixes.MICRO, StandardPrefixes.NANO],
|
191
|
+
"lumen": [],
|
192
|
+
"lux": [],
|
193
|
+
"becquerel": [StandardPrefixes.KILO, StandardPrefixes.MEGA, StandardPrefixes.GIGA],
|
194
|
+
"gray": [StandardPrefixes.MILLI, StandardPrefixes.MICRO],
|
195
|
+
"sievert": [StandardPrefixes.MILLI, StandardPrefixes.MICRO],
|
196
|
+
"hertz": [StandardPrefixes.KILO, StandardPrefixes.MEGA, StandardPrefixes.GIGA],
|
197
|
+
"newton": [StandardPrefixes.KILO, StandardPrefixes.MILLI],
|
198
|
+
"bar": [StandardPrefixes.MILLI], # Common non-SI unit
|
199
|
+
"liter": [StandardPrefixes.MILLI, StandardPrefixes.MICRO], # Common non-SI unit
|
200
|
+
}
|
201
|
+
|
202
|
+
# Initialize lookup caches on module load
|
203
|
+
_initialize_lookup_caches()
|
@@ -7,23 +7,24 @@ Unit definitions, constants and registry for the high-performance unit system.
|
|
7
7
|
|
8
8
|
from dataclasses import dataclass
|
9
9
|
|
10
|
-
from
|
10
|
+
from ..dimensions import DimensionSignature
|
11
11
|
from .prefixes import SIPrefix, StandardPrefixes
|
12
12
|
|
13
13
|
|
14
|
-
@dataclass(frozen=True)
|
14
|
+
@dataclass(frozen=True, slots=True)
|
15
15
|
class UnitDefinition:
|
16
|
-
"""Immutable unit definition
|
16
|
+
"""Immutable unit definition for the unit system."""
|
17
|
+
|
17
18
|
name: str
|
18
19
|
symbol: str
|
19
20
|
dimension: DimensionSignature
|
20
21
|
si_factor: float
|
21
22
|
si_offset: float = 0.0
|
22
23
|
base_unit_name: str | None = None # Base unit without prefix
|
23
|
-
prefix: SIPrefix | None = None
|
24
|
-
|
24
|
+
prefix: SIPrefix | None = None # SI prefix if applicable
|
25
|
+
|
25
26
|
@classmethod
|
26
|
-
def with_prefix(cls, base_def:
|
27
|
+
def with_prefix(cls, base_def: "UnitDefinition", prefix: SIPrefix) -> "UnitDefinition":
|
27
28
|
"""Create a new unit definition with an SI prefix."""
|
28
29
|
return cls(
|
29
30
|
name=prefix.apply_to_name(base_def.name),
|
@@ -32,80 +33,82 @@ class UnitDefinition:
|
|
32
33
|
si_factor=base_def.si_factor * prefix.factor,
|
33
34
|
si_offset=base_def.si_offset,
|
34
35
|
base_unit_name=base_def.name,
|
35
|
-
prefix=prefix
|
36
|
+
prefix=prefix,
|
36
37
|
)
|
37
38
|
|
38
39
|
|
39
40
|
class UnitConstant:
|
40
|
-
"""Unit constant that provides type safety
|
41
|
-
|
41
|
+
"""Unit constant that provides type safety."""
|
42
|
+
|
43
|
+
__slots__ = ("definition", "name", "symbol", "dimension", "si_factor", "_hash_cache")
|
44
|
+
|
42
45
|
def __init__(self, definition: UnitDefinition):
|
43
46
|
self.definition = definition
|
44
47
|
self.name = definition.name
|
45
48
|
self.symbol = definition.symbol
|
46
49
|
self.dimension = definition.dimension
|
47
50
|
self.si_factor = definition.si_factor
|
48
|
-
|
49
|
-
|
51
|
+
self._hash_cache = hash(self.name)
|
52
|
+
|
53
|
+
def __str__(self) -> str:
|
50
54
|
return self.symbol
|
51
|
-
|
52
|
-
def __eq__(self, other):
|
53
|
-
"""
|
55
|
+
|
56
|
+
def __eq__(self, other) -> bool:
|
57
|
+
"""Equality check for unit constants."""
|
54
58
|
return isinstance(other, UnitConstant) and self.name == other.name
|
55
|
-
|
56
|
-
def __hash__(self):
|
59
|
+
|
60
|
+
def __hash__(self) -> int:
|
57
61
|
"""Enable unit constants as dictionary keys."""
|
58
|
-
return
|
62
|
+
return self._hash_cache
|
59
63
|
|
60
64
|
|
61
|
-
class
|
62
|
-
"""
|
63
|
-
|
65
|
+
class Registry:
|
66
|
+
"""Unit registry with pre-computed conversion tables."""
|
67
|
+
|
68
|
+
__slots__ = ("units", "conversion_table", "dimensional_groups", "_finalized", "base_units", "prefixable_units", "_conversion_cache", "_dimension_cache")
|
69
|
+
|
64
70
|
def __init__(self):
|
65
71
|
self.units: dict[str, UnitDefinition] = {}
|
66
72
|
self.conversion_table: dict[tuple[str, str], float] = {} # (from_unit, to_unit) -> factor
|
67
73
|
self.dimensional_groups: dict[int | float, list[UnitDefinition]] = {}
|
68
|
-
self._dimension_cache: dict[int | float, UnitConstant] = {} # Cache for common dimension mappings
|
69
74
|
self._finalized = False
|
70
75
|
self.base_units: dict[str, UnitDefinition] = {} # Track base units for prefix generation
|
71
76
|
self.prefixable_units: set[str] = set() # Track which units can have prefixes
|
77
|
+
# Cache for frequently used conversions
|
78
|
+
self._conversion_cache: dict[tuple[str, str], float] = {}
|
79
|
+
# Cache for common dimension mappings
|
80
|
+
self._dimension_cache: dict[int | float, UnitConstant] = {}
|
72
81
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
def register_unit(self, unit_def: UnitDefinition):
|
82
|
+
def register_unit(self, unit_def: UnitDefinition) -> None:
|
77
83
|
"""Register a single unit definition."""
|
78
84
|
if self._finalized:
|
79
85
|
raise RuntimeError("Cannot register units after registry is finalized")
|
80
|
-
|
86
|
+
|
81
87
|
self.units[unit_def.name] = unit_def
|
82
|
-
|
88
|
+
|
83
89
|
# Group by dimension
|
84
90
|
dim_sig = unit_def.dimension._signature
|
85
|
-
if dim_sig
|
86
|
-
self.dimensional_groups[dim_sig]
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
unit_def: UnitDefinition,
|
92
|
-
prefixes: list[StandardPrefixes] | None = None
|
93
|
-
):
|
91
|
+
if dim_sig in self.dimensional_groups:
|
92
|
+
self.dimensional_groups[dim_sig].append(unit_def)
|
93
|
+
else:
|
94
|
+
self.dimensional_groups[dim_sig] = [unit_def]
|
95
|
+
|
96
|
+
def register_with_prefixes(self, unit_def: UnitDefinition, prefixes: list[StandardPrefixes] | None = None) -> None:
|
94
97
|
"""
|
95
98
|
Register a unit and automatically generate prefixed variants.
|
96
|
-
|
99
|
+
|
97
100
|
Args:
|
98
101
|
unit_def: The base unit definition
|
99
102
|
prefixes: List of StandardPrefixes enum values to apply. If None, uses common prefixes.
|
100
103
|
"""
|
101
104
|
if self._finalized:
|
102
105
|
raise RuntimeError("Cannot register units after registry is finalized")
|
103
|
-
|
106
|
+
|
104
107
|
# Register base unit
|
105
108
|
self.register_unit(unit_def)
|
106
109
|
self.base_units[unit_def.name] = unit_def
|
107
110
|
self.prefixable_units.add(unit_def.name)
|
108
|
-
|
111
|
+
|
109
112
|
# Generate and register prefixed variants
|
110
113
|
if prefixes:
|
111
114
|
for prefix_enum in prefixes:
|
@@ -113,37 +116,62 @@ class HighPerformanceRegistry:
|
|
113
116
|
if prefix.name: # Skip NONE prefix (empty name)
|
114
117
|
prefixed_unit = UnitDefinition.with_prefix(unit_def, prefix)
|
115
118
|
self.register_unit(prefixed_unit)
|
116
|
-
|
117
|
-
def finalize_registration(self):
|
119
|
+
|
120
|
+
def finalize_registration(self) -> None:
|
118
121
|
"""Called after all units registered to precompute conversions."""
|
119
122
|
if not self._finalized:
|
120
123
|
self._precompute_conversions()
|
121
124
|
self._finalized = True
|
122
125
|
|
123
|
-
def _precompute_conversions(self):
|
124
|
-
"""Pre-compute all unit conversions for
|
125
|
-
self.conversion_table.clear()
|
126
|
+
def _precompute_conversions(self) -> None:
|
127
|
+
"""Pre-compute all unit conversions for fast lookup."""
|
128
|
+
self.conversion_table.clear()
|
129
|
+
self._conversion_cache.clear()
|
130
|
+
|
126
131
|
for group in self.dimensional_groups.values():
|
132
|
+
if len(group) <= 1:
|
133
|
+
continue # Skip groups with single units
|
134
|
+
|
135
|
+
# Compute conversion factors for all unit pairs
|
127
136
|
for from_unit in group:
|
128
137
|
for to_unit in group:
|
129
138
|
if from_unit != to_unit:
|
130
139
|
factor = from_unit.si_factor / to_unit.si_factor
|
131
|
-
|
132
|
-
|
133
|
-
|
140
|
+
self.conversion_table[(from_unit.name, to_unit.name)] = factor
|
141
|
+
|
134
142
|
def convert(self, value: float, from_unit: UnitConstant, to_unit: UnitConstant) -> float:
|
135
|
-
"""
|
136
|
-
|
143
|
+
"""Convert a value between units with optimized lookups."""
|
144
|
+
# ULTRA-FAST PATH: Same unit - no conversion needed (most common case)
|
145
|
+
if from_unit.name == to_unit.name:
|
137
146
|
return value
|
138
|
-
|
139
|
-
#
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
#
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
147
|
+
|
148
|
+
# OPTIMIZATION: Extract names once to avoid repeated attribute access
|
149
|
+
from_name = from_unit.name
|
150
|
+
to_name = to_unit.name
|
151
|
+
key = (from_name, to_name)
|
152
|
+
|
153
|
+
# STREAMLINED CACHE: Direct dictionary access with batched operations
|
154
|
+
conversion_cache = self._conversion_cache
|
155
|
+
if key in conversion_cache:
|
156
|
+
return value * conversion_cache[key]
|
157
|
+
|
158
|
+
# OPTIMIZED LOOKUP: Direct table access
|
159
|
+
conversion_table = self.conversion_table
|
160
|
+
if key in conversion_table:
|
161
|
+
factor = conversion_table[key]
|
162
|
+
# Cache frequently used conversions - direct assignment for speed
|
163
|
+
if len(conversion_cache) < 50:
|
164
|
+
conversion_cache[key] = factor
|
165
|
+
return value * factor
|
166
|
+
|
167
|
+
# FAST FALLBACK: Direct SI factor calculation with caching
|
168
|
+
from_si = from_unit.si_factor
|
169
|
+
to_si = to_unit.si_factor
|
170
|
+
factor = from_si / to_si
|
171
|
+
if len(conversion_cache) < 50:
|
172
|
+
conversion_cache[key] = factor
|
173
|
+
return value * factor
|
174
|
+
|
175
|
+
|
176
|
+
# Global unit registry
|
177
|
+
registry = Registry()
|
qnty/utils/__init__.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
"""Shared utilities and helper functions."""
|
2
|
+
|
3
|
+
from .protocols import ExpressionProtocol, TypeRegistry, VariableProtocol, is_expression, is_variable, register_expression_type, register_variable_type
|
4
|
+
from .scope_discovery import ScopeDiscoveryService, discover_variables_from_scope
|
5
|
+
|
6
|
+
__all__ = [
|
7
|
+
"ScopeDiscoveryService",
|
8
|
+
"discover_variables_from_scope",
|
9
|
+
"TypeRegistry",
|
10
|
+
"ExpressionProtocol",
|
11
|
+
"VariableProtocol",
|
12
|
+
"register_expression_type",
|
13
|
+
"register_variable_type",
|
14
|
+
"is_expression",
|
15
|
+
"is_variable",
|
16
|
+
]
|
@@ -0,0 +1,23 @@
|
|
1
|
+
"""
|
2
|
+
Caching utilities for the qnty library.
|
3
|
+
|
4
|
+
Provides centralized cache management for improved performance and memory efficiency.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .manager import (
|
8
|
+
CacheStats,
|
9
|
+
UnifiedCacheManager,
|
10
|
+
clear_all_caches,
|
11
|
+
get_cache_manager,
|
12
|
+
get_cache_statistics,
|
13
|
+
get_memory_usage,
|
14
|
+
)
|
15
|
+
|
16
|
+
__all__ = [
|
17
|
+
"UnifiedCacheManager",
|
18
|
+
"CacheStats",
|
19
|
+
"get_cache_manager",
|
20
|
+
"clear_all_caches",
|
21
|
+
"get_cache_statistics",
|
22
|
+
"get_memory_usage",
|
23
|
+
]
|