diagonal.cpp serif/solver/normalization/diagonal.hpp functional stdexcept utility serif/solver/normalization/detail/validation.hpp serif/utils/error/errors.hpp serif serif::solver serif::solver::normalization #include"serif/solver/normalization/diagonal.hpp" #include<functional> #include<stdexcept> #include<utility> #include"serif/solver/normalization/detail/validation.hpp" #include"serif/utils/error/errors.hpp" namespaceserif::solver::normalization { namespace{ [[nodiscard]]doublenormalization_norm_squared(std::span<constdouble>factors,std::span<constdouble>physical){ detail::require_normalization_size(physical.size(),factors.size()); doublenorm_squared=0.0; for(std::size_tindex=0;index<physical.size();++index) { constdoublenormalized=factors[index]*physical[index]; norm_squared+=normalized*normalized; } returnnorm_squared; } } voiddetail::require_normalization_size(std::size_treceived,std::size_texpected){ usingnamespaceutils::errors; serif_ensure<SERiFErrorCode::NORMALIZATION_VECTOR_SIZE_MISMATCH,std::invalid_argument>(received==expected,"Normalizationreceivedavectoroflength{}butexpected{}.Supplyavectorinthepreparedcoordinatelayout.",received,expected); } voiddetail::apply_normalization(conststd::span<constdouble>factors,conststd::span<constdouble>input,std::span<double>output,constboolinverse) { usingnamespaceutils::errors; require_normalization_size(input.size(),factors.size()); require_normalization_size(output.size(),factors.size()); if(input.data()!=output.data()&&!input.empty()) { conststd::less<constdouble*>before; constboolinput_ends_before_output=!before(output.data(),input.data()+input.size()); constbooloutput_ends_before_input=!before(input.data(),output.data()+output.size()); serif_ensure<SERiFErrorCode::NORMALIZATION_BUFFER_OVERLAP,std::invalid_argument>(input_ends_before_output||output_ends_before_input,"Normalizationinputandoutputoverlappartially.Usethesamespanforanin-placeconversionorprovidedisjointstorage."); } for(std::size_tindex=0;index<input.size();++index) { output[index]=inverse?input[index]/factors[index]:factors[index]*input[index]; } } DiagonalNormalization::DiagonalNormalization(std::vector<double>state,std::vector<double>residual):m_state_factors(std::move(state)),m_residual_factors(std::move(residual)){} voidDiagonalNormalization::normalize_state(conststd::span<constdouble>physical,conststd::span<double>normalized)const{ detail::apply_normalization(m_state_factors,physical,normalized,false); } voidDiagonalNormalization::denormalize_state(conststd::span<constdouble>normalized,conststd::span<double>physical)const{ detail::apply_normalization(m_state_factors,normalized,physical,true); } voidDiagonalNormalization::normalize_residual(conststd::span<constdouble>physical,conststd::span<double>normalized)const{ detail::apply_normalization(m_residual_factors,physical,normalized,false); } voidDiagonalNormalization::denormalize_residual(conststd::span<constdouble>normalized,conststd::span<double>physical)const{ detail::apply_normalization(m_residual_factors,normalized,physical,true); } doubleDiagonalNormalization::state_norm_squared(conststd::span<constdouble>physical)const{ returnnormalization_norm_squared(m_state_factors,physical); } doubleDiagonalNormalization::residual_norm_squared(conststd::span<constdouble>physical)const{ returnnormalization_norm_squared(m_residual_factors,physical); } std::expected<DiagonalNormalization,std::string>make_diagonal_normalization(std::vector<double>state,std::vector<double>residual){ for(conststd::span<constdouble>factors:{std::span<constdouble>{state},std::span<constdouble>{residual}}) { constautovalid=detail::validate_factors(factors); if(!valid) { returnstd::unexpected(valid.error()); } } returnDiagonalNormalization{std::move(state),std::move(residual)}; } }