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