Line data Source code
1 : #pragma once 2 : 3 : #include "Cloneable.h" 4 : #include "DataDescriptor.h" 5 : #include "LinearOperator.h" 6 : 7 : #include <memory> 8 : 9 : namespace elsa 10 : { 11 : /** 12 : * @brief Abstract base class representing a residual, i.e. a vector-valued mapping. 13 : * 14 : * @author Matthias Wieczorek - initial code 15 : * @author Tobias Lasser - modularization, streamlining 16 : * 17 : * @tparam data_t data type for the domain and range of the operator, defaulting to real_t 18 : * 19 : * A residual is a vector-valued mapping representing an error (or mismatch). For real numbers 20 : * this corresponds to \f$ \mathbb{R}^n\to\mathbb{R}^m \f$ (e.g. \f$ x \mapsto Ax-b \f$ for 21 : * linear residuals). In order to measure this error, the residual can be used as input to a 22 : * Functional. 23 : */ 24 : template <typename data_t = real_t> 25 : class Residual : public Cloneable<Residual<data_t>> 26 : { 27 : public: 28 : /** 29 : * @brief Constructor for the residual, mapping from domain to range 30 : * 31 : * @param[in] domainDescriptor describing the domain of the residual 32 : * @param[in] rangeDescriptor describing the range of the residual 33 : */ 34 : Residual(const DataDescriptor& domainDescriptor, const DataDescriptor& rangeDescriptor); 35 : 36 : /// default destructor 37 3884 : ~Residual() override = default; 38 : 39 : /// return the domain descriptor 40 : const DataDescriptor& getDomainDescriptor() const; 41 : 42 : /// return the range descriptor 43 : const DataDescriptor& getRangeDescriptor() const; 44 : 45 : /** 46 : * @brief evaluate the residual at x and return the result 47 : * 48 : * @param[in] x input DataContainer (in the domain of the residual) 49 : * 50 : * @returns result DataContainer (in the range of the residual) containing the result of 51 : * the evaluation of the residual at x 52 : * 53 : * Please note: this method uses evaluate(x, result) to perform the actual operation. 54 : */ 55 : DataContainer<data_t> evaluate(const DataContainer<data_t>& x) const; 56 : 57 : /** 58 : * @brief evaluate the residual at x and store in result 59 : * 60 : * @param[in] x input DataContainer (in the domain of the residual) 61 : * @param[out] result output DataContainer (in the range of the residual) 62 : * 63 : * Please note: this method calls the method evaluateImpl that has to be overridden in 64 : * derived classes. (Why is this method here not virtual itself? Because you cannot 65 : * have a non-virtual function overloading a virtual one [evaluate with one vs. two args].) 66 : */ 67 : void evaluate(const DataContainer<data_t>& x, DataContainer<data_t>& result) const; 68 : 69 : /** 70 : * @brief return the Jacobian (first derivative) of the residual at x. 71 : * 72 : * @param[in] x input DataContainer (in the domain of the residual) at which the 73 : * Jacobian of the residual will be evaluated 74 : * 75 : * @returns a LinearOperator (the Jacobian) 76 : * 77 : * Please note: this method calls the method getJacobianImpl that has to be overridden in 78 : * derived classes. (This is not strictly necessary, it's just for consistency with 79 : * evaluate.) 80 : */ 81 : LinearOperator<data_t> getJacobian(const DataContainer<data_t>& x); 82 : 83 : protected: 84 : /// the data descriptor of the domain of the residual 85 : std::unique_ptr<DataDescriptor> _domainDescriptor; 86 : 87 : /// the data descriptor of the range of the residual 88 : std::unique_ptr<DataDescriptor> _rangeDescriptor; 89 : 90 : /// implement the polymorphic comparison operation 91 : bool isEqual(const Residual<data_t>& other) const override; 92 : 93 : /// the evaluate method that has to be overridden in derived classes 94 : virtual void evaluateImpl(const DataContainer<data_t>& x, 95 : DataContainer<data_t>& result) const = 0; 96 : 97 : /// the getJacobian method that has to be overriden in derived classes 98 : virtual LinearOperator<data_t> getJacobianImpl(const DataContainer<data_t>& x) = 0; 99 : }; 100 : } // namespace elsa