[mlpack] 104/207: Fix support for printing arma objects with custom precision
Barak A. Pearlmutter
barak+git at pearlmutter.net
Thu Mar 23 17:53:44 UTC 2017
This is an automated email from the git hooks/post-receive script.
bap pushed a commit to branch master
in repository mlpack.
commit 18942ed3748b74fd0274061f57107e29fb109298
Author: shikhar <shikharbhardwaj68 at gmail.com>
Date: Wed Mar 1 01:12:05 2017 +0530
Fix support for printing arma objects with custom precision
---
src/mlpack/core/util/prefixedoutstream.hpp | 16 ++--
src/mlpack/core/util/prefixedoutstream_impl.hpp | 119 +++++++++++++++++++++++-
src/mlpack/tests/prefixedoutstream_test.cpp | 37 ++++++++
3 files changed, 165 insertions(+), 7 deletions(-)
diff --git a/src/mlpack/core/util/prefixedoutstream.hpp b/src/mlpack/core/util/prefixedoutstream.hpp
index 4b04297..af41d7b 100644
--- a/src/mlpack/core/util/prefixedoutstream.hpp
+++ b/src/mlpack/core/util/prefixedoutstream.hpp
@@ -19,11 +19,7 @@
#include <streambuf>
#include <stdexcept>
-#include <boost/lexical_cast.hpp>
-#include <boost/utility/enable_if.hpp>
-#include <boost/type_traits.hpp>
-
-#include <mlpack/core/util/sfinae_utility.hpp>
+#include <mlpack/core/arma_extend/arma_extend.hpp> // Includes Armadillo
namespace mlpack {
namespace util {
@@ -128,11 +124,19 @@ class PrefixedOutStream
* Conducts the base logic required in all the operator << overloads. Mostly
* just a good idea to reduce copy-pasta.
*
+ * Calls 2 different overloads to be able to output arma objects with custom
+ * precision
+ *
* @tparam T The type of the data to output.
* @param val The The data to be output.
*/
template<typename T>
- void BaseLogic(const T& val);
+ typename std::enable_if<!arma::is_arma_type<T>::value, void>::type
+ BaseLogic(const T& val);
+
+ template<typename T>
+ typename std::enable_if<arma::is_arma_type<T>::value, void>::type
+ BaseLogic(const T& val);
/**
* Output the prefix, but only if we need to and if we are allowed to.
diff --git a/src/mlpack/core/util/prefixedoutstream_impl.hpp b/src/mlpack/core/util/prefixedoutstream_impl.hpp
index a81bbf1..78cd774 100644
--- a/src/mlpack/core/util/prefixedoutstream_impl.hpp
+++ b/src/mlpack/core/util/prefixedoutstream_impl.hpp
@@ -33,7 +33,8 @@ PrefixedOutStream& PrefixedOutStream::operator<<(const T& s)
}
template<typename T>
-void PrefixedOutStream::BaseLogic(const T& val)
+typename std::enable_if<!arma::is_arma_type<T>::value, void>::type
+PrefixedOutStream::BaseLogic(const T& val)
{
// We will use this to track whether or not we need to terminate at the end of
// this call (only for streams which terminate after a newline).
@@ -135,6 +136,122 @@ void PrefixedOutStream::BaseLogic(const T& val)
}
}
+template<typename T>
+typename std::enable_if<arma::is_arma_type<T>::value, void>::type
+PrefixedOutStream::BaseLogic(const T& val)
+{
+ // We will use this to track whether or not we need to terminate at the end of
+ // this call (only for streams which terminate after a newline).
+ bool newlined = false;
+ std::string line;
+
+ // If we need to, output the prefix.
+ PrefixIfNeeded();
+
+ std::ostringstream convert;
+ // Sync flags and precision with destination stream
+ convert.setf(destination.flags());
+ convert.precision(destination.precision());
+
+ // Check if the stream is in the default state
+ if(convert.flags() == 4098 && convert.precision() == 6)
+ {
+ convert << val;
+ }
+ else
+ {
+ val.raw_print(convert);
+ }
+
+ if (convert.fail())
+ {
+ PrefixIfNeeded();
+ if (!ignoreInput)
+ {
+ destination << "Failed type conversion to string for output; output not "
+ "shown." << std::endl;
+ newlined = true;
+ }
+ }
+ else
+ {
+ line = convert.str();
+
+ // If the length of the casted thing was 0, it may have been a stream
+ // manipulator, so send it directly to the stream and don't ask questions.
+ if (line.length() == 0)
+ {
+ // The prefix cannot be necessary at this point.
+ if (!ignoreInput) // Only if the user wants it.
+ destination << val;
+
+ return;
+ }
+
+ // Now, we need to check for newlines in the output and print it.
+ size_t nl;
+ size_t pos = 0;
+ while ((nl = line.find('\n', pos)) != std::string::npos)
+ {
+ PrefixIfNeeded();
+
+ // Only output if the user wants it.
+ if (!ignoreInput)
+ {
+ destination << line.substr(pos, nl - pos);
+ destination << std::endl;
+ }
+
+ newlined = true; // Ensure this is set for the fatal exception if needed.
+ carriageReturned = true; // Regardless of whether or not we display it.
+
+ pos = nl + 1;
+ }
+
+ if (pos != line.length()) // We need to display the rest.
+ {
+ PrefixIfNeeded();
+ if (!ignoreInput)
+ destination << line.substr(pos);
+ }
+ }
+
+ // If we displayed a newline and we need to throw afterwards, do that.
+ if (fatal && newlined)
+ {
+ if (!ignoreInput)
+ destination << std::endl;
+
+ // Print a backtrace, if we can.
+#ifdef HAS_BFD_DL
+ if (fatal && !ignoreInput)
+ {
+ size_t nl;
+ size_t pos = 0;
+
+ Backtrace bt;
+ std::string btLine = bt.ToString();
+ while ((nl = btLine.find('\n', pos)) != std::string::npos)
+ {
+ PrefixIfNeeded();
+
+ if (!ignoreInput)
+ {
+ destination << btLine.substr(pos, nl - pos);
+ destination << std::endl;
+ }
+
+ carriageReturned = true; // Regardless of whether or not we display it.
+
+ pos = nl + 1;
+ }
+ }
+#endif
+
+ throw std::runtime_error("fatal error; see Log::Fatal output");
+ }
+}
+
// This is an inline function (that is why it is here and not in .cc).
void PrefixedOutStream::PrefixIfNeeded()
{
diff --git a/src/mlpack/tests/prefixedoutstream_test.cpp b/src/mlpack/tests/prefixedoutstream_test.cpp
index b2f214f..05ce1e0 100644
--- a/src/mlpack/tests/prefixedoutstream_test.cpp
+++ b/src/mlpack/tests/prefixedoutstream_test.cpp
@@ -104,6 +104,43 @@ BOOST_AUTO_TEST_CASE(TestArmadilloPrefixedOutStream)
BASH_GREEN "[INFO ] " BASH_CLEAR "hello 1.0000 1.5000 2.0000\n"
BASH_GREEN "[INFO ] " BASH_CLEAR " 2.5000 3.0000 3.5000\n"
BASH_GREEN "[INFO ] " BASH_CLEAR " 4.0000 4.5000 5.0000\n");
+
+ // Try to print armadillo objects with custom precision
+ ss << std::fixed;
+ ss << std::setprecision(6);
+ ss.str("");
+
+ pss << test;
+
+ BOOST_REQUIRE_EQUAL(ss.str(), BASH_GREEN "[INFO ] " BASH_CLEAR "1.000000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "1.500000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "2.000000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "2.500000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "3.000000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "3.500000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "4.000000\n");
+
+ // Try printing a matrix, with higher precision
+ ss << std::setprecision(8);
+ ss.str("");
+
+ pss << test2;
+
+ BOOST_REQUIRE_EQUAL(ss.str(),
+ BASH_GREEN "[INFO ] " BASH_CLEAR "1.00000000 1.50000000 2.00000000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "2.50000000 3.00000000 3.50000000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR "4.00000000 4.50000000 4.99999000\n");
+
+ // Test stream after reset
+ ss << std::setprecision(6);
+ ss.unsetf(std::ios::floatfield);
+ ss.str("");
+
+ pss << test2;
+ BOOST_REQUIRE_EQUAL(ss.str(),
+ BASH_GREEN "[INFO ] " BASH_CLEAR " 1.0000 1.5000 2.0000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR " 2.5000 3.0000 3.5000\n"
+ BASH_GREEN "[INFO ] " BASH_CLEAR " 4.0000 4.5000 5.0000\n");
}
/**
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/mlpack.git
More information about the debian-science-commits
mailing list