diff --git a/ChangeLog b/ChangeLog index 3acc9519..24e28841 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2025-05-21 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): RcppArmadillo 14.4.3-1 + * inst/NEWS.Rd: Idem + * configure.ac: Idem + * configure: Idem + + * inst/include/armadillo_bits/: Sync with Armadillo 14.4.3 + 2025-04-25 Dirk Eddelbuettel * DESCRIPTION (Version, Date): RcppArmadillo 14.4.2-1 diff --git a/DESCRIPTION b/DESCRIPTION index ee4fd06d..a930ea60 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,8 +1,8 @@ Package: RcppArmadillo Type: Package Title: 'Rcpp' Integration for the 'Armadillo' Templated Linear Algebra Library -Version: 14.4.2-1 -Date: 2025-04-25 +Version: 14.4.3-1 +Date: 2025-05-21 Authors@R: c(person("Dirk", "Eddelbuettel", role = c("aut", "cre"), email = "edd@debian.org", comment = c(ORCID = "0000-0001-6419-907X")), person("Romain", "Francois", role = "aut", diff --git a/configure b/configure index b5c5309d..e2b9c49d 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72 for RcppArmadillo 14.4.2-1. +# Generated by GNU Autoconf 2.72 for RcppArmadillo 14.4.3-1. # # Report bugs to . # @@ -603,8 +603,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='RcppArmadillo' PACKAGE_TARNAME='rcpparmadillo' -PACKAGE_VERSION='14.4.2-1' -PACKAGE_STRING='RcppArmadillo 14.4.2-1' +PACKAGE_VERSION='14.4.3-1' +PACKAGE_STRING='RcppArmadillo 14.4.3-1' PACKAGE_BUGREPORT='edd@debian.org' PACKAGE_URL='' @@ -1222,7 +1222,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -'configure' configures RcppArmadillo 14.4.2-1 to adapt to many kinds of systems. +'configure' configures RcppArmadillo 14.4.3-1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1284,7 +1284,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of RcppArmadillo 14.4.2-1:";; + short | recursive ) echo "Configuration of RcppArmadillo 14.4.3-1:";; esac cat <<\_ACEOF @@ -1365,7 +1365,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -RcppArmadillo configure 14.4.2-1 +RcppArmadillo configure 14.4.3-1 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc. @@ -1481,7 +1481,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by RcppArmadillo $as_me 14.4.2-1, which was +It was created by RcppArmadillo $as_me 14.4.3-1, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw @@ -3980,7 +3980,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by RcppArmadillo $as_me 14.4.2-1, which was +This file was extended by RcppArmadillo $as_me 14.4.3-1, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4035,7 +4035,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -RcppArmadillo config.status 14.4.2-1 +RcppArmadillo config.status 14.4.3-1 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 5be33ea2..77da8d17 100644 --- a/configure.ac +++ b/configure.ac @@ -11,7 +11,7 @@ AC_PREREQ([2.69]) ## Process this file with autoconf to produce a configure script. -AC_INIT([RcppArmadillo],[14.4.2-1],[edd@debian.org]) +AC_INIT([RcppArmadillo],[14.4.3-1],[edd@debian.org]) ## Set R_HOME, respecting an environment variable if one is set : ${R_HOME=$(R RHOME)} diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 9704d650..caa763f4 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -3,6 +3,16 @@ \newcommand{\ghpr}{\href{https://github.com/RcppCore/RcppArmadillo/pull/#1}{##1}} \newcommand{\ghit}{\href{https://github.com/RcppCore/RcppArmadillo/issues/#1}{##1}} +\section{Changes in RcppArmadillo version 14.4.3-1 (2025-05-21)}{ + \itemize{ + \item Upgraded to Armadillo release 14.4.3 (Filtered Espresso) + \itemize{ + \item Fix for several corner cases involving handling of non-finite + elements by sparse matrices + } + } +} + \section{Changes in RcppArmadillo version 14.4.2-1 (2025-04-25)}{ \itemize{ \item Upgraded to Armadillo release 14.4.2 (Filtered Espresso) diff --git a/inst/include/armadillo_bits/MapMat_meat.hpp b/inst/include/armadillo_bits/MapMat_meat.hpp index ee63c1ef..5a99578c 100644 --- a/inst/include/armadillo_bits/MapMat_meat.hpp +++ b/inst/include/armadillo_bits/MapMat_meat.hpp @@ -970,18 +970,17 @@ MapMat_val::operator*=(const eT in_val) if(it != it_end) { - if(in_val != eT(0)) - { - eT& val = (*it).second; - - val *= in_val; - - if(val == eT(0)) { map_ref.erase(it); } - } - else - { - map_ref.erase(it); - } + eT& val = (*it).second; + + val *= in_val; + + if(val == eT(0)) { map_ref.erase(it); } + } + else + { + const eT val = eT(0) * in_val; // in case in_val is inf or nan + + if(val != eT(0)) { parent.set_val(index, val); } } } @@ -1009,9 +1008,7 @@ MapMat_val::operator/=(const eT in_val) } else { - // silly operation, but included for completeness - - const eT val = eT(0) / in_val; + const eT val = eT(0) / in_val; // in case in_val is zero or nan if(val != eT(0)) { parent.set_val(index, val); } } @@ -1481,18 +1478,11 @@ SpMat_MapMat_val::mul(const eT in_val) if(it != it_end) { - if(in_val != eT(0)) - { - eT& val = (*it).second; - - val *= in_val; - - if(val == eT(0)) { map_ref.erase(it); } - } - else - { - map_ref.erase(it); - } + eT& val = (*it).second; + + val *= in_val; + + if(val == eT(0)) { map_ref.erase(it); } s_parent.sync_state = 1; @@ -1500,19 +1490,15 @@ SpMat_MapMat_val::mul(const eT in_val) } else { - // element not found, ie. it's zero; zero multiplied by anything is zero, except for nan and inf - if(arma_isfinite(in_val) == false) + const eT result = eT(0) * in_val; // in case in_val is inf or nan + + if(result != eT(0)) { - const eT result = eT(0) * in_val; + m_parent.set_val(index, result); + + s_parent.sync_state = 1; - if(result != eT(0)) // paranoia, in case compiling with -ffast-math - { - m_parent.set_val(index, result); - - s_parent.sync_state = 1; - - access::rw(s_parent.n_nonzero) = m_parent.get_n_nonzero(); - } + access::rw(s_parent.n_nonzero) = m_parent.get_n_nonzero(); } } } @@ -1554,19 +1540,15 @@ SpMat_MapMat_val::div(const eT in_val) } else { - // element not found, ie. it's zero; zero divided by anything is zero, except for zero and nan - if( (in_val == eT(0)) || (arma_isnan(in_val)) ) + const eT result = eT(0) / in_val; // in case in_val is zero or nan + + if(result != eT(0)) { - const eT result = eT(0) / in_val; + m_parent.set_val(index, result); + + s_parent.sync_state = 1; - if(result != eT(0)) // paranoia, in case compiling with -ffast-math - { - m_parent.set_val(index, result); - - s_parent.sync_state = 1; - - access::rw(s_parent.n_nonzero) = m_parent.get_n_nonzero(); - } + access::rw(s_parent.n_nonzero) = m_parent.get_n_nonzero(); } } } diff --git a/inst/include/armadillo_bits/SpMat_meat.hpp b/inst/include/armadillo_bits/SpMat_meat.hpp index 36bebec9..34d92024 100644 --- a/inst/include/armadillo_bits/SpMat_meat.hpp +++ b/inst/include/armadillo_bits/SpMat_meat.hpp @@ -612,33 +612,26 @@ SpMat::operator*=(const eT val) { arma_debug_sigprint(); - if(val != eT(0)) + sync_csc(); + invalidate_cache(); + + const uword n_nz = n_nonzero; + + eT* vals = access::rwp(values); + + bool has_zero = false; + + for(uword i=0; i::operator*= (const eT val) { arma_debug_sigprint(); - if(val == eT(0)) { (*this).zeros(); return; } - SpMat& m_local = const_cast< SpMat& >(m); const umat& ci = U_ci.M; diff --git a/inst/include/armadillo_bits/SpSubview_meat.hpp b/inst/include/armadillo_bits/SpSubview_meat.hpp index 757be653..5f86dc93 100644 --- a/inst/include/armadillo_bits/SpSubview_meat.hpp +++ b/inst/include/armadillo_bits/SpSubview_meat.hpp @@ -157,8 +157,6 @@ SpSubview::operator*=(const eT val) { arma_debug_sigprint(); - if(val == eT(0)) { (*this).zeros(); return *this; } - if((n_elem == 0) || (n_nonzero == 0)) { return *this; } m.sync_csc(); diff --git a/inst/include/armadillo_bits/SpValProxy_meat.hpp b/inst/include/armadillo_bits/SpValProxy_meat.hpp index 242ec07e..cd7e7738 100644 --- a/inst/include/armadillo_bits/SpValProxy_meat.hpp +++ b/inst/include/armadillo_bits/SpValProxy_meat.hpp @@ -148,24 +148,17 @@ inline SpValProxy& SpValProxy::operator*=(const eT rhs) { - if(rhs != eT(0)) + if(val_ptr) { - if(val_ptr) - { - // The value already exists and merely needs to be updated. - *val_ptr *= rhs; - parent.invalidate_cache(); - check_zero(); - } + *val_ptr *= rhs; + parent.invalidate_cache(); + check_zero(); } else { - if(val_ptr) - { - // Since we are multiplying by zero, the value can be deleted. - parent.delete_element(row, col); - val_ptr = nullptr; - } + const eT val = eT(0) * rhs; // in case rhs is inf or nan + + if(val != eT(0)) { val_ptr = &parent.insert_element(row, col, val); } } return *this; @@ -178,37 +171,17 @@ inline SpValProxy& SpValProxy::operator/=(const eT rhs) { - if(rhs != eT(0)) // I hope this is true! + if(val_ptr) { - if(val_ptr) - { - *val_ptr /= rhs; - parent.invalidate_cache(); - check_zero(); - } + *val_ptr /= rhs; + parent.invalidate_cache(); + check_zero(); } else { - if(val_ptr) - { - *val_ptr /= rhs; // That is where it gets ugly. - // Now check if it's 0. - if(*val_ptr == eT(0)) - { - parent.delete_element(row, col); - val_ptr = nullptr; - } - } - else - { - eT val = eT(0) / rhs; // This may vary depending on type and implementation. - - if(val != eT(0)) - { - // Ok, now we have to insert it. - val_ptr = &parent.insert_element(row, col, val); - } - } + const eT val = eT(0) / rhs; // in case rhs is zero or nan + + if(val != eT(0)) { val_ptr = &parent.insert_element(row, col, val); } } return *this; diff --git a/inst/include/armadillo_bits/arma_version.hpp b/inst/include/armadillo_bits/arma_version.hpp index 44249a71..bff877e8 100644 --- a/inst/include/armadillo_bits/arma_version.hpp +++ b/inst/include/armadillo_bits/arma_version.hpp @@ -23,7 +23,7 @@ #define ARMA_VERSION_MAJOR 14 #define ARMA_VERSION_MINOR 4 -#define ARMA_VERSION_PATCH 2 +#define ARMA_VERSION_PATCH 3 #define ARMA_VERSION_NAME "Filtered Espresso" diff --git a/inst/include/armadillo_bits/compiler_setup.hpp b/inst/include/armadillo_bits/compiler_setup.hpp index b263899a..a5034d0e 100644 --- a/inst/include/armadillo_bits/compiler_setup.hpp +++ b/inst/include/armadillo_bits/compiler_setup.hpp @@ -172,6 +172,10 @@ #pragma message("INFO: support for GCC versions older than 8.1 is deprecated" #endif + #if (ARMA_GCC_VERSION >= 170000) + #undef ARMA_IGNORE_DEPRECATED_MARKER + #endif + #define ARMA_GOOD_COMPILER #undef arma_hot @@ -229,6 +233,12 @@ // #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) @@ -477,7 +487,7 @@ #undef major -// WARNING: option 'ARMA_IGNORE_DEPRECATED_MARKER' will be removed; +// 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) diff --git a/inst/include/armadillo_bits/fn_accu.hpp b/inst/include/armadillo_bits/fn_accu.hpp index b7287dcf..14a9b428 100644 --- a/inst/include/armadillo_bits/fn_accu.hpp +++ b/inst/include/armadillo_bits/fn_accu.hpp @@ -1121,6 +1121,8 @@ accu(const SpGlue& expr) arma_conform_assert_same_size(px.get_n_rows(), px.get_n_cols(), py.get_n_rows(), py.get_n_cols(), "element-wise multiplication"); + if( (px.get_n_nonzero() == 0) && (py.get_n_nonzero() == 0) ) { return eT(0); } + typedef typename SpProxy::stored_type px_Q_type; typedef typename SpProxy::stored_type py_Q_type; @@ -1162,10 +1164,14 @@ accu(const SpGlue& expr) if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { + acc += (*x_it) * eT(0); // in case (*x_it) is inf or nan + ++x_it; } else // x is closer to the end { + acc += eT(0) * (*y_it); // in case (*y_it) is inf or nan + ++y_it; } } diff --git a/inst/include/armadillo_bits/fn_misc.hpp b/inst/include/armadillo_bits/fn_misc.hpp index 52d85ac2..fcef65a4 100644 --- a/inst/include/armadillo_bits/fn_misc.hpp +++ b/inst/include/armadillo_bits/fn_misc.hpp @@ -149,8 +149,8 @@ logspace(const double A, const double B, const uword N = 50u) //! kept for compatibility with old user code template -arma_warn_unused -arma_inline +arma_frown("change arma::is_finite(val) to std::isfinite(val)") +inline bool is_finite(const eT x, const typename arma_scalar_only::result* junk = nullptr) { @@ -163,7 +163,7 @@ is_finite(const eT x, const typename arma_scalar_only::result* junk = nullpt //! kept for compatibility with old user code template -arma_warn_unused +arma_frown("change arma::is_finite(X) to X.is_finite()") inline bool is_finite(const Base& X) @@ -177,7 +177,7 @@ is_finite(const Base& X) //! kept for compatibility with old user code template -arma_warn_unused +arma_frown("change arma::is_finite(X) to X.is_finite()") inline bool is_finite(const SpBase& X) @@ -191,7 +191,7 @@ is_finite(const SpBase& X) //! kept for compatibility with old user code template -arma_warn_unused +arma_frown("change arma::is_finite(X) to X.is_finite()") inline bool is_finite(const BaseCube& X) diff --git a/inst/include/armadillo_bits/spdiagview_meat.hpp b/inst/include/armadillo_bits/spdiagview_meat.hpp index 66166e31..186391e1 100644 --- a/inst/include/armadillo_bits/spdiagview_meat.hpp +++ b/inst/include/armadillo_bits/spdiagview_meat.hpp @@ -134,8 +134,6 @@ spdiagview::operator*=(const eT val) { arma_debug_sigprint(); - if(val == eT(0)) { (*this).zeros(); return; } - SpMat& t_m = const_cast< SpMat& >(m); const uword t_n_elem = n_elem; diff --git a/inst/include/armadillo_bits/spglue_schur_meat.hpp b/inst/include/armadillo_bits/spglue_schur_meat.hpp index b8ed3193..efefb97d 100644 --- a/inst/include/armadillo_bits/spglue_schur_meat.hpp +++ b/inst/include/armadillo_bits/spglue_schur_meat.hpp @@ -60,13 +60,13 @@ spglue_schur::apply_noalias(SpMat& out, const SpProxy& pa, const SpProxy arma_conform_assert_same_size(pa.get_n_rows(), pa.get_n_cols(), pb.get_n_rows(), pb.get_n_cols(), "element-wise multiplication"); - if( (pa.get_n_nonzero() == 0) || (pb.get_n_nonzero() == 0) ) + if( (pa.get_n_nonzero() == 0) && (pb.get_n_nonzero() == 0) ) { out.zeros(pa.get_n_rows(), pa.get_n_cols()); return; } - const uword max_n_nonzero = (std::min)(pa.get_n_nonzero(), pb.get_n_nonzero()); + const uword max_n_nonzero = pa.get_n_nonzero() + pb.get_n_nonzero(); // Resize memory to upper bound out.reserve(pa.get_n_rows(), pa.get_n_cols(), max_n_nonzero); @@ -82,24 +82,19 @@ spglue_schur::apply_noalias(SpMat& out, const SpProxy& pa, const SpProxy while( (x_it != x_end) || (y_it != y_end) ) { + eT out_val; + const uword x_it_row = x_it.row(); const uword x_it_col = x_it.col(); const uword y_it_row = y_it.row(); const uword y_it_col = y_it.col(); + bool use_y_loc = false; + if(x_it == y_it) { - const eT out_val = (*x_it) * (*y_it); - - if(out_val != eT(0)) - { - access::rw(out.values[count]) = out_val; - - access::rw(out.row_indices[count]) = x_it_row; - access::rw(out.col_ptrs[x_it_col + 1])++; - ++count; - } + out_val = (*x_it) * (*y_it); ++x_it; ++y_it; @@ -108,14 +103,32 @@ spglue_schur::apply_noalias(SpMat& out, const SpProxy& pa, const SpProxy { if((x_it_col < y_it_col) || ((x_it_col == y_it_col) && (x_it_row < y_it_row))) // if y is closer to the end { + out_val = (*x_it) * eT(0); // in case (*x_it) is inf or nan + ++x_it; } else { + out_val = eT(0) * (*y_it); // in case (*y_it) is inf or nan + ++y_it; + + use_y_loc = true; } } + if(out_val != eT(0)) + { + access::rw(out.values[count]) = out_val; + + const uword out_row = (use_y_loc == false) ? x_it_row : y_it_row; + const uword out_col = (use_y_loc == false) ? x_it_col : y_it_col; + + access::rw(out.row_indices[count]) = out_row; + access::rw(out.col_ptrs[out_col + 1])++; + ++count; + } + arma_check( (count > max_n_nonzero), "internal error: spglue_schur::apply_noalias(): count > max_n_nonzero" ); } diff --git a/inst/include/armadillo_bits/spop_misc_meat.hpp b/inst/include/armadillo_bits/spop_misc_meat.hpp index 14fc9330..5da73142 100644 --- a/inst/include/armadillo_bits/spop_misc_meat.hpp +++ b/inst/include/armadillo_bits/spop_misc_meat.hpp @@ -45,16 +45,7 @@ spop_scalar_times::apply(SpMat& out, const SpOp(in.aux)); - } - else - { - const SpProxy P(in.m); - - out.zeros( P.get_n_rows(), P.get_n_cols() ); - } + out.init_xform(in.m, priv::functor_scalar_times(in.aux)); } @@ -83,19 +74,9 @@ spop_cx_scalar_times::apply(SpMat< std::complex >& out, c { arma_debug_sigprint(); - typedef typename T1::pod_type T; - typedef typename std::complex out_eT; + typedef typename T1::pod_type T; - if(in.aux_out_eT != out_eT(0)) - { - out.init_xform_mt(in.m, priv::functor_cx_scalar_times(in.aux_out_eT)); - } - else - { - const SpProxy P(in.m); - - out.zeros( P.get_n_rows(), P.get_n_cols() ); - } + out.init_xform_mt(in.m, priv::functor_cx_scalar_times(in.aux_out_eT)); }