Error in using max function with Armadillo sparse matrices - c++

Here is the code that I am getting error(type mismatch) on line no. with max:
#include <iostream>
#include <stdlib.h>
#include <math.h>
#include<armadillo>
using namespace std;
using namespace arma;
int main(int argc, char** argv) {
umat loc;
loc<<0<<0<<3<<endr
<<2<<4<<4<<endr;
vec val={1,2,3};
sp_mat m(loc,val);
double t=arma::max(sum(square(m),1)) + 1.0;
cout<<t<<endl;
return 0;
}
Can somebody tell me why is that error happening and how to get around this.
Note: cout<<max(sum(square(m),1)) prints the result to console but adding any number to the output flags error.

If you want to convert a 1x1 matrix into a pure scalar (like double), use the as_scalar() function. Same goes for any Armadillo expression that results in a 1x1 matrix.
It's a good idea to read the Armadillo documentation thoroughly before posting questions on Stackoverflow.
Modifying your example:
umat loc = { { 0, 0, 3 },
{ 2, 4, 4 } };
vec val = {1, 2, 3};
sp_mat m(loc,val);
m.print("m:");
max(sum(square(m),1)).print("expression:");
double t = as_scalar( max(sum(square(m),1)) );
cout << t << endl;

You haven't told us (and I can't find in the documentation) exactly what data type is returned by arma::max(sum(square(m),1))
You have tested that whatever it is does not implicitly convert to double and whatever it is can be sent to a stream and when that is done it looks like a double.
My guess is it is something that can be explicitly converted to double so try:
(double)arma::max(sum(square(m),1)) + 1.0
The documentation shows the returned value for a dense matrix being used to initialize a double so that is obviously a type than can be explicitly converted to double. I had initially missed the thing you linked for me effectively saying sum does something on sparse matrix compatible with what it does on dense. So you can almost conclude (rather than just guess) that max(sum(m)) should be the same type (explicitly convertible to double).
If that doesn't work, we will really need a full quote of the error message, not just a summary of what it seems to mean.
Now that we have an error message, we can see this is a flaw in Armadillo's template metaprogramming:
Operations are stacked in template meta programming in order to avoid creating excess temporary objects. Then the meta programming must resolve the whole mess when the result is used.
If this is a minor flaw in the meta programming, you could add just one trivial temporary to fix it:
double t = arma::max(sum(square(m),1));
cout << t+1.0 endl;
But you probably already tried that. So you may need more temporaries and you probably need to give them exact correct types (rather than use auto). My first guess would be:
colvec v = sum(square(m),1);
Then see what works with arma::max(v)
(Earlier I made a negative comment on an answer that suggested starting with auto temporaries for each step. That answer was deleted. It wasn't far wrong. But I'd still say it was wrong to start there without seeing the template meta-programming failures and likely, though I'm not sure, wrong to use auto to try to bypass a meta-programming failure.)

Related

How can I initialize an array in C++ using a variable initialized at runtime? [duplicate]

This question already has an answer here:
Array[n] vs Array[10] - Initializing array with variable vs numeric literal
(1 answer)
Closed 12 months ago.
What i would like to do is declare an array with "dim" size :int A[dim];.
Now, this works if I declare something like const int dim = 1 but doesn't with const int dim = round(x);, which is what i need to do. (Where x comes from cin >> x.)
Note: With "doesn't work" i refer to Visual Studio Code throwing red wavy line under dim in int A[dim]; and displaying the following when hovering it with my mouse:
`
expression must have a constant valueC/C++(28)
main.cpp(15, 11): the value of variable "dim" (declared at line 13) cannot be used as a constant
`
This is the relevant code:
#include <iostream>
using namespace std;
int main(){
float x;
cin >> x;
const int dim = round(x);
int A[dim];
int i = 0;
}
}
Given the context i believe the error is caused by one of two reasons:
Some characteristic of round() that makes the const int dim = round(x) not recognized as constant from the array later.
The problem is the x and not the round() so cin >> x is the reason.
[Thanks for whoever can explain me what I'm missing or point to some documentation that does. I have done some research but I haven't found a solution to this. Also this is my first question on SO, so tell me if I should change/improve something]
EDIT: Apparently the problem isn't in the round(x) as I previously thought because simply replacing const int dim = round(x); with const int dim = x; gives the same "error".
So the problem has to do with cin >> x .
EDIT 2 Note: I'm looking for a solution that doesn't use std::vector. We haven't studied it yet in the course so I believe the algorithm(from which i took the relevant code) shouldn't comprehend it.
Final Edit I didn't realize that, as #paulmckenzie clarified, using cin made the array dynamic because the imput comes in runtime, it was a really stupid error but I apologize, I'm really a beginner. In my defense we really haven't talked about dynamic size arrays so I guess that's what threw me off. I realized from the beginning I was missing something very basic, sorry for wasting time, I'll put even more time analyzing everything before posting next time.
The size of an array variable must be compile time constant in C++. User input is not compile time constant, hence it cannot be used as the size of an array variable.
In order to create an array with runtime size, you must instead create a dynamic array. The simplest way to do that is to use std::vector from the standard library.
EDIT 2 Note: I'm looking for a solution that doesn't use std::vector.
It's possible to create a dynamic array without std::vector, but that requires the use and understanding of more advanced concepts. Using new expressions directly is more difficult, error prone and is something that isn't (or shouldn't) be done in most programs in practice.
Of course, another solution is to just not use user input but rather an array with constant size.

boost:multiprecision

I have just started using boost::multiprecision trying to speed up some calculations previously done in Matlab. I found quite an unexpected problem, though. My calculations involve complex numbers, so I am using cpp_complex_50 type (e.g. cpp_complex_50 A, B;)
At some point I need to use boost::math::tools::bracket_and_solve_root() function, which requires that the function it works on returns real values. Here comes my problem... I cannot convert my complex multiprecision variable A.real() to any type that is real, eg. to cpp_dec_float_50 type or even double. The task should be streightforward, but I am virtually drowned in error complaints from my compiler (MSVC2015), and cannot solve it. Any hints at how to convert the data are more than welcome.
A somewhat connected question is the problem of initialization of cpp_complex_50 type variables with real values. At the moment I can only use data of type double at initialization, which means I am loosing some accuracy at the initialization stage already, e.g.:
cpp_complex_50 A = 4.0 * boost::math::constants::pi<double>(); // it works
but
cpp_complex_50 A = 4.0 * boost::math::constants::pi<cpp_dec_float_50>(); // It does NOT work
Any hints are needed. I am stuck at this, despite nice initial results.
Regards
Pawel
cpp_complex uses cpp_bin_float.
Live On Compiler Explorer
#include <boost/multiprecision/cpp_complex.hpp>
#include <iostream>
namespace bmp = boost::multiprecision;
int main() {
using Complex = bmp::cpp_complex_100;
using Real = Complex::value_type;
Real r = 4.0 * boost::math::constants::pi<Real>();
Complex b(r, {});
// or
b = r.convert_to<Complex>();
std::cout << b.str(100) << std::endl;
}
Prints
12.56637061435917295385057353311801153678867759750042328389977836923126562514483599451213930136846827
Following valuable comment from sehe... the code
cpp_complex_50 A = 4.0 * boost::math::constants::pi<cpp_bin_float_50>();
cout << A << endl;
works, producing:
12.5663706143591729538505735331180115367886775975
Similarely,
cpp_bin_float_50 B = A.real();
cout << B << endl;
works as well, printing the same.

How does one pass an integer, to a pointer, to an std::array<double, integer>, while satisfying a constnt expression?

I have a function noise.cpp which is currently of the form,
double* noise(int* steps, ...)
//some code
std::array<double, *steps> NoiseOut;
//rest of code
Which is being tested and accessed by cppnoise.cpp,
#include <random>
#include <cmath>
#include<stdio.h>
#include <iostream>
#include "noise.h"
main(){
double* out;
int steps = 8;
int* ptr = &steps;
out = noise(ptr, 1, 1000, 0.1, 1, 3);
printf("TEST \n");
std::cout << out[0];
}
With header file,
extern double* noise(int*, double, double, double, double, double);
Previously I accessed the noise.cpp function through Python where the NoiseOut array was initially, double* NoiseOut = new double[steps]; with desirable results, but this method resulted in a memory leak.
Initially I tried deleting the allocated memory. But the function returns NoiseOut, so I am not sure if that's possible? So, instead I found out that the modern way is to use std::array as it comes with some form of garbage collection. If I tried to do,
double* noise(int steps, ...)
std::array<double, steps> NoiseOut;
I was told steps was not a constant expression. I tried every which way of constexpr, const, and static but, with no success. Usually with the same error error: ‘steps’ is not a constant expression. Also, the reason I pass a pointer from cppnoise.cpp to noise.cpp is because I read somewhere that the pointer is easier to work with, later in compile-time? Such that maybe I could convert it to a constant expression? Probably a fever dream.
So, how can I declare an integer value in a program, which I pass to a function, which is usable in an std::array without causing that error?
NOTE: I am very new to c++ and work primarily with SQL, Python, R, and SageMath.
std::array is ill suited for this because you don't know what size you need until the code runs. std::array needs to know the size when it is compiled.
Using new gives a dynamic array size at run time, which is why you could use it before.
If you are concerned about memory leaks (or actually, in general), then I suggest using an std::vector instead:
#include <vector>
//...
std::vector<double> NoiseOut;
NoiseOut.reserve(*steps);
An std::vector should allow you to do most everything an std::array or C Array would allow you to so, though I suggest reading up on its documentation (linked above). Note that std::vector also comes with its own garbage collection of sorts in the same way std::array does.

C++, checking if a variable is initialized when I can't use NULL/0

I need to check if a variable is initialised. I am new to C++ so perhaps I am thinking about this in the wrong way. I want to do the following:
if (variable) {
// do some stuff
}
My first thought was to set the value to NULL at declaration. However, it turns out NULL is identical to 0 in C++. Unfortunately my variable is a double that can be 0. The solutions I could find online are all regarding pointers and just say to use nullptr but this is not possible in my case of course.
What alternatives do I have here?
General way to do this is to use std::optional
https://en.cppreference.com/w/cpp/utility/optional
This data type wraps the inner type and provides methods to tell you if it has been set or not.
Note that you'll need a C++ 17 compiler.
Here's an example. You can see it's pretty easy to use and you don't need to create sentinel values (i.e. special values that are interpreted for the case of being not set).
#include <iostream>
#include <cstdlib>
#include <optional>
using namespace std;
int main()
{
optional<double> speed;
if (!speed)
{
cout << "speed not set" << endl;
}
speed = 0;
if (speed)
{
cout << "speed set to " << *speed << endl;
}
}
My knowledge in C++ is very limited, but judging from your description I believe that you are using primitive built-in type of C++ (int, double, bool, ...). If this is the case, then it is hard to know if your variable has been initialized since the primitive type all have their default value in case it is declared but not assigned a value.
One way I used to walk around this problem is that always init the variables with special default values. However, if the variables happen to be assigned values that match the default, that could be a problem.
However, I find it rarely happen because if you are using a library, then the class should have a method/ variable... to let you know the status of the current instance if necessary. Otherwise, the class should init default valid values, or you are using it the wrong way. If you are creating your own class, then it is easy to add a status variable to it, right?
Like I said, my knowledge is very limited, I could be wrong though.

swapping first and last element in stack c++ using stl

i created an account so i can get some help with stacks in STL , i need to write a function that takes stack as a parameter and swaps the first element with the last element , i searched the site for some help i found one :"https://stackoverflow.com/a/36188943/9990214" , i tried the same thing , but i keep getting this error : expression must have a constant value with red line under "int tmp[sz-1];".
it keeps giving me the error before reaching the main , any help would be appreciated , keep in mind am trying to write the function using STL.
ps : i tried replying with a comment to the person who answered the question but it's not allowing me to do that because i need 50 reputation.
using namespace std;
void rev(stack<int>&x){
int sz=x.size(),mytop,mybottom;
mytop=x.top();
x.pop();
int tmp[sz-1],i=0;
while(!x.empty()){
mybottom=x.top();
tmp[i++]=mybottom;
x.pop();
}
stack<int> returnIt;
returnIt.push(mybottom);
for(i=0;i<=sz-3;i++){
returnIt.push(tmp[i]);
}
returnIt.push(mytop);
while(!returnIt.empty()){
int tt=returnIt.top();
x.push(tt);
returnIt.pop();
}
}
The reason you're getting an error is that variable-length arrays are not a part of standard C++. This matters for your definition of tmp:
int tmp[sz-1], i=0; //sz is not known at compile-time, therefore, this is invalid code
Some compilers will allow code like this by allowing VLA's, but not being standard, you should use a different solution. Usually, for tasks like this, std::vector is ideal:
std::vector<int> tmp(sz - 1);
int i = 0;
This should compile (so long as you #include<vector> alongside your other includes), and should have the behavior you expect from your code.