Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/cmake-multi-platform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ jobs:
c_compiler: clang
cpp_compiler: clang++
build_type: Release
# ── Ubuntu: GCC-14 + ASAN/UBSAN ────────────────
- os: ubuntu-24.04
c_compiler: gcc-14
cpp_compiler: g++-14
build_type: Debug
sanitizers: ON
# ── Windows: MSVC ──────────────────────────────
- os: windows-latest
c_compiler: cl
Expand All @@ -63,6 +69,7 @@ jobs:
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-DNUMSIM_CAS_BUILD_EXAMPLES=ON
-DNUMSIM_CAS_SANITIZERS=${{ matrix.sanitizers || 'OFF' }}
-S ${{ github.workspace }}
- name: Build
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
Expand Down
6 changes: 6 additions & 0 deletions include/numsim_cas/scalar/scalar_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ class scalar_expression : public expression {
const scalar_expression &operator=(scalar_expression const &) = delete;
};

template <class T>
concept scalar_expr_holder =
requires { typename std::remove_cvref_t<T>::expr_type; } &&
std::is_base_of_v<scalar_expression,
typename std::remove_cvref_t<T>::expr_type>;

expression_holder<scalar_expression>
tag_invoke(detail::neg_fn, std::type_identity<scalar_expression>,
expression_holder<scalar_expression> const &e);
Expand Down
7 changes: 0 additions & 7 deletions include/numsim_cas/scalar/scalar_std.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@

namespace numsim::cas {

template <class T> using decay_t = std::remove_cvref_t<T>;

template <class T>
concept scalar_expr_holder = requires {
typename decay_t<T>::expr_type;
} && std::is_base_of_v<scalar_expression, typename decay_t<T>::expr_type>;

[[nodiscard]] std::string
to_string(expression_holder<scalar_expression> const &expr);

Expand Down
6 changes: 6 additions & 0 deletions include/numsim_cas/tensor/tensor_expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ class tensor_expression : public expression {
// return os;
// }

template <class T>
concept tensor_expr_holder =
requires { typename std::remove_cvref_t<T>::expr_type; } &&
std::is_base_of_v<tensor_expression,
typename std::remove_cvref_t<T>::expr_type>;

expression_holder<tensor_expression>
tag_invoke(detail::neg_fn, std::type_identity<tensor_expression>,
expression_holder<tensor_expression> const &e);
Expand Down
29 changes: 15 additions & 14 deletions include/numsim_cas/tensor/tensor_functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ constexpr inline auto make_tensor_data(std::size_t dim, std::size_t rank) {
return make_tensor_data_imp<T>().evaluate(dim, rank);
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] inline expression_holder<tensor_expression> dev(Expr &&expr) {
if (is_same<kronecker_delta>(expr))
return make_expression<tensor_zero>(expr.get().dim(), expr.get().rank());
Expand Down Expand Up @@ -58,7 +58,7 @@ template <typename Expr>
return result;
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] inline expression_holder<tensor_expression> sym(Expr &&expr) {
if (is_same<kronecker_delta>(expr))
return expr;
Expand Down Expand Up @@ -94,7 +94,7 @@ template <typename Expr>
return result;
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] inline expression_holder<tensor_expression> vol(Expr &&expr) {
if (is_same<kronecker_delta>(expr))
return expr;
Expand Down Expand Up @@ -130,7 +130,7 @@ template <typename Expr>
return result;
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] inline expression_holder<tensor_expression> skew(Expr &&expr) {
if (is_same<kronecker_delta>(expr))
return make_expression<tensor_zero>(expr.get().dim(), expr.get().rank());
Expand Down Expand Up @@ -169,7 +169,7 @@ template <typename Expr>
namespace detail_ip {
/// If RHS is a rank-2 projector and both index sets are {1,2},
/// normalize X:{1,2} P:{1,2} → sym/dev/vol/skew(X).
template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
inline std::optional<expression_holder<tensor_expression>>
try_normalize_reversed_projector(ExprLHS &&lhs, sequence const &lhs_indices,
ExprRHS &&rhs, sequence const &rhs_indices) {
Expand Down Expand Up @@ -198,7 +198,7 @@ try_normalize_reversed_projector(ExprLHS &&lhs, sequence const &lhs_indices,
}
} // namespace detail_ip

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] inline auto inner_product(ExprLHS &&lhs, sequence &&lhs_indices,
ExprRHS &&rhs, sequence &&rhs_indices) {
if (auto norm = detail_ip::try_normalize_reversed_projector(lhs, lhs_indices,
Expand All @@ -209,7 +209,7 @@ template <typename ExprLHS, typename ExprRHS>
std::forward<ExprRHS>(rhs), std::move(rhs_indices));
}

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] inline auto
inner_product(ExprLHS &&lhs, sequence const &lhs_indices, ExprRHS &&rhs,
sequence const &rhs_indices) {
Expand All @@ -221,7 +221,7 @@ inner_product(ExprLHS &&lhs, sequence const &lhs_indices, ExprRHS &&rhs,
rhs_indices);
}

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] constexpr inline auto otimes(ExprLHS &&lhs, ExprRHS &&rhs) {
sequence lhs_indices(lhs.get().rank()), rhs_indices(rhs.get().rank());
std::iota(std::begin(lhs_indices), std::end(lhs_indices), std::size_t{0});
Expand All @@ -231,7 +231,7 @@ template <typename ExprLHS, typename ExprRHS>
std::forward<ExprRHS>(rhs), std::move(rhs_indices));
}

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] constexpr inline auto
otimes(ExprLHS &&lhs, sequence &&lhs_indices, ExprRHS &&rhs,
sequence &&rhs_indices) {
Expand All @@ -240,21 +240,21 @@ otimes(ExprLHS &&lhs, sequence &&lhs_indices, ExprRHS &&rhs,
std::forward<ExprRHS>(rhs), std::move(rhs_indices));
}

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] constexpr inline auto otimesu(ExprLHS &&lhs, ExprRHS &&rhs) {
return make_expression<outer_product_wrapper>(
std::forward<ExprLHS>(lhs), std::move(sequence{1, 3}),
std::forward<ExprRHS>(rhs), std::move(sequence{2, 4}));
}

template <typename ExprLHS, typename ExprRHS>
template <tensor_expr_holder ExprLHS, tensor_expr_holder ExprRHS>
[[nodiscard]] constexpr inline auto otimesl(ExprLHS &&lhs, ExprRHS &&rhs) {
return make_expression<outer_product_wrapper>(
std::forward<ExprLHS>(lhs), std::move(sequence{1, 4}),
std::forward<ExprRHS>(rhs), std::move(sequence{2, 3}));
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] constexpr inline auto permute_indices(Expr &&expr,
sequence &&indices) {
if (is_same<basis_change_imp>(expr)) {
Expand Down Expand Up @@ -302,7 +302,7 @@ template <typename Expr>
std::move(indices));
}

template <typename Expr>
template <tensor_expr_holder Expr>
[[nodiscard]] constexpr inline auto trans(Expr &&expr) {
if (is_same<basis_change_imp>(expr)) {
auto const &bc = expr.template get<basis_change_imp>();
Expand All @@ -313,7 +313,8 @@ template <typename Expr>
sequence{2, 1});
}

template <typename Expr> [[nodiscard]] constexpr inline auto inv(Expr &&expr) {
template <tensor_expr_holder Expr>
[[nodiscard]] constexpr inline auto inv(Expr &&expr) {
if (is_same<tensor_inv>(expr))
return expr.template get<tensor_inv>().expr();
// identity_tensor and kronecker_delta are self-inverse. This also avoids
Expand Down
20 changes: 3 additions & 17 deletions include/numsim_cas/tensor/tensor_std.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,7 @@ namespace numsim::cas {
return ss.str();
}

template <
typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<numsim::cas::tensor_expression,
typename std::remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<
std::is_base_of_v<numsim::cas::scalar_expression,
typename std::remove_cvref_t<ExprRHS>::expr_type>,
bool> = true>
template <tensor_expr_holder ExprLHS, scalar_expr_holder ExprRHS>
[[nodiscard]] auto pow(ExprLHS &&expr_lhs, ExprRHS &&expr_rhs) {
// pow(A, 0) → identity
if (is_same<scalar_zero>(expr_rhs) ||
Expand All @@ -66,13 +57,8 @@ template <
std::forward<ExprLHS>(expr_lhs), std::forward<ExprRHS>(expr_rhs));
}

template <
typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<numsim::cas::tensor_expression,
typename std::remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<std::is_integral_v<ExprRHS>, bool> = true>
template <tensor_expr_holder ExprLHS, typename ExprRHS>
requires std::is_integral_v<std::remove_cvref_t<ExprRHS>>
[[nodiscard]] auto pow(ExprLHS &&expr_lhs, ExprRHS &&expr_rhs) {
auto constant{
numsim::cas::make_expression<numsim::cas::scalar_constant>(expr_rhs)};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ class tensor_to_scalar_expression : public expression {
operator=(tensor_to_scalar_expression const &) = delete;
};

template <class T>
concept tensor_to_scalar_expr_holder =
requires { typename std::remove_cvref_t<T>::expr_type; } &&
std::is_base_of_v<tensor_to_scalar_expression,
typename std::remove_cvref_t<T>::expr_type>;

expression_holder<tensor_to_scalar_expression>
tag_invoke(detail::neg_fn, std::type_identity<tensor_to_scalar_expression>,
expression_holder<tensor_to_scalar_expression> const &e);
Expand Down
55 changes: 10 additions & 45 deletions include/numsim_cas/tensor_to_scalar/tensor_to_scalar_std.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,8 @@ to_string(const expression_holder<tensor_to_scalar_expression> &expr) {
return ss.str();
}

template <typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<tensor_to_scalar_expression,
typename remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<
std::is_base_of_v<tensor_to_scalar_expression,
typename remove_cvref_t<ExprRHS>::expr_type>,
bool> = true>
template <tensor_to_scalar_expr_holder ExprLHS,
tensor_to_scalar_expr_holder ExprRHS>
[[nodiscard]] auto pow(ExprLHS &&expr_lhs, ExprRHS &&expr_rhs) {
// pow(1, x) --> 1
if (is_same<tensor_to_scalar_one>(expr_lhs))
Expand Down Expand Up @@ -60,59 +53,35 @@ template <typename ExprLHS, typename ExprRHS,
return _lhs.accept(visitor);
}

template <typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<tensor_to_scalar_expression,
typename remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<std::is_arithmetic_v<ExprRHS>, bool> = true>
template <tensor_to_scalar_expr_holder ExprLHS, typename ExprRHS>
requires std::is_arithmetic_v<std::remove_cvref_t<ExprRHS>>
[[nodiscard]] auto pow(ExprLHS &&expr_lhs, ExprRHS &&expr_rhs) {
auto constant{make_expression<tensor_to_scalar_scalar_wrapper>(
make_expression<scalar_constant>(expr_rhs))};
return pow(std::forward<ExprLHS>(expr_lhs), std::move(constant));
}

template <typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<tensor_to_scalar_expression,
typename remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<std::is_fundamental_v<ExprRHS>, bool> = true>
template <tensor_to_scalar_expr_holder ExprLHS, typename ExprRHS>
requires std::is_fundamental_v<std::remove_cvref_t<ExprRHS>>
[[nodiscard]] auto pow(ExprLHS const &expr_lhs, ExprRHS &&expr_rhs) {
auto constant{make_expression<tensor_to_scalar_scalar_wrapper>(
make_expression<scalar_constant>(expr_rhs))};
return pow(expr_lhs, std::move(constant));
}

template <typename ExprLHS, typename ExprRHS,
std::enable_if_t<
std::is_base_of_v<tensor_to_scalar_expression,
typename remove_cvref_t<ExprLHS>::expr_type>,
bool> = true,
std::enable_if_t<
std::is_base_of_v<scalar_expression,
typename remove_cvref_t<ExprRHS>::expr_type>,
bool> = true>
template <tensor_to_scalar_expr_holder ExprLHS, scalar_expr_holder ExprRHS>
[[nodiscard]] auto pow(ExprLHS &&expr_lhs, ExprRHS &&expr_rhs) {
return pow(std::forward<ExprLHS>(expr_lhs),
make_expression<tensor_to_scalar_scalar_wrapper>(
std::forward<ExprRHS>(expr_rhs)));
}

template <
typename Expr,
std::enable_if_t<std::is_same_v<typename std::decay_t<Expr>::expr_type,
tensor_to_scalar_expression>,
bool> = true>
template <tensor_to_scalar_expr_holder Expr>
[[nodiscard]] auto log(Expr &&expr) {
return make_expression<tensor_to_scalar_log>(std::forward<Expr>(expr));
}

template <
typename Expr,
std::enable_if_t<std::is_same_v<typename std::decay_t<Expr>::expr_type,
tensor_to_scalar_expression>,
bool> = true>
template <tensor_to_scalar_expr_holder Expr>
[[nodiscard]] auto exp(Expr &&expr) {
// exp(0) → 1
if (is_same<tensor_to_scalar_zero>(expr))
Expand All @@ -125,11 +94,7 @@ template <
return make_expression<tensor_to_scalar_exp>(std::forward<Expr>(expr));
}

template <
typename Expr,
std::enable_if_t<std::is_same_v<typename std::decay_t<Expr>::expr_type,
tensor_to_scalar_expression>,
bool> = true>
template <tensor_to_scalar_expr_holder Expr>
[[nodiscard]] auto sqrt(Expr &&expr) {
// sqrt(0) → 0
if (is_same<tensor_to_scalar_zero>(expr))
Expand Down