namespace pressio{ namespace rom{
// -----------------------------------------------------------------------------
// Trait: ReducedState<T>
//
// Determines whether a type T is a valid reduced state type in the Pressio ROM
// framework.
//
// Specialization:
// - When PRESSIO_ENABLE_TPL_EIGEN is defined, this trait is specialized
// for Eigen vector types via ::pressio::is_vector_eigen<T>, and inherits
// from std::true_type.
//
// Usage:
// - Used in static_asserts and SFINAE to constrain templates to valid reduced
// state vector types.
//
// Example:
// static_assert(ReducedState<MyVectorType>::value, "Invalid reduced state type");
//
// Notes:
// - Additional specializations can be added for other TPLs like Kokkos
// if and when we add support for that.
// -----------------------------------------------------------------------------
template<class T, class = void>
struct ReducedState : std::false_type{};
#ifdef PRESSIO_ENABLE_TPL_EIGEN
template<class T>
struct ReducedState<
T, std::enable_if_t< ::pressio::is_vector_eigen<T>::value > > : std::true_type{};
#endif
// -----------------------------------------------------------------------------
// Trait: PossiblyAffineTrialColumnSubspace<T>
//
// This trait determines whether a type T conforms to the interface expected
// of a trial column subspace used in pressio ROMs.
template<class T, class enable = void>
struct PossiblyAffineTrialColumnSubspace : std::false_type{};
template<class T>
struct PossiblyAffineTrialColumnSubspace<
T,
std::enable_if_t<
// must define T::reduced_state_type
// and it must be a valid reduced state
::pressio::has_reduced_state_typedef<T>::value &&
ReducedState<typename T::reduced_state_type>::value &&
// must define T::basis_matrix_type
::pressio::has_basis_matrix_typedef<T>::value &&
// must define T::full_state_type
::pressio::has_full_state_typedef<T>::value &&
// full state and basis matrix must be copy-constructible
std::is_copy_constructible< typename T::full_state_type>::value &&
std::is_copy_constructible< typename T::basis_matrix_type>::value &&
// all must have valid Traits specializations
all_have_traits<
typename T::reduced_state_type,
typename T::full_state_type,
typename T::basis_matrix_type>::value &&
// full state must be rank-1
Traits<typename T::full_state_type>::rank == 1 &&
// basis matrix must be rank-2
Traits<typename T::basis_matrix_type>::rank == 2 &&
// T must be move-constructible and move assignable
std::is_move_constructible<T>::value &&
std::is_assignable<T&, T&&>::value &&
// must have: createReducedState() ->reduced_state_type
has_const_create_reduced_state_return_result<T>::value &&
// must have: createFullState() ->full_state_type
has_const_create_full_state_return_result<T>::value &&
// must have: createFullStateFromReducedState(reduced) ->full_state_type
has_const_create_full_state_from_reduced_state<T>::value &&
// must have: mapFromReducedState(reduced, full) ->void
has_const_map_from_reduced_state_return_void<T>::value &&
// must have: basisOfTranslatedSpace() ->const basis_matrix_type&
std::is_same<
decltype( std::declval<T const>().basisOfTranslatedSpace() ),
typename T::basis_matrix_type const &
>::value &&
// must have: translationVector() ->const full_state_type&
std::is_same<
decltype(std::declval<T const>().translationVector()),
const typename T::full_state_type &
>::value &&
// must have: basis() ->const basis_matrix_type&
std::is_same<
decltype( std::declval<T const>().basis() ),
const typename T::basis_matrix_type &
>::value &&
// must have: dimension() ->integral type
std::is_integral<
decltype( std::declval<T const>().dimension() )
>::value &&
// must have: isColumnSpace() ->bool
std::is_same<
decltype( std::declval<T const>().isColumnSpace() ),
bool
>::value &&
// must have: isRowSpace() ->bool
std::is_same<
decltype( std::declval<T const>().isRowSpace() ),
bool
>::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: PossiblyAffineRealValuedTrialColumnSubspace<T>
//
// Builds on PossiblyAffineTrialColumnSubspace<T> by further requiring that
// all scalar types (underlying the reduced state, full state, and basis matrix)
// are floating-point types.
template<class T, class enable = void>
struct PossiblyAffineRealValuedTrialColumnSubspace: std::false_type{};
template<class T>
struct PossiblyAffineRealValuedTrialColumnSubspace<
T,
std::enable_if_t<
// must already satisfy all affine subspace checks
PossiblyAffineTrialColumnSubspace<T>::value &&
// reduced state's scalar type must be floating-point
std::is_floating_point< scalar_trait_t<typename T::reduced_state_type> >::value &&
// full state's scalar type must be floating-point
std::is_floating_point< scalar_trait_t<typename T::full_state_type> >::value &&
// basis matrix's scalar type must be floating-point
std::is_floating_point< scalar_trait_t<typename T::basis_matrix_type> >::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: SteadyFomWithJacobianAction<T, JacobianActionOperandType>
//
// This trait determines whether a type `T` represents a valid *steady* full-order
// model (FOM) interface with support for computing residuals and applying the
// Jacobian to an operand (Jacobian action).
//
// This trait inherits from std::true_type if all of the following are satisfied:
// - `T` defines the required type aliases (state_type, residual_type).
// - `T` provides factory methods to create residuals and Jacobian action results.
// - `T` exposes a const-qualified method named:
// void residualAndJacobianAction(
// const state_type &,
// residual_type &,
// const JacobianActionOperandType &,
// std::optional<fom_jac_action_t<T, JacobianActionOperandType> *>
// )
//
// Otherwise, the trait inherits from std::false_type.
//
// This is typically used to statically constrain the type `T` in the ROM API
// when constructing a steady ROM problem.
// -----------------------------------------------------------------------------
template<class T, class JacobianActionOperandType, class enable = void>
struct SteadyFomWithJacobianAction : std::false_type{};
template<class T, class JacobianActionOperandType>
struct SteadyFomWithJacobianAction<
T, JacobianActionOperandType,
std::enable_if_t<
// Must define: T::state_type
::pressio::has_state_typedef<T>::value &&
// Must define: T::residual_type
::pressio::has_residual_typedef<T>::value &&
// State and residual types must be copy-constructible
std::is_copy_constructible<typename T::state_type>::value &&
std::is_copy_constructible<typename T::residual_type>::value &&
// Must provide: T::createResidual() returning residual_type
::pressio::rom::has_const_create_residual_method_return_result<
T, typename T::residual_type >::value &&
// Must provide: T::createResultOfJacobianActionOn(operand) returning non-void
::pressio::rom::has_const_create_result_of_jacobian_action_on<
T, JacobianActionOperandType>::value &&
// The resulting jacobian action type must be copy-constructible
std::is_copy_constructible<
impl::fom_jac_action_t<T, JacobianActionOperandType>
>::value &&
// Must implement:
// void residualAndJacobianAction(state, residual, operand, optional<jac_action*>)
std::is_void<
decltype
(
std::declval<T const>().residualAndJacobianAction
(
std::declval<typename T::state_type const&>(),
std::declval<typename T::residual_type &>(),
std::declval<JacobianActionOperandType const&>(),
std::declval< std::optional<impl::fom_jac_action_t<T, JacobianActionOperandType> *> >()
)
)
>::value
>
> : std::true_type{};
template<class T, class JacobianActionOperandType, class enable = void>
struct RealValuedSteadyFomWithJacobianAction : std::false_type{};
template<class T, class JacobianActionOperandType>
struct RealValuedSteadyFomWithJacobianAction<
T, JacobianActionOperandType,
std::enable_if_t<
SteadyFomWithJacobianAction<T, JacobianActionOperandType>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::residual_type> >::value
&& std::is_floating_point<
scalar_trait_t< impl::fom_jac_action_t<T, JacobianActionOperandType> >
>::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: SemiDiscreteFom<T>
//
// Determines whether a type `T` represents a valid semi-discrete FOM
// interface for time-dependent problems of the form:
//
// d/dt y(t) = f(y, t)
//
// The model must provide time, state, and RHS (velocity) types, as well as
// a const-qualified method to compute the RHS given a state and time.
//
// If all requirements are met, the trait inherits from std::true_type.
// Otherwise, it inherits from std::false_type.
//
// This trait is used in Pressio to statically validate that a type conforms
// to the minimal interface needed for time integration of ODE-based FOMs.
// -----------------------------------------------------------------------------
template<class T, class enable = void>
struct SemiDiscreteFom : std::false_type{};
template<class T>
struct SemiDiscreteFom<
T,
std::enable_if_t<
// Must define: T::time_type
::pressio::has_time_typedef<T>::value &&
// Must define: T::state_type
::pressio::has_state_typedef<T>::value &&
// Must define: T::rhs_type (i.e., velocity or RHS vector)
::pressio::has_rhs_typedef<T>::value &&
// state_type must be copy-constructible
std::is_copy_constructible<typename T::state_type>::value &&
// rhs_type must be copy-constructible
std::is_copy_constructible<typename T::rhs_type>::value &&
// Must provide: createRhs() ->rhs_type
::pressio::ode::has_const_create_rhs_method_return_result<
T, typename T::rhs_type
>::value &&
// Must implement: rhs(state, time, result) ->void
::pressio::rom::has_const_rhs_method_accept_state_indvar_result_return_void<
T,
typename T::state_type,
typename T::time_type,
typename T::rhs_type
>::value
>
> : std::true_type{};
template<class T, class enable = void>
struct RealValuedSemiDiscreteFom : std::false_type{};
template<class T>
struct RealValuedSemiDiscreteFom<
T,
std::enable_if_t<
SemiDiscreteFom<T>::value
&& std::is_floating_point< typename T::time_type>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::rhs_type> >::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: SemiDiscreteFomWithJacobianAction<T, JacobianActionOperandType>
//
// Determines whether a type `T` represents a valid time-dependent full-order model (FOM)
// interface (i.e., a semi-discrete system) that also supports applying the Jacobian to
// an operand (Jacobian-action interface).
//
// Inherits from std::true_type if all the following conditions are satisfied:
// - `T` satisfies the SemiDiscreteFom trait.
// - `T` can create a result container for a Jacobian-action via
// createResultOfJacobianActionOn(operand)
// - The resulting Jacobian-action object is copy-constructible.
// - `T` implements a const-qualified method of the form:
// void applyJacobian(
// const state_type&,
// const operand_type&,
// const time_type&,
// result_type& )
//
// Otherwise, inherits from std::false_type.
// This is typically used to statically constrain the type `T` in the ROM API
// when constructing unsteady implicit ROM problems.
// -----------------------------------------------------------------------------
template<class T, class JacobianActionOperandType, class enable = void>
struct SemiDiscreteFomWithJacobianAction : std::false_type{};
template<class T, class JacobianActionOperandType>
struct SemiDiscreteFomWithJacobianAction<
T, JacobianActionOperandType,
std::enable_if_t<
SemiDiscreteFom<T>::value
&& ::pressio::rom::has_const_create_result_of_jacobian_action_on<
T, JacobianActionOperandType>::value
&& std::is_copy_constructible<
impl::fom_jac_action_t<T, JacobianActionOperandType>
>::value
&& ::pressio::rom::has_const_apply_jacobian_method_accept_state_operand_time_result_return_void<
T, typename T::state_type,
JacobianActionOperandType, typename T::time_type,
impl::fom_jac_action_t<T, JacobianActionOperandType>
>::value
>
> : std::true_type{};
template<class T, class OperandType, class enable = void>
struct RealValuedSemiDiscreteFomWithJacobianAction : std::false_type{};
template<class T, class OperandType>
struct RealValuedSemiDiscreteFomWithJacobianAction<
T, OperandType,
std::enable_if_t<
RealValuedSemiDiscreteFom<T>::value
&& SemiDiscreteFomWithJacobianAction<T, OperandType>::value
&& std::is_floating_point<
scalar_trait_t< impl::fom_jac_action_t<T, OperandType> >
>::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: SemiDiscreteFomWithMassMatrixAction<T, MassMatrixActionOperandType>
//
// Determines whether a type `T` represents a valid time-dependent full-order model (FOM)
// that also supports applying the *mass matrix* to a given operand, i.e., implements
// a mass matrix action interface.
//
// If all conditions are met, the trait inherits from std::true_type.
// Otherwise, it inherits from std::false_type.
//
// Required interface for T:
// - Satisfies the `SemiDiscreteFom` trait.
// - Provides:
// - createResultOfMassMatrixActionOn(operand) ->returns result object
// - applyMassMatrix(state, operand, time, result) ->void
//
// -----------------------------------------------------------------------------
template<class T, class MassMatrixActionOperandType, class enable = void>
struct SemiDiscreteFomWithMassMatrixAction : std::false_type{};
template<class T, class MassMatrixActionOperandType>
struct SemiDiscreteFomWithMassMatrixAction<
T, MassMatrixActionOperandType,
std::enable_if_t<
SemiDiscreteFom<T>::value
//
&& std::is_copy_constructible<
decltype
(
std::declval<T const>().createResultOfMassMatrixActionOn
(
std::declval<MassMatrixActionOperandType const &>()
)
)
>::value
&& std::is_void<
decltype
(
std::declval<T const>().applyMassMatrix
(
std::declval<typename T::state_type const&>(),
std::declval<MassMatrixActionOperandType const&>(),
std::declval<typename T::time_type const &>(),
std::declval<impl::fom_mass_matrix_action_t<T, MassMatrixActionOperandType> &>()
)
)
>::value
>
> : std::true_type{};
template<class T, class MassMatrixActionOperandType, class enable = void>
struct RealValuedSemiDiscreteFomWithMassMatrixAction : std::false_type{};
template<class T, class MassMatrixActionOperandType>
struct RealValuedSemiDiscreteFomWithMassMatrixAction<
T, MassMatrixActionOperandType,
std::enable_if_t<
RealValuedSemiDiscreteFom<T>::value
&& SemiDiscreteFomWithMassMatrixAction<T, MassMatrixActionOperandType>::value
&& std::is_floating_point<
scalar_trait_t< impl::fom_mass_matrix_action_t<T, MassMatrixActionOperandType> >
>::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: SemiDiscreteFomWithJacobianAndMassMatrixAction<T, OperandType>
//
// Determines whether a type `T` represents a valid time-dependent full-order model (FOM)
// that supports both:
// - Jacobian-action interface (applyJacobian)
// - Mass matrix action interface (applyMassMatrix)
//
// This trait inherits from std::true_type only if both of the following traits
// are satisfied for the same operand type:
// - SemiDiscreteFomWithJacobianAction<T, OperandType>
// - SemiDiscreteFomWithMassMatrixAction<T, OperandType>
//
// Otherwise, it inherits from std::false_type.
//
// This trait is used when both the Jacobian and mass matrix actions
// are required (e.g., implicit Galerkin with mass matrix).
// -----------------------------------------------------------------------------
template<class T, class OperandType, class enable = void>
struct SemiDiscreteFomWithJacobianAndMassMatrixAction : std::false_type{};
template<class T, class OperandType>
struct SemiDiscreteFomWithJacobianAndMassMatrixAction<
T, OperandType,
std::enable_if_t<
SemiDiscreteFomWithJacobianAction<T, OperandType>::value
&& SemiDiscreteFomWithMassMatrixAction<T, OperandType>::value
>
> : std::true_type{};
template<class T, class OperandType, class enable = void>
struct RealValuedSemiDiscreteFomWithJacobianAndMassMatrixAction : std::false_type{};
template<class T, class OperandType>
struct RealValuedSemiDiscreteFomWithJacobianAndMassMatrixAction<
T, OperandType,
std::enable_if_t<
RealValuedSemiDiscreteFomWithJacobianAction<T, OperandType>::value
&& RealValuedSemiDiscreteFomWithMassMatrixAction<T, OperandType>::value
>
> : std::true_type{};
// -----------------------------------------------------------------------------
// Trait: FullyDiscreteSystemWithJacobianAction<T, TotalNumStates, OperandType>
//
// Determines whether a type `T` conforms to the interface of a fully-discrete
// full-order model (FOM) that supports computing residuals and Jacobian actions
// for multiple time levels (e.g., backward differentiation formulas).
//
// This trait is enabled only if all of the following hold:
// - The number of states (`TotalNumStates`) is either 2 or 3 (currently supported).
// - `T` defines the following typedefs:
// -time_type, state_type, discrete_residual_type
// - `state_type` and `discrete_residual_type` are copy-constructible.
// - `T` provides:
// - createDiscreteTimeResidual() ->discrete_residual_type
// - createResultOfDiscreteTimeJacobianActionOn(Operand) ->copyable result type
// - `T` implements a method of the form:
//
// void discreteTimeResidualAndJacobianAction(
// StepCountType stepNumber,
// time_type time,
// std::array<state_type, TotalNumStates> const& states,
// discrete_residual_type& residual,
// OperandType const& operand,
// ResultType& result);
//
// This trait is typically used to enforce constraints for FOMs employed in
// projection-based ROMs using fully-discrete time integration schemes.
// -----------------------------------------------------------------------------
template<class T, int TotalNumStates, class JacobianActionOperandType, class = void>
struct FullyDiscreteSystemWithJacobianAction : std::false_type{};
template<class T, int TotalNumStates, class JacobianActionOperandType>
struct FullyDiscreteSystemWithJacobianAction<
T, TotalNumStates, JacobianActionOperandType,
std::enable_if_t<
// Supported values: must be 2 or 3 states for fully-discrete stepping
(TotalNumStates == 2 || TotalNumStates == 3) &&
// Must define time_type, state_type, discrete_residual_type
::pressio::has_time_typedef<T>::value &&
::pressio::has_state_typedef<T>::value &&
::pressio::has_discrete_residual_typedef<T>::value &&
// state_type and residual_type must be copyable
std::is_copy_constructible<typename T::state_type>::value &&
std::is_copy_constructible<typename T::discrete_residual_type>::value &&
// Must provide: createDiscreteTimeResidual() ->discrete_residual_type
std::is_same<
typename T::discrete_residual_type,
decltype(std::declval<T const>().createDiscreteTimeResidual())
>::value &&
// Must provide: createResultOfDiscreteTimeJacobianActionOn(operand) ->copyable result type
std::is_copy_constructible<
decltype(
std::declval<T const>().createResultOfDiscreteTimeJacobianActionOn(
std::declval<JacobianActionOperandType const &>()
)
)
>::value &&
// Must implement: discreteTimeResidualAndJacobianAction(...) ->void
::pressio::rom::has_const_discrete_residual_jacobian_action_method<
T,
TotalNumStates,
typename ::pressio::ode::StepCount::value_type,
typename T::time_type,
typename T::state_type,
typename T::discrete_residual_type,
JacobianActionOperandType,
impl::fully_discrete_fom_jac_action_t<T, JacobianActionOperandType>
>::value
>
> : std::true_type{};
template<class T, int TotalNumStates, class OperandType, class enable = void>
struct RealValuedFullyDiscreteSystemWithJacobianAction : std::false_type{};
template<class T, int TotalNumStates, class OperandType>
struct RealValuedFullyDiscreteSystemWithJacobianAction<
T, TotalNumStates, OperandType,
std::enable_if_t<
FullyDiscreteSystemWithJacobianAction<T, TotalNumStates, OperandType>::value
&& std::is_floating_point< scalar_trait_t<typename T::state_type> >::value
&& std::is_floating_point< scalar_trait_t<typename T::discrete_residual_type> >::value
&& std::is_floating_point<
scalar_trait_t< impl::fully_discrete_fom_jac_action_t<T, OperandType> >
>::value
>
> : std::true_type{};
// ----------------------------------------------------------------------------
// VARIOUS
// ----------------------------------------------------------------------------
template <class T, class MaskerType, class = void>
struct MaskableWith : std::false_type{};
template <class T, class MaskerType>
struct MaskableWith<
T, MaskerType,
std::enable_if_t<
std::is_copy_constructible<
decltype
(std::declval<MaskerType const>().createResultOfMaskActionOn
(std::declval<T const &>())
)
>::value
&& std::is_void<
decltype
(
std::declval<MaskerType const>()
(
std::declval<T const &>(),
std::declval<impl::mask_action_t<MaskerType, T> &>()
)
)
>::value
>
> : std::true_type{};
}} // end namespace pressio::rom