Proper save/restore of RNG state in boost::random behaving unexpectedly - boost

I have a small test program that attempts to save and restore the state of a random number generator using boost::random, but it is not behaving as the documentation indicates. From the boost docs:
Classes which model a pseudo-random number generator should also model the Streamable concept, i.e. implement operator<< and operator>>. If so, operator<< writes all current state of the pseudo-random number generator to the given ostream so that operator>> can restore the state at a later time. The state shall be written in a platform-independent manner, but it is assumed that the locales used for writing and reading be the same. The pseudo-random number generator with the restored state and the original at the just-written state shall be equivalent.
As I understand it, if a RNG state is saved and then a number is pulled from it, the state should change. If the state is later restored, this should allow the exact same number to be generated as the generator has been rolled back. I made a test program that examines this, but at first glance it seems like the state is not restored. Consider the code:
unsigned int s = static_cast<unsigned int>(std::time(0));
//typedef boost::minstd_rand base_generator_type;
typedef boost::mt19937 base_generator_type;
base_generator_type randgen(s);
boost::uniform_01<base_generator_type> getrand(randgen);
//boost::normal_distribution<float> noise(0,1);
//boost::variate_generator<base_generator_type,
//boost::normal_distribution<float> > getrand(randgen, noise);
double numsbefore[2], numsrightafter[2], numsnew[4];
//generate a short sequence, save it, and display
numsbefore[0] = getrand();
numsbefore[1] = getrand();
cout << "First Sequence, before save: "
<< numsbefore[0] << " "
<< numsbefore[1] << endl;
//save the current RNG state to a file using the stream interface
std::ofstream rngfileout("test_rngfile.txt");
rngfileout << randgen;
rngfileout.close();
//generate the next two numbers and display
numsrightafter[0] = getrand();
numsrightafter[1] = getrand();
cout << "Next, right after save: "
<< numsrightafter[0] << " "
<< numsrightafter[1] << endl;
//read in the RNG state that was saved, back into the RNG, restoring the state
//to be such as it was prior to the most recent two calls to randgen()
std::ifstream rngfilein("test_rngfile.txt", ifstream::in);
if(!rngfilein.good())
{
cout << "Couldn't read from file\n";
return 0;
}
rngfilein >> randgen;
rngfilein.close();
//declare and initialize a new variate generator to the newly-restored generator
boost::uniform_01<base_generator_type> getrand2(randgen);
// boost::variate_generator<base_generator_type,
// boost::normal_distribution<float> > getrand2(randgen, noise);
//copy the new variate function into the old one, to allow us to use
//the old one on the restored generator
getrand = getrand2;
//generate the next sequence
//The first two should be the same as the most recent two called
//The next two should be new random numbers
numsnew[0] = getrand();
numsnew[1] = getrand();
numsnew[2] = getrand();
numsnew[3] = getrand();
cout << "Restored, Next: "
<< numsnew[0] << " "
<< numsnew[1] << " "
<< numsnew[2] << " "
<< numsnew[3] << endl;
The output for a given time seed is:
First Sequence, before save: 0.970021 0.266862
Next, right after save: 0.110485 0.267466
Restored, Next: 0.970021 0.266862 0.110485 0.267466
The code's comments illustrate what I think should be happening. Also, some lines include commented code to do the same test with a different generator and different distribution. The same problem occurs for any of those: the next two values taken from the generator randgen after the state has been restored are not the same as the two that are generated immediately after the save, as they should be.
Upon closer inspection (debugging), it appears that calls to the variate generator getrand() do not change the state of the generator randgen at all no matter how many times I call getrand() on it, and so when I save it, it remains the same as if it were just created, and thus, when I pull from it again after restoration, it just starts from the beginning.
Shouldn't each call to the generator cause the state to advance? How am I even getting sequences that are not the same numbers if the RNG state never changes? Is the generator I'm viewing/saving not the "real" one, or something?
Also, the assignment operation of getrand = getrand2 might look sketchy but the = operator is defined for those,and replacing the last 4 calls with getrand2() doesn't make a difference.

Is the generator I'm viewing/saving not the "real" one, or something?
That is indeed the case. The uniform_01 constructor you're using actually makes a copy of the provided engine, rather than taking a reference.
If you're using Boost 1.39 or later, you can use it like this instead:
boost::uniform_01<> getrand;
getrand(randgen);
If you're stuck on an older Boost and you don't need getrand to be copyable, changing uniform_01's type parameter from base_generator_type to base_generator_type& should also work.

Related

How to make a simualtion in verilog have different results everytime if it has random values?

I want to generate a different output of the same code every time I run it as it has random values assigned to some variables. Is there a way to do that, for example seeding using time as in C?
Sample code that has the randomization in it:
class ABC;
rand bit [4 : 0] arr []; // dynamic array
constraint arr_size{
arr.size() >= 2;
arr.size() <= 6;
}
endclass
module constraint_array_randomization();
ABC test_class;
initial begin
test_class = new();
test_class.randomize();
$display("The array has the value = %p ", test_class.arr);
end
endmodule
I this is probably dependent on the tool that is being used. For example xcelium from cadence supports xrun -seed some_seed(Questa has -sv_seed some_seed I think). I am certain all tools support something similar. Look for simulation tool reference/manual/guide/help it may support random seed for every simulation run.
Not sure if this is possible from inside of simulation.
As mentioned in the comments for Questa, -sv_seed random should do the trick.
Usually, having an uncontrolled random seeding at simulation creates repeatability issues. In other words, it would be very difficult to debug a failing case if you do not know the seed. But if you insist, then read the following.
You can mimic the 'c' way of randomizing with time. However, there is no good way in verilog to access system time. Therfore, there is no good way to do time based seeding from within the program.
However as always, there is a work-around available. For example, one can use the $system call to get the system time (is system-dependent). Then the srandom function can be used to set the seed. The following (linux-based) example might work for you (or you can tune it up for your system).
Here the time is provided as unix-time by the date +'%s' command. It writes it into a file and then reads from it as 'int' using $fopen/$fscan.
module constraint_array_randomization();
ABC test_class;
int today ;
initial begin
// get system time
$system("date +'%s' > date_file"); // write date into a file
fh = $fopen("date_file", "r");
void'($fscanf(fh, "%d", today)); // cast to void to avoid warnings
$fclose(fh);
$system("rm -f date_file"); // remove the file
$display("time = %d", today);
test_class = new();
test_class.srandom(today); // seed it
test_class.randomize();
$display("The array has the value = %p ", test_class.arr);
end
endmodule

Cannot programmatically change boost multiprecision mpfr precision

Keep in mind that Precision is based on the total number of digits and not the decimal places, but I need a way to set the Decimal places and all I can find is Precision, so I am trying to work with it, so I account for the number of digits in the whole number, in order to get this to work, but that is not working.
I want to do some math and return with a set precision value, the function takes a string of a very large number with a very large decimal precision and returns it as a string set to the number of decimals passed in as precision:
#include <boost/multiprecision/mpfr.hpp>
QString multiply(const QString &mThis, const QString &mThat, const unsigned int &precison)
{
typedef boost::multiprecision::number<mpfr_float_backend<0> > my_mpfr_float;
my_mpfr_float aThis(mThis.toStdString());
my_mpfr_float aThat(mThat.toStdString());
my_mpfr_float::default_precision(precison);
my_mpfr_float ans = (aThis * aThat);
return QString::fromStdString(ans.str());
}
I have tried it without the typedef, same problem;
MathWizard::multiply("123456789.123456789", "123456789.123456789", 20);
18 digits of Precision, 9 + 9, I should ask for 30
will return 22 decimal places
15241578780673678.51562
instead of 20
15241578780673678.516
So why is it off by 2?
I would like to make the precision change after the math, but it seems you have to set it before, and not like the examples that boost shows in their example, but still does not return the correct value, doing it after does not change value.
Update: Compare what I did to what they say works in this Post:
how to change at runtime number precision with boost::multiprecision
typedef number<gmp_float<0> > mpf_float;
mpfr_float a = 2;
mpfr_float::default_precision(1000);
std::cout << mpfr_float::default_precision() << std::endl;
std::cout << sqrt(a) << std::endl; // print root-2
I have noticed differences between gmp_float, mpf_float (using boost/multiprecision/gmp.hpp) and mpfr_float, and mpfr_float will give me a closer precision, for example, if I take the number (1/137):
mpf_float
0.007299270072992700729927007299270072992700729927007299270073
only 1 Precision, 23 digits when set to 13
0.00729927007299270072993
mpfr_float
0.007299270072992700729929
only 1 Precision, 16 digits when set to 13
0.0072992700729928
With only 1 Precision I would expect my answer to be have one less decimal.
The other data types do similar, I did try them all, so this code will work the same for all the data types described here:
boost 1.69.0: multiprecision Chapter 1
I also must point out that I rely on Qt since this function is used in a QtQuick Qml Felgo App, and actually I could not figure out to convert this to string without converting it to an exponent, even though I used ans.str() for both, my guess is that fromStdString does something different then std::string(ans.str()).
I figure if I can not figure his out, I will just do String Rounding to get the correct precision.
std::stringstream ss;
ss.imbue(std::locale(""));
ss << std::fixed << std::setprecision(int(precison)) << ans.str();
qDebug() << "divide(" << mThis << "/" << mThat << " # " << precison << " =" << QString::fromStdString(ss.str()) << ")";
return QString::fromStdString(ss.str());
I still could not get away without using QString, but this did not work, it returns 16 digits instead of 13, I know that is a different question, as such I just post it to show my alternatives do not work any better at this point. Also note that the divide function works the same as the multiply, I used used that example to show the math has nothing to do with this, but all the samples they are showing me do not seem to work correctly, and I do not understand why, so just to make the steps clear:
Create back end: typedef boost::multiprecision::number > my_mpfr_float;
Set Precision: my_mpfr_float::default_precision(precision);
Set initial value of variable: my_mpfr_float aThis(mThis.toStdString());
Do some math if you want, return value with correct Precision.
I must be missing something.
I know I can just get the length of the string, and if longer than Precision, then check if Precision + 1 is greater than 5, if so add 1 to Precision and return a substring of 0, Precision and be done with all this Correct way of doing things, I could even do this in JavaScript after the return, and just forget about doing it the Correct way, but I still think I am just missing something, because I can not believe this is the way this is actually supposed to work.
Submitted Bug Report: https://github.com/boostorg/multiprecision/issues/127

Reverse iterator is being advanced by std::set::erase

I am trying to erase the element that I just traversed into. I initially forgot to store the return value of s1.erase(... inside the for loop to ultimately set the condition to exit the loop. With the way the code is right now, I expected the loop to continue indefinitely. But it works just the way it was originally intended to work.
It looks like std::erase advances the iterator and stores the value in rit. I am not able to find any documentation that explains this behavior.
https://en.cppreference.com/w/cpp/container/set/erase says that the iterator returned has to be stored. All arguments of the set::erase are passed by value, so how is the reverse iterator being advanced?
How is this loop completing?
std::set<int> s1;
s1.insert(20);
s1.insert(30);
s1.insert(50);
auto rit = s1.rbegin();
for (; rit!= s1.rend();)
{
std::cout << "rit is " << *rit << " size is " << s1.size() << std::endl;
s1.erase(std::next(rit).base());
std::cout << "rit after erase is " << *rit << std::endl;
}
The output is
rit is 50 size is 3
rit after erase is 30
rit is 30 size is 2
rit after erase is 20
rit is 20 size is 1
Segmentation fault
Recall that reverse_iterator::base() is always one element behind the apparent iterator's value. For example, after auto rit = s1.rbegin(), *rit returns the last element, while rit.base() == s1.end().
In other words, *rit == *prev(rit.base())
In your loop, initially rit.base() == s1.end(). Then std::next(rit).base() refers to the last element; that element is being erased. In std::set, erasing an element only invalidates iterators to that element, but not any others. s1.end() is still a valid iterator, and so is rit, with rit.base() still equal to s1.end(). So on the next iteration of the loop, you erase the last element again, and leave rit.base() == s1.end() again. And so on.
At some point, the last element is erased, s1 becomes empty, and then *rit exhibits undefined behavior. Recall that *rit == *prev(rit.base()), but there is no previous element anymore.

Double approximation using lexical_cast

When I use following line of code
std::wcout << boost::lexical_cast<std::wstring>(5.453) << std::endl;
I obtain the following result on the console
5.4530000000000003
What's be best way to approximate the number in order to obtain the same number that I use for conversion?

How do I handle multiple notification of ReadDirectoryChangesW()?

I implemented using ReadDirectoryChangesW() function to figure out any change information of files of the specific directory.
However, the API sent me duplicated notifications. For example, I monitor the directory "C:\abc\" using only FILE_NOTIFY_CHANGE_SIZE flag without watching subdirectory. And, I tried edit and save a image file on the directory. ex) C:\abc\imageFile.png
Then, two or much more the notifications were sent me. Actually, I understand why there are multiple notifications. I read this article. (http://blogs.msdn.com/b/oldnewthing/archive/2014/05/07/10523172.aspx)
But, I don't know how to handle the multiple notifications.
My goal is synchronizing the image files on some win32 application when the images are changed.
The documentation for FILE_NOTIFY_INFORMATION tells us:
NextEntryOffset
The number of bytes that must be skipped to get to the next record. A value of zero indicates that this is the last record.
So we check that field, and if it isn't zero, we create a new pointer which is that many bytes past the old one. The code will look something like this:
FILE_NOTIFY_INFORMATION* p = &s.changeInformation;
while (1) {
std::wcout << L" action " << p->Action << L"\n";
std::wcout << L" file ";
std::wcout.write(p->FileName, p->FileNameLength / sizeof (wchar_t)) << L"\n";
if (!p->NextEntryOffset) break;
p = reinterpret_cast<decltype(p)>(p->NextEntryOffset + reinterpret_cast<uintptr_t>(p));
}
We have to cast, because the value is in bytes, and pointer arithmetic automatically measures distances in objects not bytes.

Resources