소스 검색

Adds single-value analogues to Zip/Map in Tuple/Apply

Caleb Fangmeier 8 년 전
부모
커밋
ae79fbb143
4개의 변경된 파일218개의 추가작업 그리고 76개의 파일을 삭제
  1. 20 5
      api.hpp
  2. 53 1
      container.hpp
  3. 41 0
      dataset.hpp
  4. 104 70
      value.hpp

+ 20 - 5
api.hpp

@@ -28,6 +28,26 @@ namespace fv{
         return new Zip<ArgTypes...>(args..., alias);
     }
 
+    template <typename Ret, typename... ArgTypes>
+    Map<Ret(ArgTypes...)>* map(Function<Ret(ArgTypes...)>& fn,
+                                        Zip<ArgTypes...>* arg, const std::string& alias=""){
+        return new Map<Ret(ArgTypes...)>(fn, arg, alias);
+    }
+
+
+    template <typename... ArgTypes>
+    Tuple<ArgTypes...>* tuple(Value<ArgTypes>*... args, const std::string& alias=""){
+        return new Tuple<ArgTypes...>(args..., alias);
+    }
+
+    template <typename Ret, typename... ArgTypes>
+    Apply<Ret(ArgTypes...)>* apply(Function<Ret(ArgTypes...)>& fn,
+                                   Tuple<ArgTypes...>* arg, const std::string& alias=""){
+        return new Apply<Ret(ArgTypes...)>(fn, arg, alias);
+    }
+
+
+
     template <typename T1, typename T2>
     Pair<T1, T2>* pair(Value<T1>* val1, Value<T2>* val2, const std::string& alias=""){
         return new Pair<T1,T2>(val1, val2, alias);
@@ -38,11 +58,6 @@ namespace fv{
         return pair<T1,T2>(lookup<T1>(name1), lookup<T2>(name2), alias);
     }
 
-    template <typename Ret, typename... ArgTypes>
-    Map<Ret(ArgTypes...)>* map(Function<Ret(ArgTypes...)>& fn,
-                                        Zip<ArgTypes...>* arg, const std::string& alias=""){
-        return new Map<Ret(ArgTypes...)>(fn, arg, alias);
-    }
 
     template <typename T>
     Max<T>* max(Value<std::vector<T>>* v, const std::string alias){

+ 53 - 1
container.hpp

@@ -1,3 +1,33 @@
+/**
+ * @file
+ * @author  Caleb Fangmeier <caleb@fangmeier.tech>
+ * @version 0.1
+ *
+ * @section LICENSE
+ *
+ *
+ * MIT License
+ *
+ * Copyright (c) 2017 Caleb Fangmeier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
 #ifndef container_hpp
 #define container_hpp
 #include <typeindex>
@@ -30,12 +60,20 @@ std::string get_type_name(const std::type_index& index){
 
 namespace fv{
 
+/**
+ * Enumeration of different options that can be used to save Containers. Not
+ * all options are allowed for all Containers.
+ */
 enum SaveOption{
     PNG = 0,
     PDF = 1,
     ROOT = 2
 };
 
+/**
+ * Generic, untyped parent class of Container. Used to allow for placing
+ * Containers of disparate types in common data structures.
+ */
 class GenContainer{
     private:
         std::string name;
@@ -72,8 +110,14 @@ class GenContainer{
             save_as(get_name(), option);
         }
 };
-typedef std::map<std::string, GenContainer*> ContainerSet;
 
+/**
+ * A class that is used to "hold" values. When an event is loaded, the
+ * associated filters on this container are checked. If they all pass, the
+ * \c _fill() method is called and the Container can access the stored Value
+ * object to process it. For example, if the Container is a ROOT Histogram
+ * object, it may call <tt>container->Fill(value->get_value())</tt>.
+ */
 template <typename H>
 class Container : public GenContainer{
     protected:
@@ -88,6 +132,14 @@ class Container : public GenContainer{
 
 };
 
+/**
+ * Calculate the Mean of a Value over a series of observations. This class is
+ * given a value of some type that supports addition and division(eg. a \c
+ * float) and yields the mean value. Note that this implementation does \i not
+ * support serialization so it is not incredibly useful. See the ROOT
+ * Containers for Containers that support serialization using ROOT's
+ * facilities.
+ */
 template <typename T>
 class ContainerMean : public Container<T>{
     private:

+ 41 - 0
dataset.hpp

@@ -1,3 +1,33 @@
+/**
+ * @file
+ * @author  Caleb Fangmeier <caleb@fangmeier.tech>
+ * @version 0.1
+ *
+ * @section LICENSE
+ *
+ *
+ * MIT License
+ *
+ * Copyright (c) 2017 Caleb Fangmeier
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
 #ifndef dataset_hpp
 #define dataset_hpp
 #include <iostream>
@@ -6,6 +36,17 @@
 #include "log.hpp"
 
 namespace fv{
+
+typedef std::map<std::string, GenContainer*> ContainerSet;
+
+/*
+ * A DataSet is a generic source of data that is used to populate
+ * ObservedValues. For each ObservedValue, it is recommened that the DataSet
+ * have a field whose value is updated when the load_next() method is called. A
+ * pointer to this value is then passed during the creation of the
+ * ObservedValue. It is important, therefore, that the location in memory of
+ * the data not change from event to event.
+ */
 class DataSet{
     private:
         void summary(){

+ 104 - 70
value.hpp

@@ -60,36 +60,37 @@
  */
 namespace fv{
 
-template <typename F, typename Tuple, bool Done, int Total, int... N>
+template <typename F, typename TUPLE, bool Done, int Total, int... N>
 struct call_impl
 {
-    static auto call(F f, Tuple && t)
+    static auto call(F& f, TUPLE && t)
     {
-        return call_impl<F, Tuple, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<Tuple>(t));
+        return call_impl<F, TUPLE, Total == 1 + sizeof...(N), Total, N..., sizeof...(N)>::call(f, std::forward<TUPLE>(t));
     }
 };
 
-template <typename F, typename Tuple, int Total, int... N>
-struct call_impl<F, Tuple, true, Total, N...>
+template <typename F, typename TUPLE, int Total, int... N>
+struct call_impl<F, TUPLE, true, Total, N...>
 {
-    static auto call(F f, Tuple && t)
+    static auto call(F& f, TUPLE && t)
     {
-        return f(std::get<N>(std::forward<Tuple>(t))...);
+        return f(std::get<N>(std::forward<TUPLE>(t))...);
     }
 };
 
 /**
- * This calls a function of type F with the contents of the tuple as arguments
+ * This calls a function of type F with the contents of the tuple as separate arguments.
  *  \see http://stackoverflow.com/questions/10766112/c11-i-can-go-from-multiple-args-to-tuple-but-can-i-go-from-tuple-to-multiple
  */
-template <typename F, typename Tuple>
-auto call(F f, Tuple && t)
+template <typename F, typename TUPLE>
+auto call(F& f, TUPLE && t)
 {
-    typedef typename std::decay<Tuple>::type ttype;
-    return call_impl<F, Tuple, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<Tuple>(t));
+    typedef typename std::decay<TUPLE>::type ttype;
+    return call_impl<F, TUPLE, 0 == std::tuple_size<ttype>::value, std::tuple_size<ttype>::value>::call(f, std::forward<TUPLE>(t));
 }
 
 template<typename> class Function; // undefined
+
 /**
  * Parent class to all Function classes. Holds a class-level collection of all
  * created function objects.
@@ -141,7 +142,7 @@ class GenFunction {
             ss << "The following functions have been registered" << std::endl;
             for(auto p : function_registry){
                 if (p.second == nullptr) continue;
-                ss << "-->" << p.second->name << std::endl;
+                ss << "-->" << p.second->name  << "@" << p.second << std::endl;
                 ss << format_code(p.second->impl);
             }
             return ss.str();
@@ -346,7 +347,7 @@ class Value : public GenValue{
 
 
 /**
- * A generic, observed, value.
+ * A value supplied by the dataset, not derived.
  * An ObservedValue is the interface to your dataset. Upon creation, an
  * ObservedValue is given a pointer to an object of type T. When an observation
  * is loaded into memory, the value at the location referenced by that pointer
@@ -371,7 +372,7 @@ class ObservedValue : public Value<T>{
 
 
 /**
- * A generic, derived, value.
+ * A Value derived from some other Values, not directly from the dataset.
  * A DerivedValue is generally defined as some function of other Value objects.
  * For example, a Pair is a function of two other Value objects that makes a
  * pair of them. Note that these other Value objects are free to be either
@@ -410,7 +411,6 @@ class DerivedValue : public Value<T>{
            value_valid(false) { }
 
         T& get_value(){
-            /* std::cout << "getting value of " << this->get_name() << std::endl; */
             if (!value_valid){
                 update_value();
                 value_valid = true;
@@ -478,10 +478,6 @@ class _Zip<> {
             return std::make_tuple();
         }
 
-        bool _verify_integrity() {
-            return true;
-         }
-
         std::string _get_name(){
             return "";
         }
@@ -506,10 +502,6 @@ class _Zip<Head, Tail...> : private _Zip<Tail...> {
             return std::tuple_cat(std::make_tuple(head->get_value()[idx]),tail_tuple);
         }
 
-        bool _verify_integrity() {
-            return (head != nullptr) &&_Zip<Tail...>::_verify_integrity();
-         }
-
         std::string _get_name(){
             return head->get_name()+","+_Zip<Tail...>::_get_name();
         }
@@ -562,6 +554,13 @@ class Zip : public DerivedValue<std::vector<std::tuple<ArgTypes...>>>,
 };
 
 template<typename> class Map; // undefined
+/**
+ * Maps a function over an input vector. The input vector must be a vector of
+ * tuples, where the the elements of the tuple match the arguments of the
+ * function. For example if the function takes two floats as arguments, the
+ * tuple should contain two floats. The Value object required by Map will
+ * typically be created as a Zip.
+ */
 template <typename Ret, typename... ArgTypes>
 class Map<Ret(ArgTypes...)> : public DerivedValue<std::vector<Ret>>{
     private:
@@ -577,66 +576,101 @@ class Map<Ret(ArgTypes...)> : public DerivedValue<std::vector<Ret>>{
 
     public:
         Map(Function<Ret(ArgTypes...)>& fn, Zip<ArgTypes...>* arg, const std::string& alias)
-          :DerivedValue<std::vector<Ret>>("map_over("+fn.get_name()+":"+arg->get_name()+")", alias),
+          :DerivedValue<std::vector<Ret>>("map("+fn.get_name()+":"+arg->get_name()+")", alias),
            fn(fn), arg(arg){ }
 
 };
 
+template<typename... T> class _Tuple;
+template<>
+class _Tuple<> {
+    protected:
+
+        std::tuple<> _get_value(){
+            return std::make_tuple();
+        }
+
+        std::string _get_name(){
+            return "";
+        }
+
+    public:
+        _Tuple() { }
+};
+
+template<typename Head, typename... Tail>
+class _Tuple<Head, Tail...> : private _Tuple<Tail...> {
+    protected:
+        Value<Head>* head;
+
+        typename std::tuple<Head,Tail...> _get_value(){
+            auto tail_tuple = _Tuple<Tail...>::_get_value();
+            return std::tuple_cat(std::make_tuple(head->get_value()),tail_tuple);
+        }
+
+
+        std::string _get_name(){
+            return head->get_name()+","+_Tuple<Tail...>::_get_name();
+        }
+
+    public:
+        _Tuple() { }
+
+        _Tuple(Value<Head>* head, Value<Tail>*... tail)
+          : _Tuple<Tail...>(tail...),
+            head(head) { }
+};
+
+/**
+ * Takes a series of Value objects and bundles them together into a std::tuple
+ * object. Typically, this is most usefull when one wants to apply a function
+ * to a few values and store the result. This class can be used in conjunction
+ * with Apply to achieve this.
+ */
+template <typename... ArgTypes>
+class Tuple : public DerivedValue<std::tuple<ArgTypes...>>,
+              private _Tuple<ArgTypes...>{
+    protected:
+        void update_value(){
+            this->value = _Tuple<ArgTypes...>::_get_value();
+        }
+
+        std::string _get_name(){
+            return "tuple("+_Tuple<ArgTypes...>::_get_name()+")";
+        }
+
+    public:
+        Tuple(Value<ArgTypes>*... args, const std::string& alias)
+          :DerivedValue<std::tuple<ArgTypes...>>("", alias),
+           _Tuple<ArgTypes...>(args...) {
+            this->set_name(_get_name());
+        }
+};
+
+template<typename> class Apply; // undefined
 /**
- * Takes a set of four Value<std::vector<T> > objects and a function of four Ts
- * and returns a std::vector<R>. This is used in, for instance, calculating the
- * energy of a set of particles when one has separate arrays containing pt,
- * eta, phi, and mass. These arrays are first wrapped up in VectorWrappers and
- * then passes along with a function to calculate the energy into a ZipMapFour.
- * The result of this calculation is a new vector containing the energy for
- * each particle. Note that if the input vectors are not all the same size,
- * calculations are only performed up to the size of the shortest.
- * \see MiniTreeDataSet
- * \todo find way to implement for arbitrary number(and possibly type) of
- * vector inputs.
+ * Applies a function to a tuple of values and returns a value. This will
+ * typically be called with a Tuple object as an argument.
  */
-template <typename R, typename T>
-class ZipMapFour : public DerivedValue<std::vector<R> >{
+template <typename Ret, typename... ArgTypes>
+class Apply<Ret(ArgTypes...)> : public DerivedValue<Ret>{
     private:
-        Function<R(T, T, T, T)>& f;
-        Value<std::vector<T> >* v1;
-        Value<std::vector<T> >* v2;
-        Value<std::vector<T> >* v3;
-        Value<std::vector<T> >* v4;
+        Function<Ret(ArgTypes...)>& fn;
+        Tuple<ArgTypes...>* arg;
 
         void update_value(){
-            std::vector<T> v1_val = v1->get_value();
-            std::vector<T> v2_val = v2->get_value();
-            std::vector<T> v3_val = v3->get_value();
-            std::vector<T> v4_val = v4->get_value();
-
-            int n;
-            std::tie(n, std::ignore) = std::minmax({v1_val.size(), v2_val.size(), v3_val.size(), v4_val.size()});
-            this->value.resize(n);
-            for (int i=0; i<n; i++){
-                this->value[i] = f(v1_val[i], v2_val[i], v3_val[i], v4_val[i]);
-            }
+            auto &tup = arg->get_value();
+            this->value = call(fn, tup);
         }
 
     public:
-        ZipMapFour(Function<R(T, T, T, T)>& f,
-                   Value<std::vector<T> >* v1, Value<std::vector<T> >* v2,
-                   Value<std::vector<T> >* v3, Value<std::vector<T> >* v4, const std::string alias)
-          :DerivedValue<std::vector<R> >("zipmap("+f.get_name()+":"+v1->get_name()+","+v2->get_name()+","+
-                                                                    v3->get_name()+","+v4->get_name()+")", alias),
-           f(f), v1(v1), v2(v2), v3(v3), v4(v4) { }
-
-        ZipMapFour(Function<R(T, T, T, T)>& f,
-                   const std::string& label1, const std::string& label2,
-                   const std::string& label3, const std::string& label4, const std::string alias)
-          :ZipMapFour(f,
-                      dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label1)),
-                      dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label2)),
-                      dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label3)),
-                      dynamic_cast<Value<std::vector<T> >*>(GenValue::get_value(label4)),
-                      alias){ }
+        Apply(Function<Ret(ArgTypes...)>& fn, Tuple<ArgTypes...>* arg, const std::string& alias)
+          :DerivedValue<Ret>("apply("+fn.get_name()+":"+arg->get_name()+")", alias),
+           fn(fn), arg(arg){ }
+
 };
 
+
 /**
  * Returns the count of elements in the input vector passing a test function.
  */