unitforge 0.4.0__tar.gz → 0.4.1__tar.gz

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 (87) hide show
  1. {unitforge-0.4.0 → unitforge-0.4.1}/Cargo.lock +2 -2
  2. {unitforge-0.4.0 → unitforge-0.4.1}/Cargo.toml +2 -2
  3. {unitforge-0.4.0 → unitforge-0.4.1}/PKG-INFO +1 -1
  4. {unitforge-0.4.0 → unitforge-0.4.1}/src/impl_macros.rs +17 -0
  5. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities.template.rs +29 -0
  6. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/runtime_quantity.rs +51 -2
  7. {unitforge-0.4.0 → unitforge-0.4.1}/tests/test_quantities.py +5 -0
  8. {unitforge-0.4.0 → unitforge-0.4.1}/unitforge_macros/Cargo.toml +1 -1
  9. {unitforge-0.4.0 → unitforge-0.4.1}/unitforge_macros/src/lib.rs +11 -2
  10. {unitforge-0.4.0 → unitforge-0.4.1}/.gitignore +0 -0
  11. {unitforge-0.4.0 → unitforge-0.4.1}/.gitlab-ci.yml +0 -0
  12. {unitforge-0.4.0 → unitforge-0.4.1}/Readme.md +0 -0
  13. {unitforge-0.4.0 → unitforge-0.4.1}/Readme_py.md +0 -0
  14. {unitforge-0.4.0 → unitforge-0.4.1}/install_hooks.sh +0 -0
  15. {unitforge-0.4.0 → unitforge-0.4.1}/pyproject.toml +0 -0
  16. {unitforge-0.4.0 → unitforge-0.4.1}/python/unitforge/__init__.py +0 -0
  17. {unitforge-0.4.0 → unitforge-0.4.1}/python/unitforge/__init__.pyi +0 -0
  18. {unitforge-0.4.0 → unitforge-0.4.1}/python/unitforge/py.typed +0 -0
  19. {unitforge-0.4.0 → unitforge-0.4.1}/scripts/generate_python_stubs.py +0 -0
  20. {unitforge-0.4.0 → unitforge-0.4.1}/src/internal.rs +0 -0
  21. {unitforge-0.4.0 → unitforge-0.4.1}/src/lib.rs +0 -0
  22. {unitforge-0.4.0 → unitforge-0.4.1}/src/prelude.rs +0 -0
  23. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/acceleration.rs +0 -0
  24. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/angle.rs +0 -0
  25. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/angular_acceleration.rs +0 -0
  26. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/angular_velocity.rs +0 -0
  27. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/area.rs +0 -0
  28. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/area_of_moment.rs +0 -0
  29. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/charge.rs +0 -0
  30. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/compliance.rs +0 -0
  31. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/density.rs +0 -0
  32. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/distance.rs +0 -0
  33. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force.rs +0 -0
  34. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_area.rs +0 -0
  35. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_distance.rs +0 -0
  36. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_div_distance_power_four.rs +0 -0
  37. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_per_volume.rs +0 -0
  38. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_stress.rs +0 -0
  39. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/force_volume.rs +0 -0
  40. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/inverse_angle.rs +0 -0
  41. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/inverse_area.rs +0 -0
  42. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/inverse_distance.rs +0 -0
  43. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/inverse_stress.rs +0 -0
  44. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/mass.rs +0 -0
  45. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/mass_div_time_squared_volume.rs +0 -0
  46. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/mass_per_distance.rs +0 -0
  47. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/rotational_stiffness.rs +0 -0
  48. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/stiffness.rs +0 -0
  49. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/strain.rs +0 -0
  50. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/stress.rs +0 -0
  51. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/stress_squared.rs +0 -0
  52. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/time.rs +0 -0
  53. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/velocity.rs +0 -0
  54. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/velocity_squared.rs +0 -0
  55. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/voltage.rs +0 -0
  56. {unitforge-0.4.0 → unitforge-0.4.1}/src/quantities/volume.rs +0 -0
  57. {unitforge-0.4.0 → unitforge-0.4.1}/src/relations.rs +0 -0
  58. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/bindings/matrix3_py.template.rs +0 -0
  59. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/bindings/vector3_py.template.rs +0 -0
  60. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/matrix2.rs +0 -0
  61. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/matrix2x3.rs +0 -0
  62. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/matrix3.rs +0 -0
  63. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/matrix3x2.rs +0 -0
  64. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/vector2.rs +0 -0
  65. {unitforge-0.4.0 → unitforge-0.4.1}/src/small_linalg/vector3.rs +0 -0
  66. {unitforge-0.4.0 → unitforge-0.4.1}/test.sh +0 -0
  67. {unitforge-0.4.0 → unitforge-0.4.1}/tests/common/mod.rs +0 -0
  68. {unitforge-0.4.0 → unitforge-0.4.1}/tests/matrix2.rs +0 -0
  69. {unitforge-0.4.0 → unitforge-0.4.1}/tests/matrix2x3.rs +0 -0
  70. {unitforge-0.4.0 → unitforge-0.4.1}/tests/matrix3.rs +0 -0
  71. {unitforge-0.4.0 → unitforge-0.4.1}/tests/matrix3x2.rs +0 -0
  72. {unitforge-0.4.0 → unitforge-0.4.1}/tests/ndarray_dot.rs +0 -0
  73. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantities.rs +0 -0
  74. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/construction.rs +0 -0
  75. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/enum_iter.rs +0 -0
  76. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/metadata.rs +0 -0
  77. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/normalization.rs +0 -0
  78. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/relations.rs +0 -0
  79. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core/scalar_edges.rs +0 -0
  80. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_core.rs +0 -0
  81. {unitforge-0.4.0 → unitforge-0.4.1}/tests/quantity_serde.rs +0 -0
  82. {unitforge-0.4.0 → unitforge-0.4.1}/tests/small_linalg_edge_cases.rs +0 -0
  83. {unitforge-0.4.0 → unitforge-0.4.1}/tests/small_linalg_interfaces.rs +0 -0
  84. {unitforge-0.4.0 → unitforge-0.4.1}/tests/test_small_linalg.py +0 -0
  85. {unitforge-0.4.0 → unitforge-0.4.1}/tests/typecheck/mypy_smoke.py +0 -0
  86. {unitforge-0.4.0 → unitforge-0.4.1}/tests/vector2.rs +0 -0
  87. {unitforge-0.4.0 → unitforge-0.4.1}/tests/vector3.rs +0 -0
@@ -369,7 +369,7 @@ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
369
369
 
370
370
  [[package]]
371
371
  name = "unitforge"
372
- version = "0.4.0"
372
+ version = "0.4.1"
373
373
  dependencies = [
374
374
  "ndarray",
375
375
  "num-traits",
@@ -384,7 +384,7 @@ dependencies = [
384
384
 
385
385
  [[package]]
386
386
  name = "unitforge_macros"
387
- version = "0.4.0"
387
+ version = "0.4.1"
388
388
  dependencies = [
389
389
  "regex",
390
390
  ]
@@ -4,7 +4,7 @@ crate-type = ["cdylib", "rlib"]
4
4
 
5
5
  [package]
6
6
  name = "unitforge"
7
- version = "0.4.0"
7
+ version = "0.4.1"
8
8
  edition = "2021"
9
9
  authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
10
10
  description = "A library for unit and quantity consistent computations in Rust"
@@ -23,7 +23,7 @@ pyo3 = { version = "0.26.0", features = ["extension-module", "auto-initialize",
23
23
  numpy = { version = "0.26.0", optional = true }
24
24
  strum = { version = "0.28.0", optional = true }
25
25
  strum_macros = { version = "0.28.0", optional = true }
26
- unitforge_macros = { version = "0.4.0", path = "unitforge_macros" }
26
+ unitforge_macros = { version = "0.4.1", path = "unitforge_macros" }
27
27
 
28
28
  [features]
29
29
  serde = ["dep:serde", "dep:serde_json", "ndarray/serde"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: unitforge
3
- Version: 0.4.0
3
+ Version: 0.4.1
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -275,6 +275,23 @@ macro_rules! impl_quantity {
275
275
  fn __rmul__(&self, rhs: f64) -> PyResult<Self> {
276
276
  Ok(*self * rhs)
277
277
  }
278
+
279
+ fn __pow__(
280
+ lhs: PyRef<Self>,
281
+ rhs: i32,
282
+ _modulo: Option<Py<PyAny>>,
283
+ ) -> PyResult<Py<PyAny>> {
284
+ let py = lhs.py();
285
+ let lhs_ref = lhs.into_pyobject(py)?;
286
+ let lhs_quantity = Quantity::from_py_any(&lhs_ref)
287
+ .map_err(|e| PyValueError::new_err(e.to_string()))?;
288
+ match lhs_quantity.powi(rhs) {
289
+ Ok(value) => Ok(value.to_pyobject(py)?),
290
+ Err(_) => Err(PyValueError::new_err(
291
+ "Power of given object is not possible.",
292
+ )),
293
+ }
294
+ }
278
295
  }
279
296
 
280
297
  impl fmt::Display for $type {
@@ -12,6 +12,7 @@ pub enum QuantityOperationError {
12
12
  SubError,
13
13
  MulError,
14
14
  DivError,
15
+ PowError,
15
16
  SqrtError,
16
17
  ComparisonError,
17
18
  }
@@ -23,6 +24,7 @@ impl fmt::Display for QuantityOperationError {
23
24
  QuantityOperationError::SubError => write!(f, "Subtraction operation failed"),
24
25
  QuantityOperationError::MulError => write!(f, "Multiplication operation failed"),
25
26
  QuantityOperationError::DivError => write!(f, "Division operation failed"),
27
+ QuantityOperationError::PowError => write!(f, "Power operation failed"),
26
28
  QuantityOperationError::SqrtError => write!(f, "Sqrt operation failed"),
27
29
  QuantityOperationError::ComparisonError => write!(f, "Comparison operation failed"),
28
30
  }
@@ -171,6 +173,33 @@ impl Quantity {
171
173
  _=> Err(QuantityOperationError::SqrtError)
172
174
  }
173
175
  }
176
+
177
+ pub fn reciprocal(&self) -> Result<Self, QuantityOperationError> {
178
+ match self {
179
+ Quantity::FloatQuantity(v) => Ok(Self::FloatQuantity(1.0 / v)),
180
+ // __QUANTITY_RECIPROCALS__
181
+ _ => Err(QuantityOperationError::PowError),
182
+ }
183
+ }
184
+
185
+ pub fn powi(&self, exponent: i32) -> Result<Self, QuantityOperationError> {
186
+ if exponent == 0 {
187
+ return Ok(Self::FloatQuantity(1.0));
188
+ }
189
+
190
+ let base = if exponent < 0 {
191
+ self.reciprocal()?
192
+ } else {
193
+ *self
194
+ };
195
+ let mut result = base;
196
+
197
+ for _ in 1..exponent.unsigned_abs() {
198
+ result = (result * base).map_err(|_| QuantityOperationError::PowError)?;
199
+ }
200
+
201
+ Ok(result)
202
+ }
174
203
  }
175
204
 
176
205
  impl PartialOrd for Quantity {
@@ -1,7 +1,8 @@
1
1
  use crate::common::approx_eq;
2
2
  use unitforge::{
3
- Distance, DistanceUnit, Force, ForceDistanceUnit, ForceUnit, Mass, MassUnit, Quantity,
4
- PhysicsQuantity, StiffnessUnit, Unit,
3
+ AreaUnit, Distance, DistanceUnit, Force, ForceDistanceUnit, ForceUnit, InverseAreaUnit,
4
+ InverseDistanceUnit, Mass, MassUnit, PhysicsQuantity, Quantity, StiffnessUnit, Unit,
5
+ VolumeUnit,
5
6
  };
6
7
 
7
8
  #[test]
@@ -168,6 +169,54 @@ fn sqrt_rejects_non_square_quantity() {
168
169
  assert!(quantity.sqrt().is_err());
169
170
  }
170
171
 
172
+ #[test]
173
+ fn powi_builds_higher_order_quantity_when_relations_exist() {
174
+ let quantity = Quantity::DistanceQuantity(Distance::new(2.0, DistanceUnit::m));
175
+
176
+ let squared = quantity.powi(2).unwrap();
177
+ let cubed = quantity.powi(3).unwrap();
178
+
179
+ assert!(approx_eq(
180
+ squared.to(Unit::AreaUnit(AreaUnit::msq)).unwrap(),
181
+ 4.0,
182
+ 1e-10
183
+ ));
184
+ assert!(approx_eq(
185
+ cubed.to(Unit::VolumeUnit(VolumeUnit::mcb)).unwrap(),
186
+ 8.0,
187
+ 1e-10
188
+ ));
189
+ }
190
+
191
+ #[test]
192
+ fn powi_builds_inverse_quantity_when_relations_exist() {
193
+ let quantity = Quantity::DistanceQuantity(Distance::new(2.0, DistanceUnit::m));
194
+
195
+ let inverse = quantity.powi(-1).unwrap();
196
+ let inverse_squared = quantity.powi(-2).unwrap();
197
+
198
+ assert!(approx_eq(
199
+ inverse
200
+ .to(Unit::InverseDistanceUnit(InverseDistanceUnit::_m))
201
+ .unwrap(),
202
+ 0.5,
203
+ 1e-10
204
+ ));
205
+ assert!(approx_eq(
206
+ inverse_squared
207
+ .to(Unit::InverseAreaUnit(InverseAreaUnit::_msq))
208
+ .unwrap(),
209
+ 0.25,
210
+ 1e-10
211
+ ));
212
+ }
213
+
214
+ #[test]
215
+ fn powi_rejects_missing_quantity_relation() {
216
+ let quantity = Quantity::DistanceQuantity(Distance::new(2.0, DistanceUnit::m));
217
+ assert!(quantity.powi(5).is_err());
218
+ }
219
+
171
220
  #[test]
172
221
  fn inf_multiplication() {
173
222
  let distance = Quantity::DistanceQuantity(Distance::new(1.0, DistanceUnit::m));
@@ -31,3 +31,8 @@ def test_force_stress_from_stress_squared_times_area():
31
31
  result = stress_squared * area
32
32
  assert isinstance(result, ForceStress)
33
33
  assert result.to(ForceStressUnit.Nsq_msq) == pytest.approx(6.0)
34
+
35
+ def test_power_operator():
36
+ a = Distance(2., DistanceUnit.mm)
37
+ b = a**2
38
+ assert b == Area(4., AreaUnit.mmsq)
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "unitforge_macros"
3
- version = "0.4.0"
3
+ version = "0.4.1"
4
4
  edition = "2021"
5
5
  authors = ["Dr.Q team <info@askdrq.com>", "Henrik Stromberg <henrik@askdrq.com>"]
6
6
  description = "Proc macros for generating units, quantities, and Python bindings in unitforge"
@@ -339,6 +339,7 @@ fn write_quantity_code(
339
339
  let mut add_matches = String::new();
340
340
  let mut sub_matches = String::new();
341
341
  let mut sqrt_matches = String::new();
342
+ let mut reciprocal_matches = String::new();
342
343
  let mut quantity_kind_id_impls = String::new();
343
344
  let mut unit_kind_id_impls = String::new();
344
345
  let mut unit_variant_id_impls = String::new();
@@ -464,8 +465,15 @@ fn write_quantity_code(
464
465
  for caps in mul_macro_re.captures_iter(content) {
465
466
  let lhs = &caps[1];
466
467
  let rhs = &caps[2];
467
- let mut res = caps[3].to_string();
468
- if res == "f64" {
468
+ let raw_res = &caps[3];
469
+ let mut res = raw_res.to_string();
470
+ if raw_res == "f64" {
471
+ reciprocal_matches += &format!(
472
+ " Quantity::{lhs}Quantity(v) => Ok(Quantity::{rhs}Quantity(<{rhs} as crate::PhysicsQuantity>::from_raw(1.0 / v.as_f64()))),\n",
473
+ );
474
+ reciprocal_matches += &format!(
475
+ " Quantity::{rhs}Quantity(v) => Ok(Quantity::{lhs}Quantity(<{lhs} as crate::PhysicsQuantity>::from_raw(1.0 / v.as_f64()))),\n",
476
+ );
469
477
  res = "Float".to_string();
470
478
  }
471
479
  mul_matches += &format!(
@@ -555,6 +563,7 @@ fn write_quantity_code(
555
563
  .replace("// __ADD_QUANTITY_MATCHES__", &add_matches)
556
564
  .replace("// __SUB_QUANTITY_MATCHES__", &sub_matches)
557
565
  .replace("// __QUANTITY_SQRTS__", &sqrt_matches)
566
+ .replace("// __QUANTITY_RECIPROCALS__", &reciprocal_matches)
558
567
  .replace("// __QUANTITY_KIND_ID_IMPLS__", &quantity_kind_id_impls)
559
568
  .replace("// __UNIT_KIND_ID_IMPLS__", &unit_kind_id_impls)
560
569
  .replace("// __UNIT_VARIANT_ID_IMPLS__", &unit_variant_id_impls)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes