/*============================================================================= This file is part of FLINT. FLINT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. FLINT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with FLINT; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =============================================================================*/ /****************************************************************************** Copyright (C) 2013 Tom Bachmann ******************************************************************************/ // Sketch of a generic vector class. #ifndef CXX_VECTOR_H #define CXX_VECTOR_H #include #include #include "expression.h" #include "evaluation_tools.h" #include "ltuple.h" #include "mp.h" namespace flint { FLINT_DEFINE_BINOP(vector_at) template class vector_expression; namespace detail { template struct vector_wrapper : derived_wrapper2 { }; template struct vector_at_traits { typedef FLINT_BINOP_ENABLE_RETTYPE(vector_at, Expr, Idx) ref_t; typedef ref_t cref_t; static ref_t at(const Expr& v, Idx i) {return vector_at(v, i);} }; template struct vector_at_traits : Traits { }; } template class vector_expression : public expression, Operation, Data> { public: typedef expression, Operation, Data> base_t; typedef typename Underlying_traits::ref_t ref_t; typedef typename Underlying_traits::cref_t cref_t; typedef typename Underlying_traits::idx_t idx_t; typedef typename Underlying_traits::underlying_t underlying_t; typedef typename Underlying_traits::arrayref_t arrayref_t; typedef typename Underlying_traits::arraysrcref_t arraysrcref_t; vector_expression() {} template explicit vector_expression(const T& t) : base_t(t) {} template vector_expression(const T& t, const U& u) : base_t(t, u) {} template vector_expression(const T& t, const U& u, const V& v) : base_t(t, u, v) {} template vector_expression& operator=(const T& t) { this->set(t); return *this; } template typename detail::vector_at_traits::ref_t operator[](Idx idx) { return detail::vector_at_traits::at(*this, idx); } template typename detail::vector_at_traits::cref_t operator[](Idx idx) const { return detail::vector_at_traits::at(*this, idx); } idx_t size() const {return Underlying_traits::size(*this);} arrayref_t _array() {return Underlying_traits::array(*this);} arraysrcref_t _array() const {return Underlying_traits::array(*this);} typename base_t::evaluated_t create_temporary() const { return Underlying_traits::create_temporary(*this); } protected: explicit vector_expression(const Data& d) : base_t(d) {} template friend class expression; }; namespace vectors { // Similar to matrices, the size of a vector expression has to be known in // order to allocate temporary objects. In this case, the generic // implementation looks for any vector immediate subexpression and returs its // size. This makes sense since mixing vectors of differing sizes usually makes // no sense. // Thus specialisation is usually only necessary in constructor-like operations, // which do not involve vector immediates. template struct outsize { template static unsigned get(const Expr& e) { return tools::find_subexpr_T(e)._data().size; } }; // Hack for ltuple_get, similar to the matrices case. template struct outsize > { template static unsigned get(const Expr& e) { return outsize::get( e._data().head); } }; } namespace detail { template struct basic_vector_traits { typedef unsigned idx_t; typedef Ref ref_t; typedef const Cref cref_t; typedef T underlying_t; typedef ArrayT* arrayref_t; typedef const ArrayT* arraysrcref_t; template static ref_t at(Expr& e, unsigned i) { return e.evaluate()._data().array[i]; } template static cref_t at(const Expr& e, unsigned i) { return e.evaluate()._data().array[i]; } template static arrayref_t array(Expr& e) { return e.evaluate()._data().array; } template static arraysrcref_t array(const Expr& e) { return e.evaluate()._data().array; } }; template struct rtfixed_size_traits : basic_vector_traits { template static unsigned size(const Expr& e) { return vectors::outsize::get(e); } template static typename Expr::evaluated_t create_temporary(const Expr& e) { return typename Expr::evaluated_t(e.size()); } }; template struct fixed_size_traits : basic_vector_traits { template static unsigned size(const Expr& e) { return Expr::evaluated_t::data_t::size; } template static typename Expr::evaluated_t create_temporary(const Expr& e) { return typename Expr::evaluated_t(); } }; template struct wrapped_vector_traits : rtfixed_size_traits { typedef Size idx_t; template static Ref at(Expr& e, idx_t i) { return e.evaluate()._data().at(i); } template static Cref at(const Expr& e, idx_t i) { return e.evaluate()._data().at(i); } }; template struct rtfixed_size_data { const unsigned size; T* array; rtfixed_size_data(unsigned n) : size(n), array(new T[n]) {} ~rtfixed_size_data() {delete[] array;} rtfixed_size_data(const rtfixed_size_data& o) : size(o.size) { // TODO this is very non-optimal ... (?) array = new T[size]; for(unsigned i = 0;i < size;++i) { array[i] = o.array[i]; } } }; template struct fixed_size_data { static const unsigned size = n; T array[n]; }; } // detail template struct make_vector { typedef vector_expression, operations::immediate, detail::rtfixed_size_data > type; }; template struct make_vector_n { typedef vector_expression, operations::immediate, detail::fixed_size_data > type; }; template struct enable_vector_rules : mp::false_ { }; template struct enable_vector_rules< vector_expression > : mp::true_ { }; namespace rules { // temporary allocation inside ltuples template struct instantiate_temporaries, vector_expression > { typedef ltuple_expression Expr; typedef vector_expression T; static T get(const Expr& e) { return T(vectors::outsize::get(e)); } }; template struct binary_expression, operations::vector_at_op, T> { typedef typename Traits::underlying_t return_t; template static void doit(V& to, const vector_expression& v, T i) { to = Traits::at(v, i); } }; template struct to_string, traits::is_implemented > > >::type> { static std::string get(const Expr& e, int base) { // TODO inefficient std::string res = "("; for(typename Expr::idx_t i = 0;i < e.size();++i) { res += e[i].to_string(); if(i != e.size() - 1) res += ", "; } res += ")"; return res; } }; template struct equals >::type> { static bool get(const Expr& e1, const Expr& e2) { if(e1.size() != e2.size()) return false; for(typename Expr::idx_t i = 0;i < e1.size();++i) if(e1[i] != e2[i]) return false; return true; } }; namespace rvdetail { template struct translate_data; template struct translate_expr { typedef translate_data trdata_t; typedef typename Expr::underlying_t ul_t; typedef typename ul_t::template make_helper< typename Expr::operation_t, typename trdata_t::type> make_helper; typedef typename make_helper::type type; template static type make(const Expr& e, Idx idx) { return make_helper::make(trdata_t::make(e._data(), idx)); } }; template struct translate_expr >::type> { typedef typename Expr::cref_t type; template static type make(const Expr& e, Idx idx) { return e[idx]; } }; template struct translate_data > { typedef translate_expr::type> trexpr; typedef translate_data trtail; typedef tuple type; template static type make(const tuple& e, Idx idx) { return type(trexpr::make(e.head, idx), trtail::make(e.tail, idx)); } }; template<> struct translate_data { typedef empty_tuple type; template static type make(empty_tuple, Idx) {return empty_tuple();} }; template struct enable_evaluation : mp::false_ {typedef void vector_t;}; template struct enable_evaluation::type> >::type> : enable_vector_rules::type::evaluated_t> { typedef typename traits::basetype::type::evaluated_t vector_t; }; template struct enable_evaluation > : mp::and_, enable_evaluation > { typedef typename enable_evaluation::vector_t vector_t; }; template<> struct enable_evaluation : mp::true_ { }; } //rvdetail // TODO this is a bit greedy .. template struct evaluation >::type> { typedef rvdetail::translate_data translator; typedef typename translator::type trdata_t; typedef typename mp::find_evaluation< Op, trdata_t, result_is_temporary>::type rule_t; typedef typename rvdetail::enable_evaluation::vector_t vector_t; typedef typename vector_t::evaluated_t return_t; // TODO typedef typename rule_t::temporaries_t temporaries_t; typedef typename rule_t::return_t trreturn_t; template static void doit(const Data& input, temporaries_t temps, Return* output) { for(typename return_t::idx_t i = 0;i < output->size();++i) { rule_t::doit(translator::make(input, i), temps, &((*output)[i])); } } }; // TODO scalar multiplication etc } // rules } // flint #endif