Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1e03a5f1b | ||
|
|
9abc29ce78 | ||
|
|
bb2a42e6d1 | ||
|
|
e677071ca3 | ||
|
|
141e1f1e36 | ||
|
|
369041632a | ||
|
|
dbb6c5f583 | ||
|
|
def86fdf86 | ||
|
|
bb8bdf3458 | ||
|
|
3edd07b103 | ||
|
|
962f1385b1 | ||
|
|
d449a8d6a0 | ||
|
|
4c66933553 | ||
|
|
4424452a27 |
@@ -701,16 +701,6 @@ For convenience, the following matrix typedefs are defined:
|
||||
<code>Mat<<a href="#uword">sword</a>></code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
If supported by compiler and hardware, additional typedefs for matrices with half-precision element types are defined as:
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
<code>hmat</code>
|
||||
@@ -721,6 +711,9 @@ If supported by compiler and hardware, additional typedefs for matrices with hal
|
||||
<td style="vertical-align: top;">
|
||||
<code>Mat<<a href="#fp16_type">fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
@@ -732,6 +725,9 @@ If supported by compiler and hardware, additional typedefs for matrices with hal
|
||||
<td style="vertical-align: top;">
|
||||
<code>Mat<<a href="#fp16_type">cx_fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -776,7 +772,7 @@ Constructors:
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
The elements can be explicitly initialised during construction by specifying <i>fill_form</i>,
|
||||
Matrix elements can be explicitly initialised during construction by specifying <i>fill_form</i>,
|
||||
which is one of:
|
||||
<ul>
|
||||
<table>
|
||||
@@ -1095,20 +1091,6 @@ For convenience, the following column vector typedefs are defined:
|
||||
<code>Col<<a href="#uword">sword</a>></code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
The <b><i>vec</i></b> and <b><i>colvec</i></b> types have the <b>same meaning</b> and are used <b>interchangeably</b>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
If supported by compiler and hardware, additional typedefs for column vectors with half-precision element types are defined as:
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
<code>hvec</code>
|
||||
@@ -1125,6 +1107,9 @@ If supported by compiler and hardware, additional typedefs for column vectors wi
|
||||
<td style="vertical-align: top;">
|
||||
<code>Col<<a href="#fp16_type">fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
@@ -1142,12 +1127,19 @@ If supported by compiler and hardware, additional typedefs for column vectors wi
|
||||
<td style="vertical-align: top;">
|
||||
<code>Col<<a href="#fp16_type">cx_fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
The <b><i>vec</i></b> and <b><i>colvec</i></b> types have the <b>same meaning</b> and are used <b>interchangeably</b>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
In this documentation, the types <i>vec</i> or <i>colvec</i> are used for convenience; it is possible to use other column vector types instead, eg. <i>fvec</i>, <i>fcolvec</i>
|
||||
</li>
|
||||
<br>
|
||||
@@ -1178,11 +1170,7 @@ Constructors:
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
<b>Caveat:</b>
|
||||
<ul>
|
||||
<li>in Armadillo >= 10.5, the default initialisation is <code>fill::zeros</code></li>
|
||||
<li>in Armadillo <= 10.4, the default initialisation is <code>fill::none</code></li>
|
||||
</ul>
|
||||
Vector elements can be explicitly initialised during construction by specifying <i>fill_form</i>, as per the <a href="#Mat">Mat</a> class
|
||||
</li>
|
||||
<br>
|
||||
<a name="adv_constructors_col"></a>
|
||||
@@ -1390,16 +1378,6 @@ For convenience, the following row vector typedefs are defined:
|
||||
<code>Row<<a href="#uword">sword</a>></code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
If supported by compiler and hardware, additional typedefs for row vectors with half-precision element types are defined as:
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
<code>hrowvec</code>
|
||||
@@ -1410,6 +1388,9 @@ If supported by compiler and hardware, additional typedefs for row vectors with
|
||||
<td style="vertical-align: top;">
|
||||
<code>Row<<a href="#fp16_type">fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
@@ -1421,6 +1402,9 @@ If supported by compiler and hardware, additional typedefs for row vectors with
|
||||
<td style="vertical-align: top;">
|
||||
<code>Row<<a href="#fp16_type">cx_fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1458,11 +1442,7 @@ Constructors:
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
<b>Caveat:</b>
|
||||
<ul>
|
||||
<li>in Armadillo >= 10.5, the default initialisation is <code>fill::zeros</code></li>
|
||||
<li>in Armadillo <= 10.4, the default initialisation is <code>fill::none</code></li>
|
||||
</ul>
|
||||
Vector elements can be explicitly initialised during construction by specifying <i>fill_form</i>, as per the <a href="#Mat">Mat</a> class
|
||||
</li>
|
||||
<br>
|
||||
<a name="adv_constructors_row"></a>
|
||||
@@ -1680,16 +1660,6 @@ For convenience, the following cube typedefs are defined:
|
||||
<code>Cube<<a href="#uword">sword</a>></code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
If supported by compiler and hardware, additional typedefs for cubes with half-precision element types are defined as:
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
<code>hcube</code>
|
||||
@@ -1700,6 +1670,9 @@ If supported by compiler and hardware, additional typedefs for cubes with half-p
|
||||
<td style="vertical-align: top;">
|
||||
<code>Cube<<a href="#fp16_type">fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
@@ -1711,6 +1684,9 @@ If supported by compiler and hardware, additional typedefs for cubes with half-p
|
||||
<td style="vertical-align: top;">
|
||||
<code>Cube<<a href="#fp16_type">cx_fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -1740,7 +1716,7 @@ Constructors:
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
The elements can be explicitly initialised during construction by specifying <i>fill_form</i>,
|
||||
Cube elements can be explicitly initialised during construction by specifying <i>fill_form</i>,
|
||||
which is one of:
|
||||
<ul>
|
||||
<table>
|
||||
@@ -1966,7 +1942,8 @@ The root sparse matrix class is <b>SpMat<</b><i>type</i><b>></b>, where <i
|
||||
<br>
|
||||
<li>
|
||||
For convenience, the following sparse matrix typedefs are defined:
|
||||
<ul>
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
@@ -2057,17 +2034,6 @@ For convenience, the following sparse matrix typedefs are defined:
|
||||
<code>SpMat<<a href="#uword">sword</a>></code>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
If supported by compiler and hardware, additional typedefs for sparse matrices with half-precision element types are defined as:
|
||||
<br>
|
||||
<br>
|
||||
<table style="text-align: left;" border="0" cellpadding="2" cellspacing="2">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
<code>sp_hmat</code>
|
||||
@@ -2078,6 +2044,9 @@ If supported by compiler and hardware, additional typedefs for sparse matrices w
|
||||
<td style="vertical-align: top;">
|
||||
<code>SpMat<<a href="#fp16_type">fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top; text-align: right;">
|
||||
@@ -2089,6 +2058,9 @@ If supported by compiler and hardware, additional typedefs for sparse matrices w
|
||||
<td style="vertical-align: top;">
|
||||
<code>SpMat<<a href="#fp16_type">cx_fp16</a>></code>
|
||||
</td>
|
||||
<td style="vertical-align: top;">
|
||||
(only available if supported by compiler and hardware)
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -8118,7 +8090,7 @@ Generate a scalar, vector, matrix or cube with the elements set to random values
|
||||
<td style="vertical-align: top;"> </td><td style="vertical-align: top;"> </td><td style="vertical-align: top;"><i>x<sup> a-1</sup> exp( -x / b )</i></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;"><i>p<font size=+1>(</font>x | a,b<font size=+1>)</font></i></td><td style="vertical-align: top;"> <font size=+1>=</font> </td><td style="vertical-align: top;"><font size=+1><b><hr></b></font></td>
|
||||
<td style="vertical-align: top;"><i>p<font size=+1>(</font> x | a,b <font size=+1>)</font></i></td><td style="vertical-align: top;"> <font size=+1>=</font> </td><td style="vertical-align: top;"><font size=+1><b><hr></b></font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: top;"> </td><td style="vertical-align: top;"> </td><td style="vertical-align: top; text-align: center;"><i>b<sup> a</sup> Γ(a)</i></td>
|
||||
@@ -8176,6 +8148,7 @@ fmat B2 = randg<fmat>(10, 10, distr_param(2,1));
|
||||
<li><a href="#imbue">.imbue()</a></li>
|
||||
<li><a href="#size">size()</a></li>
|
||||
<li><a href="#rng_seed">RNG seed setting</a></li>
|
||||
<li><a href="https://mathworld.wolfram.com/GammaDistribution.html">gamma distribution in MathWorld</a></li>
|
||||
<li><a href="https://en.wikipedia.org/wiki/Gamma_distribution">gamma distribution in Wikipedia</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -11876,9 +11849,6 @@ See also:
|
||||
<a name="sort_index"></a>
|
||||
<b>sort_index( X )</b>
|
||||
<br><b>sort_index( X, sort_direction )</b>
|
||||
<br>
|
||||
<br><b>stable_sort_index( X )</b>
|
||||
<br><b>stable_sort_index( X, sort_direction )</b>
|
||||
<ul>
|
||||
<li>Return a vector which describes the sorted order of the elements of <i>X</i>
|
||||
(ie. it contains the indices of the elements of <i>X</i>)
|
||||
@@ -11894,8 +11864,6 @@ See also:
|
||||
<br>
|
||||
<li>The <i>sort_direction</i> argument is optional; <i>sort_direction</i> is either <code>"ascend"</code> or <code>"descend"</code>; by default <code>"ascend"</code> is used</li>
|
||||
<br>
|
||||
<li>The <i>stable_sort_index()</i> variant preserves the relative order of elements with equivalent values</li>
|
||||
<br>
|
||||
<li>For matrices and vectors with complex numbers, sorting is via absolute values</li>
|
||||
<br>
|
||||
<li>
|
||||
@@ -18717,7 +18685,7 @@ rudimentary <i>fp16</i> hardware support is present on x86-64 CPUs with the F16C
|
||||
<br>
|
||||
</ul>
|
||||
<li>
|
||||
If no compiler or hardware support is detected, support for <i>fp16</i> element types is <b>not</b> automatically enableds
|
||||
If no compiler or hardware support is detected, support for <i>fp16</i> element types is <b>not</b> automatically enabled
|
||||
</li>
|
||||
<br>
|
||||
<li>
|
||||
@@ -21448,7 +21416,7 @@ see the <a href="https://arma.sourceforge.net/faq.html#license">Questions page</
|
||||
<li>added handling of <a href="#diag">diagonal views</a> by sparse matrices
|
||||
<li>expanded <a href="#repmat">repmat()</a> to handle sparse matrices
|
||||
<li>expanded <a href="#join">join_rows()</a> and <a href="#join">join_cols()</a> to handle sparse matrices
|
||||
<li><a href="#sort_index">sort_index()</a> and <a href="#sort_index">stable_sort_index()</a> have been placed in the delayed operations framework for increased efficiency
|
||||
<li><a href="#sort_index">sort_index()</a> has been placed in the delayed operations framework for increased efficiency
|
||||
<li>use of <a href="#uword">64 bit integers</a> is automatically enabled when using a C++11 compiler</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -21660,7 +21628,7 @@ eg. <i>mat X(4, 5, fill::zeros)</i></li>
|
||||
<li>faster handling of compound expressions with submatrices and subcubes</li>
|
||||
<li>faster <a href="#trace">trace()</a></li>
|
||||
<li>added support for loading matrices as text files with <i>NaN</i> and <i>Inf</i> elements</li>
|
||||
<li>added <a href="#sort_index">stable_sort_index()</a>, which preserves the relative order of elements with equivalent values</li>
|
||||
<!-- <li>added <a href="#sort_index">stable_sort_index()</a>, which preserves the relative order of elements with equivalent values</li> -->
|
||||
<li>added handling of <a href="#SpMat">sparse matrices</a> by <a href="#stats_fns">mean()</a>, <a href="#stats_fns">var()</a>, <a href="#norm">norm()</a>, <a href="#abs">abs()</a>, <a href="#misc_fns">square()</a>, <a href="#misc_fns">sqrt()</a></li>
|
||||
<li>added saving and loading of sparse matrices in <i>arma_binary</i> format</li>
|
||||
</ul>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#define ARMA_VERSION_MAJOR 15
|
||||
#define ARMA_VERSION_MINOR 0
|
||||
#define ARMA_VERSION_PATCH 1
|
||||
#define ARMA_VERSION_PATCH 3
|
||||
#define ARMA_VERSION_NAME "Medium Roast"
|
||||
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ struct diskio
|
||||
|
||||
template<typename eT> inline static std::streamsize prepare_stream(std::ostream& f);
|
||||
|
||||
template<typename eT> inline static constexpr eT real_as_int_lower_limit();
|
||||
template<typename eT> inline static constexpr eT real_as_int_upper_limit();
|
||||
|
||||
|
||||
//
|
||||
// matrix saving
|
||||
|
||||
@@ -688,7 +688,32 @@ diskio::prepare_stream(std::ostream& f)
|
||||
|
||||
return cell_width;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename eT>
|
||||
inline
|
||||
constexpr
|
||||
eT
|
||||
diskio::real_as_int_lower_limit()
|
||||
{
|
||||
constexpr eT eT_int_accuracy_lower_limit = -( (is_fp16<eT>::value) ? eT(0x800) : ( (is_float<eT>::value) ? eT(0x1000000) : eT(0x20000000000000) ) );
|
||||
|
||||
return (std::max)( eT(std::numeric_limits<int>::lowest()), eT_int_accuracy_lower_limit );
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename eT>
|
||||
inline
|
||||
constexpr
|
||||
eT
|
||||
diskio::real_as_int_upper_limit()
|
||||
{
|
||||
constexpr eT eT_int_accuracy_upper_limit = (is_fp16<eT>::value) ? eT(0x800) : ( (is_float<eT>::value) ? eT(0x1000000) : eT(0x20000000000000) );
|
||||
|
||||
return (std::min)( eT(std::numeric_limits<int>::max()), eT_int_accuracy_upper_limit );
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -935,8 +960,8 @@ diskio::save_csv_ascii(const Mat<eT>& x, std::ostream& f, const char separator)
|
||||
uword x_n_rows = x.n_rows;
|
||||
uword x_n_cols = x.n_cols;
|
||||
|
||||
const eT eT_int_lowest = eT(std::numeric_limits<int>::lowest());
|
||||
const eT eT_int_max = eT(std::numeric_limits<int>::max());
|
||||
constexpr eT eT_int_lower = diskio::real_as_int_lower_limit<eT>();
|
||||
constexpr eT eT_int_upper = diskio::real_as_int_upper_limit<eT>();
|
||||
|
||||
for(uword row=0; row < x_n_rows; ++row)
|
||||
{
|
||||
@@ -944,7 +969,7 @@ diskio::save_csv_ascii(const Mat<eT>& x, std::ostream& f, const char separator)
|
||||
{
|
||||
const eT val = x.at(row,col);
|
||||
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lowest) && (val < eT_int_max) && (eT(int(val)) == val);
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lower) && (val < eT_int_upper) && (eT(int(val)) == val);
|
||||
|
||||
(is_real_int) ? arma_ostream::raw_print_elem(f, int(val)) : arma_ostream::raw_print_elem(f, val);
|
||||
|
||||
@@ -977,8 +1002,8 @@ diskio::save_csv_ascii(const Mat< std::complex<T> >& x, std::ostream& f, const c
|
||||
|
||||
diskio::prepare_stream<eT>(f);
|
||||
|
||||
const T T_int_lowest = T(std::numeric_limits<int>::lowest());
|
||||
const T T_int_max = T(std::numeric_limits<int>::max());
|
||||
constexpr T T_int_lower = diskio::real_as_int_lower_limit<T>();
|
||||
constexpr T T_int_upper = diskio::real_as_int_upper_limit<T>();
|
||||
|
||||
uword x_n_rows = x.n_rows;
|
||||
uword x_n_cols = x.n_cols;
|
||||
@@ -994,8 +1019,8 @@ diskio::save_csv_ascii(const Mat< std::complex<T> >& x, std::ostream& f, const c
|
||||
const T abs_i = (val_i < T(0)) ? T(-val_i) : T(val_i);
|
||||
const char sgn_i = (val_i < T(0)) ? char('-') : char('+');
|
||||
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lowest) && (val_r < T_int_max) && (T(int(val_r)) == val_r);
|
||||
const bool abs_i_is_real_int = (is_real<T>::yes) && arma_isfinite(abs_i) && (abs_i < T_int_max) && (T(int(abs_i)) == abs_i);
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lower) && (val_r < T_int_upper) && (T(int(val_r)) == val_r);
|
||||
const bool abs_i_is_real_int = (is_real<T>::yes) && arma_isfinite(abs_i) && (abs_i < T_int_upper) && (T(int(abs_i)) == abs_i);
|
||||
|
||||
(val_r_is_real_int) ? arma_ostream::raw_print_elem(f, int(val_r)) : arma_ostream::raw_print_elem(f, val_r);
|
||||
|
||||
@@ -1061,9 +1086,9 @@ diskio::save_coord_ascii(const Mat<eT>& x, std::ostream& f)
|
||||
|
||||
diskio::prepare_stream<eT>(f);
|
||||
|
||||
const eT eT_zero = eT(0);
|
||||
const eT eT_int_lowest = eT(std::numeric_limits<int>::lowest());
|
||||
const eT eT_int_max = eT(std::numeric_limits<int>::max());
|
||||
constexpr eT eT_zero = eT(0);
|
||||
constexpr eT eT_int_lower = diskio::real_as_int_lower_limit<eT>();
|
||||
constexpr eT eT_int_upper = diskio::real_as_int_upper_limit<eT>();
|
||||
|
||||
for(uword col=0; col < x.n_cols; ++col)
|
||||
for(uword row=0; row < x.n_rows; ++row)
|
||||
@@ -1075,7 +1100,7 @@ diskio::save_coord_ascii(const Mat<eT>& x, std::ostream& f)
|
||||
f << row; f.put(' ');
|
||||
f << col; f.put(' ');
|
||||
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lowest) && (val < eT_int_max) && (eT(int(val)) == val);
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lower) && (val < eT_int_upper) && (eT(int(val)) == val);
|
||||
|
||||
(is_real_int) ? arma_ostream::raw_print_elem(f, int(val)) : arma_ostream::raw_print_elem(f, val);
|
||||
|
||||
@@ -1116,9 +1141,9 @@ diskio::save_coord_ascii(const Mat< std::complex<T> >& x, std::ostream& f)
|
||||
|
||||
diskio::prepare_stream<eT>(f);
|
||||
|
||||
const eT eT_zero = eT(0);
|
||||
const T T_int_lowest = T(std::numeric_limits<int>::lowest());
|
||||
const T T_int_max = T(std::numeric_limits<int>::max());
|
||||
constexpr eT eT_zero = eT(0);
|
||||
constexpr T T_int_lower = diskio::real_as_int_lower_limit<T>();
|
||||
constexpr T T_int_upper = diskio::real_as_int_upper_limit<T>();
|
||||
|
||||
for(uword col=0; col < x.n_cols; ++col)
|
||||
for(uword row=0; row < x.n_rows; ++row)
|
||||
@@ -1133,8 +1158,8 @@ diskio::save_coord_ascii(const Mat< std::complex<T> >& x, std::ostream& f)
|
||||
const T val_r = std::real(val);
|
||||
const T val_i = std::imag(val);
|
||||
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lowest) && (val_r < T_int_max) && (T(int(val_r)) == val_r);
|
||||
const bool val_i_is_real_int = (is_real<T>::yes) && arma_isfinite(val_i) && (val_i > T_int_lowest) && (val_i < T_int_max) && (T(int(val_i)) == val_i);
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lower) && (val_r < T_int_upper) && (T(int(val_r)) == val_r);
|
||||
const bool val_i_is_real_int = (is_real<T>::yes) && arma_isfinite(val_i) && (val_i > T_int_lower) && (val_i < T_int_upper) && (T(int(val_i)) == val_i);
|
||||
|
||||
(val_r_is_real_int) ? arma_ostream::raw_print_elem(f, int(val_r)) : arma_ostream::raw_print_elem(f, val_r);
|
||||
|
||||
@@ -2966,9 +2991,9 @@ diskio::save_csv_ascii(const SpMat<eT>& x, std::ostream& f, const char separator
|
||||
uword x_n_rows = x.n_rows;
|
||||
uword x_n_cols = x.n_cols;
|
||||
|
||||
const eT eT_zero = eT(0);
|
||||
const eT eT_int_lowest = eT(std::numeric_limits<int>::lowest());
|
||||
const eT eT_int_max = eT(std::numeric_limits<int>::max());
|
||||
constexpr eT eT_zero = eT(0);
|
||||
constexpr eT eT_int_lower = diskio::real_as_int_lower_limit<eT>();
|
||||
constexpr eT eT_int_upper = diskio::real_as_int_upper_limit<eT>();
|
||||
|
||||
for(uword row=0; row < x_n_rows; ++row)
|
||||
{
|
||||
@@ -2982,7 +3007,7 @@ diskio::save_csv_ascii(const SpMat<eT>& x, std::ostream& f, const char separator
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lowest) && (val < eT_int_max) && (eT(int(val)) == val);
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lower) && (val < eT_int_upper) && (eT(int(val)) == val);
|
||||
|
||||
(is_real_int) ? arma_ostream::raw_print_elem(f, int(val)) : arma_ostream::raw_print_elem(f, val);
|
||||
}
|
||||
@@ -3064,8 +3089,8 @@ diskio::save_coord_ascii(const SpMat<eT>& x, std::ostream& f)
|
||||
|
||||
diskio::prepare_stream<eT>(f);
|
||||
|
||||
const eT eT_int_lowest = eT(std::numeric_limits<int>::lowest());
|
||||
const eT eT_int_max = eT(std::numeric_limits<int>::max());
|
||||
constexpr eT eT_int_lower = diskio::real_as_int_lower_limit<eT>();
|
||||
constexpr eT eT_int_upper = diskio::real_as_int_upper_limit<eT>();
|
||||
|
||||
typename SpMat<eT>::const_iterator iter = x.begin();
|
||||
typename SpMat<eT>::const_iterator iter_end = x.end();
|
||||
@@ -3077,7 +3102,7 @@ diskio::save_coord_ascii(const SpMat<eT>& x, std::ostream& f)
|
||||
|
||||
const eT val = (*iter);
|
||||
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lowest) && (val < eT_int_max) && (eT(int(val)) == val);
|
||||
const bool is_real_int = (is_real<eT>::yes) && arma_isfinite(val) && (val > eT_int_lower) && (val < eT_int_upper) && (eT(int(val)) == val);
|
||||
|
||||
(is_real_int) ? arma_ostream::raw_print_elem(f, int(val)) : arma_ostream::raw_print_elem(f, val);
|
||||
|
||||
@@ -3120,8 +3145,8 @@ diskio::save_coord_ascii(const SpMat< std::complex<T> >& x, std::ostream& f)
|
||||
|
||||
diskio::prepare_stream<eT>(f);
|
||||
|
||||
const T T_int_lowest = T(std::numeric_limits<int>::lowest());
|
||||
const T T_int_max = T(std::numeric_limits<int>::max());
|
||||
constexpr T T_int_lower = diskio::real_as_int_lower_limit<T>();
|
||||
constexpr T T_int_upper = diskio::real_as_int_upper_limit<T>();
|
||||
|
||||
typename SpMat<eT>::const_iterator iter = x.begin();
|
||||
typename SpMat<eT>::const_iterator iter_end = x.end();
|
||||
@@ -3136,8 +3161,8 @@ diskio::save_coord_ascii(const SpMat< std::complex<T> >& x, std::ostream& f)
|
||||
const T val_r = std::real(val);
|
||||
const T val_i = std::imag(val);
|
||||
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lowest) && (val_r < T_int_max) && (T(int(val_r)) == val_r);
|
||||
const bool val_i_is_real_int = (is_real<T>::yes) && arma_isfinite(val_i) && (val_i > T_int_lowest) && (val_i < T_int_max) && (T(int(val_i)) == val_i);
|
||||
const bool val_r_is_real_int = (is_real<T>::yes) && arma_isfinite(val_r) && (val_r > T_int_lower) && (val_r < T_int_upper) && (T(int(val_r)) == val_r);
|
||||
const bool val_i_is_real_int = (is_real<T>::yes) && arma_isfinite(val_i) && (val_i > T_int_lower) && (val_i < T_int_upper) && (T(int(val_i)) == val_i);
|
||||
|
||||
(val_r_is_real_int) ? arma_ostream::raw_print_elem(f, int(val_r)) : arma_ostream::raw_print_elem(f, val_r);
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
|
||||
|
||||
//! \addtogroup fn_shift
|
||||
//! \addtogroup fn_circshift
|
||||
//! @{
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
// TODO: deprecate in favour of circshift()
|
||||
template<typename T1>
|
||||
arma_warn_unused
|
||||
arma_inline
|
||||
inline
|
||||
typename
|
||||
enable_if2
|
||||
<
|
||||
@@ -50,7 +50,7 @@ shift
|
||||
|
||||
template<typename T1>
|
||||
arma_warn_unused
|
||||
arma_inline
|
||||
inline
|
||||
typename
|
||||
enable_if2
|
||||
<
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -59,6 +59,156 @@ struct gemm_emul_tinysq
|
||||
|
||||
|
||||
|
||||
struct gemm_emul_large_mp_helper
|
||||
{
|
||||
template<typename eT>
|
||||
arma_hot
|
||||
inline
|
||||
static
|
||||
void
|
||||
copy_row(eT* out_mem, const Mat<eT>& in, const uword row)
|
||||
{
|
||||
const uword n_rows = in.n_rows;
|
||||
const uword n_cols = in.n_cols;
|
||||
|
||||
const eT* in_mem_row = in.memptr() + row;
|
||||
|
||||
for(uword i=0; i < n_cols; ++i)
|
||||
{
|
||||
out_mem[i] = (*in_mem_row);
|
||||
|
||||
in_mem_row += n_rows;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
#if defined(ARMA_USE_OPENMP)
|
||||
//! emulation of gemm(), for non-complex matrices only, as it assumes only simple transposes (ie. doesn't do hermitian transposes)
|
||||
//! parallelised version
|
||||
template<const bool do_trans_A=false, const bool do_trans_B=false, const bool use_alpha=false, const bool use_beta=false>
|
||||
struct gemm_emul_large_mp
|
||||
{
|
||||
template<typename eT, typename TA, typename TB>
|
||||
arma_hot
|
||||
inline
|
||||
static
|
||||
void
|
||||
apply
|
||||
(
|
||||
Mat<eT>& C,
|
||||
const TA& A,
|
||||
const TB& B,
|
||||
const eT alpha = eT(1),
|
||||
const eT beta = eT(0)
|
||||
)
|
||||
{
|
||||
arma_debug_sigprint();
|
||||
|
||||
const uword A_n_rows = A.n_rows;
|
||||
const uword A_n_cols = A.n_cols;
|
||||
|
||||
const uword B_n_rows = B.n_rows;
|
||||
const uword B_n_cols = B.n_cols;
|
||||
|
||||
if( (do_trans_A == false) && (do_trans_B == false) )
|
||||
{
|
||||
const uword n_threads = uword(mp_thread_limit::get());
|
||||
|
||||
podarray<eT> tmp(A_n_cols * n_threads, arma_nozeros_indicator());
|
||||
|
||||
eT* tmp_mem = tmp.memptr();
|
||||
|
||||
#pragma omp parallel for schedule(static) num_threads(int(n_threads))
|
||||
for(uword row_A=0; row_A < A_n_rows; ++row_A)
|
||||
{
|
||||
const uword thread_id = uword(omp_get_thread_num());
|
||||
|
||||
eT* A_rowdata = tmp_mem + (A_n_cols * thread_id);
|
||||
|
||||
gemm_emul_large_mp_helper::copy_row(A_rowdata, A, row_A);
|
||||
|
||||
for(uword col_B=0; col_B < B_n_cols; ++col_B)
|
||||
{
|
||||
const eT acc = op_dot::direct_dot(B_n_rows, A_rowdata, B.colptr(col_B));
|
||||
|
||||
if( (use_alpha == false) && (use_beta == false) ) { C.at(row_A,col_B) = acc; }
|
||||
else if( (use_alpha == true ) && (use_beta == false) ) { C.at(row_A,col_B) = alpha*acc; }
|
||||
else if( (use_alpha == false) && (use_beta == true ) ) { C.at(row_A,col_B) = acc + beta*C.at(row_A,col_B); }
|
||||
else if( (use_alpha == true ) && (use_beta == true ) ) { C.at(row_A,col_B) = alpha*acc + beta*C.at(row_A,col_B); }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if( (do_trans_A == true) && (do_trans_B == false) )
|
||||
{
|
||||
const int n_threads = mp_thread_limit::get();
|
||||
|
||||
#pragma omp parallel for schedule(static) num_threads(n_threads)
|
||||
for(uword col_A=0; col_A < A_n_cols; ++col_A)
|
||||
{
|
||||
// col_A is interpreted as row_A when storing the results in matrix C
|
||||
|
||||
const eT* A_coldata = A.colptr(col_A);
|
||||
|
||||
for(uword col_B=0; col_B < B_n_cols; ++col_B)
|
||||
{
|
||||
const eT acc = op_dot::direct_dot(B_n_rows, A_coldata, B.colptr(col_B));
|
||||
|
||||
if( (use_alpha == false) && (use_beta == false) ) { C.at(col_A,col_B) = acc; }
|
||||
else if( (use_alpha == true ) && (use_beta == false) ) { C.at(col_A,col_B) = alpha*acc; }
|
||||
else if( (use_alpha == false) && (use_beta == true ) ) { C.at(col_A,col_B) = acc + beta*C.at(col_A,col_B); }
|
||||
else if( (use_alpha == true ) && (use_beta == true ) ) { C.at(col_A,col_B) = alpha*acc + beta*C.at(col_A,col_B); }
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if( (do_trans_A == false) && (do_trans_B == true) )
|
||||
{
|
||||
Mat<eT> BB;
|
||||
op_strans::apply_mat_noalias(BB, B);
|
||||
|
||||
gemm_emul_large_mp<false, false, use_alpha, use_beta>::apply(C, A, BB, alpha, beta);
|
||||
}
|
||||
else
|
||||
if( (do_trans_A == true) && (do_trans_B == true) )
|
||||
{
|
||||
// using trans(A)*trans(B) = trans(B*A) equivalency; assuming no hermitian transpose
|
||||
|
||||
const uword n_threads = uword(mp_thread_limit::get());
|
||||
|
||||
podarray<eT> tmp(B_n_cols * n_threads, arma_nozeros_indicator());
|
||||
|
||||
eT* tmp_mem = tmp.memptr();
|
||||
|
||||
#pragma omp parallel for schedule(static) num_threads(int(n_threads))
|
||||
for(uword row_B=0; row_B < B_n_rows; ++row_B)
|
||||
{
|
||||
const uword thread_id = uword(omp_get_thread_num());
|
||||
|
||||
eT* B_rowdata = tmp_mem + (B_n_cols * thread_id);
|
||||
|
||||
gemm_emul_large_mp_helper::copy_row(B_rowdata, B, row_B);
|
||||
|
||||
for(uword col_A=0; col_A < A_n_cols; ++col_A)
|
||||
{
|
||||
const eT acc = op_dot::direct_dot(A_n_rows, B_rowdata, A.colptr(col_A));
|
||||
|
||||
if( (use_alpha == false) && (use_beta == false) ) { C.at(col_A,row_B) = acc; }
|
||||
else if( (use_alpha == true ) && (use_beta == false) ) { C.at(col_A,row_B) = alpha*acc; }
|
||||
else if( (use_alpha == false) && (use_beta == true ) ) { C.at(col_A,row_B) = acc + beta*C.at(col_A,row_B); }
|
||||
else if( (use_alpha == true ) && (use_beta == true ) ) { C.at(col_A,row_B) = alpha*acc + beta*C.at(col_A,row_B); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//! emulation of gemm(), for non-complex matrices only, as it assumes only simple transposes (ie. doesn't do hermitian transposes)
|
||||
template<const bool do_trans_A=false, const bool do_trans_B=false, const bool use_alpha=false, const bool use_beta=false>
|
||||
struct gemm_emul_large
|
||||
@@ -78,13 +228,28 @@ struct gemm_emul_large
|
||||
)
|
||||
{
|
||||
arma_debug_sigprint();
|
||||
|
||||
|
||||
const uword A_n_rows = A.n_rows;
|
||||
const uword A_n_cols = A.n_cols;
|
||||
|
||||
const uword B_n_rows = B.n_rows;
|
||||
const uword B_n_cols = B.n_cols;
|
||||
|
||||
#if defined(ARMA_USE_OPENMP)
|
||||
{
|
||||
// TODO: replace with more sophisticated threshold mechanism
|
||||
|
||||
constexpr uword threshold = uword(30);
|
||||
|
||||
if( (A_n_rows >= threshold) && (A_n_cols >= threshold) && (B_n_rows >= threshold) && (B_n_cols >= threshold) && (mp_thread_limit::in_parallel() == false) )
|
||||
{
|
||||
gemm_emul_large_mp<do_trans_A, do_trans_B, use_alpha, use_beta>::apply(C,A,B,alpha,beta);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if( (do_trans_A == false) && (do_trans_B == false) )
|
||||
{
|
||||
arma_aligned podarray<eT> tmp(A_n_cols);
|
||||
|
||||
@@ -203,6 +203,74 @@ struct gemv_emul_helper
|
||||
|
||||
|
||||
|
||||
#if defined(ARMA_USE_OPENMP)
|
||||
//! Partial emulation of BLAS gemv().
|
||||
//! 'y' is assumed to have been set to the correct size (ie. taking into account the transpose)
|
||||
//! parallelised version
|
||||
template<const bool do_trans_A=false, const bool use_alpha=false, const bool use_beta=false>
|
||||
struct gemv_emul_mp
|
||||
{
|
||||
template<typename eT, typename TA>
|
||||
arma_hot
|
||||
inline
|
||||
static
|
||||
void
|
||||
apply( eT* y, const TA& A, const eT* x, const eT alpha = eT(1), const eT beta = eT(0) )
|
||||
{
|
||||
arma_debug_sigprint();
|
||||
|
||||
const int n_threads = mp_thread_limit::get();
|
||||
|
||||
const uword A_n_rows = A.n_rows;
|
||||
const uword A_n_cols = A.n_cols;
|
||||
|
||||
if(do_trans_A == false)
|
||||
{
|
||||
#pragma omp parallel for schedule(static) num_threads(n_threads)
|
||||
for(uword row=0; row < A_n_rows; ++row)
|
||||
{
|
||||
const eT acc = gemv_emul_helper::dot_row_col(A, x, row, A_n_cols);
|
||||
|
||||
if( (use_alpha == false) && (use_beta == false) ) { y[row] = acc; }
|
||||
else if( (use_alpha == true ) && (use_beta == false) ) { y[row] = alpha*acc; }
|
||||
else if( (use_alpha == false) && (use_beta == true ) ) { y[row] = acc + beta*y[row]; }
|
||||
else if( (use_alpha == true ) && (use_beta == true ) ) { y[row] = alpha*acc + beta*y[row]; }
|
||||
}
|
||||
}
|
||||
else
|
||||
if(do_trans_A == true)
|
||||
{
|
||||
if(is_cx<eT>::no)
|
||||
{
|
||||
#pragma omp parallel for schedule(static) num_threads(n_threads)
|
||||
for(uword col=0; col < A_n_cols; ++col)
|
||||
{
|
||||
// col is interpreted as row when storing the results in 'y'
|
||||
|
||||
const eT acc = op_dot::direct_dot(A_n_rows, A.colptr(col), x);
|
||||
|
||||
if( (use_alpha == false) && (use_beta == false) ) { y[col] = acc; }
|
||||
else if( (use_alpha == true ) && (use_beta == false) ) { y[col] = alpha*acc; }
|
||||
else if( (use_alpha == false) && (use_beta == true ) ) { y[col] = acc + beta*y[col]; }
|
||||
else if( (use_alpha == true ) && (use_beta == true ) ) { y[col] = alpha*acc + beta*y[col]; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat<eT> AA;
|
||||
|
||||
op_htrans::apply_mat_noalias(AA, A);
|
||||
|
||||
gemv_emul_mp<false, use_alpha, use_beta>::apply(y, AA, x, alpha, beta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//! \brief
|
||||
//! Partial emulation of BLAS gemv().
|
||||
//! 'y' is assumed to have been set to the correct size (ie. taking into account the transpose)
|
||||
@@ -222,6 +290,21 @@ struct gemv_emul
|
||||
const uword A_n_rows = A.n_rows;
|
||||
const uword A_n_cols = A.n_cols;
|
||||
|
||||
#if defined(ARMA_USE_OPENMP)
|
||||
{
|
||||
// TODO: replace with more sophisticated threshold mechanism
|
||||
|
||||
constexpr uword threshold = uword(200);
|
||||
|
||||
if( (A_n_rows >= threshold) && (A_n_cols >= threshold) && (mp_thread_limit::in_parallel() == false) )
|
||||
{
|
||||
gemv_emul_mp<do_trans_A, use_alpha, use_beta>::apply(y, A, x, alpha, beta);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if(do_trans_A == false)
|
||||
{
|
||||
if(A_n_rows == 1)
|
||||
|
||||
@@ -365,14 +365,30 @@ op_vectorise_cube_col::apply_subview(Mat<eT>& out, const subview_cube<eT>& sv)
|
||||
|
||||
out.set_size(sv.n_elem, 1);
|
||||
|
||||
if(sv.n_elem == 0) { return; }
|
||||
|
||||
eT* out_mem = out.memptr();
|
||||
|
||||
for(uword s=0; s < sv_ns; ++s)
|
||||
for(uword c=0; c < sv_nc; ++c)
|
||||
if( (sv_nr == 1) && (sv_nc == 1) && (sv.aux_slice1 == 0) )
|
||||
{
|
||||
arrayops::copy(out_mem, sv.slice_colptr(s,c), sv_nr);
|
||||
const uword sv_m_n_elem_slice = sv.m.n_elem_slice;
|
||||
|
||||
out_mem += sv_nr;
|
||||
const eT* sv_m_ptr = &( sv.m.at(sv.aux_row1, sv.aux_col1, 0) );
|
||||
|
||||
for(uword s=0; s < sv_ns; ++s)
|
||||
{
|
||||
out_mem[s] = (*sv_m_ptr); sv_m_ptr += sv_m_n_elem_slice;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(uword s=0; s < sv_ns; ++s)
|
||||
for(uword c=0; c < sv_nc; ++c)
|
||||
{
|
||||
arrayops::copy(out_mem, sv.slice_colptr(s,c), sv_nr);
|
||||
|
||||
out_mem += sv_nr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ operator<< (std::ostream& o, const Base<eT,T1>& X)
|
||||
{
|
||||
arma_debug_sigprint();
|
||||
|
||||
const unwrap<T1> tmp(X.get_ref());
|
||||
const quasi_unwrap<T1> tmp(X.get_ref());
|
||||
|
||||
arma_ostream::print(o, tmp.M, true);
|
||||
|
||||
|
||||
@@ -969,3 +969,134 @@ TEMPLATE_TEST_CASE("mat_mul_fp_compare", "[mat_mul]", TEST_FLOAT_TYPES)
|
||||
REQUIRE( accu(abs(diff3)) == Approx(eT(0)).margin(margin * diff3.n_elem) );
|
||||
REQUIRE( accu(abs(diff4)) == Approx(eT(0)).margin(margin * diff4.n_elem) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if defined(ARMA_USE_BLAS)
|
||||
TEMPLATE_TEST_CASE("mat_mul_int_compare", "[mat_mul]", u32, s32, u64, s64)
|
||||
{
|
||||
typedef TestType eT;
|
||||
|
||||
const uword n_trials = 5;
|
||||
|
||||
for (uword trial = 0; trial < n_trials; ++trial)
|
||||
{
|
||||
uword m = randi<uword>(distr_param(10, 500));
|
||||
uword n = randi<uword>(distr_param(10, 500));
|
||||
uword k = randi<uword>(distr_param(10, 500));
|
||||
|
||||
Mat<eT> A = randi<Mat<eT>>(m, n, distr_param(0, 100));
|
||||
Mat<eT> At = randi<Mat<eT>>(n, m, distr_param(0, 100));
|
||||
Mat<eT> B = randi<Mat<eT>>(n, k, distr_param(0, 100));
|
||||
Mat<eT> Bt = randi<Mat<eT>>(k, n, distr_param(0, 100));
|
||||
|
||||
// compare against BLAS implementation
|
||||
mat Ad = conv_to<mat>::from(A);
|
||||
mat Atd = conv_to<mat>::from(At);
|
||||
mat Bd = conv_to<mat>::from(B);
|
||||
mat Btd = conv_to<mat>::from(Bt);
|
||||
|
||||
Mat<eT> C = A * B;
|
||||
mat Cd = Ad * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = A * Bt.t();
|
||||
Cd = Ad * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = At.t() * B;
|
||||
Cd = Atd.t() * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = At.t() * Bt.t();
|
||||
Cd = Atd.t() * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
// now test variants with alpha
|
||||
|
||||
C = 2 * A * B;
|
||||
Cd = 2 * Ad * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = 2 * A * Bt.t();
|
||||
Cd = 2 * Ad * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = 2 * At.t() * B;
|
||||
Cd = 2 * Atd.t() * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C = 2 * At.t() * Bt.t();
|
||||
Cd = 2 * Atd.t() * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
// variants with beta
|
||||
|
||||
C.ones(A.n_rows, B.n_cols);
|
||||
C = 2 * C + A * B;
|
||||
Cd.ones(Ad.n_rows, Bd.n_cols);
|
||||
Cd = 2 * Cd + Ad * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(A.n_rows, Bt.n_rows);
|
||||
C = 2 * C + A * Bt.t();
|
||||
Cd.ones(Ad.n_rows, Btd.n_rows);
|
||||
Cd = 2 * Cd + Ad * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(At.n_cols, B.n_cols);
|
||||
C = 2 * C + At.t() * B;
|
||||
Cd.ones(Atd.n_cols, Bd.n_cols);
|
||||
Cd = 2 * Cd + Atd.t() * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(At.n_cols, Bt.n_rows);
|
||||
C = 2 * C + At.t() * Bt.t();
|
||||
Cd.ones(Atd.n_cols, Btd.n_rows);
|
||||
Cd = 2 * Cd + Atd.t() * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
// variants with both alpha and beta
|
||||
|
||||
C.ones(A.n_rows, B.n_cols);
|
||||
C = 2 * C + 3 * A * B;
|
||||
Cd.ones(Ad.n_rows, Bd.n_cols);
|
||||
Cd = 2 * Cd + 3 * Ad * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(A.n_rows, Bt.n_rows);
|
||||
C = 2 * C + 3 * A * Bt.t();
|
||||
Cd.ones(Ad.n_rows, Btd.n_rows);
|
||||
Cd = 2 * Cd + 3 * Ad * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(At.n_cols, B.n_cols);
|
||||
C = 2 * C + 3 * At.t() * B;
|
||||
Cd.ones(Atd.n_cols, Bd.n_cols);
|
||||
Cd = 2 * Cd + 3 * Atd.t() * Bd;
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
|
||||
C.ones(At.n_cols, Bt.n_rows);
|
||||
C = 2 * C + 3 * At.t() * Bt.t();
|
||||
Cd.ones(Atd.n_cols, Btd.n_rows);
|
||||
Cd = 2 * Cd + 3 * Atd.t() * Btd.t();
|
||||
|
||||
REQUIRE( approx_equal( conv_to<mat>::from(C), Cd, "both", 1e-5, 1e-5 ) );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user