95 Commits

Author SHA1 Message Date
Mateusz Pusz a438594b8c fix: use explicit quantity construction instead of deprecated Rep * reference for offset units (#808)
`round`/`floor`/`ceil` with an integer representation built a one-unit
delta via `representation_values<Rep>::one() * reference`. That operator
is `[[deprecated]]` for offset units (e.g. temperatures) because such a
product is ambiguous between a point and a delta, so calling these
functions on `deg_C`/`deg_F` quantities triggered a deprecation warning
(a hard error under `-Werror=deprecated-declarations`).

Replace the pattern with the explicit two-argument `quantity{value,
reference}` constructor (the delta interpretation, matching what `delta`
does internally) everywhere it appeared:

- `math.h`: `floor`, `ceil`, `round`
- `bits/sudo_cast.h`: the zero-delta used in quantity_point conversions,
  where the reference is genuinely an offset unit for temperature points
- `utility/random.h`: all distributions, whose `Q` is always a delta

Add regression tests exercising `floor`/`ceil`/`round` on integer
`deg_C` deltas (including negatives and round-half-to-even) plus the
originally reported `round<deg_F>(delta<deg_C>(1))` case.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 23:56:57 +02:00
Mateusz Pusz 7a03123a01 refactor(utility): move safe_int and constrained into the mp_units::utility namespace
safe_int, constrained, their error policies, and the safe_iN aliases are
non-framework add-ons, so their public names move out of mp_units into the
mp_units::utility extension tier (next to the representation concepts already
there). The headers move to core/include/mp-units/utility/ accordingly but stay
in the core component: safe_int reuses the core 128-bit integer toolkit
(integral, is_signed_v, int128_t, ...) that also backs the scaling engine, so it
bridges to mp_units::detail with a single using-directive rather than relocating
or duplicating that toolkit. overflow_policies stays framework (it backs bounded
quantity point origins). No deprecation shims: these types are unreleased.

Also fixes utility/representation.h, whose public concepts delegated via the
unqualified detail::X. That resolved to mp_units::detail only as long as
mp_units::utility::detail did not exist; now that constrained/safe_int introduce
it, the references are qualified to ::mp_units::detail:: so they stay
order-independent (this surfaced only in the module build).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 23:58:39 +02:00
Mateusz Pusz ce833d344d refactor(utility): deprecate the mp_units:: rep shims and migrate consumers
The cartesian_vector and random distribution types now live in
mp_units::utility. Turn the transitional mp_units:: shims into proper
[[deprecated]] aliases (gcc-12 keeps a plain using-declaration because
CTAD through a deprecated alias template is broken there), and migrate
all in-tree consumers to mp_units::utility:: so the deprecations don't
trip -Werror. cartesian_tensor keeps no shim: it is unreleased (added in
2.6.0, never shipped), so it lives only at mp_units::utility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 18:55:19 +02:00
Mateusz Pusz 805bb969d2 feat(representation): add embed/project conversions between 2D and 3D cartesian types
`embed` is the canonical inclusion of the plane into space and `project` the
canonical projection back, for both vectors and tensors:
- vector: embed (x,y) -> (x,y,0); project (x,y,z) -> (x,y)
- tensor: embed the 2x2 into the top-left block of a zeroed 3x3; project keeps
  that top-left 2x2 block

They are explicit named free functions (no implicit cross-dimension conversion),
each defined for a single source dimension (embed: 2D only; project: 3D only).
The zero fill is the additive identity derived from a component (`x - x`), so no
value-initialization of the element type is required.

Also route `tensor_product` through `cartesian_tensor_from` instead of a
default-constructed result, matching the other constructing operations (the
element type need not be default-constructible).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:16:14 +02:00
Mateusz Pusz f84e10aef2 feat(representation): parameterize cartesian_vector/tensor on a compile-time dimension N
`cartesian_vector<T, N>` and `cartesian_tensor<T, N>` now take a compile-time
dimension N in {2, 3} (default 3), so a planar model pays nothing for an unused
third component. Operations close at a matching N: tensor_product of two
N-vectors yields an N x N tensor, inner_product(N x N tensor, N-vector) yields
an N-vector, and mixing dimensions is ill-formed. vector_product is the 3D axial
vector for N=3 and the 2D perp-dot (pseudo)scalar for N=2. N is deduced from the
argument count (2/3 components -> 2D/3D vector; 4/9 -> 2x2/3x3 tensor).

Also:
- element conversions build via member initializer lists (no default-construct-
  then-assign), and every constructing tensor operation builds through a new
  cartesian_tensor_from helper instead of a default-constructed result, so the
  element type need not be default-constructible
- a compile-time `extent` query (per-axis count, std::extent semantics) on both,
  usable as both `x.extent` and `x.extent()`

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 22:02:53 +02:00
Mateusz Pusz 3195c7d0eb fix(representation): gate cartesian_vector/tensor element conversions on implicitly_scalable
The converting and variadic constructors (and converting assignment) keyed their implicit/explicit
decision on `std::convertible_to` alone, which let a truncating floating-point -> integer element
conversion (e.g. `cartesian_vector<double>` -> `cartesian_vector<int>`) convert implicitly -
inconsistent with a quantity's rep, where the conversion must also be non-truncating.

Add a `detail::ImplicitlyConvertibleScalar` guard that keeps `std::convertible_to` (an element type
need not be fundamental and may define its own implicit-conversion rules) and defers the
non-truncating decision to the `implicitly_scalable` customization point, passing identical `one`
units so it degenerates to the rep-only decision. Deferring to the CPO rather than hardcoding its
`treat_as_floating_point`-based default keeps element conversions consistent with a user's
`implicitly_scalable` specialization. An FP target or a widening stays implicit; an FP -> integer
element conversion becomes explicit (still constructible). Converting assignment is restricted to the
implicit case for the same reason.

Adds static_assert coverage to the cartesian vector/tensor runtime tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 20:25:25 +02:00
Mateusz Pusz e061bf0ef8 refactor(representation): replace disable_real/NotQuantity with disable_representation
Consolidate the representation opt-outs into one character-agnostic customization
point and align the documentation with the two-axis model.

- Add `disable_representation<T>` in `customization_points.h`: a specializable
  opt-out that bars a type from being a quantity representation regardless of
  character. Its default (`is_quantity_abstraction<value_type_t<T>>`) rejects a
  quantity or quantity-like type, and any container of them; `bool` is opted out
  explicitly. This retires both `disable_real` and the `NotQuantity` guard.
- Rename the internal predicate `is_quantity_like` -> `is_quantity_abstraction`
  (it covers `Quantity || QuantityLike`) so it no longer collides with the
  `QuantityLike` customization family.
- The representation tier now leads with one shared `RepresentationBaseline`
  guard (not opted out + `UnitMagnitudeScalable`), which short-circuits a quantity
  before any character concept instantiates its operators (avoiding a
  satisfaction cycle).
- Docs: restructure `representation_types.md` around the two character axes
  (field via `numeric_field`, order via `tensor_order`) with a common baseline,
  the new `disable_representation` section, and consistent unit-magnitude-aware
  scaling terminology; align `concepts.md` and `using_custom_representation_types.md`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 21:36:07 +02:00
Mateusz Pusz 703235d1d4 refactor(representation): intrinsic order/field traits and two-tier character concepts
Replace the `disable_vector`/`disable_tensor` opt-outs with intrinsic,
adapter-overridable traits and split representation classification into two tiers.

- `customization_points.h` now owns the customizable surface: the `real`/`imag`/
  `modulus` CPOs plus the `numeric_field` (field axis) and `tensor_order` (order
  axis) traits. Adapters specialize these; the derived concepts stay with the
  rest of the concept model in `representation_concepts.h`.
- `numeric_field` is the single source of truth for the field axis (default:
  `real()`/`imag()` API detection). Field matching is exact and disjoint - a real
  quantity needs a real representation and a complex one a complex representation.
- `tensor_order` is detected structurally (two-index access -> 2, one-index -> 1,
  otherwise 0) and overridable. Order matching is rank-ordered: a lower-order
  representation fills a higher-order slot.
- Character concepts (`Real`/`Complex`, rank-ordered `Scalar`/`Vector`/`Tensor`)
  carry no representation-validity, so in V3 they can also classify a quantity by
  its character. The `*Representation` concepts are `NotQuantity`-first + character
  + `UnitMagnitudeScalable`; leading with `NotQuantity` rejects a quantity before
  its operators are instantiated, avoiding a constraint-satisfaction cycle.
- Eigen/Blaze adapters declare `numeric_field` from their element type (they expose
  `real()`/`imag()` on real types too, which the API default would misread as complex).
- Rename `MagnitudeScalable` -> `UnitMagnitudeScalable` and `UsesMagnitudeAwareScaling`
  -> `UsesUnitMagnitudeAwareScaling` to disambiguate scaling by a `unit_magnitude`
  from the value/L2 magnitude (the `magnitude` CPO).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 19:17:05 +02:00
Mateusz Pusz dd5854a965 refactor(test): drop the legacy character enum from the test suite
Replace `using enum quantity_character_legacy` plus bare character names in the ISQ/HEP
tests with local `quantity_character` constants (`scalar`, `complex_scalar`, `vector`,
`tensor`) built from `quantity_tensor_order` / `quantity_field`, and switch the
`RepresentationOf` / `QUANTITY_SPEC_` character arguments in the concept and quantity-spec
tests to the bare-axis spelling. `real_scalar` is renamed to `scalar` for consistency with
the order-named constants. `apparent_power` (derived from the complex `complex_power`)
pins `quantity_field::real`, matching the library definition.

This removes the final legacy-enum usage from the repository.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 00:10:20 +02:00
Mateusz Pusz 2d75493c4b feat: complex vector and tensor support added 2026-06-24 22:52:54 +02:00
Mateusz Pusz b6fab4e2a8 feat(cartesian_tensor): add built-in second-order tensor representation type
Add `cartesian_tensor<T>`, a fixed 3x3 second-order Cartesian tensor that
serves as a representation type for tensor-character quantities (e.g.
`isq::stress`, `isq::strain`, `isq::moment_of_inertia`), which previously had
no instantiable representation. It mirrors the `cartesian_vector` design
(hidden-friend operations in a `*_iface` base, const-qualified operator
constraints, no `operator%`).

Operations follow ISO 80000-2:2019 clause 18 (second order): `+`, `-`, unary
`-`, scalar `*`//`, compound assignments, `==`; `tensor_product` (dyadic of two
vectors, 2-18.21), `inner_product` (tensor.tensor 2-18.23, tensor.vector
2-18.24), `scalar_product` (double-dot `:`, 2-18.25), and a Frobenius norm.
Fourth-order `T(x)S` (2-18.22), `transpose`/`trace`, and `a.T` are intentionally
out of scope for now.

Activate the previously stubbed tensor representation concepts: `Tensor` is a
permissive mirror of `Vector` (a tensor of order zero is a scalar and of order
one is a vector, ISO 80000-2:2019 18), so real scalars and `cartesian_vector`
also satisfy tensor character as degenerate lower-rank cases. A genuine
second-order `cartesian_tensor` opts out of the lower-rank `Vector` concept via
`disable_vector`, and `std::complex` opts out of `Tensor` via `disable_tensor`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 13:45:48 +02:00
Mateusz Pusz 1298be79ca refactor(cartesian_vector): model const operands in operator constraints
Refine the requires-expressions of the `cartesian_vector` operators to
constrain on `const`-qualified operands, matching the fact that the
operators take their arguments by `const` reference. A type whose
`operator+` (etc.) is not const-correct would previously have wrongly
satisfied the constraint.

The compound-assignment constraints are ref-qualified as well (mutable
lhs, const rhs) while keeping the `-> std::same_as<T&>` return-type check.

Also strengthen the unit-vector test to assert the resulting component
values (not just that the norm is 1) and to exercise the free
`unit_vector()` function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 21:50:03 +02:00
Mateusz Pusz 5c8c4ad5ae feat: external linear algebra libraries integrations added + quantity::magnitude() member function
Resolves #301
2026-06-22 18:51:56 +02:00
Mateusz Pusz 1c54623024 feat: import std; enabled for g++ 2026-06-03 21:29:55 +02:00
Mateusz Pusz ff2cb6c516 fix(test): Unicode characters removed from runtime test descriptions 2026-05-25 21:37:59 +02:00
Mateusz Pusz 8f4a13f50f fix: silence MSVC Debug C4702 by giving if constexpr chains an explicit else
MSVC's Debug code generator does not dead-code-eliminate after an `if constexpr`
chain whose branches all return, so the fallthrough `return` after the chain is
flagged C4702 (unreachable) on instantiations where one of the branches is
selected.  Release builds optimize the dead path out and never complain.

Restructure two places so the fallback lives inside an explicit `else` /
returning helper instead of a fallthrough:

  * `enforce_bounds()` (quantity_point.h): wrap the `return q;` fallback in
    `else { return q; }` after the existing `if constexpr` chain.
  * `compare_quantities()` (quantity.h): hoist the floating-point / already-widest
    fallback into a local `fallback_cmp` lambda invoked from both arms of the
    `if constexpr` chain.  Keeps the existing float-equal suppression.

For `CHECK_THROWS_AS` in constrained_test.cpp, Catch2's macro expands into a
try/catch whose catch arm becomes unreachable when the body calls a `[[noreturn]]`
function; suppress C4702 around that one TEST_CASE since the macro is not ours
to restructure.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 21:52:39 +02:00
Mateusz Pusz 1ee12968fe fix: wide_product_of is a dead code on platforms with __int128 + missing header for fixed_point_test.cpp 2026-05-24 20:09:58 +02:00
Mateusz Pusz 982fc526c0 feat: 💥 quantity_from_unit_zero() renamed back to quanity_from_zero() and limited to default_point_origin + qp.in(Unit) changes the origin for offset units 2026-05-21 22:46:12 +02:00
Mateusz Pusz 2690296059 feat: quantity_point text output added for default_point_origin 2026-05-21 18:38:09 +02:00
Mateusz Pusz 7c5769d549 test: check_non_negative propagates through relative_point_origin 2026-05-06 22:28:32 +02:00
Mateusz Pusz 0a33e0a0e6 refactor: quantity point bounds are now specified directly in origin - quantity_bounds_for customization point removed 2026-04-25 21:00:31 +02:00
Mateusz Pusz 76a7692180 test: constrained runtime unit tests refactored to SECTIONS 2026-04-11 20:32:39 +02:00
Mateusz Pusz 12300bcd23 feat: safe_int and blog article about it added 2026-04-11 20:30:28 +02:00
Mateusz Pusz 459211fc7a feat: quantity point bounds design finalized 2026-04-03 23:38:47 +02:00
Mateusz Pusz 500046873b feat: two more overflow policies added 2026-03-31 13:52:20 +02:00
Mateusz Pusz 6d555b73bd feat: norm() added to a cartesian_vector 2026-03-11 22:25:08 +01:00
Mateusz Pusz efbc844199 fix: fixed-point arithmetic for integer unit conversions (#580) (#764)
* Fix #580: use fixed-point arithmetic for integer unit conversions

Introduce a fixed-point implementation for unit conversions involving
integer representations, avoiding loss of significant digits that
previously occurred when the conversion factor was not a whole number.

New files:
- src/core/include/mp-units/bits/fixed_point.h: double_width_int<T> and
  fixed_point<T,n> types for exact rational scaling of integer values.
  Uses __int128 when available (__SIZEOF_INT128__) for 64-bit integers.
- src/core/include/mp-units/framework/scaling.h: public scaling_traits<>
  customization point and scale<To>(M, value) free function. Provides
  built-in specializations for floating-point and integer-like types.
- test/static/fixed_point_test.cpp: static assertions for the new types.
- test/runtime/fixed_point_test.cpp: runtime arithmetic edge-case tests.

Modified:
- sudo_cast.h: replace hand-rolled conversion_value_traits / sudo_cast_value
  machinery with a single scale<To::rep>(c_mag, ...) call.
- representation_concepts.h: add MagnitudeScalable concept; replace
  ComplexScalar with HasComplexOperations (which is its definition).
- customization_points.h: add unspecified_rep tag and declare the primary
  scaling_traits<> template.
- framework.h / CMakeLists.txt: wire in the new headers.
- hacks.h: add MP_UNITS_DIAGNOSTIC_IGNORE_PEDANTIC and
  MP_UNITS_DIAGNOSTIC_IGNORE_SIGN_CONVERSION macros.
- example/measurement.cpp: add scaling_traits specializations for
  measurement<T> to demonstrate the customization point.
- test/static/{international,usc}_test.cpp: disable two tests that are
  blocked on issue #614.

Co-authored-by: Tobias Hanhart <burnpanck@users.noreply.github.com>

* Fix value_Type typo in floating_point_scaling_factor_type specialization

The partial specialization for types with a nested value_type used
'value_Type' (capital T) instead of 'value_type', making the entire
specialization dead code as the requires-clause could never be satisfied.

Also fix 'mantiassa' -> 'mantissa' in the adjacent comment.

* Fix docstring typos in scaling_traits documentation

- 'quantitiy' -> 'quantity'
- 'dictatet' -> 'dictated'
- 'convetrible' -> 'convertible'
- 'implemenation' -> 'implementation'
- 'availabe' -> 'available'

* Fix conflict resolution error: keep ComplexScalar name from master

When resolving the merge conflict in representation_concepts.h, the
PR's renamed version of the concept ('HasComplexOperations') was used
instead of master's established name ('ComplexScalar'). The two concepts
are semantically equivalent — burnpanck simply renamed it in his branch.

Revert to the canonical 'ComplexScalar' name while retaining the new
'MagnitudeScalable' concept which was the actual addition from the PR.

* Fix measurement.cpp: remove duplicate class definition from merge

The PR branched from a version where measurement<T> was defined inline
in measurement.cpp. Master later moved the class to example/include/
measurement.h and changed measurement.cpp to #include that header.

The squash merge therefore introduced a duplicate definition: the class
from the header and the PR's inline class were both visible, causing
an 'ambiguous reference' error. Remove the now-redundant inline class;
the scaling_traits specializations added by the PR work correctly with
the class from measurement.h.

* style: pre-commit

* docs: chapters anchors improved in the "custom representation" chapter

* docs: value conversions chapter improved

* refactor: scaling support refactored

* fix: clang-16 crash fixed

* docs: `measurement` example documentation updated to match changes

* fix: use exact wide-integer arithmetic for rational unit conversions on all platforms

On ARM / Apple Silicon, long double == double (64-bit mantissa).  The old
fixed_point<T>(long double) initialiser lost ~12 bits of precision for 64-bit
integer types when representing the scaling ratio, producing an error of ~49
units for the 10/9 (degree → gradian) conversion with a 10^18 input value.

Fix by splitting the integer-path else-branch into two cases:

  • Pure rational M (is_integral(M * (denominator(M) / numerator(M))) == true):
    use (value * numerator) / denominator via double_width_int_for_t<> arithmetic.
    This is exact on every platform regardless of long double width.

  • Irrational M (involves π etc.): keep the long double fixed_point approximation.
    These conversions are inherently approximate; small values still produce correct
    truncated results on all platforms.

Update the test comment to reflect the new exact-arithmetic path.

Fixes CI failures on clang-18/ARM and apple-clang-16.

* fix: replace floating-point TeX-point test with exact integer equivalent

72.27 is not exactly representable as double (it rounds to 72.2699...96).
Multiplying by the conversion factor 100/7227 via long double gives a result
≥ 1.0 on x86 (80-bit long double, 64-bit mantissa) only by chance, but
0.99999...978 on ARM / Apple Silicon where long double == double (52-bit).

The correct mathematical statement is: 7227 tex_point = 100 inch (exact
rational relationship).  Use that integer form instead of the inexact 72.27
double literal so the test is correct and platform-independent.

---------

Co-authored-by: Tobias Hanhart <burnpanck@users.noreply.github.com>
2026-03-07 21:02:37 +01:00
Mateusz Pusz 9a374a5646 refactor: isq::time swapped with isq::duration 2026-01-09 09:22:37 +01:00
Mateusz Pusz 6d10a154fa feat: 💥 pi and π is now a unit constant (pi magnitude constant renamed to pi_c) 2025-12-28 13:35:54 +01:00
Roth Michaels 507b2dbd0d fix: enable runtime usage of inverse function by using compile-time unit extraction
Replace runtime unit access (q.unit) with compile-time type extraction
(get_unit(R)) in the inverse function implementation. This prevents the
function from becoming an immediate function when consteval unit operators
are used, allowing inverse to work with runtime variables.

Key changes:
- math.h: Use get_unit(R) instead of q.unit in both code paths
- test: Add comprehensive runtime inverse tests

This surgical fix preserves maximum compile-time optimization while
enabling DSP applications that need runtime inverse calculations.

Fixes compilation error with Clang:
"call to immediate function 'inverse' is not a constant expression"

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 09:07:08 +00:00
Mateusz Pusz 2a2a53d5e8 build: projectPrefix CMake variable removed 2025-11-02 15:08:20 -08:00
Mateusz Pusz 37dfa39dba build: wg21-linear_algebra dependency removed 2025-07-11 16:59:13 +02:00
Mateusz Pusz 35798a0f39 refactor: ostream.h header file made deprecated 2025-06-20 10:40:10 +02:00
Mateusz Pusz 50c05bddb3 refactor: format.h header file made deprecated 2025-06-20 09:06:49 +02:00
Mateusz Pusz 5a0e350be7 feat: lerp and midpoint for points added 2025-02-13 14:26:51 +01:00
Mateusz Pusz 47a82f466c refactor: scalar and complex renamed to real_scalar and complex_scalar respectively + concepts refactoring + electromagnetism fixes 2025-02-11 17:26:19 +01:00
Mateusz Pusz 88439828a5 feat: std::numeric_limits support added
Resolves #408
2025-02-05 18:04:43 +01:00
Mateusz Pusz 0b14d69539 feat: quantity::one() removed
Related to #408
2025-02-05 12:08:32 +01:00
Mateusz Pusz 465f88d500 refactor: 💥 is_XXX customization points for representation types removed 2024-11-26 14:48:08 +01:00
Mateusz Pusz 0c09008671 fix: clang is too stupid to provide a deprecation warning for text_encoding 2024-11-21 11:25:57 +01:00
Mateusz Pusz 2cf64f20c5 fix: cartesian_vector convertibility tests fixed 2024-11-14 20:40:08 +01:00
Mateusz Pusz a7cf015a3e feat: add compound assignment operators to cartesian_vector 2024-11-14 20:38:50 +01:00
Mateusz Pusz 4b5d37e83e feat: constructors of cartesian_vector refactored 2024-11-14 20:30:12 +01:00
Mateusz Pusz 420ffef6c5 fix(test): missing header files added 2024-11-12 18:12:36 +01:00
Mateusz Pusz 73ad1f08d4 fix: fmt_test fixed to use delta to create a quantity of thermodynamic_temperature 2024-11-12 16:20:51 +01:00
Mateusz Pusz 5a206c3ef1 test: cartesian_vector used in fmt_test 2024-11-12 14:38:51 +01:00
Mateusz Pusz 6c3c1fe5f7 feat: cartesian_vector added 2024-11-12 14:34:18 +01:00
Mateusz Pusz d8574022f1 test: _surface tension_ replaced with _entropy_ in an fmt test 2024-11-12 14:21:36 +01:00
Mateusz Pusz c6344c26ee style: missing empty line at the end of the file added 2024-11-12 11:31:26 +01:00
Mateusz Pusz 78204c7e5f test: runtime unit tests refactored to have a bigger granularity (less top level tests) 2024-11-12 11:27:52 +01:00