Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 1452 new to matrix signatures #508

Merged
merged 9 commits into from
Apr 3, 2017

Conversation

randommm
Copy link
Member

@randommm randommm commented Mar 16, 2017

Submisison Checklist

  • Run unit tests: ./runTests.py test/unit/math/prim/mat/fun/to_matrix_test.cpp (hope it suffices)
  • Run cpplint: make cpplint
  • Declare copyright holder and open-source license: see below

Summary:

Fix issue #507

Implemented a bunch of new to_matrix functions

  • to_matrix(matrix, int, int)
  • to_matrix(vector, int, int)
  • to_matrix(row_vector, int, int)
  • to_matrix(int[], int, int)
  • to_matrix(matrix, int, int, int)
  • to_matrix(vector, int, int, int)
  • to_matrix(row_vector, int, int, int)
  • to_matrix(real[], int, int, int)
  • to_matrix(int[], int, int, int)

Intended Effect:

Make users life easier.

How to Verify:

Unit tests included.

Side Effects:

Almost none other than users (and me) starting to get confused with this bunch of function signatures.

Documentation:

Included.

Reviewer Suggestions:

Anyone

Copyright and Licensing

Marco Inacio

By submitting this pull request, the copyright holder is agreeing to license the submitted work under the following licenses:

@bob-carpenter
Copy link
Contributor

That was just a timeout on the last failure and I kicked off the test that failed again.

Copy link
Contributor

@bob-carpenter bob-carpenter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments inline. Most of these are just formatting. And thanks for the pull request!

@@ -3,6 +3,7 @@

#include <stan/math/prim/scal/fun/promote_elements.hpp>
#include <vector>
#include <cstddef>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is cstddef being added? It looks like it would have passed header tests before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oddly, it was not passing on my local compiler either with g or clang (clang version 3.8.1-12ubuntu1 (tags/RELEASE_381/final) and g++ (Ubuntu 6.2.0-5ubuntu12) 6.2.0 20161005 with lastest "stable" Ubuntu) complaining about size_t not being defined, but I can change it back if you wish, it might just be an Ubuntu bug anyway.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, that's fine --- if you need it for size_t --- that always gets included for me in <vector> so we don't usually need it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe then it's an issue of Ubuntu system include files? I got the following error:

    g++ -w -Wfatal-errors -I . -isystem lib/eigen_3.2.9 -isystem lib/boost_1.62.0 -isystemlib/cvodes_2.9.0/include -Wall -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DNO_FPRINTF_OUTPUT -pipe -Wno-unused-function -Wno-uninitialized -Wno-c++11-long-long   -c -O0 -include stan/math/prim/arr/fun/promote_elements.hpp -o /dev/null test/dummy.cpp
    In file included from <command-line>:0:0:
    ./stan/math/prim/arr/fun/promote_elements.hpp: In static member function ‘static std::vector<T> stan::math::promote_elements<std::vector<T>, std::vector<S> >::promote(const std::vector<S>&)’:
    ./stan/math/prim/arr/fun/promote_elements.hpp:30:14: error: ‘size_t’ was not declared in this scope
             for (size_t i = 0; i < u.size(); ++i)
                  ^~~~~~
    compilation terminated due to -Wfatal-errors.
    ****



    clang++ -w -Wfatal-errors -I . -isystem lib/eigen_3.2.9 -isystem lib/boost_1.62.0 -isystemlib/cvodes_2.9.0/include -Wall -DBOOST_RESULT_OF_USE_TR1 -DBOOST_NO_DECLTYPE -DBOOST_DISABLE_ASSERTS -DNO_FPRINTF_OUTPUT -pipe -Wno-unused-function -Wno-uninitialized -Wno-c++11-long-long   -c -O0 -include stan/math/prim/arr/fun/promote_elements.hpp -o /dev/null test/dummy.cpp
    In file included from <built-in>:325:
    In file included from <command line>:5:
    ./stan/math/prim/arr/fun/promote_elements.hpp:30:14: fatal error: unknown type
          name 'size_t'; did you mean '__gnu_cxx::size_t'?
            for (size_t i = 0; i < u.size(); ++i)
                 ^~~~~~
                 __gnu_cxx::size_t
    /usr/bin/../lib/gcc/x86_64-linux-gnu/6.2.0/../../../../include/c++/6.2.0/ext/new_allocator.h:44:14: note: 
          '__gnu_cxx::size_t' declared here
      using std::size_t;
                 ^
    1 error generated.

#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <Eigen/Dense>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The include on line 7 is all you need---it includes Eigen/Dense and makes sure everything's include din the right order.

#include <vector>

namespace stan {
namespace math {
/**
* Returns a matrix with dynamic dimensions constructed from
* an Eigen matrix which is either a row vector, column vector, or matrix.
* an Eigen matrix which is either
* a row vector, column vector, or matrix.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please include as much on a line as you can.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence cannot fit on 2 lines (of 80 characters), but I changed it now to:
* Returns a matrix with dynamic dimensions constructed from an
* Eigen matrix which is either a row vector, column vector,
* or matrix.

Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>
result(rows, cols);
for (int i=0, ij=0; i < cols; i++)
for (int j=0; j < rows; j++, ij++)
result(ij) = x[j][i];
return result;
} else {
return Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> (0, 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like it wasn't something introduced in this pull request, but I'd like to follow the rules laid out in Martin's awesome Refactoring book on code style, where exceptional cases are called out and return and then the rest of the code continues not in an else-block. So that'd be:

if (rows == 0)
  return Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> (0, 0);

and then the rest of the code isn't nested. Up to you if you want to change this one. The benefit is that it makes it easier to see the usual line of execution and the exceptional case.

Also, no reason to define a local variable for rows. You can just use x.rows() and x.cols() thoughout.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since rows and cols are used multiple times (on each iteration of the loop), having them defined locally does speed up thing, doesn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, after some tests, it does seem to make a less than 1 second difference for really large matrices (like 10000 x 10000), probably not worth the trouble, and probably make things slower to small matrices.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But (yet another comment, sorry) here we actually don't have

  int rows = x.rows()
  int cols = x.cols()

but actually

  int rows = x.size();
  int cols = x[0].size();

So in this specific case I think it's worth keeping the local variables to help keep the code readable.

"vector size", size);
Eigen::Matrix<double,
Eigen::Dynamic, Eigen::Dynamic> result(m, n);
double* datap = result.data();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can do this without the bare pointer! Just remove datap and in place of it in assignment, use

result(i) = x[i];

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, it was probably slightly faster before check constraints of Eigen was disabled in Stan, but now it might just be the same thing, just making things harder to read.

* @param x matrix
* @param m rows
* @param n columns
* @param cm column-major indicator:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like this shold be a bool given that it has boolean values.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, but it is OK to consider it True when the user gives something other than 1 or 0 as the value of col_major? (or is it the opposite and C/C++ cast non 0/1 int to bool false?)

for (int j=0; j < n; j++, ij++)
result(i, j) = x(ij);
return result;
} else {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then you can get rid of this test because the bool will have to be 0 or 1. And you can replace if (cm == 1) with just if (cm), though I'd prefer col_major as the variable name so it's easier to understand (no big deal if you like cm better).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, by the way, why is m used for the number of rows and n for the number of cols? Isn't this the opposite of the "convention"?

boost::math::tools::promote_args<T, double>::type,
Eigen::Dynamic, Eigen::Dynamic>
to_matrix(const std::vector<T>& x, int m, int n, int cm) {
if (cm == 1) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment as in previous

int cols = x.cols();
Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>
result(rows, cols);
for (int i=0, ij=0; i < rows; i++)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spaces around = and all other operators, please. You do it in most places, but not everywhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, sorry.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you still missed the i = 0 and ij = 0 case in lines 16 and 17 (and presumably elsewhere).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I forgot to check the test file

@bob-carpenter
Copy link
Contributor

bob-carpenter commented Mar 20, 2017 via email

@bob-carpenter bob-carpenter merged commit 1bbd879 into develop Apr 3, 2017
@randommm randommm deleted the feature/issue-1452-new-to_matrix-signatures branch April 17, 2017 17:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants