207 lines
5.2 KiB
C++
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
|