[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