pfor/src/pfor/index/property/linear.h

207 lines
5.2 KiB
C++

#ifndef PFOR_PFOR_INDEX_PROPERTY_LINEAR_H
#define PFOR_PFOR_INDEX_PROPERTY_LINEAR_H
#include "../../mp/pack.h"
#include "../index.h"
#include "traits.h"
#include "injective.h"
namespace pfor {
namespace index {
namespace prop {
struct Linear;
}
template<typename L, typename R>
struct ComputeProperty<prop::Linear, op::Minus, L, R> {
using type = Pack<prop::Linear>;
};
template<typename L, typename R>
struct ComputeProperty<prop::Linear, op::Addition, L, R> {
using type = If<containsProperties<R, Pack<prop::Linear>>, Pack<prop::Linear>, Pack<>>;
};
template<typename L, typename R>
struct ComputeProperty<prop::Linear, op::Subtraction, L, R> {
using type = If<containsProperties<R, Pack<prop::Linear>>, Pack<prop::Linear>, Pack<>>;
};
template<typename S>
struct InferProperty<prop::Linear, S> {
using type = Pack<prop::Injective>;
};
/**
* @brief tags an index expression as linear
*
* Usually, this is not required as this property is automatically deduced
*/
template<typename Expr, typename P>
auto linear(IndexImpl<Expr, P>) {
return IndexImpl<Expr, AddProperties<P, Pack<prop::Linear>>>{};
}
/**
* @brief tests if an index has linear property
*
* @param Index an index
*
* @return true if Index is linear
*/
template<typename Index>
struct IsLinear {
static constexpr bool value = hasProperties<Index, Pack<prop::Linear>>;
};
template<typename P>
struct IsLinear<IndexP<P>>: std::true_type {};
template<Value b, typename P>
struct IsLinear<Index<b, P>>: std::true_type {};
template<Value b, typename P, typename LhsP, typename RhsP>
struct IsLinear<IndexImpl<Pack<op::Addition, IndexP<LhsP>, Index<b, RhsP>>, P>>: std::true_type {};
template<Value a, typename P, typename LhsP, typename RhsP>
struct IsLinear<IndexImpl<Pack<op::Multiplication, IndexP<LhsP>, Index<a, RhsP>>, P>>: std::true_type {};
template<Value a, Value b, typename P, typename InP, typename InLhsP, typename InRhsP, typename RhsP>
struct IsLinear<
IndexImpl<Pack<op::Addition,
IndexImpl<Pack<op::Multiplication, IndexP<InLhsP>, Index<a, InRhsP>>, InP>,
Index<b, RhsP>>, P>
>: std::true_type {};
template<typename Index>
constexpr bool isLinear = IsLinear<Index>::value;
/**
*/
template<typename> struct LinearSlope;
template<typename P>
struct LinearSlope<IndexP<P>> {
static constexpr Value value = 1;
};
template<Value b, typename P>
struct LinearSlope<Index<b, P>> {
static constexpr Value value = 0;
};
template<Value b, typename P, typename LhsP, typename RhsP>
struct LinearSlope<IndexImpl<Pack<op::Addition, IndexP<LhsP>, Index<b, RhsP>>, P>> {
static constexpr Value value = 1;
};
template<Value a, typename P, typename LhsP, typename RhsP>
struct LinearSlope<IndexImpl<Pack<op::Multiplication, IndexP<LhsP>, Index<a, RhsP>>, P>> {
static constexpr Value value = a;
};
template<Value a, Value b, typename P, typename InP, typename InLhsP, typename InRhsP, typename RhsP>
struct LinearSlope<
IndexImpl<Pack<op::Addition,
IndexImpl<Pack<op::Multiplication, IndexP<InLhsP>, Index<a, InRhsP>>, InP>,
Index<b, RhsP>>, P>
> {
static constexpr Value value = a;
};
template<typename E>
constexpr Value linearSlope = LinearSlope<E>::value;
/**
*/
template<typename> struct LinearOffset;
template<typename P>
struct LinearOffset<IndexP<P>> {
static constexpr Value value = 0;
};
template<Value b, typename P>
struct LinearOffset<Index<b, P>> {
static constexpr Value value = b;
};
template<Value b, typename P, typename LhsP, typename RhsP>
struct LinearOffset<IndexImpl<Pack<op::Addition, IndexP<LhsP>, Index<b, RhsP>>, P>> {
static constexpr Value value = b;
};
template<Value a, typename P, typename LhsP, typename RhsP>
struct LinearOffset<IndexImpl<Pack<op::Multiplication, IndexP<LhsP>, Index<a, RhsP>>, P>> {
static constexpr Value value = 0;
};
template<Value a, Value b, typename P, typename InP, typename InLhsP, typename InRhsP, typename RhsP>
struct LinearOffset<
IndexImpl<Pack<op::Addition,
IndexImpl<Pack<op::Multiplication, IndexP<InLhsP>, Index<a, InRhsP>>, InP>,
Index<b, RhsP>>, P>
> {
static constexpr Value value = b;
};
template<typename E>
constexpr Value linearOffset = LinearOffset<E>::value;
/**
*/
template<typename... Indices> struct AllLinear: std::integral_constant<bool, packAll<Pack<Indices...>, IsLinear>> {};
template<typename... Indices>
constexpr bool allLinear = AllLinear<Indices...>::value;
namespace impl {
using ILinear = AddProperties<Pack<>, Pack<prop::Linear>>;
}
/**
*/
template<Value a, Value b>
struct LinearIndexImpl {
using type = IndexImpl<Pack<op::Addition, IndexImplExpr<op::Multiplication, IndexImplExpr<>, Index<a>>, Index<b>>, impl::ILinear>;
};
template<>
struct LinearIndexImpl<0, 0> {
using type = Index<0, impl::ILinear>;
};
template<Value b>
struct LinearIndexImpl<0, b> {
using type = Index<b, impl::ILinear>;
};
template<Value a>
struct LinearIndexImpl<a, 0> {
using type = IndexImpl<Pack<op::Multiplication, IndexImplExpr<>, Index<a>>, impl::ILinear>;
};
template<Value b>
struct LinearIndexImpl<1, b> {
using type = IndexImpl<Pack<op::Addition, IndexImplExpr<>, Index<b>>, impl::ILinear>;
};
template<>
struct LinearIndexImpl<1, 0> {
using type = IndexP<impl::ILinear>;
};
template<Value a, Value b>
using LinearIndex = typename LinearIndexImpl<a, b>::type;
}
}
#endif