I decided to get to know c++11 <random> better, so I wrote such a code:
std::mt19937 gen(10);
std::piecewise_linear_distribution<> d(Range.begin(), Range.end(),
RangeValues.begin());
std::map<int, unsigned int> hist;
for (int n = 0; ++n != iterations;)
++hist[std::round(d(gen))];
for (auto p : hist)
std::cout << std::setw(2) << p.first << ": "
<< std::string(p.second/(iterations/200), '*') << '\n';
For some reason std::random_device seems to not work on Coliru, so I entered a const sample seed instead. I presume, that it is UB hence IIRC it is based heavily on hardware, and that's why it's not supported on Coliru (correct me if I am wrong). On Ideone it does work however.
Then I ported it to run on VS2012, the only difference being an own implementation of std::round:
return number < 0.0 ? std::ceil(number - 0.5) : std::floor(number + 0.5);
It works perfectly correct on Coliru, but when I compile and run it on VS2012, the output is just wrong.
Any idea how to correct this, and more importantly, why it happens?
Am I doing something wrong, or is VS2012 not the smart one here?
It seems that this is a Visual Studio issue. I've tried the program below (adapted from the OP) and the output generated by GCC 4.7.2, Clang 3.2 and Intel 13.1.0 are very reasonable whereas the one generated by Visual Studio Nov 2012 CTP is completely different.
The probability density is piecewise linear and defined by arrays x and p in the following way. A piecewise linear function connecting the points (x[i], p[i]) for i = 0, ..., N (where N = x.size() - 1) is built. Then this function is normalized (by dividing it by its integral) to get the probability density.
#include <iostream>
#include <iomanip>
#include <string>
#include <random>
#include <array>
int main() {
std::mt19937 gen(10);
std::array<double, 3> x = {{0, 20, 40}};
std::array<double, 3> p = {{0, 1, 0}};
std::piecewise_linear_distribution<> dist(x.begin(), x.end(), p.begin());
std::array<int, 40> hist = {{0}};
for (size_t i = 0; i < 200000; ++i)
++hist[static_cast<size_t>(dist(gen))];
for (size_t n = 0; n < hist.size(); ++n)
std::cout << std::setfill('0') << std::setw(2) << n << ' ' <<
std::string(hist[n] / 200, '*') << std::endl;
std::cout << "\nValues in interval [20, 21[ : " << hist[20] << std::endl;
}
In our example, the polygonal function connects (0, 0), (20, 1) and (40, 0). Hence, its shape is an isosceles triangle with base 40 and height 1 which yields an area of 20. Therefore, the probability density f connects (0, 0), (20, 1/20) and (40, 0). This implies that in the interval [20, 21[ we could expect around f(20) * (21 - 20) = 1/20 * 1 = 1/20 results of the draw. In total we draw 200,000 values and then, we can expect around 10,000 points in [20, 21[.
GCC, Clang and Intel report 9734 points in [20, 21[ and display a pattern that is quite similar to an isosceles triangle:
00 *
01 ***
02 *****
03 ********
04 ***********
05 **************
06 ***************
07 ******************
08 ********************
09 ************************
10 **************************
11 ****************************
12 *******************************
13 *********************************
14 ***********************************
15 ***************************************
16 *****************************************
17 ******************************************
18 **********************************************
19 ************************************************
20 ************************************************
21 *********************************************
22 *******************************************
23 *****************************************
24 **************************************
25 ************************************
26 **********************************
27 ******************************
28 ****************************
29 **************************
30 ***********************
31 ********************
32 ******************
33 ****************
34 *************
35 ***********
36 *********
37 ******
38 ***
39 *
Values in interval [20, 21[ : 9734
Unfortunately, Visual Studio Nov 2012 CTP gives this:
00 ********************************************** [truncated]
01 **********************************************
02 ***********************************
03 *****************************
04 **************************
05 ***********************
06 *********************
07 ********************
08 *******************
09 ******************
10 *****************
11 ****************
12 ***************
13 **************
14 **************
15 **************
16 *************
17 *************
18 *************
19 ************
20 ************
21 *************
22 *************
23 *************
24 *************
25 **************
26 ***************
27 ***************
28 ****************
29 *****************
30 ******************
31 *******************
32 *******************
33 *********************
34 ***********************
35 **************************
36 *****************************
37 ***********************************
38 **********************************************
39 ********************************************** [truncated]
Values in interval [20, 21[ : 2496
Notes:
I've truncated Visual Studio output for better displaying.
A better estimate for the number of points in [20, 21[ is 200,000 * (0.5 * (f(20) + f(21))) * (21 - 20) = 100,000 * (1/20 + 1/20 - 1/400) = 10,000 - 250 = 9750.
Related
This question already has answers here:
Py_initialize / Py_Finalize not working twice with numpy
(2 answers)
Closed 9 months ago.
The question is about Python.h (embedded Python 3.10). Here in this minimal example where I Py_Initialize, import numpy and then Py_DecRef it. After that I Py_Finalize and repeat the process one more time:
#include <Python.h>
#include <memory>
#include <iostream>
class Pyth
{
public:
explicit Pyth()
{
size_t len = 11;
auto pname = Py_DecodeLocale("PythonCrash", &len);
Py_SetProgramName(pname);
Py_InitializeEx(0);
auto *mname = PyUnicode_FromWideChar(L"numpy", 5);
auto *pmod = PyImport_Import(mname);
Py_DecRef(mname);
if (pmod)
Py_DecRef(pmod);
}
~Pyth()
{
std::cerr << "Fin: " << Py_FinalizeEx() << std::endl;
}
};
int main()
{
int i = 2;
while (i > 0) {
std::cerr << "Go: " << i << std::endl;
auto* ptr = new Pyth();
std::cerr << "new pyth" << std::endl;
delete ptr;
std::cerr << "del pyth" << std::endl;
--i;
}
return 0;
}
I'm getting an error after I try to finalize for the second time but stacks shows it's on second initialization attampt. The error does not appear if I won't do any work (that is, if I just initialize and finalize in a loop).
Here is the output:
17:27:41: Debugging /home/sms/build-PythonCrash-Desktop-Debug/PythonCrash ...
Go: 2
new pyth
Fin: 0
del pyth
Go: 1
new pyth
Fin: Traceback (most recent call last):
File "/usr/lib64/python3.10/site-packages/numpy/__init__.py", line 150, in <module>
from . import core
File "/usr/lib64/python3.10/site-packages/numpy/core/__init__.py", line 22, in <module>
from . import multiarray
File "/usr/lib64/python3.10/site-packages/numpy/core/multiarray.py", line 12, in <module>
from . import overrides
File "/usr/lib64/python3.10/site-packages/numpy/core/overrides.py", line 7, in <module>
from numpy.core._multiarray_umath import (
SystemError: /builddir/build/BUILD/Python-3.10.4/Objects/structseq.c:481: bad argument to internal function
0
del pyth
17:27:42: Debugging of /home/sms/build-PythonCrash-Desktop-Debug/PythonCrash has finished with exit code 0.
Here is the stack:
1 PyArray_Item_INCREF
2 PyArray_FromScalar
3 gentype_nonzero_number.lto_priv
4 PyObject_IsTrue.part.0
5 _PyEval_EvalFrameDefault
6 _PyEval_Vector
7 _PyObject_FastCallDictTstate
8 slot_tp_init
9 type_call
10 _PyObject_MakeTpCall
11 _PyEval_EvalFrameDefault
12 _PyEval_Vector
13 _PyEval_EvalFrameDefault
14 _PyEval_Vector
15 method_vectorcall
16 _PyEval_EvalFrameDefault
17 _PyEval_Vector
18 method_vectorcall
19 _PyEval_EvalFrameDefault
20 _PyEval_Vector
21 method_vectorcall
22 _PyEval_EvalFrameDefault
23 _PyEval_Vector
24 _PyEval_EvalFrameDefault
25 _PyEval_Vector
26 _PyEval_EvalFrameDefault
27 _PyEval_Vector
28 _PyObject_VectorcallTstate.lto_priv.5
29 object_vacall
30 _PyObject_CallMethodIdObjArgs
31 PyImport_ImportModuleLevelObject
32 builtin___import__
33 cfunction_call
34 _PyObject_MakeTpCall
35 _PyObject_CallFunctionVa
36 PyObject_CallFunction
37 PyImport_Import
38 PyImport_ImportModule
39 _PyCodecRegistry_Init
40 _PyCodec_Lookup
41 config_get_codec_name
42 init_interp_main
43 pyinit_main
44 Py_InitializeFromConfig
45 Py_InitializeEx
46 Pyth::Pyth (main.cpp, 15)
47 main (main.cpp, 36)
'len' is an internal function of python so you cannot do an assignment. try changing len to "o_locale_len" or, something, shorter but just not 'len'.
I'm searching for a function in c++ which i give it ( min , mode , max ) then it returns a random number generated by triangular distribution. If there is a code for implementing this function ,it will be so good.
std::piecewise_linear_distribution can be used to model a triangular distribution.
Here's an example based on the sample code on the linked cppreference page that generates a triangular distribution that generates numbers between 0 and 30 with a peak at 20:
#include <random>
#include <iostream>
#include <iomanip>
#include <array>
#include <map>
std::piecewise_linear_distribution<double> triangular_distribution(double min, double peak, double max)
{
std::array<double, 3> i{min, peak, max};
std::array<double, 3> w{0, 1, 0};
return std::piecewise_linear_distribution<double>{i.begin(), i.end(), w.begin()};
}
int main() {
std::random_device rd;
// create a mersenne twister PRNG seeded from some implementation-defined random source
std::mt19937 gen(rd());
// create a triangular distribution with a minimum of 0, a peak at 20, and a maximum of 30
auto dist = triangular_distribution(0, 20, 30);
std::map<int, int> hist;
// use our distribution to generate 10,000 random numbers
// (truncated to integers for the sake of output; the generated numbers are actually real numbers)
for (int i = 0; i < 10000; ++i) {
double num = dist(gen);
++hist[num];
}
// print out a nice histogram of the numbers generated
for(auto p : hist) {
std::cout << std::setw(2) << std::setfill('0') << p.first << ' '
<< std::string(p.second/10,'*') << '\n';
}
}
Possible output:
00 **
01 *****
02 ******
03 ************
04 **************
05 ******************
06 **********************
07 *************************
08 **************************
09 *********************************
10 ************************************
11 **************************************
12 *************************************
13 ********************************************
14 **************************************************
15 **************************************************
16 *******************************************************
17 *******************************************************
18 ************************************************************
19 *****************************************************************
20 **************************************************************
21 *******************************************************
22 ************************************************
23 *******************************************
24 ***************************************
25 ******************************
26 **************************
27 ****************
28 ***********
29 ***
You can sample from a simple triangle distribution T by summing two uniforms, U₁ and U₂. In C terms this would be:
float U1 = (float)rand() / RAND_MAX;
float U2 = (float)rand() / RAND_MAX;
float T = U1 + U2;
Scale accordingly: the result is between 0 and 2 with a mode of 1.
Im having an issue using opencv trying to convert an image to an array. The conversion works however i seem to have incorrect dimensions in the resulting array:
#include <opencv2/opencv.hpp>
int main()
{
auto img = cv::imread("test.jpg", CV_LOAD_IMAGE_COLOR);
std::cout << "img cols: " << img.cols << " img rows: "
<< img.rows << " channels: " << img.channels() << std::endl;
std::vector<float> array2;
if (img.isContinuous()) {
array2.assign((float*)img.ptr(0), (float*)(img.ptr(img.rows - 1)) + img.cols);
std::cout << array2.size() << "\n";
}
return 0;
}
The output from the first print line results in :
img cols: 416 img rows: 416 channels: 3
Which is correct, however after assigning the data to the array the dimensions are : 518336 , when they should be 519168 (416*416*3).
Could anyone possibly suggest what exactly is causing the resulting array to be smaller than expected?
There are several problems with your code:
First of all, cv::imread("test.jpg", CV_LOAD_IMAGE_COLOR); will (on success) return a cv::Mat with datatype CV_8UC3, however you're accessing the elements as floats. This means that the values you will read will be garbage, and you will also end up reading past the end of the pixel buffer.
If you want floats, then you need to do some conversion/casting, either before or during the act of copying.
The second problem lies in your calculation of the "end" pointer, where you seem to forget that you're dealing with a multi-channel cv::Mat. In case of a CV_8UC3 matrix, each pixel is represented by 3 bytes, hence there are cols*channels bytes per row. (That's why you're short by 2*416 elements)
Not really a problem, but a limitation -- your code only works for continuous Mats.
I would take a somewhat different approach, and take advantage of functionality provided by OpenCV.
Option 1
Use cv::Mat::copyTo, since OutputArray can wrap a std::vector<T>. However, for this to work, the source Mat needs to have 1 channel and 1 row. We can achieve this efficiently using cv::Mat::reshape, but the Mat needs to be continuous, so that limitation stays.
std::vector<uchar> to_array_v1(cv::Mat3b const& img)
{
std::vector<uchar> a;
if (img.isContinuous()) {
img.reshape(1, 1).copyTo(a);
}
return a;
}
Option 2
Use MatIterators which we can get using cv::Mat::begin and cv::Mat::end. The iterators will work correctly even on a non-continuous Mat, however we need them to iterate over bytes, so we need to reshape the matrix to a single channel one. Since we're not changing the number of rows, the reshape will also work on a non-continuous Mat.
std::vector<uchar> to_array_v2(cv::Mat3b const& img)
{
cv::Mat1b tmp(img.reshape(1));
return std::vector<uchar>(tmp.begin(), tmp.end());
}
Option 3
The approach suggested by Silencer, using the rather poorly documented cv::Mat::datastart and cv::Mat::dataend members. The documentation of cv::Mat::locateROI sheds some more light on the meaning of those member variables:
However, each submatrix contains information (represented by datastart and dataend fields) that helps reconstruct the original matrix size and the position of the extracted submatrix within the original matrix.
This means that this approach has 2 limitations: it needs a continous matrix, and it won't work correctly for a submatrix, even if it's continuous. (Specifically, for a continuous submatrix, it would return the entire buffer of the "parent" matrix)
std::vector<uchar> to_array_v3(cv::Mat3b const& img)
{
std::vector<uchar> a;
if (img.isContinuous() && !img.isSubmatrix()) {
a.assign(img.datastart, img.dataend);
}
return a;
}
Test Code
#include <opencv2/opencv.hpp>
#include <iostream>
#include <numeric>
#include <vector>
// Paste implementations from the answer here
cv::Mat3b test_image()
{
cv::Mat1b m(4, 4);
std::iota(m.begin(), m.end(), 0);
cv::Mat3b img;
cv::merge(std::vector<cv::Mat1b>{ m * 3, m * 3 + 1, m * 3 + 2 }, img);
return img;
}
void print(cv::Mat3b const& img)
{
std::cout << "Continuous: " << (img.isContinuous() ? "yes" : "no") << '\n';
std::cout << "Submatrix: " << (img.isSubmatrix() ? "yes" : "no") << '\n';
std::cout << img << "\n";
}
void print(std::vector<uchar> const& a)
{
if (a.empty()) {
std::cout << "empty";
} else {
for (auto n : a) {
std::cout << int(n) << ' ';
}
}
std::cout << "\n";
}
void test(cv::Mat3b const& img)
{
print(img);
print(to_array_v1(img));
print(to_array_v2(img));
print(to_array_v3(img));
}
int main()
{
cv::Mat3b img(test_image());
test(img);
cv::Mat3b img2(img(cv::Rect(0, 0, 3, 3)));
test(img2);
cv::Mat3b img3(img(cv::Rect(1, 1, 3, 1)));
test(img3);
return 0;
}
Running this program will produce the following output:
Continuous: yes
Submatrix: no
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11;
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23;
24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35;
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
Continuous: no
Submatrix: yes
[ 0, 1, 2, 3, 4, 5, 6, 7, 8;
12, 13, 14, 15, 16, 17, 18, 19, 20;
24, 25, 26, 27, 28, 29, 30, 31, 32]
empty
0 1 2 3 4 5 6 7 8 12 13 14 15 16 17 18 19 20 24 25 26 27 28 29 30 31 32
empty
Continuous: yes
Submatrix: yes
[ 15, 16, 17, 18, 19, 20, 21, 22, 23]
15 16 17 18 19 20 21 22 23
15 16 17 18 19 20 21 22 23
empty
Mat img = imread("test.png");
std::vector<uchar> arr;
// convert Mat of CV_8UC3 to std::vector<uchar> if continuous
if(img.isContinuous()){
arr.assign(img.datastart, img.dataend);
}
class DataStorage{
// 0 1 2 3 4 5 6 7 8
string Data[20][4]={{"Wee","50","1","First"},{"Wee","22","2","First"},
// 9 10 11 12 13 14 15 16
{"Jason","26","3","First"},{"Krappa","12","4","First"},
// 17 18 19 20 21 22 23 24
{" "," ","5","First"},{" "," ","6","Economy"},
//25 26 27 28 29 30 31 32
{"Kappa","15","7","Economy"},{"Eraser","17","8","Economy"},
//33 34 35 36 37 38 39 40
{" "," ","9","Economy"},{"Morty"," ","10","Economy"},
//41 42 43 44 45 46 47 48
{"Rick"," ","11","Economy"},{"Amanda","10","12","Economy"},
//49 50 51 52 53 54 55 56
{"Lee","","13","Economy"},{"MingLee"," ","14","Economy"},
//57 58 59 60 61 62 63 64
{"Beauty"," ","15","Economy"},{"S4head"," ","16","Economy"},
//65 66 67 68 69 70 71 72
{"Ivan"," ","17","Economy"},{"Dex"," ","18","Economy"},
//73 74 75 76 77 78 79 80
{"Chua"," ","19","Economy"},{"Haha"," ","20","Economy"},};
};
int main(){
}
How do I call the value in array and change the value in array? Do I need to make some function to get value from the input and pass it into a variable in class and set it into my array?
I'm not sure what you're asking when you say How do I call the value in array and change the value in array? but I think you're asking how do you change the value of an array element.
To modify an array element you assign the array's index to what you're changing the array's element to; however, remember that C++ arrays are 0-index arrays meaning when you start counting their elements at 0. For example the following code modifies the element at index 5. Live preview
#include <iostream>
int array[10] = {1, 5, 33, 7, -23, 2, 8, 54, 19, 2};
int main() {
std::cout << array[5] << std::endl;
array[5] = 100; // Set the value of the element at index 5 to 100
std::cout << array[5] << std::endl;
return 0;
}
If you want to have Data as a class member of DataStorage you have to initialize it in the member initialization list. I also highly recommend to use an abstraction for the bare array, like std::array. This allows to use bounds-checked access with the at() function. You can then access Data and change it's contents.
#include <array>
#include <iostream>
#include <string>
class DataStorage
{
public:
std::array<std::array<std::string,4>,20> Data;
DataStorage() : Data({{
{{"Wee","50","1","First"}},
{{"Wee","22","2","First"}},
{{"Jason","26","3","First"}},
{{"Krappa","12","4","First"}},
{{" "," ","5","First"}},
{{" "," ","6","Economy"}},
{{"Kappa","15","7","Economy"}},
{{"Eraser","17","8","Economy"}},
{{" "," ","9","Economy"}},
{{"Morty"," ","10","Economy"}},
{{"Rick"," ","11","Economy"}},
{{"Amanda","10","12","Economy"}},
{{"Lee","","13","Economy"}},
{{"MingLee"," ","14","Economy"}},
{{"Beauty"," ","15","Economy"}},
{{"S4head"," ","16","Economy"}},
{{"Ivan"," ","17","Economy"}},
{{"Dex"," ","18","Economy"}},
{{"Chua"," ","19","Economy"}},
{{"Haha"," ","20","Economy"}}
}}) {}
};
int main()
{
DataStorage d;
std::cout << d.Data.at(10).at(2) << '\n'; // prints 11
d.Data.at(10).at(2) = "1729";
std::cout << d.Data.at(10).at(2) << '\n'; // prints 1729
}
I have a float array Eigen::ArrayXf which I need to decimate (i.e. pick 1 out of f.i. 8 samples).
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0, Eigen::InnerStride<8> >(signal.data(), length, 1).eval();
which works, with a caveat: I need to know how long length is, and it can be specified too long, leading to runtime errors.
Q: is there a way to decimate all that is possible, so that resultant length is == signal.size() / 8 ?
Two things. You are using the c'tor for mapping a matrix:
Map (
PointerArgType dataPtr,
Index nbRows,
Index nbCols,
const StrideType & a_stride = StrideType()
)
Constructor in the dynamic-size matrix case.
Parameters
dataPtr pointer to the array to map
nbRows the number of rows of the matrix expression
nbCols the number of columns of the matrix expression
a_stride optional Stride object, passing the strides.
I think you want the c'tor for a vector:
Map ( PointerArgType dataPtr,
Index a_size,
const StrideType & a_stride = StrideType()
)
Constructor in the dynamic-size vector case.
Parameters
dataPtr pointer to the array to map
a_size the size of the vector expression
a_stride optional Stride object, passing the strides.
The second thing is that you want length == signal.size())/8. Is that always a whole integer, or are you rounding up? If the data is 16 in length and you want the positions [0] and [8], then use 1+(signal.size()-1)/8 as the length parameter:
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0, Eigen::InnerStride<8> >(signal.data(), 1+((signal.size()-1)/8) ).eval();
For example:
#include <Eigen/Core>
#include <iostream>
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
Eigen::VectorXf signal;
signal.setLinSpaced(64, 0.0, 63.);
cout << "Original signal:" << endl << signal.transpose() << endl;
Eigen::ArrayXf decimatedSignal = Eigen::Map<Eigen::ArrayXf, 0,
Eigen::InnerStride<8> >(signal.data(), 1+((signal.size()-1)/8)).eval();
cout << endl << "Decimated:" << endl << decimatedSignal.transpose() << endl;
return 0;
}
outputs
Original signal:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
Decimated:
0 8 16 24 32 40 48 56
which I think is exactly what you want.