Skip to content

Commit c4f58ce

Browse files
Upgrade ensmallen to 3.10.0 (#70)
* Upgrade ensmallen to 3.10.0 * Update NEWS.md with recent changes --------- Co-authored-by: coatless <[email protected]>
1 parent c651dd3 commit c4f58ce

File tree

208 files changed

+7127
-3475
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

208 files changed

+7127
-3475
lines changed

ChangeLog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
2025-09-30 James Balamuta <[email protected]>
2+
3+
* DESCRIPTION (Version): Release 3.10.0
4+
* NEWS.md: Update for Ensmallen release 3.10.0
5+
* inst/include/ensmallen_bits: Upgraded to Ensmallen 3.10.0
6+
* inst/include/ensmallen.hpp: ditto
7+
18
2025-09-09 James Balamuta <[email protected]>
29

310
* DESCRIPTION: Updated requirements for RcppArmadillo

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: RcppEnsmallen
22
Title: Header-Only C++ Mathematical Optimization Library for 'Armadillo'
3-
Version: 0.2.22.1.2
3+
Version: 0.3.10.0.1
44
Authors@R: c(
55
person("James Joseph", "Balamuta", email = "[email protected]",
66
role = c("aut", "cre", "cph"),

NEWS.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,64 @@
1+
# RcppEnsmallen 0.3.10.0.1
2+
3+
- Upgraded to ensmallen 3.10.0: "Unexpected Rain" (2025-09-30)
4+
- SGD-like optimizers now all divide the step size by the batch size so that
5+
step sizes don't need to be tuned in addition to batch sizes. If you require
6+
behavior from ensmallen 2, define the `ENS_OLD_SEPARABLE_STEP_BEHAVIOR` macro
7+
before including `ensmallen.hpp`
8+
([#431](https://github.com/mlpack/ensmallen/pull/431)).
9+
- Remove deprecated `ParetoFront()` and `ParetoSet()` from multi-objective
10+
optimizers ([#435](https://github.com/mlpack/ensmallen/pull/435)). Instead,
11+
pass objects to the `Optimize()` function; see the documentation for each
12+
multi-objective optimizer for more details. A typical transition will change
13+
code like:
14+
```c++
15+
optimizer.Optimize(objectives, coordinates);
16+
arma::cube paretoFront = optimizer.ParetoFront();
17+
arma::cube paretoSet = optimizer.ParetoSet();
18+
```
19+
to instead gather the Pareto front and set in the call:
20+
```c++
21+
arma::cube paretoFront, paretoSet;
22+
optimizer.Optimize(objectives, coordinates, paretoFront, paretoSet);
23+
```
24+
- Remove deprecated constructor for Active CMA-ES that takes `lowerBound` and
25+
`upperBound` ([#435](https://github.com/mlpack/ensmallen/pull/435)).
26+
Instead, pass an instantiated `BoundaryBoxConstraint` to the constructor. A
27+
typical transition will change code like:
28+
```c++
29+
ActiveCMAES<FullSelection, BoundaryBoxConstraint> opt(lambda,
30+
lowerBound, upperBound, ...);
31+
```
32+
into
33+
```c++
34+
ActiveCMAES<FullSelection, BoundaryBoxConstraint> opt(lambda,
35+
BoundaryBoxConstraint(lowerBound, upperBound), ...);
36+
```
37+
- Add proximal gradient optimizers for L1-constrained and other related
38+
problems: `FBS`, `FISTA`, and `FASTA`
39+
([#427](https://github.com/mlpack/ensmallen/pull/427)). See the
40+
documentation for more details.
41+
- The `Lambda()` and `Sigma()` functions of the `AugLagrangian` optimizer,
42+
which could be used to retrieve the Lagrange multipliers and penalty
43+
parameter after optimization, are now deprecated
44+
([#439](https://github.com/mlpack/ensmallen/pull/439)). Instead, pass a
45+
vector and a double to the `Optimize()` function directly:
46+
```c++
47+
augLag.Optimize(function, coordinates, lambda, sigma)
48+
```
49+
and these will be filled with the final Lagrange multiplier estimates and
50+
penalty parameters.
51+
- Fix include statement in `tests/de_test.cpp`
52+
([#419](https://github.com/mlpack/ensmallen/pull/419)).
53+
- Fix `exactObjective` output for SGD-like optimizers when the number of
54+
iterations is an even number of epochs
55+
([#417](https://github.com/mlpack/ensmallen/pull/417)).
56+
- Increase tolerance in `demon_sgd_test.cpp`
57+
([#420](https://github.com/mlpack/ensmallen/pull/420)).
58+
- Set cmake version range to 3.5...4.0
59+
([#422](https://github.com/mlpack/ensmallen/pull/422)).
60+
61+
162
# RcppEnsmallen 0.2.22.1.2
263

364
- `-DARMA_USE_CURRENT` added to `PKG_CXXFLAGS` to use Armadillo 15.0.2 or higher

inst/include/ensmallen.hpp

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,16 @@
3434

3535
#include <armadillo>
3636

37-
#if ((ARMA_VERSION_MAJOR < 10) || ((ARMA_VERSION_MAJOR == 10) && (ARMA_VERSION_MINOR < 8)))
37+
#if defined(COOT_VERSION_MAJOR) && \
38+
((COOT_VERSION_MAJOR >= 2) || \
39+
(COOT_VERSION_MAJOR == 2 && COOT_VERSION_MINOR >= 1))
40+
// The version of Bandicoot is new enough that we can use it.
41+
#undef ENS_HAVE_COOT
42+
#define ENS_HAVE_COOT
43+
#endif
44+
45+
#if ((ARMA_VERSION_MAJOR < 10) || \
46+
((ARMA_VERSION_MAJOR == 10) && (ARMA_VERSION_MINOR < 8)))
3847
#error "need Armadillo version 10.8 or newer"
3948
#endif
4049

@@ -69,7 +78,10 @@
6978
#include "ensmallen_bits/log.hpp" // TODO: should move to another place
7079

7180
#include "ensmallen_bits/utility/any.hpp"
72-
#include "ensmallen_bits/utility/arma_traits.hpp"
81+
#include "ensmallen_bits/utility/proxies.hpp"
82+
#include "ensmallen_bits/utility/function_traits.hpp"
83+
#include "ensmallen_bits/utility/using.hpp"
84+
#include "ensmallen_bits/utility/detect_callbacks.hpp"
7385
#include "ensmallen_bits/utility/indicators/epsilon.hpp"
7486
#include "ensmallen_bits/utility/indicators/igd.hpp"
7587
#include "ensmallen_bits/utility/indicators/igd_plus.hpp"
@@ -109,8 +121,10 @@
109121
#include "ensmallen_bits/cne/cne.hpp"
110122
#include "ensmallen_bits/de/de.hpp"
111123
#include "ensmallen_bits/eve/eve.hpp"
124+
#include "ensmallen_bits/fasta/fasta.hpp"
125+
#include "ensmallen_bits/fbs/fbs.hpp"
126+
#include "ensmallen_bits/fista/fista.hpp"
112127
#include "ensmallen_bits/ftml/ftml.hpp"
113-
114128
#include "ensmallen_bits/fw/frank_wolfe.hpp"
115129
#include "ensmallen_bits/gradient_descent/gradient_descent.hpp"
116130
#include "ensmallen_bits/grid_search/grid_search.hpp"

inst/include/ensmallen_bits/ada_belief/ada_belief.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class AdaBelief
9797
typename MatType,
9898
typename GradType,
9999
typename... CallbackTypes>
100-
typename std::enable_if<IsArmaType<GradType>::value,
100+
typename std::enable_if<IsMatrixType<GradType>::value,
101101
typename MatType::elem_type>::type
102102
Optimize(SeparableFunctionType& function,
103103
MatType& iterate,

inst/include/ensmallen_bits/ada_belief/ada_belief_update.hpp

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class AdaBeliefUpdate
7979
class Policy
8080
{
8181
public:
82+
typedef typename MatType::elem_type ElemType;
83+
8284
/**
8385
* This constructor is called by the SGD Optimize() method before the start
8486
* of the iteration update process.
@@ -89,10 +91,16 @@ class AdaBeliefUpdate
8991
*/
9092
Policy(AdaBeliefUpdate& parent, const size_t rows, const size_t cols) :
9193
parent(parent),
94+
beta1(ElemType(parent.beta1)),
95+
beta2(ElemType(parent.beta2)),
96+
epsilon(ElemType(parent.epsilon)),
9297
iteration(0)
9398
{
9499
m.zeros(rows, cols);
95100
s.zeros(rows, cols);
101+
// Prevent underflow.
102+
if (epsilon == ElemType(0) && parent.epsilon != 0.0)
103+
epsilon = 10 * std::numeric_limits<ElemType>::epsilon();
96104
}
97105

98106
/**
@@ -109,18 +117,18 @@ class AdaBeliefUpdate
109117
// Increment the iteration counter variable.
110118
++iteration;
111119

112-
m *= parent.beta1;
113-
m += (1 - parent.beta1) * gradient;
120+
m *= beta1;
121+
m += (1 - beta1) * gradient;
114122

115-
s *= parent.beta2;
116-
s += (1 - parent.beta2) * arma::pow(gradient - m, 2.0) + parent.epsilon;
123+
s *= beta2;
124+
s += (1 - beta2) * pow(gradient - m, 2) + epsilon;
117125

118-
const double biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
119-
const double biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
126+
const ElemType biasCorrection1 = 1 - std::pow(beta1, ElemType(iteration));
127+
const ElemType biasCorrection2 = 1 - std::pow(beta2, ElemType(iteration));
120128

121129
// And update the iterate.
122-
iterate -= ((m / biasCorrection1) * stepSize) / (arma::sqrt(s /
123-
biasCorrection2) + parent.epsilon);
130+
iterate -= ((m / biasCorrection1) * ElemType(stepSize)) /
131+
(sqrt(s / biasCorrection2) + epsilon);
124132
}
125133

126134
private:
@@ -133,6 +141,11 @@ class AdaBeliefUpdate
133141
// The exponential moving average of squared gradient values.
134142
GradType s;
135143

144+
// Parent parameters converted to the element type of the matrix.
145+
ElemType beta1;
146+
ElemType beta2;
147+
ElemType epsilon;
148+
136149
// The number of iterations.
137150
size_t iteration;
138151
};

inst/include/ensmallen_bits/ada_bound/ada_bound.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class AdaBoundType
107107
typename MatType,
108108
typename GradType,
109109
typename... CallbackTypes>
110-
typename std::enable_if<IsArmaType<GradType>::value,
110+
typename std::enable_if<IsMatrixType<GradType>::value,
111111
typename MatType::elem_type>::type
112112
Optimize(DecomposableFunctionType& function,
113113
MatType& iterate,

inst/include/ensmallen_bits/ada_bound/ada_bound_update.hpp

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ class AdaBoundUpdate
9696
class Policy
9797
{
9898
public:
99+
typedef typename MatType::elem_type ElemType;
100+
99101
/**
100102
* This constructor is called by the SGD Optimize() method before the start
101103
* of the iteration update process.
@@ -105,10 +107,24 @@ class AdaBoundUpdate
105107
* @param cols Number of columns in the gradient matrix.
106108
*/
107109
Policy(AdaBoundUpdate& parent, const size_t rows, const size_t cols) :
108-
parent(parent), first(true), initialStepSize(0), iteration(0)
110+
parent(parent),
111+
finalLr(ElemType(parent.finalLr)),
112+
gamma(ElemType(parent.gamma)),
113+
epsilon(ElemType(parent.epsilon)),
114+
beta1(ElemType(parent.beta1)),
115+
beta2(ElemType(parent.beta2)),
116+
first(true),
117+
initialStepSize(0),
118+
iteration(0)
109119
{
110120
m.zeros(rows, cols);
111121
v.zeros(rows, cols);
122+
123+
// Check for underflows in conversions.
124+
if (gamma == ElemType(0) && parent.gamma != 0.0)
125+
gamma = 10 * std::numeric_limits<ElemType>::epsilon();
126+
if (epsilon == ElemType(0) && parent.epsilon != 0.0)
127+
epsilon = 10 * std::numeric_limits<ElemType>::epsilon();
112128
}
113129

114130
/**
@@ -129,30 +145,30 @@ class AdaBoundUpdate
129145
if (first)
130146
{
131147
first = false;
132-
initialStepSize = stepSize;
148+
initialStepSize = ElemType(stepSize);
133149
}
134150

135151
// Increment the iteration counter variable.
136152
++iteration;
137153

138154
// Decay the first and second moment running average coefficient.
139-
m *= parent.beta1;
140-
m += (1 - parent.beta1) * gradient;
155+
m *= beta1;
156+
m += (1 - beta1) * gradient;
141157

142-
v *= parent.beta2;
143-
v += (1 - parent.beta2) * (gradient % gradient);
158+
v *= beta2;
159+
v += (1 - beta2) * (gradient % gradient);
144160

145-
const ElemType biasCorrection1 = 1.0 - std::pow(parent.beta1, iteration);
146-
const ElemType biasCorrection2 = 1.0 - std::pow(parent.beta2, iteration);
161+
const ElemType biasCorrection1 = 1 - std::pow(beta1, ElemType(iteration));
162+
const ElemType biasCorrection2 = 1 - std::pow(beta2, ElemType(iteration));
147163

148-
const ElemType fl = parent.finalLr * stepSize / initialStepSize;
149-
const ElemType lower = fl * (1.0 - 1.0 / (parent.gamma * iteration + 1));
150-
const ElemType upper = fl * (1.0 + 1.0 / (parent.gamma * iteration));
164+
const ElemType fl = finalLr * ElemType(stepSize) / initialStepSize;
165+
const ElemType lower = fl * (1 - 1 / (gamma * iteration + 1));
166+
const ElemType upper = fl * (1 + 1 / (gamma * iteration));
151167

152-
// Applies bounds on actual learning rate.
153-
iterate -= arma::clamp((stepSize *
154-
std::sqrt(biasCorrection2) / biasCorrection1) / (arma::sqrt(v) +
155-
parent.epsilon), lower, upper) % m;
168+
// Applies bounds on actual learning rate.
169+
iterate -= clamp((ElemType(stepSize) *
170+
std::sqrt(biasCorrection2) / biasCorrection1) / (sqrt(v) + epsilon),
171+
lower, upper) % m;
156172
}
157173

158174
private:
@@ -165,11 +181,18 @@ class AdaBoundUpdate
165181
// The exponential moving average of squared gradient values.
166182
GradType v;
167183

184+
// Parameters of the parent, casted to the element type of the problem.
185+
ElemType finalLr;
186+
ElemType gamma;
187+
ElemType epsilon;
188+
ElemType beta1;
189+
ElemType beta2;
190+
168191
// Whether this is the first call of the Update method.
169192
bool first;
170193

171194
// The initial (Adam) learning rate.
172-
double initialStepSize;
195+
ElemType initialStepSize;
173196

174197
// The number of iterations.
175198
size_t iteration;

0 commit comments

Comments
 (0)