Program Listing for File NonlinearSolver.h#
↰ Return to documentation for file (include/Karana/SOADyn/NonlinearSolver.h)
/*
* Copyright (c) 2024-2026 Karana Dynamics Pty Ltd. All rights reserved.
*
* NOTICE TO USER:
*
* This source code and/or documentation (the "Licensed Materials") is
* the confidential and proprietary information of Karana Dynamics Inc.
* Use of these Licensed Materials is governed by the terms and conditions
* of a separate software license agreement between Karana Dynamics and the
* Licensee ("License Agreement"). Unless expressly permitted under that
* agreement, any reproduction, modification, distribution, or disclosure
* of the Licensed Materials, in whole or in part, to any third party
* without the prior written consent of Karana Dynamics is strictly prohibited.
*
* THE LICENSED MATERIALS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
* KARANA DYNAMICS DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
* BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, AND
* FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL KARANA DYNAMICS BE LIABLE FOR ANY DAMAGES WHATSOEVER,
* INCLUDING BUT NOT LIMITED TO LOSS OF PROFITS, DATA, OR USE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, WHETHER IN CONTRACT, TORT,
* OR OTHERWISE ARISING OUT OF OR IN CONNECTION WITH THE LICENSED MATERIALS.
*
* U.S. Government End Users: The Licensed Materials are a "commercial item"
* as defined at 48 C.F.R. 2.101, and are provided to the U.S. Government
* only as a commercial end item under the terms of this license.
*
* Any use of the Licensed Materials in individual or commercial software must
* include, in the user documentation and internal source code comments,
* this Notice, Disclaimer, and U.S. Government Use Provision.
*/
/**
* @file
* @brief Contains the declarations for the NonLinearSolver class and associated Eigen functors.
*/
#pragma once
#include "Karana/KCore/LockingBase.h"
#include "Karana/Math/Defs.h"
#include <functional>
#include <unsupported/Eigen/NonLinearOptimization>
// #include <unsupported/Eigen/NumericalDiff>
#include "Karana/Math/KaranaNumericalDiff.h"
namespace Karana::Dynamics {
namespace kc = Karana::Core;
namespace km = Karana::Math;
/// Nonlinear function to solve.
using cost_fn = std::function<void(km::ConstVecSlice, km::VecSlice)>;
/// Jacobian for the nonlinear function.
using jac_fn = std::function<void(km::ConstVecSlice, km::MatSlice)>;
/**
* @brief NonlinearSolver class manages a nonlinear problem and associated solver.
*/
class NonlinearSolver : public kc::LockingBase {
public:
/**
* @brief NonlinearSolver constructor. This is a container that holds the information
* needed to solve a nonlinear problem and constructs internal state using healthiness
* before each solve. Calls down into child classes for implementation details.
*
* @param name The name of the nonlinear solver.
* @param input_dim The number of inputs.
* @param value_dim The number of values (outputs).
* @param f The cost function. This should take in a vector of inputs and output a
* vector of outputs.
* @param j The jacobian function. This is optional, if not specified, the jacobian
* will be computed by forward numerical differentiation.
*/
NonlinearSolver(
std::string_view name, int input_dim, int value_dim, cost_fn f, jac_fn j = nullptr);
/**
* @brief Get the cost function.
* @returns The cost function.
*/
cost_fn getF();
/**
* @brief Set the cost function. After setting the function, you will need to re-create the
* solver if one has already been set. Otherwise, the solver will still retain the
* old cost function.
* @param f The cost function.
*/
void setF(cost_fn f);
/**
* @brief Get the jacobian function.
* @returns The jacobian function.
*/
jac_fn getJac();
/**
* @brief Set the jacobian function. After setting the jacobian.function, you will need to
* re-create the solver if one has already been set. Otherwise, the solver will still retain
* the old cost function.
* @param jac The jacobian function.
*/
void setJac(jac_fn jac);
/**
* @brief Solve the nonlinear system.
*
* Some solvers may support upper and lower bounds; pass an empty
* vector for no bounds, or a NaN entry for no bounds on a given variable.
*
* @param x The initial guess.
* @param lb Lower bounds on parameters.
* @param ub Upper bounds on parameters.
* @return The norm squared of the final cost error. */
double solve(km::Vec &x, const km::Vec &lb = {}, const km::Vec &ub = {});
/**
* @brief Set stopping tolerance for reduction in residual norm
*
* @param ftol New tolerance value
*/
void setFTol(double ftol);
/**
* @brief Set stopping tolerance for jacobian norm
*
* @param gtol New tolerance value
*/
void setGTol(double gtol);
/**
* @brief Set stopping tolerance for changes in parameter value
*
* @param xtol New tolerance value
*/
void setXTol(double xtol);
/// Contains status of last solve() call
enum Status {
/// Successfully converged to target tolerance
CONVERGED,
/// Hit iteration or time limit before converging
DID_NOT_CONVERGE,
/// Hit an error internally
FAILED,
/// Solver hasn't been run; no status to return
NOT_RUN_YET,
};
/**
* @brief Get the status of the last solve() call.
*
* @return Status The outcome of the most recent solve() call.
*/
Status getStatus() const;
/**
* @brief Get the dimensionality of the input space
*
* @return int Input space dimensionality.
*/
int getInputDim() const;
/**
* @brief Get the dimensionality of the value space
*
* @return int Value space dimensionality.
*/
int getValueDim() const;
/**
* @brief Get the number of cost function evaluations for the last solve, or -1 if no solves
* have been run
*
* @return int Number of cost function evaluations
*/
int getLastNumEvals() const;
protected:
/**
* @brief Child class implementation of solve routine; stores converged solution in
* input.
*
* @param x State variable that holds initial guess and stores solution at the end.
* @param lb Lower bounds on parameters; only supported by Ceres solvers.
* @param ub Upper bounds on parameters; only supported by Ceres solvers.
*/
virtual void _solve(km::Vec &x, const km::Vec &lb, const km::Vec &ub) = 0;
/// Dimensionality of input space
int _input_dim;
/// Dimensionality of value (output) space
int _value_dim;
/// Cost function F(x)
cost_fn _f;
/// Jacobian function dF/dx
jac_fn _j;
/// Number of function evals on last call
int _last_num_evals;
/// Stopping tolerance for reduction in residual norm
double _ftol;
/// Stopping tolerance for jacobian norm
double _gtol;
/// Stopping tolerance for changes in parameter value
double _xtol;
/// Cached status for return
Status _status;
};
} // namespace Karana::Dynamics