1

How to call lpNorm with a templated matrix as input?

Here is the issue from my code:

template<class number>
void normalize_in_place(Matrix<number,Dynamic,Dynamic> & A, level l, axis a){

  const int p = lp_norms::level2pvalue(l);
  switch ( a ) {
    case row: 
      // TODO: get lpnorm working. 
      A = A.transpose().cwiseQuotient(A.rowwise().lpNorm<p>()).transpose();
      //A = A.transpose().cwiseQuotient(A.rowwise().norm()).transpose();
      break;
    case col:
      // TODO: get lpnorm working. 
      //A = A.cwiseQuotient(A.colwise().lpNorm<p>());
      A = A.cwiseQuotient(A.colwise().norm());
      break;
  }
}

Fails during compile with:

error: expected primary expression before [ close parenthesis of lpNorm function ]

where I have substituted the brackets for the arrow you would see on compiler output.

** After refreshing my eigen with the July 23rd release, I get the following error:

error: invalid operands of types ‘’ and ‘const int’ to binary ‘operator<’ A = A.transpose().cwiseQuotient(A.rowwise().lpNorm

()).transpose();

Apparently, lpNorm is not resolving; however, I have included Eigen/Dense, and the standard .norm() works.

No matter which configuration I use, it does not work.

What is the correct way to call the lpNorm?

Chris
  • 28,822
  • 27
  • 83
  • 158
  • 2
    Does `rwiseQuotient` even exist? [Create a Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Lack Oct 28 '18 at 17:52
  • @Lack yeah, updated. – Chris Oct 28 '18 at 18:08
  • That is still not a MCVE (how can anyone compile it without the definitions of `level`, `axis`, etc.?) but enough to answer. – Lack Oct 28 '18 at 18:24

1 Answers1

5

If you have this code inside a template where the type of A depends on template parameters:

A.rowwise().lpNorm<p>();

The template keyword is needed before a template function:

A.rowwise().template lpNorm<p>();

See Where and why do I have to put the "template" and "typename" keywords?.

Without the template keyword, GCC tries to treat the < in <p> as the less-than operator and produces the error message you see. Clang gives a more helpful error message, error: missing 'template' keyword prior to dependent template name 'lpNorm'.

Also note that the template argument p in lpNorm<p> must be a constant expression (evaluated at compile time). It seems that in your example, lp_norms::level2pvalue(l) will not be a constant expression.

Lack
  • 1,625
  • 1
  • 17
  • 29
  • Ok, great, so what you are telling me is I need a compiled switch for all selections of `p` values, correct? – Chris Oct 28 '18 at 18:33
  • There are two parts: 1. `template` keyword, 2. `p` must be constant expression (which I just added to my answer). I don't know what `level l` is but a solution may be to make it a template parameter. – Lack Oct 28 '18 at 18:36
  • Ah, ok, I see you have updated to answer my question. So, it will be impossible for me to provide the possible range of lpNorms to an end user using the Eigen lpNorm without macros and recompilation. – Chris Oct 28 '18 at 18:42
  • It impossible to call Eigen's `lpNorm

    ()` if `p` is not known at compile time. It may be possible, even in your case, to know `p` at compile time: does the code calling `normalize_in_place` know `l` at compile time? Otherwise note that Eigen's `lpNorm` template really just chooses between several functions [defined in Dot.h](https://eigen.tuxfamily.org/dox/Dot_8h_source.html#l00199) (special cases for `p`=1, 2, and infinity, and a general case for other `p`.) At worst you could write your own version of `lpNorm` that checks whether p is infinity at runtime.

    – Lack Oct 28 '18 at 18:54
  • yeah that is my plan. It seems to me that there isn't much use for cases other than 1, 2 and infinity; but a math savvy user who does not know how the code (or code in general) works may like to screw around with these inputs. So I may implement the interior cases myself. – Chris Oct 29 '18 at 14:04