Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Comment thread
gabrielfrasantos marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Refer to the documentation to quickly integrate and utilize the library's signal
| [Solvers](doc/solvers/README.md) | Gaussian Elimination, Levinson-Durbin, Durand-Kerner, Cholesky, DARE, Runge-Kutta ODE Integrators (RK4 + Dormand-Prince), Spectral Radius & Discrete Stability Margin, QR Decomposition (Householder / Givens), LU Decomposition with Partial Pivoting, Singular Value Decomposition (Golub-Kahan) |
| [Nonlinear Control](doc/nonlinear_control/README.md) | Feedback Linearization, Backstepping Control, Model Reference Adaptive Control (MRAC) |
| [Robust Control](doc/robust_control/README.md) | Active Disturbance Rejection Control (ADRC + ESO), Sliding Mode Control (SMC), Disturbance Observer (DOB), H∞ State-Feedback Control |
| [Performance Optimization](doc/performance-optimization/README.md) | Compiler optimizations, SIMD |
| [Performance Optimization](doc/performance-optimization/README.md) | Compiler optimizations |

Each category page lists its algorithms with a brief description and links to the detailed documentation.

Expand Down
16 changes: 8 additions & 8 deletions doc/optimization/Optimizer.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Overview & Motivation

An **optimizer** adjusts a model's parameter vector $\theta \in \mathbb{R}^P$ to minimize a [loss function](../losses/Loss.md) $\mathcal{L}(\theta)$. The simplest and most fundamental strategy is **gradient descent**: repeatedly step in the direction of steepest descent:
An **optimizer** adjusts a model's parameter vector $\theta \in \mathbb{R}^P$ to minimize a loss function $\mathcal{L}(\theta)$. The simplest and most fundamental strategy is **gradient descent**: repeatedly step in the direction of steepest descent:

$$\theta_{t+1} = \theta_t - \eta \, \nabla_\theta \mathcal{L}(\theta_t)$$

Expand All @@ -14,7 +14,7 @@ This library provides a batch gradient descent optimizer with a fixed learning r

### The Gradient

The gradient $\nabla_\theta \mathcal{L}$ is obtained via [back-propagation](../NeuralNetwork.md). Each component $\frac{\partial \mathcal{L}}{\partial \theta_i}$ tells how much the loss changes when $\theta_i$ is perturbed by a small amount. The gradient points **uphill**; subtracting it moves **downhill**.
The gradient $\nabla_\theta \mathcal{L}$ is obtained via back-propagation. Each component $\frac{\partial \mathcal{L}}{\partial \theta_i}$ tells how much the loss changes when $\theta_i$ is perturbed by a small amount. The gradient points **uphill**; subtracting it moves **downhill**.

### Convergence Conditions

Expand Down Expand Up @@ -127,12 +127,12 @@ graph TD
Opt -.->|"analytical solution at η→∞, 1 step"| LR
```

| Component | Relationship |
|-----------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| [Loss Functions](../losses/Loss.md) | Provides the `Cost()` and `Gradient()` the optimizer calls each iteration |
| [Model](../model/Model.md) | Passes initial parameters to the optimizer and receives optimized parameters back |
| [Regularization](../regularization/Regularization.md) | Adds a penalty gradient to $\nabla\mathcal{L}$, biasing the optimizer toward simpler models |
| [Linear Regression](../../estimators/LinearRegression.md) | For MSE on a linear model, gradient descent converges to the same solution as the normal equation |
| Component | Relationship |
|--------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| Loss Functions | Provides the `Cost()` and `Gradient()` the optimizer calls each iteration |
| Model | Passes initial parameters to the optimizer and receives optimized parameters back |
| [Regularization](../regularization/Regularization.md) | Adds a penalty gradient to $\nabla\mathcal{L}$, biasing the optimizer toward simpler models |
| [Linear Regression](../estimators/LinearRegression.md) | For MSE on a linear model, gradient descent converges to the same solution as the normal equation |

## References & Further Reading

Expand Down
10 changes: 5 additions & 5 deletions doc/regularization/Regularization.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ graph TD
Reg -.->|"L2 + MSE = Ridge regression"| LR
```

| Component | Relationship |
|-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| [Loss Functions](../losses/Loss.md) | Regularization is a penalty *added to* the loss: $\mathcal{L}_{\text{total}} = \mathcal{L} + \lambda\Omega$ |
| [Optimizer](../optimizer/Optimizer.md) | Receives the combined gradient $\nabla\mathcal{L} + \lambda\nabla\Omega$ |
| [Linear Regression](../../estimators/LinearRegression.md) | L2-regularized MSE with a linear model is **Ridge regression**; L1 is **Lasso** |
| Component | Relationship |
|--------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
| Loss Functions | Regularization is a penalty *added to* the loss: $\mathcal{L}_{\text{total}} = \mathcal{L} + \lambda\Omega$ |
| [Optimizer](../optimization/Optimizer.md) | Receives the combined gradient $\nabla\mathcal{L} + \lambda\nabla\Omega$ |
| [Linear Regression](../estimators/LinearRegression.md) | L2-regularized MSE with a linear model is **Ridge regression**; L1 is **Lasso** |

## References & Further Reading

Expand Down
13 changes: 11 additions & 2 deletions numerical/analysis/FastFourierTransform.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace analysis
class TwiddleFactors
{
public:
virtual ~TwiddleFactors() = default;
virtual math::Complex<QNumberType>& operator[](std::size_t n) = 0;
};

Expand All @@ -20,9 +21,17 @@ namespace analysis
"FastFourierTransform can only be instantiated with math::QNumber types.");

public:
constexpr std::size_t Log2(std::size_t n)
virtual ~FastFourierTransform() = default;

static constexpr std::size_t Log2(std::size_t n)
{
return (n <= 1) ? 0 : 1 + Log2(n >> 1);
std::size_t result = 0;
while (n > 1)
{
n >>= 1;
++result;
}
return result;
}

using VectorComplex = infra::BoundedVector<math::Complex<QNumberType>>;
Expand Down
62 changes: 59 additions & 3 deletions numerical/analysis/test/TestFastFourierTransformRadix2Impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,35 @@ namespace
typename VectorReal::template WithMaxSize<Length> timeDomain;
typename VectorComplex::template WithMaxSize<Length> frequencyDomain;
};

class MockTwiddleFactorsDegenerate
: public analysis::TwiddleFactors<float, 0>
{
public:
math::Complex<float>& operator[](std::size_t) override
{
return dummy;
}

private:
math::Complex<float> dummy{};
};

class TestFastFourierTransformCoverage : public ::testing::Test
{};

class TestFastFourierTransformSingleSample : public ::testing::Test
{
protected:
MockTwiddleFactorsDegenerate tw;
analysis::FastFourierTransformRadix2Impl<float, 1> fft{ tw };
};
}

TYPED_TEST(TestFastFourierTransform, log2_runtime_both_branches)
{
auto& fftInst = *this->fft;
EXPECT_EQ(fftInst.Log2(1), 0u);
EXPECT_EQ(fftInst.Log2(8), 3u);
EXPECT_EQ(analysis::FastFourierTransform<TypeParam>::Log2(1), 0u);
EXPECT_EQ(analysis::FastFourierTransform<TypeParam>::Log2(8), 3u);
}

TYPED_TEST(TestFastFourierTransform, zero_input_produces_zero_output)
Expand Down Expand Up @@ -302,3 +324,37 @@ TEST_F(TestFastFourierTransformFloat, all_bins_match_direct_dft)
EXPECT_NEAR(result[k].Imaginary(), refImag, 1e-3f);
}
}

TEST_F(TestFastFourierTransformCoverage, twiddle_factors_virtual_destructor)
{
MockTwiddleFactors<float> tf;
(void)tf;
}

TEST_F(TestFastFourierTransformCoverage, fft_base_virtual_destructor)
{
MockTwiddleFactors<float> tw;
analysis::FastFourierTransformRadix2Impl<float, 8> fft{ tw };
(void)fft;
}

TEST_F(TestFastFourierTransformCoverage, log2_static_one_returns_zero)
{
EXPECT_EQ(analysis::FastFourierTransform<float>::Log2(1), 0u);
}

TEST_F(TestFastFourierTransformCoverage, log2_static_eight_returns_three)
{
EXPECT_EQ(analysis::FastFourierTransform<float>::Log2(8), 3u);
}

TEST_F(TestFastFourierTransformSingleSample, forward_single_sample_is_identity)
{
typename analysis::FastFourierTransform<float>::VectorReal::template WithMaxSize<1> input;
input.push_back(0.5f);

auto& result = fft.Forward(input);

EXPECT_NEAR(result[0].Real(), 0.5f, 1e-5f);
EXPECT_NEAR(result[0].Imaginary(), 0.0f, 1e-5f);
}
1 change: 1 addition & 0 deletions numerical/controllers/interfaces/PidDriver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace controllers
class PidDriver
{
public:
virtual ~PidDriver() = default;
virtual void Read(const infra::Function<void(QNumberType)>& onDone) = 0;
virtual void ControlAction(QNumberType) = 0;
virtual void Start(std::chrono::system_clock::duration sampleTime) = 0;
Expand Down
4 changes: 4 additions & 0 deletions numerical/estimators/Estimator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ namespace estimators
"OfflineEstimator only supports float or QNumber types");

public:
virtual ~OfflineEstimator() = default;

using CoefficientsMatrix = math::Matrix<T, Features + 1, 1>;
using DesignMatrix = math::Matrix<T, Features + 1, Features + 1>;
using InputMatrix = math::Matrix<T, Features, 1>;
Expand All @@ -27,6 +29,8 @@ namespace estimators
"OnlineEstimator only supports float or QNumber types");

public:
virtual ~OnlineEstimator() = default;

using CoefficientsMatrix = math::Matrix<T, Features, 1>;
using DesignMatrix = math::Matrix<T, Features, Features>;
using InputMatrix = math::Matrix<T, Features, 1>;
Expand Down
11 changes: 7 additions & 4 deletions numerical/math/test/TestQNumber.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ namespace

using QNumberTypes = ::testing::Types<math::Q31, math::Q15>;
TYPED_TEST_SUITE(QNumberTest, QNumberTypes);

class QNumberUtilTest : public ::testing::Test
{};
}

TYPED_TEST(QNumberTest, DefaultConstructorIsZero)
Expand Down Expand Up @@ -324,27 +327,27 @@ TYPED_TEST(QNumberTest, ToFloatFreeFunction_QNumber)
EXPECT_NEAR(math::ToFloat(a), 0.25f, math::Tolerance<float>());
}

TEST(QNumberUtilTest, ToFloatFreeFunction_Float)
TEST_F(QNumberUtilTest, ToFloatFreeFunction_Float)
{
EXPECT_FLOAT_EQ(math::ToFloat(0.5f), 0.5f);
EXPECT_FLOAT_EQ(math::ToFloat(-0.3f), -0.3f);
}

TEST(QNumberUtilTest, MinMaxLowest_Float)
TEST_F(QNumberUtilTest, MinMaxLowest_Float)
{
EXPECT_GT(math::Min<float>(), 0.0f);
EXPECT_GT(math::Max<float>(), 1.0f);
EXPECT_LT(math::Lowest<float>(), 0.0f);
}

TEST(QNumberUtilTest, MinMaxLowest_Q31)
TEST_F(QNumberUtilTest, MinMaxLowest_Q31)
{
EXPECT_NEAR(math::Min<math::Q31>(), -0.9999f, 1e-3f);
EXPECT_NEAR(math::Max<math::Q31>(), 0.9999f, 1e-3f);
EXPECT_NEAR(math::Lowest<math::Q31>(), -0.9999f, 1e-3f);
}

TEST(QNumberUtilTest, MinMaxLowest_Q15)
TEST_F(QNumberUtilTest, MinMaxLowest_Q15)
{
EXPECT_NEAR(math::Min<math::Q15>(), -0.9999f, 1e-3f);
EXPECT_NEAR(math::Max<math::Q15>(), 0.9999f, 1e-3f);
Expand Down
1 change: 0 additions & 1 deletion numerical/math/test_doubles/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ target_link_libraries(numerical.math_test_helper INTERFACE

target_sources(numerical.math_test_helper PRIVATE
MatrixTestSupport.hpp
SingleInstructionMultipleDataStub.hpp
)
135 changes: 0 additions & 135 deletions numerical/math/test_doubles/SingleInstructionMultipleDataStub.hpp

This file was deleted.

2 changes: 2 additions & 0 deletions numerical/optimization/Optimizer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ namespace optimization
"Optimizer can only be instantiated with math::QNumber types.");

public:
virtual ~Optimizer() = default;

using Vector = math::Vector<QNumberType, NumberOfFeatures>;

struct Result
Expand Down
2 changes: 2 additions & 0 deletions numerical/solvers/Solver.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ namespace solvers
"Solver dimensions must be positive");

public:
virtual ~Solver() = default;

using SolutionVector = math::Vector<T, N>;
using InputMatrix = math::Matrix<T, N, N>;
using InputVector = math::Vector<T, N>;
Expand Down
Loading