Page MenuHomec4science

value_checker.hpp
No OneTemporary

File Metadata

Created
Fri, Nov 1, 12:55

value_checker.hpp

/*------------------------------------------------------------------------------
Copyright (c)2015 F. Georget <fabieng@princeton.edu>, Princeton University
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------------------------------------------------------*/
#ifndef SPECMICP_UTILS_VALUECHECKER_HPP
#define SPECMICP_UTILS_VALUECHECKER_HPP
/*!
\file value_checker.hpp
\brief Framework to check and validate vectors
The user uses and/or define checker and predicates to validates the vector.
This is a header-only module using template metaprogramming.
Each checker and predicates are defined as types wich allows us to compose
them easily.
Example :
The following example check that :
- every value in the vector is finite and in the range [0.0, 1.0]
- at least one value is non-zero
\code{.cpp}
specmicp_upper_bound_predicate(LessOrEqualThanOne, 1.0);
bool check_vector(const Vector& vector) {
using predicate_all = PredicateAnd<
PredicateAnd<IsFinite,IsNonNegative>,
LessOrEqualThanOne
>;
using predicate_one = IsNonZero;
using checker = Composer<
TrueForAll<predicate_all>,
TrueForAtLeastOne<predicate_one>
>;
auto value = checker::check(vector);
if (value >= IsValidVector::error) {
ERROR << "Vector is incorrecct";
return false;
}
return true
}
\endcode
*/
#include "../types.hpp"
#include "functional"
namespace specmicp {
//! \brief namespace dedicated to functions and types used to validate vectors
namespace value_checker {
//! \brief Return code Of the checker
enum class IsValidVector {
good, //!< Nothing to report
warning, //!< Something smells fishy
error, //!< Error, please correct
critical //!< Mayde, Mayde, abort the computation
};
//! \brief Return the maximum error level between two error levels
constexpr IsValidVector max_error_level(IsValidVector err1, IsValidVector err2) {
return (err1>err2)?err1:err2;
}
/*!
\brief Base class for a checker
\tparam Derived derived class
Derived class must implement the static check_impl method.
\code{.cpp}
struct DerivedValueChecker: public ValueChecker<DerivedValuedChecker>
{
static IsValidVector check_impl(const Vector& vector) {
// check vector
return IsValidVector::good;
}
};
\endcode
*/
template <typename Derived>
struct ValueChecker {
//! \brief Check the vector
static IsValidVector check(const Vector& vector) {
return Derived::check_impl(vector);
}
};
//! \brief Compose two checkers together
//!
//! The composer will run the two checks and return the maximum error.
//! If Checker1 return a critical error, checker2 will not be run.
template <typename Checker1, typename Checker2>
struct Composer: public ValueChecker<Composer<Checker1,Checker2>>
{
static IsValidVector check_impl(const Vector& vector) {
auto val1 = Checker1::check(vector);
if (val1 < IsValidVector::critical)
{
const auto val2 = Checker2::check(vector);
val1 = max_error_level(val1, val2);
};
return val1;
}
};
//! \brief Check if Predicate is true for every value in the vector
template <typename Predicate,
IsValidVector error_level=IsValidVector::error>
struct TrueForAll: public ValueChecker<TrueForAll<Predicate, error_level>>
{
static IsValidVector check_impl(const Vector& vector) {
bool flag = false;
for (index_t ind=0; ind<vector.rows(); ++ind)
{
if (not Predicate::run(vector(ind))) {
flag = true;
break;
}
}
if (flag) return error_level;
return IsValidVector::good;
}
};
//! \brief Check if Predicate is true for at least one value in the vector
template <typename Predicate,
IsValidVector error_level=IsValidVector::error>
struct TrueForAtLeastOne: public ValueChecker<TrueForAtLeastOne<Predicate, error_level>>
{
static IsValidVector check_impl(const Vector& vector) {
bool flag = false;
for (index_t ind=0; ind<vector.rows(); ++ind)
{
if (Predicate::run(vector(ind))) {
flag = true;
break;
}
}
if (not flag) return error_level;
return IsValidVector::good;
}
};
/*!
\brief Check the norm
\tparam Predicate a predicate (derived class of value_checker::Predicate)
\tparam error_level error level to raise if the condition is not true
\tparam p norm to use
use Eigen::Infinity for the infinit norm
\code{.cpp}
Vector vector;
// fill vector
using validator = NormChecker<IsFinite,
IsValidVector::Critical,
Eigen::Infinity>;
auto retcode = validator::check(vector);
\endcode
*/
template <typename Predicate,
IsValidVector error_level=IsValidVector::error,
int p=2>
struct NormChecker: public ValueChecker<NormChecker<Predicate, error_level>>
{
static IsValidVector check_impl(const Vector& vector) {
const scalar_t norm = vector.lpNorm<p>();
if (not Predicate::run(norm))
return error_level;
return IsValidVector::good;
}
};
/*!
\brief Base class for a Predicate
The derived class must implement the
`bool function_impl(const scalar_t& value)' method.
Example
\code{cpp}
struct BiggerThan2: public Predicate<BiggerThan2> {
static bool functor_impl(const scalar_t& value) {
return (value > 2);
}
};
\endcode
Macros and common composer are defined to ease the process of creating predicates.
\sa PredicateNot, PredicateAnd, PredicateOr, PredicateXOr,
specmicp_create_value_predicate,
specmicp_lower_bound_predicate, specmicp_strict_lower_bound_predicate.
specmicp_upper_bound_predicate, specmicp_strict_upper_bound_predicate
*/
template <typename Derived>
struct Predicate
{
static bool run(const scalar_t& value) {
return Derived::run_impl(value);
}
};
//! \brief Negate a predicate
template <typename PredicateT>
struct PredicateNot: public Predicate<PredicateNot<PredicateT>>
{
static bool run_impl(const scalar_t& value) {
return (not PredicateT::run(value));
}
};
/*!
\brief And operation on two predicates
Check that the two predicates are true
\code{.cpp}
using and_predicate = PredicateAnd<IsFinite,IsNonNegative>;
using checker = TrueForAll<and_predicate>;
auto retcode = checker::check(vector);
\endcode
*/
template <typename Predicate1, typename Predicate2>
struct PredicateAnd: public Predicate<PredicateAnd<Predicate1,Predicate2>>
{
static bool run_impl(const scalar_t& value) {
return (Predicate1::run(value) and Predicate2::run(value));
}
};
//! \brief Or operation on two predicates
//!
//! Performs the or operation on two predicates
template <typename Predicate1, typename Predicate2>
struct PredicateOr: public Predicate<PredicateOr<Predicate1,Predicate2>>
{
static bool run_impl(const scalar_t& value) {
return (Predicate1::run(value) or Predicate2::run(value));
}
};
//! \brief XOr operation on two predicates
//!
//! Performs the exclusive or operation on two predicates
template <typename Predicate1, typename Predicate2>
struct PredicateXOr: public Predicate<PredicateXOr<Predicate1,Predicate2>>
{
static bool run_impl(const scalar_t& value) {
return (Predicate1::run(value) != Predicate2::run(value));
}
};
} //end namespace value_checker
} //end namespace specmicp
/*!
\def specmicp_create_value_predicate
\brief Create a predicate with name 'name'
The expression must test 'value'
Example :
\code{.cpp}
specmicp_create_value_predicate(LowerThan5, (value < 5));
//
{
using checker = TrueForAll<LowerThan5>;
auto return_code = checker::check(vector);
}
\endcode
*/
#define specmicp_create_value_predicate(name, expression) \
struct name: public specmicp::value_checker::Predicate<name> { \
static bool run_impl(const scalar_t& value) { \
return (expression); \
} \
}
//! \def specmicp_lower_bound_predicate
//! \brief Create a predicate that check the lower bound
#define specmicp_lower_bound_predicate(name, bound) \
specmicp_create_value_predicate(name, (value >= bound))
//! \def specmicp_strict_lower_bound_predicate
//! \brief Create a predicate that check the lower bound
#define specmicp_strict_lower_bound_predicate(name, bound) \
specmicp_create_value_predicate(name, (value > bound))
//! \def specmicp_upper_bound_predicate
//! \brief Create a predicate that check the upper bound
#define specmicp_upper_bound_predicate(name, bound) \
specmicp_create_value_predicate(name, (value <= bound))
//! \def specmicp_strict_upper_bound_predicate
//! \brief Create a predicate that check the upper bound
#define specmicp_strict_upper_bound_predicate(name, bound) \
specmicp_create_value_predicate(name, (value < bound))
namespace specmicp {
namespace value_checker {
//! \class IsNonNegative
//! \brief Test if a value is non negative
specmicp_lower_bound_predicate(IsNonNegative, (0.0));
//! \class IsNonZero
//! \brief Test if a value is non zero
specmicp_create_value_predicate(IsNonZero, (value != 0));
//! \class IsFinite
//! \brief Test if a value is finite
specmicp_create_value_predicate(IsFinite, (std::isfinite(value)));
} //end namespace value_checker
} //end namespace specmicp
#endif // SPECMICP_UTILS_VALUECHECKER_HPP

Event Timeline