Compare commits

...
36 Commits
Author SHA1 Message Date
conrad e3a8c5663c use internal function 2025-09-15 10:19:27 +10:00
conrad 999b1d6496 patch bump 2025-08-14 15:19:33 +10:00
conrad 0709bf71b4 use _OPENMP corresponding to OpenMP 4.0 2025-08-14 15:19:04 +10:00
conrad c0d401727a require OpenMP 4.0 for seq_cst memory order clause 2025-08-13 18:22:24 +10:00
conrad d77fa2bbb4 use seq_cst for openmp atomic read/write 2025-08-13 17:38:17 +10:00
conrad 98c13f4bc7 patch bump 2025-08-08 13:56:43 +10:00
conrad 92cd541f57 move conformance check to avoid doing two checks 2025-08-05 23:51:07 +10:00
conrad f002bffd96 simplified fallback in handling of op_sum specialisations 2025-08-05 23:43:29 +10:00
conrad cba9c87169 fix 2025-08-05 12:39:40 +10:00
conrad 12628de147 patch bump 2025-07-21 11:51:08 +10:00
conrad 16d102510f show sylvester() instead of deprecatated syl() 2025-07-21 11:40:40 +10:00
conrad 87626c836a document ARMA_DONT_OPTIMISE_INVEXPR and ARMA_DONT_OPTIMISE_POWEXPR 2025-07-19 01:30:05 +10:00
conrad 6e7f5c3601 add macro to disable optimisation of pow() 2025-07-16 13:21:36 +10:00
conrad 7ac92e7999 restore compile time deprecation message 2025-07-14 14:50:51 +10:00
conrad fc11d3683d restore compile time deprecation message 2025-07-14 14:50:03 +10:00
conrad 3eb25b1b16 allow to optionally disable optimised handling of pow() 2025-07-14 14:36:22 +10:00
conrad a197882af1 better wording 2025-07-12 18:49:12 +10:00
conrad 0dd9ac9a02 better wording 2025-07-12 18:48:09 +10:00
conradsnicta 5d62ce315c Merge branch 'seb/add_an_ignore' into '14.6.x'
Adds the missing argument Xst to the 'arma_ignore list'

See merge request conradsnicta/armadillo-code!142
2025-07-12 01:15:44 +00:00
Seb James 51d56e7c59 Adds the missing argument Xst to the 'arma_ignore list' 2025-07-12 01:15:44 +00:00
conrad 17db28c133 remove outdated comments 2025-07-07 21:46:12 +10:00
conrad b801feb467 simplifications 2025-07-07 20:29:59 +10:00
conrad ec95397bc4 cleanup 2025-07-07 15:45:57 +10:00
conrad 851828d427 speedup 2025-07-05 13:03:45 +10:00
conrad 1192e1ac19 better wording 2025-07-04 13:31:21 +10:00
conrad 2293bf45cc cleanup warnings 2025-07-04 13:24:56 +10:00
conrad bb7ed84ded expand deprecation message with refactoring suggestion 2025-07-03 15:48:32 +10:00
conrad d1305141d2 version bump 2025-07-02 16:46:17 +10:00
conrad f3ed7ace06 mark as RC2 2025-07-01 21:48:15 +10:00
conrad ed8d293f93 fix 2025-07-01 12:35:50 +10:00
conrad ce007b7164 restore previous setup 2025-06-30 19:23:14 +10:00
conrad b2664f138b restore previous setup 2025-06-30 19:22:21 +10:00
conrad 300bd731ca cleanup 2025-06-30 19:20:10 +10:00
conrad 9843393a7a cleanup 2025-06-30 19:18:03 +10:00
conrad 98a885b9c2 mark as RC1 2025-06-30 19:16:06 +10:00
conrad 0b4542fc88 restore previous setup 2025-06-30 19:15:02 +10:00
24 changed files with 258 additions and 289 deletions
+3 -3
View File
@@ -41,7 +41,7 @@
## NOTE: More details: https://arma.sourceforge.net/faq.html
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
cmake_minimum_required(VERSION 3.5...3.10 FATAL_ERROR)
if(POLICY CMP0025)
# enable differentiation between vanilla Clang and AppleClang
@@ -102,13 +102,13 @@ endif()
if(DEFINED CMAKE_CXX_COMPILER_ID AND DEFINED CMAKE_CXX_COMPILER_VERSION)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(NOT (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 8.1.0))
if(NOT (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 6.1.0))
if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
message(STATUS "Added '-std=c++14' to compiler flags")
endif()
else()
message(FATAL_ERROR "Compiler too old; need at least gcc 8.1")
message(FATAL_ERROR "Compiler too old; need at least gcc 6.1")
endif()
else()
if(NOT (${CMAKE_MAJOR_VERSION} LESS 3))
Vendored
+1 -1
View File
@@ -6,7 +6,7 @@ check_cmake()
{
(cmake --version) </dev/null >/dev/null 2>&1 ||
{
echo "error: cmake 3.10+ is required to configure and install Armadillo"
echo "error: cmake 3.5+ is required to configure and install Armadillo"
echo ""
echo "cmake can be installed via your system's package manager,"
echo "or downloaded from https://cmake.org"
+70 -27
View File
@@ -483,7 +483,7 @@ Conrad Sanderson and Ryan Curtin.
<tr><td><a href="#solve">solve</a></td><td>&nbsp;</td><td>solve systems of linear equations</td></tr>
<tr><td><a href="#svd">svd</a></td><td>&nbsp;</td><td>singular value decomposition</td></tr>
<tr><td><a href="#svd_econ">svd_econ</a></td><td>&nbsp;</td><td>economical singular value decomposition</td></tr>
<tr style="background-color: #F5F5F5;"><td><a href="#syl">syl</a></td><td>&nbsp;</td><td>Sylvester equation solver</td></tr>
<tr style="background-color: #F5F5F5;"><td><a href="#sylvester">sylvester</a></td><td>&nbsp;</td><td>Sylvester equation solver</td></tr>
</tbody>
</table>
</ul>
@@ -606,7 +606,7 @@ The root matrix class is <b>Mat&lt;</b><i>type</i><b>&gt;</b>, where <i>type</i>
</li>
<br>
<li>
For convenience the following typedefs have been defined:
For convenience, the following typedefs are defined:
<ul>
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
@@ -920,7 +920,7 @@ and inherits most of the member functions
</li>
<br>
<li>
For convenience the following typedefs have been defined:
For convenience, the following typedefs are defined:
<ul>
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
@@ -1219,7 +1219,7 @@ and inherits most of the member functions
</li>
<br>
<li>
For convenience the following typedefs have been defined:
For convenience, the following typedefs are defined:
<ul>
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
@@ -1477,7 +1477,7 @@ The root cube class is <b>Cube&lt;</b><i>type</i><b>&gt;</b>, where <i>type</i>
</li>
<br>
<li>
For convenience the following typedefs have been defined:
For convenience, the following typedefs are defined:
<ul>
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
@@ -1823,7 +1823,7 @@ The root sparse matrix class is <b>SpMat&lt;</b><i>type</i><b>&gt;</b>, where <i
</li>
<br>
<li>
For convenience the following typedefs have been defined:
For convenience, the following typedefs are defined:
<ul>
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
<tbody>
@@ -1952,7 +1952,7 @@ zero-valued elements are never stored
<br>
<li>
This class behaves in a similar manner to the dense matrix <a href="#Mat">Mat</a> class;
however, member functions which set all elements to non-zero values (and hence do not make sense for sparse matrices) have been deliberately omitted;
however, member functions which set all elements to non-zero values (and hence do not make sense for sparse matrices) are deliberately omitted;
examples of omitted functions: <a href="#fill">.fill()</a>, <a href="#ones_member">.ones()</a>, +=&nbsp;scalar, etc.
</li>
<br>
@@ -10649,7 +10649,7 @@ See also:
<li>For vector <i>V</i>, return its normalised version (ie. having unit <i>p</i>-norm)</li>
<br>
<li>
For matrix <i>X</i>, return its normalised version, where each column (<i>dim&thinsp;=&thinsp;0</i>) or row (<i>dim&thinsp;=&thinsp;1</i>) has been normalised to have unit <i>p</i>-norm</li>
For matrix <i>X</i>, return its normalised version, where each column (<i>dim&thinsp;=&thinsp;0</i>) or row (<i>dim&thinsp;=&thinsp;1</i>) is normalised to have unit <i>p</i>-norm</li>
<br>
<li>
The <i>p</i> argument is optional; by default <i>p&thinsp;=&thinsp;2</i> is used
@@ -13928,7 +13928,7 @@ See also:
<li><a href="#inv">inv()</a></li>
<li><a href="#pinv">pinv()</a></li>
<li><a href="#rcond">rcond()</a></li>
<li><a href="#syl">syl()</a></li>
<li><a href="#sylvester">sylvester()</a></li>
<li><a href="#spsolve">spsolve()</a> - solve sparse system of linear equations</li>
<li><a href="https://mathworld.wolfram.com/LinearSystemofEquations.html">linear system of equations in MathWorld</a></li>
<li><a href="https://en.wikipedia.org/wiki/Linear_system_of_equations">system of linear equations in Wikipedia</a></li>
@@ -14102,8 +14102,9 @@ See also:
<div class="pagebreak"></div><div class="noprint"><hr class="greyline"><br></div>
<a name="syl"></a>
<b>X = syl( A, B, C )</b>
<br><b>syl( X, A, B, C )</b>
<a name="sylvester"></a>
<b>X = sylvester( A, B, C )</b>
<br><b>sylvester( X, A, B, C )</b>
<ul>
<li>Solve the Sylvester equation, ie. <i>AX + XB + C = 0</i>, where <i>X</i> is unknown</li>
<br>
@@ -14112,8 +14113,8 @@ See also:
<li>
If no solution is found:
<ul>
<li><i>syl(A,B,C)</i> resets <i>X</i> and throws a <i>std::runtime_error</i> exception</li>
<li><i>syl(X,A,B,C)</i> resets <i>X</i> and returns a bool set to <i>false</i> (exception is not thrown)</li>
<li><i>sylvester(A,B,C)</i> resets <i>X</i> and throws a <i>std::runtime_error</i> exception</li>
<li><i>sylvester(X,A,B,C)</i> resets <i>X</i> and returns a bool set to <i>false</i> (exception is not thrown)</li>
</ul>
</li>
<br>
@@ -14125,10 +14126,10 @@ mat A(5, 5, fill::randu);
mat B(5, 5, fill::randu);
mat C(5, 5, fill::randu);
mat X1 = syl(A, B, C);
mat X1 = sylvester(A, B, C);
mat X2;
syl(X2, A, B, C);
sylvester(X2, A, B, C);
</pre>
</ul>
</li>
@@ -18351,20 +18352,18 @@ Convenience short forms (typedefs) for complex element types:
<td>
<b><code>cx_double</code></b>
</td>
<td>&nbsp;<br>
</td>
<td>&nbsp;=&nbsp;</td>
<td>
equivalent to <code>std::complex&lt;double&gt;</code>
<code>std::complex&lt;double&gt;</code>
</td>
</tr>
<tr>
<td>
<b><code>cx_float</code></b>
</td>
<td>&nbsp;<br>
</td>
<td>&nbsp;=&nbsp;</td>
<td>
equivalent to <code>std::complex&lt;float&gt;</code>
<code>std::complex&lt;float&gt;</code>
</td>
</tr>
</tbody>
@@ -19249,7 +19248,7 @@ int main()
If the above program is stored as <i>example.cpp</i>,
under Linux and macOS it can be compiled using:
<br>
<ul><code>g++ example.cpp -o example -std=c++11 -O2 -larmadillo</code></ul>
<ul><code>g++ example.cpp -o example -std=c++14 -O2 -larmadillo</code></ul>
</li>
<br>
<li>
@@ -19360,7 +19359,7 @@ Disable use of LAPACK; overrides <i>ARMA_USE_LAPACK</i>
<td style="vertical-align: top;">
Enable use of BLAS, or a high-speed replacement for BLAS (eg. OpenBLAS, Intel MKL, or the Accelerate framework).
BLAS is used for <a href="#operators">matrix multiplication</a>.
Without BLAS, Armadillo will use a built-in matrix multiplication routine, which might be slower for large matrices.
Without BLAS, Armadillo will use a rudimentary matrix multiplication routine, which might be slower for large matrices.
</td>
</tr>
<tr>
@@ -19566,7 +19565,7 @@ the <i>hdf5.h</i> header file must be available on your system and you will need
&nbsp;
</td>
<td style="vertical-align: top;">
Disable the use of the HDF5 library; overrides <i>ARMA_USE_HDF5</i>
Disable use of the HDF5 library; overrides <i>ARMA_USE_HDF5</i>
</td>
</tr>
<tr>
@@ -19611,7 +19610,7 @@ you will need to link with the FFTW3 library (eg. <code><i>-lfftw3</i></code>)
&nbsp;
</td>
<td style="vertical-align: top;">
Disable the use of the FFTW3 library; overrides <i>ARMA_USE_FFTW3</i>
Disable use of the FFTW3 library; overrides <i>ARMA_USE_FFTW3</i>
</td>
</tr>
<tr>
@@ -19655,7 +19654,7 @@ Disable use of <i>std::mutex</i>; applicable if your compiler and/or environment
&nbsp;
</td>
<td style="vertical-align: top;">
Disable automatically optimised handling of band matrices by <a href="#solve">solve()</a> and <a href="#chol">chol()</a>
Disable optimised handling of band matrices by <a href="#solve">solve()</a> and <a href="#chol">chol()</a>
</td>
</tr>
<tr>
@@ -19677,7 +19676,7 @@ Disable automatically optimised handling of band matrices by <a href="#solve">so
&nbsp;
</td>
<td style="vertical-align: top;">
Disable automatically optimised handling of symmetric/hermitian positive definite matrices by
Disable optimised handling of symmetric/hermitian positive definite matrices by
<a href="#solve">solve()</a>,
<a href="#inv">inv()</a>,
<a href="#pinv">pinv()</a>,
@@ -19701,6 +19700,50 @@ Disable automatically optimised handling of symmetric/hermitian positive definit
</tr>
<tr>
<td style="vertical-align: top;">
<code>ARMA_DONT_OPTIMISE_INVEXPR</code>
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
Disable optimised handling of <a href="#inv">inv()</a> and <a href="#inv_sympd">inv_sympd()</a> within compound expressions
</td>
</tr>
<tr>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<code>ARMA_DONT_OPTIMISE_POWEXPR</code>
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
Disable optimised handling of <a href="#pow">pow()</a>
</td>
</tr>
<tr>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
<td style="vertical-align: top;">
&nbsp;
</td>
</tr>
<tr>
<td style="vertical-align: top;">
<code>ARMA_USE_OPENMP</code>
</td>
<td style="vertical-align: top;">
+9 -9
View File
@@ -615,7 +615,7 @@ Cube<eT>::get_mat_ptr(const uword in_slice) const
#if defined(ARMA_USE_OPENMP)
{
#pragma omp atomic read
#pragma omp atomic read seq_cst
mat_ptr = mat_ptrs[in_slice];
}
#elif defined(ARMA_USE_STD_MUTEX)
@@ -634,12 +634,12 @@ Cube<eT>::get_mat_ptr(const uword in_slice) const
{
#pragma omp critical (arma_Cube_mat_ptrs)
{
#pragma omp atomic read
#pragma omp atomic read seq_cst
mat_ptr = mat_ptrs[in_slice];
if(mat_ptr == nullptr) { mat_ptr = create_mat_ptr(in_slice); }
#pragma omp atomic write
#pragma omp atomic write seq_cst
mat_ptrs[in_slice] = mat_ptr;
}
}
@@ -2872,7 +2872,7 @@ Cube<eT>::Cube(const eOpCube<T1, eop_type>& X)
init_cold();
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -2902,7 +2902,7 @@ Cube<eT>::operator=(const eOpCube<T1, eop_type>& X)
init_warm(X.get_n_rows(), X.get_n_cols(), X.get_n_slices());
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -2932,7 +2932,7 @@ Cube<eT>::operator+=(const eOpCube<T1, eop_type>& X)
if(bad_alias) { const Cube<eT> tmp(X); return (*this).operator+=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -2962,7 +2962,7 @@ Cube<eT>::operator-=(const eOpCube<T1, eop_type>& X)
if(bad_alias) { const Cube<eT> tmp(X); return (*this).operator-=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -2992,7 +2992,7 @@ Cube<eT>::operator%=(const eOpCube<T1, eop_type>& X)
if(bad_alias) { const Cube<eT> tmp(X); return (*this).operator%=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -3022,7 +3022,7 @@ Cube<eT>::operator/=(const eOpCube<T1, eop_type>& X)
if(bad_alias) { const Cube<eT> tmp(X); return (*this).operator/=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
+6 -6
View File
@@ -5201,7 +5201,7 @@ Mat<eT>::Mat(const eOp<T1, eop_type>& X)
init_cold();
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -5231,7 +5231,7 @@ Mat<eT>::operator=(const eOp<T1, eop_type>& X)
init_warm(X.get_n_rows(), X.get_n_cols());
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -5260,7 +5260,7 @@ Mat<eT>::operator+=(const eOp<T1, eop_type>& X)
if(bad_alias) { const Mat<eT> tmp(X); return (*this).operator+=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -5289,7 +5289,7 @@ Mat<eT>::operator-=(const eOp<T1, eop_type>& X)
if(bad_alias) { const Mat<eT> tmp(X); return (*this).operator-=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -5335,7 +5335,7 @@ Mat<eT>::operator%=(const eOp<T1, eop_type>& X)
if(bad_alias) { const Mat<eT> tmp(X); return (*this).operator%=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
@@ -5364,7 +5364,7 @@ Mat<eT>::operator/=(const eOp<T1, eop_type>& X)
if(bad_alias) { const Mat<eT> tmp(X); return (*this).operator/=(tmp); }
if(is_same_type<eop_type, eop_pow>::value)
if(arma_config::optimise_powexpr && is_same_type<eop_type, eop_pow>::value)
{
constexpr bool eT_non_int = is_non_integral<eT>::value;
+7
View File
@@ -65,6 +65,13 @@ struct arma_config
#endif
#if defined(ARMA_OPTIMISE_POWEXPR)
static constexpr bool optimise_powexpr = true;
#else
static constexpr bool optimise_powexpr = false;
#endif
#if defined(ARMA_CHECK_CONFORMANCE)
static constexpr bool check_conform = true;
#else
+2 -2
View File
@@ -312,7 +312,7 @@ struct state_type
int out;
#if defined(ARMA_USE_OPENMP)
#pragma omp atomic read
#pragma omp atomic read seq_cst
out = state;
#elif defined(ARMA_USE_STD_MUTEX)
out = state.load();
@@ -328,7 +328,7 @@ struct state_type
operator= (const int in_state)
{
#if defined(ARMA_USE_OPENMP)
#pragma omp atomic write
#pragma omp atomic write seq_cst
state = in_state;
#elif defined(ARMA_USE_STD_MUTEX)
state.store(in_state);
+3 -3
View File
@@ -22,9 +22,9 @@
#define ARMA_VERSION_MAJOR 14
#define ARMA_VERSION_MINOR 5
#define ARMA_VERSION_PATCH 0
#define ARMA_VERSION_NAME "experimental"
#define ARMA_VERSION_MINOR 6
#define ARMA_VERSION_PATCH 3
#define ARMA_VERSION_NAME "Caffe Mocha"
+17 -19
View File
@@ -158,12 +158,18 @@
// #pragma message ("using GCC extensions")
#if (__GNUC__ < 8)
#error "*** newer compiler required; need at least gcc 8.1 ***"
#undef ARMA_GCC_VERSION
#define ARMA_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#if (ARMA_GCC_VERSION < 60100)
#error "*** newer compiler required; need gcc 6.1 or newer ***"
#endif
#if (__GNUC__ >= 17)
#undef ARMA_IGNORE_DEPRECATED_MARKER
// gcc 6.1 has proper C++14 support and fixes an OpenMP related bug:
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57580
#if (ARMA_GCC_VERSION < 80100)
#pragma message("INFO: support for GCC versions older than 8.1 is deprecated")
#endif
#define ARMA_GOOD_COMPILER
@@ -223,12 +229,6 @@
// #pragma message ("using Clang extensions")
#if defined(__clang_major__) && !defined(__apple_build_version__)
#if (__clang_major__ >= 24)
#undef ARMA_IGNORE_DEPRECATED_MARKER
#endif
#endif
#define ARMA_GOOD_COMPILER
#if !defined(__has_attribute)
@@ -394,16 +394,17 @@
#if !defined(ARMA_DONT_USE_OPENMP)
#if (defined(_OPENMP) && (_OPENMP >= 201107))
#if (defined(_OPENMP) && (_OPENMP >= 201307))
#undef ARMA_USE_OPENMP
#define ARMA_USE_OPENMP
#endif
#endif
#if ( defined(ARMA_USE_OPENMP) && (!defined(_OPENMP) || (defined(_OPENMP) && (_OPENMP < 201107))) )
#if ( defined(ARMA_USE_OPENMP) && (!defined(_OPENMP) || (defined(_OPENMP) && (_OPENMP < 201307))) )
// OpenMP 3.0 required for parallelisation of loops with unsigned integers
// OpenMP 3.1 required for atomic read and atomic write
// OpenMP 3.1 required for atomic read/write
// OpenMP 4.0 required for seq_cst memory order clause in atomic read/write
#undef ARMA_USE_OPENMP
#undef ARMA_PRINT_OPENMP_WARNING
#define ARMA_PRINT_OPENMP_WARNING
@@ -411,11 +412,10 @@
#if defined(ARMA_PRINT_OPENMP_WARNING) && !defined(ARMA_DONT_PRINT_OPENMP_WARNING)
#pragma message ("WARNING: use of OpenMP disabled; compiler support for OpenMP 3.1+ not detected")
#pragma message ("WARNING: use of OpenMP disabled; compiler support for OpenMP 4.0+ not detected")
#if (defined(_OPENMP) && (_OPENMP < 201107))
#if (defined(_OPENMP) && (_OPENMP < 201307))
#pragma message ("NOTE: your compiler has an outdated version of OpenMP")
#pragma message ("NOTE: consider upgrading to a better compiler")
#endif
#endif
@@ -449,6 +449,7 @@
#undef ARMA_DETECTED_FAKE_GCC
#undef ARMA_DETECTED_FAKE_CLANG
#undef ARMA_GCC_VERSION
#undef ARMA_PRINT_OPENMP_WARNING
@@ -476,9 +477,6 @@
#undef major
// WARNING: option 'ARMA_IGNORE_DEPRECATED_MARKER' is not supported when compiling with gcc 17+ or clang 24+
// WARNING: disabling deprecation messages is counter-productive
#if defined(ARMA_IGNORE_DEPRECATED_MARKER)
#undef arma_deprecated
#define arma_deprecated
+14 -8
View File
@@ -166,6 +166,11 @@
//// of inv() and inv_sympd() within compound expressions
#endif
#if !defined(ARMA_OPTIMISE_POWEXPR)
#define ARMA_OPTIMISE_POWEXPR
//// Comment out the above line to disable optimised handling of pow()
#endif
#if !defined(ARMA_CHECK_CONFORMANCE)
#define ARMA_CHECK_CONFORMANCE
//// Comment out the above line to disable conformance checks for bounds and size.
@@ -211,7 +216,7 @@
#if defined(ARMA_DEFAULT_OSTREAM)
#pragma message ("WARNING: support for ARMA_DEFAULT_OSTREAM is deprecated and will be removed;")
#pragma message ("WARNING: option ARMA_DEFAULT_OSTREAM is deprecated and will be removed;")
#pragma message ("WARNING: use ARMA_COUT_STREAM and ARMA_CERR_STREAM instead")
#endif
@@ -290,7 +295,7 @@
// for compatibility with earlier versions of Armadillo
#if defined(ARMA_DONT_USE_CXX11_MUTEX)
#pragma message ("WARNING: support for ARMA_DONT_USE_CXX11_MUTEX is deprecated and will be removed;")
#pragma message ("WARNING: option ARMA_DONT_USE_CXX11_MUTEX is deprecated and will be removed;")
#pragma message ("WARNING: use ARMA_DONT_USE_STD_MUTEX instead")
#undef ARMA_USE_STD_MUTEX
#endif
@@ -319,9 +324,6 @@
#if defined(ARMA_BLAS_LONG) || defined(ARMA_BLAS_LONG_LONG)
#undef ARMA_BLAS_64BIT_INT
#define ARMA_BLAS_64BIT_INT
// #pragma message ("options ARMA_BLAS_LONG and ARMA_BLAS_LONG_LONG are deprecated;")
// #pragma message ("use ARMA_BLAS_64BIT_INT instead")
#endif
#if defined(ARMA_DONT_OPTIMISE_BAND) || defined(ARMA_DONT_OPTIMISE_SOLVE_BAND)
@@ -336,6 +338,10 @@
#undef ARMA_OPTIMISE_INVEXPR
#endif
#if defined(ARMA_DONT_OPTIMISE_POWEXPR)
#undef ARMA_OPTIMISE_POWEXPR
#endif
#if defined(ARMA_DONT_CHECK_CONFORMANCE)
#if defined(ARMA_CHECK_CONFORMANCE) && (ARMA_WARN_LEVEL >= 2)
#pragma message ("WARNING: conformance checks disabled")
@@ -381,12 +387,12 @@
#undef ARMA_CRIPPLED_LAPACK
#endif
// WARNING: option ARMA_IGNORE_DEPRECATED_MARKER will be removed
// WARNING: option ARMA_CRIPPLED_LAPACK will be removed
// WARNING: option ARMA_IGNORE_DEPRECATED_MARKER is deprecated and will be removed
// WARNING: option ARMA_CRIPPLED_LAPACK is deprecated and will be removed
#if defined(ARMA_CRIPPLED_LAPACK)
#if (!defined(ARMA_IGNORE_DEPRECATED_MARKER))
#pragma message ("option ARMA_CRIPPLED_LAPACK is deprecated and will be removed")
#pragma message ("WARNING: option ARMA_CRIPPLED_LAPACK is deprecated and will be removed")
#endif
#endif
+14 -8
View File
@@ -166,6 +166,11 @@
//// of inv() and inv_sympd() within compound expressions
#endif
#if !defined(ARMA_OPTIMISE_POWEXPR)
#define ARMA_OPTIMISE_POWEXPR
//// Comment out the above line to disable optimised handling of pow()
#endif
#if !defined(ARMA_CHECK_CONFORMANCE)
#define ARMA_CHECK_CONFORMANCE
//// Comment out the above line to disable conformance checks for bounds and size.
@@ -211,7 +216,7 @@
#if defined(ARMA_DEFAULT_OSTREAM)
#pragma message ("WARNING: support for ARMA_DEFAULT_OSTREAM is deprecated and will be removed;")
#pragma message ("WARNING: option ARMA_DEFAULT_OSTREAM is deprecated and will be removed;")
#pragma message ("WARNING: use ARMA_COUT_STREAM and ARMA_CERR_STREAM instead")
#endif
@@ -290,7 +295,7 @@
// for compatibility with earlier versions of Armadillo
#if defined(ARMA_DONT_USE_CXX11_MUTEX)
#pragma message ("WARNING: support for ARMA_DONT_USE_CXX11_MUTEX is deprecated and will be removed;")
#pragma message ("WARNING: option ARMA_DONT_USE_CXX11_MUTEX is deprecated and will be removed;")
#pragma message ("WARNING: use ARMA_DONT_USE_STD_MUTEX instead")
#undef ARMA_USE_STD_MUTEX
#endif
@@ -319,9 +324,6 @@
#if defined(ARMA_BLAS_LONG) || defined(ARMA_BLAS_LONG_LONG)
#undef ARMA_BLAS_64BIT_INT
#define ARMA_BLAS_64BIT_INT
// #pragma message ("options ARMA_BLAS_LONG and ARMA_BLAS_LONG_LONG are deprecated;")
// #pragma message ("use ARMA_BLAS_64BIT_INT instead")
#endif
#if defined(ARMA_DONT_OPTIMISE_BAND) || defined(ARMA_DONT_OPTIMISE_SOLVE_BAND)
@@ -336,6 +338,10 @@
#undef ARMA_OPTIMISE_INVEXPR
#endif
#if defined(ARMA_DONT_OPTIMISE_POWEXPR)
#undef ARMA_OPTIMISE_POWEXPR
#endif
#if defined(ARMA_DONT_CHECK_CONFORMANCE)
#if defined(ARMA_CHECK_CONFORMANCE) && (ARMA_WARN_LEVEL >= 2)
#pragma message ("WARNING: conformance checks disabled")
@@ -381,12 +387,12 @@
#undef ARMA_CRIPPLED_LAPACK
#endif
// WARNING: option ARMA_IGNORE_DEPRECATED_MARKER will be removed
// WARNING: option ARMA_CRIPPLED_LAPACK will be removed
// WARNING: option ARMA_IGNORE_DEPRECATED_MARKER is deprecated and will be removed
// WARNING: option ARMA_CRIPPLED_LAPACK is deprecated and will be removed
#if defined(ARMA_CRIPPLED_LAPACK)
#if (!defined(ARMA_IGNORE_DEPRECATED_MARKER))
#pragma message ("option ARMA_CRIPPLED_LAPACK is deprecated and will be removed")
#pragma message ("WARNING: option ARMA_CRIPPLED_LAPACK is deprecated and will be removed")
#endif
#endif
+1
View File
@@ -1441,6 +1441,7 @@ inline void arma_debug_check(bool state, const char* msg) { arma_conform_check(
out << "\n@ arma_config::optimise_band = " << arma_config::optimise_band;
out << "\n@ arma_config::optimise_sym = " << arma_config::optimise_sym;
out << "\n@ arma_config::optimise_invexpr = " << arma_config::optimise_invexpr;
out << "\n@ arma_config::optimise_powexpr = " << arma_config::optimise_powexpr;
out << "\n@ arma_config::check_conform = " << arma_config::check_conform;
out << "\n@ arma_config::check_nonfinite = " << arma_config::check_nonfinite;
out << "\n@ arma_config::fast_math = " << arma_config::fast_math;
+4 -4
View File
@@ -407,14 +407,14 @@ accu(const eOp<T1,eop_pow>& expr)
typedef eOp<T1,eop_pow> expr_type;
if(expr.aux == eT(2))
if(arma_config::optimise_powexpr && (expr.aux == eT(2)))
{
typedef eOp<T1,eop_square> modified_expr_type;
return accu( reinterpret_cast< const modified_expr_type& >(expr) );
}
if((expr.aux == eT(0.5)) && is_non_integral<eT>::value)
if(arma_config::optimise_powexpr && (expr.aux == eT(0.5)) && is_non_integral<eT>::value)
{
typedef eOp<T1,eop_sqrt> modified_expr_type;
@@ -1048,14 +1048,14 @@ accu(const eOpCube<T1,eop_pow>& expr)
typedef eOpCube<T1,eop_pow> expr_type;
if(expr.aux == eT(2))
if(arma_config::optimise_powexpr && (expr.aux == eT(2)))
{
typedef eOpCube<T1,eop_square> modified_expr_type;
return accu( reinterpret_cast< const modified_expr_type& >(expr) );
}
if((expr.aux == eT(0.5)) && is_non_integral<eT>::value)
if(arma_config::optimise_powexpr && (expr.aux == eT(0.5)) && is_non_integral<eT>::value)
{
typedef eOpCube<T1,eop_sqrt> modified_expr_type;
+5 -5
View File
@@ -29,19 +29,19 @@ class conv_to
public:
template<typename in_eT>
arma_frown("use as_scalar() instead") inline static out_eT from(const in_eT& in, const typename arma_scalar_only<in_eT>::result* junk = nullptr);
arma_frown("replace conv_to<...>::from(X) with as_scalar(X)") inline static out_eT from(const in_eT& in, const typename arma_scalar_only<in_eT>::result* junk = nullptr);
template<typename in_eT, typename T1>
arma_frown("use as_scalar() instead") inline static out_eT from(const Base<in_eT, T1>& in, const typename arma_not_cx<in_eT>::result* junk = nullptr);
arma_frown("replace conv_to<...>::from(X) with as_scalar(X)") inline static out_eT from(const Base<in_eT, T1>& in, const typename arma_not_cx<in_eT>::result* junk = nullptr);
template<typename in_eT, typename T1>
arma_frown("use as_scalar() instead") inline static out_eT from(const Base<in_eT, T1>& in, const typename arma_cx_only<in_eT>::result* junk = nullptr);
arma_frown("replace conv_to<...>::from(X) with as_scalar(X)") inline static out_eT from(const Base<in_eT, T1>& in, const typename arma_cx_only<in_eT>::result* junk = nullptr);
template<typename in_eT, typename T1>
arma_frown("use as_scalar() instead") inline static out_eT from(const BaseCube<in_eT, T1>& in, const typename arma_not_cx<in_eT>::result* junk = nullptr);
arma_frown("replace conv_to<...>::from(X) with as_scalar(X)") inline static out_eT from(const BaseCube<in_eT, T1>& in, const typename arma_not_cx<in_eT>::result* junk = nullptr);
template<typename in_eT, typename T1>
arma_frown("use as_scalar() instead") inline static out_eT from(const BaseCube<in_eT, T1>& in, const typename arma_cx_only<in_eT>::result* junk = nullptr);
arma_frown("replace conv_to<...>::from(X) with as_scalar(X)") inline static out_eT from(const BaseCube<in_eT, T1>& in, const typename arma_cx_only<in_eT>::result* junk = nullptr);
};
+1 -1
View File
@@ -109,7 +109,7 @@ glue_hist::apply_noalias(Mat<uword>& out, const Mat<eT>& X, const Mat<eT>& C, co
{
const eT val = X_mem[i];
if(is_finite(val))
if(arma_isfinite(val))
{
eT opt_dist = (val >= center_0) ? (val - center_0) : (center_0 - val);
uword opt_index = 0;
+4 -7
View File
@@ -88,9 +88,7 @@ op_mean::apply_noalias(Mat<eT>& out, const Mat<eT>& X, const uword dim)
for(uword col=0; col < X_n_cols; ++col)
{
const eT* col_mem = X.colptr(col);
for(uword row=0; row < X_n_rows; ++row) { out_mem[row] += col_mem[row]; }
arrayops::inplace_plus(out_mem, X.colptr(col), X_n_rows);
}
out /= T(X_n_cols);
@@ -130,6 +128,7 @@ op_mean::apply(Cube<typename T1::elem_type>& out, const OpCube<T1,op_mean>& in)
typedef typename T1::elem_type eT;
const uword dim = in.aux_uword_a;
arma_conform_check( (dim > 2), "mean(): parameter 'dim' must be 0 or 1 or 2" );
const unwrap_cube<T1> U(in.m);
@@ -192,9 +191,7 @@ op_mean::apply_noalias(Cube<eT>& out, const Cube<eT>& X, const uword dim)
for(uword col=0; col < X_n_cols; ++col)
{
const eT* col_mem = X.slice_colptr(slice,col);
for(uword row=0; row < X_n_rows; ++row) { out_mem[row] += col_mem[row]; }
arrayops::inplace_plus(out_mem, X.slice_colptr(slice,col), X_n_rows);
}
for(uword row=0; row < X_n_rows; ++row) { out_mem[row] /= T(X_n_cols); }
@@ -211,7 +208,7 @@ op_mean::apply_noalias(Cube<eT>& out, const Cube<eT>& X, const uword dim)
if(arma_isnonfinite(old_mean))
{
tmp_vec.copy(tmp_mat, row);
tmp_vec.copy_row(tmp_mat, row);
out_mem[row] = op_mean::direct_mean_robust(old_mean, tmp_vec.memptr(), tmp_vec.n_elem);
}
+2 -2
View File
@@ -56,7 +56,7 @@ op_omit::apply(Mat<typename T1::elem_type>& out, const T1& X, functor is_omitted
typedef typename T1::elem_type eT;
if(is_Mat<T1>::value || is_subview_col<T1>::value || is_Mat<typename Proxy<T1>::stored_type>::value || Proxy<T1>::use_mp)
if(is_Mat<T1>::value || is_subview_col<T1>::value || is_Mat<typename Proxy<T1>::stored_type>::value || (arma_config::openmp && Proxy<T1>::use_mp))
{
const quasi_unwrap<T1> U(X);
@@ -160,7 +160,7 @@ op_omit_cube::apply(Mat<typename T1::elem_type>& out, const T1& X, functor is_om
typedef typename T1::elem_type eT;
if(is_Cube<T1>::value || is_Cube<typename ProxyCube<T1>::stored_type>::value || ProxyCube<T1>::use_mp)
if(is_Cube<T1>::value || is_Cube<typename ProxyCube<T1>::stored_type>::value || (arma_config::openmp && ProxyCube<T1>::use_mp))
{
const unwrap_cube<T1> U(X);
+5 -2
View File
@@ -32,10 +32,13 @@ class op_sum
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_square>, op_sum >& in);
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_pow >, op_sum >& in);
template<typename T1>
inline static void apply_generic(Mat<typename T1::elem_type>& out, const Op<T1,op_sum>& in);
template<typename eT>
inline static void apply_mat_noalias(Mat<eT>& out, const Mat<eT>& X, const uword dim);
+86 -146
View File
@@ -28,6 +28,92 @@ op_sum::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_sum>& in)
{
arma_debug_sigprint();
op_sum::apply_generic(out, in);
}
template<typename T1>
inline
void
op_sum::apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_square>, op_sum >& in)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
typedef eOp<T1,eop_square> inner_expr_type;
typedef typename inner_expr_type::proxy_type::stored_type inner_expr_P_stored_type;
if(is_Mat<inner_expr_P_stored_type>::value)
{
const uword dim = in.aux_uword_a;
arma_conform_check( (dim > 1), "sum(): parameter 'dim' must be 0 or 1" );
const quasi_unwrap<inner_expr_P_stored_type> U(in.m.P.Q);
if(U.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_mat_square_noalias(tmp, U.M, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_mat_square_noalias(out, U.M, dim);
}
return;
}
op_sum::apply_generic(out, in);
}
template<typename T1>
inline
void
op_sum::apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_pow>, op_sum >& in)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
if(arma_config::optimise_powexpr && (in.m.aux == eT(2)))
{
typedef Op< eOp<T1,eop_square>, op_sum > modified_whole_expr_type;
op_sum::apply(out, reinterpret_cast<const modified_whole_expr_type& >(in) );
return;
}
if(arma_config::optimise_powexpr && (in.m.aux == eT(0.5)) && is_non_integral<eT>::value)
{
typedef Op< eOp<T1,eop_sqrt>, op_sum > modified_whole_expr_type;
op_sum::apply(out, reinterpret_cast<const modified_whole_expr_type& >(in) );
return;
}
op_sum::apply_generic(out, in);
}
template<typename T1>
inline
void
op_sum::apply_generic(Mat<typename T1::elem_type>& out, const Op<T1,op_sum>& in)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
const uword dim = in.aux_uword_a;
@@ -72,152 +158,6 @@ op_sum::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_sum>& in)
template<typename T1>
inline
void
op_sum::apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_square>, op_sum >& in)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
typedef eOp<T1,eop_square> inner_expr_type;
typedef typename inner_expr_type::proxy_type::stored_type inner_expr_P_stored_type;
const uword dim = in.aux_uword_a;
arma_conform_check( (dim > 1), "sum(): parameter 'dim' must be 0 or 1" );
if(is_Mat<inner_expr_P_stored_type>::value)
{
const quasi_unwrap<inner_expr_P_stored_type> U(in.m.P.Q);
if(U.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_mat_square_noalias(tmp, U.M, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_mat_square_noalias(out, U.M, dim);
}
}
else
if(arma_config::openmp && Proxy<inner_expr_type>::use_mp)
{
const quasi_unwrap<inner_expr_type> U(in.m); // force evaluation of compound inner expression
if(U.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_mat_noalias(tmp, U.M, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_mat_noalias(out, U.M, dim);
}
}
else
{
const Proxy<inner_expr_type> P(in.m);
if(P.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_proxy_noalias(tmp, P, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_proxy_noalias(out, P, dim);
}
}
}
template<typename T1>
inline
void
op_sum::apply(Mat<typename T1::elem_type>& out, const Op< eOp<T1,eop_pow>, op_sum >& in)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
if(in.m.aux == eT(2))
{
typedef Op< eOp<T1,eop_square>, op_sum > modified_whole_expr_type;
op_sum::apply(out, reinterpret_cast<const modified_whole_expr_type& >(in) );
return;
}
if((in.m.aux == eT(0.5)) && is_non_integral<eT>::value)
{
typedef Op< eOp<T1,eop_sqrt>, op_sum > modified_whole_expr_type;
op_sum::apply(out, reinterpret_cast<const modified_whole_expr_type& >(in) );
return;
}
typedef eOp<T1,eop_pow> inner_expr_type;
typedef typename inner_expr_type::proxy_type::stored_type inner_expr_P_stored_type;
const uword dim = in.aux_uword_a;
arma_conform_check( (dim > 1), "sum(): parameter 'dim' must be 0 or 1" );
if( (is_Mat<inner_expr_P_stored_type>::value) || (arma_config::openmp && Proxy<inner_expr_type>::use_mp) )
{
const quasi_unwrap<inner_expr_type> U(in.m); // force evaluation of eop_pow
if(U.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_mat_noalias(tmp, U.M, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_mat_noalias(out, U.M, dim);
}
}
else
{
const Proxy<inner_expr_type> P(in.m);
if(P.is_alias(out))
{
Mat<eT> tmp;
op_sum::apply_proxy_noalias(tmp, P, dim);
out.steal_mem(tmp);
}
else
{
op_sum::apply_proxy_noalias(out, P, dim);
}
}
}
template<typename eT>
inline
void
@@ -2028,6 +2028,7 @@ sp_auxlib::run_aupd_plain
arma_ignore(n_eigvals);
arma_ignore(which);
arma_ignore(X);
arma_ignore(Xst);
arma_ignore(sym);
arma_ignore(n);
arma_ignore(tol);
-33
View File
@@ -116,37 +116,4 @@ spop_omit::apply_noalias(SpMat<typename T1::elem_type>& out, const SpProxy<T1>&
// template<typename T1, typename functor>
// inline
// void
// spop_omit::apply_direct(SpMat<typename T1::elem_type>& out, const T1& expr, functor is_omitted)
// {
// arma_debug_sigprint();
//
// typedef typename T1::elem_type eT;
//
// constexpr eT eT_zero = eT(0);
//
// out = expr;
//
// const uword N = out.n_elem;
//
// out.reshape(N, 1);
//
// out.sync();
//
// eT* values = access::rw(out.values);
//
// for(uword i=0; i < N; ++i)
// {
// eT& val = values[i];
//
// if(is_omitted(val)) { val = eT_zero; }
// }
//
// out.remove_zeros();
// }
//! @}
+1 -1
View File
@@ -31,7 +31,7 @@ TEST_CASE("bounds_1")
REQUIRE_NOTHROW( A(n_rows-1,n_cols-1) = 0 );
// out of bounds access will throw unless ARMA_NO_DEBUG is defined
// out of bounds access will throw
REQUIRE_THROWS( A(n_rows,n_cols) = 0 );
}
+1 -1
View File
@@ -113,7 +113,7 @@ TEST_CASE("fn_accu_4")
REQUIRE( accu(A % B) == Approx(double((2*4)*(A.n_rows*A.n_cols))) );
REQUIRE( accu(A(span::all,span::all) % B(span::all,span::all)) == Approx(double((2*4)*(A.n_rows*A.n_cols))) );
// A and C matrices are non-conformat, so accu() will throw unless ARMA_NO_DEBUG is defined
// A and C matrices are non-conformant
REQUIRE_THROWS( accu(A % C) );
REQUIRE_THROWS( accu(A(span::all,span::all) % C(span::all,span::all)) );
}
+1 -1
View File
@@ -110,7 +110,7 @@ TEST_CASE("mat_plus_2")
mat X(6,5);
mat Y;
REQUIRE_THROWS( Y = A+X ); // adding non-conformant matrices will throw unless ARMA_NO_DEBUG is defined
REQUIRE_THROWS( Y = A+X ); // adding non-conformant matrices will throw
}