1 /**
2  * @file function.hpp
3  * @author Ryan Curtin
4  *
5  * The Function class is a wrapper class for any objective function that
6  * provides any of the functions that an optimizer might use.
7  *
8  * ensmallen is free software; you may redistribute it and/or modify it under
9  * the terms of the 3-clause BSD license.  You should have received a copy of
10  * the 3-clause BSD license along with ensmallen.  If not, see
11  * http://www.opensource.org/licenses/BSD-3-Clause for more information.
12  */
13 #ifndef ENSMALLEN_FUNCTION_HPP
14 #define ENSMALLEN_FUNCTION_HPP
15 
16 namespace ens {
17 
18 template<typename FunctionType, typename MatType, typename GradType>
19 class Function;
20 
21 } // namespace ens
22 
23 #include "function/traits.hpp"
24 #include "function/static_checks.hpp"
25 #include "function/add_evaluate.hpp"
26 #include "function/add_gradient.hpp"
27 #include "function/add_evaluate_with_gradient.hpp"
28 #include "function/add_separable_evaluate.hpp"
29 #include "function/add_separable_gradient.hpp"
30 #include "function/add_separable_evaluate_with_gradient.hpp"
31 
32 namespace ens {
33 
34 /**
35  * The Function class is a wrapper class for any FunctionType that will add any
36  * possible derived methods.  For instance, if the given FunctionType has
37  * Evaluate() and Gradient(), then Function<FunctionType> will have
38  * EvaluateWithGradient().  This infrastructure allows two things:
39  *
40  *   1. Optimizers can expect FunctionTypes to have a wider array of functions
41  *      than those FunctionTypes may actually implement.
42  *
43  *   2. FunctionTypes don't need to implement every single method that an
44  *      optimizer might require, just those from which every method can be
45  *      inferred.
46  *
47  * This class works by inheriting from a large set of "mixin" classes that
48  * provide missing functions, if needed.  For instance, the AddGradient<> mixin
49  * will provide a Gradient() method if the given FunctionType implements an
50  * EvaluateWithGradient() method.
51  *
52  * Since all of the casting is static and each of the mixin classes is an empty
53  * class, there should be no runtime overhead at all for this functionality.  In
54  * addition, this class does not (to the best of my knowledge) rely on any
55  * undefined behavior.
56  */
57 template<typename FunctionType, typename MatType, typename GradType>
58 class Function :
59     public AddSeparableEvaluateWithGradientStatic<FunctionType, MatType,
60         GradType>,
61     public AddSeparableEvaluateWithGradientConst<FunctionType, MatType,
62         GradType>,
63     public AddSeparableEvaluateWithGradient<FunctionType, MatType, GradType>,
64     public AddSeparableGradientStatic<FunctionType, MatType, GradType>,
65     public AddSeparableGradientConst<FunctionType, MatType, GradType>,
66     public AddSeparableGradient<FunctionType, MatType, GradType>,
67     public AddSeparableEvaluateStatic<FunctionType, MatType, GradType>,
68     public AddSeparableEvaluateConst<FunctionType, MatType, GradType>,
69     public AddSeparableEvaluate<FunctionType, MatType, GradType>,
70     public AddEvaluateWithGradientStatic<FunctionType, MatType, GradType>,
71     public AddEvaluateWithGradientConst<FunctionType, MatType, GradType>,
72     public AddEvaluateWithGradient<FunctionType, MatType, GradType>,
73     public AddGradientStatic<FunctionType, MatType, GradType>,
74     public AddGradientConst<FunctionType, MatType, GradType>,
75     public AddGradient<FunctionType, MatType, GradType>,
76     public AddEvaluateStatic<FunctionType, MatType, GradType>,
77     public AddEvaluateConst<FunctionType, MatType, GradType>,
78     public AddEvaluate<FunctionType, MatType, GradType>,
79     public FunctionType
80 {
81  public:
82   // All of the mixin classes either reflect existing functionality or provide
83   // an unconstructable overload with the same name, so we can use using
84   // declarations here to ensure that they are all accessible.  Since we don't
85   // know what FunctionType has, we can't use any using declarations there.
86   using AddSeparableEvaluateWithGradientStatic<
87       FunctionType, MatType, GradType>::EvaluateWithGradient;
88   using AddSeparableEvaluateWithGradientConst<
89       FunctionType, MatType, GradType>::EvaluateWithGradient;
90   using AddSeparableEvaluateWithGradient<
91       FunctionType, MatType, GradType>::EvaluateWithGradient;
92   using AddSeparableGradientStatic<
93       FunctionType, MatType, GradType>::Gradient;
94   using AddSeparableGradientConst<FunctionType, MatType, GradType>::Gradient;
95   using AddSeparableGradient<FunctionType, MatType, GradType>::Gradient;
96   using AddSeparableEvaluateStatic<
97       FunctionType, MatType, GradType>::Evaluate;
98   using AddSeparableEvaluateConst<FunctionType, MatType, GradType>::Evaluate;
99   using AddSeparableEvaluate<FunctionType, MatType, GradType>::Evaluate;
100   using AddEvaluateWithGradientStatic<FunctionType, MatType, GradType>::EvaluateWithGradient;
101   using AddEvaluateWithGradientConst<FunctionType, MatType, GradType>::EvaluateWithGradient;
102   using AddEvaluateWithGradient<FunctionType, MatType, GradType>::EvaluateWithGradient;
103   using AddGradientStatic<FunctionType, MatType, GradType>::Gradient;
104   using AddGradientConst<FunctionType, MatType, GradType>::Gradient;
105   using AddGradient<FunctionType, MatType, GradType>::Gradient;
106   using AddEvaluateStatic<FunctionType, MatType, GradType>::Evaluate;
107   using AddEvaluateConst<FunctionType, MatType, GradType>::Evaluate;
108   using AddEvaluate<FunctionType, MatType, GradType>::Evaluate;
109 };
110 
111 } // namespace ens
112 
113 #endif
114