Commit 1d46f501 by Tianqi Yang

feat(markov): batch of parameters support

- run a batch of parameters at the same time - use multi-threading - add max coupon count support
parent c14332fd
...@@ -5,3 +5,6 @@ Debug ...@@ -5,3 +5,6 @@ Debug
*.in *.in
*.out *.out
tmp tmp
*.res
*.csv
*.xls*
File added
#include <bits/stdc++.h>
#include "markov_chain.h"
using namespace std;
const int SIM_DAYS = 10000000;
int main ()
{
int lambda;
double p;
cin >> lambda >> p;
for ( int i = 0; i < 10; ++i ) {
cout << setprecision ( 13 ) << ( 1 - simulate_prob ( lambda, p, SIM_DAYS ) ) << endl;
}
}
\ No newline at end of file
#!/bin/bash
if [ $# -eq 1 ]; then
_s=$1
else
_s=main
fi
echo "Compiling $_s.cpp..."
g++ $_s.cpp markov_chain.cpp consts.cpp -o $_s -O2 -std=c++11 -lpthread
...@@ -8,3 +8,4 @@ ...@@ -8,3 +8,4 @@
const int EXPIRE_DAYS = 30; const int EXPIRE_DAYS = 30;
const int COUPON_COST = 100; const int COUPON_COST = 100;
const int COUPON_VALUE = 50; const int COUPON_VALUE = 50;
const double COUPON_RATIO = 0.5;
...@@ -8,3 +8,4 @@ ...@@ -8,3 +8,4 @@
extern const int EXPIRE_DAYS; extern const int EXPIRE_DAYS;
extern const int COUPON_COST; extern const int COUPON_COST;
extern const int COUPON_VALUE; extern const int COUPON_VALUE;
extern const double COUPON_RATIO;
#!/usr/bin/env python3
import numpy as np
import math
print ( ' '.join ( list ( map ( str, range ( 100, 201, 2 ) ) ) ) )
a = np.logspace(math.log(0.0001,10),math.log(0.01,10),20).tolist()[0:-1] + np.logspace(math.log(0.01,10),math.log(1,10),40).tolist()
print ( ' '.join ( list ( map ( str, a ) ) ) )
#!/usr/bin/env python3
import argparse
import math
import numpy as np
import scipy
import os
import sys
def main ():
parser = argparse.ArgumentParser (prog='handle_data.py', description='Validate and handle the data generated by the simulator')
parser.add_argument ('-m', '--precision-mean', dest='precision_mean', metavar='precision_mean', type=int, help='Precision of the mean', default=3)
parser.add_argument ('-v', '--precision-var', dest='precision_var', metavar='precision_variance', type=int, help='Precision of the variance', default=-1)
parser.add_argument ('-i', '--input', dest='input', metavar='input', type=str, help='Input data file (default: simulation.res)', default='simulation.res')
parser.add_argument ('-o', '--output', dest='output', metavar='output', type=str, help='Output data file (default: result.csv)', default='result.csv')
parser.add_argument ('-r', '--repeat', dest='repeat', metavar='repeat', type=int, help='The number of simulations for each set of parameters', default=10)
args = parser.parse_args ()
line_id = 0
result = {}
with open (args.input) as IN:
data = list(IN.readlines ())
for i in range (len(data)):
data[i] = data[i].strip ()
while line_id < len(data):
cur = data[line_id]
line_id += 1
if cur == '---start':
try:
cur = data[line_id].split ()
line_id += 1
if len(cur) != 2:
print ('Syntax error at line {}: lambda or p not found: {}'.format (line_id, cur))
raise Exception ()
lbd = int (cur[0])
p = float (cur[1])
cur_res = []
for i in range (args.repeat): # pylint: disable=unused-variable
cur = data[line_id]
line_id += 1
cur_res.append (float (cur))
cur = data[line_id]
line_id += 1
if cur != '---end':
print ('Syntax error at line {}: \'---end\' not found: {}'.format (line_id, cur))
raise Exception ()
mean = np.mean (cur_res)
var = np.var (cur_res)
result[(lbd, p)] =(mean, var)
except Exception:
print ('Exception at line {}'.format (line_id))
else:
print ('Syntax error at line {}: \'---start\' not found: {}'.format (line_id, cur))
lbd_axis = []
p_axis = []
for i in result.keys ():
if i[0] not in lbd_axis:
lbd_axis.append (i[0])
if i[1] not in p_axis:
p_axis.append (i[1])
lbd_axis.sort ()
p_axis.sort ()
with open (args.output, 'w') as OUT:
mean_format = ',{:.%d}' % (args.precision_mean)
if args.precision_var == -1:
var_format = ',{}'
else:
var_format = ',{:.%d}' % (args.precision_var)
print (','.join (['Mean'] + list (map (str, p_axis))), file=OUT)
for lbd in lbd_axis:
print ('{}'.format (lbd), end='', file=OUT)
for p in p_axis:
if (lbd, p) in result:
print (mean_format.format (result[(lbd, p)][0]), end='', file=OUT)
else:
print (',N/A', file=OUT)
print (file=OUT)
print (file=OUT)
print (','.join (['Variance'] + list (map (str, p_axis))), file=OUT)
for lbd in lbd_axis:
print ('{}'.format (lbd), end='', file=OUT)
for p in p_axis:
if (lbd, p) in result:
print (var_format.format (result[(lbd, p)][1]), end='', file=OUT)
else:
print (',N/A', file=OUT)
print (file=OUT)
if __name__ == '__main__':
main ()
#include <bits/stdc++.h> #include <bits/stdc++.h>
#include "markov_chain.h" #include "markov_chain.h"
#include "progress_bar.h"
#include "thread_safe_queue.h"
using namespace std; using namespace std;
const int SIM_DAYS = 10000000; const int THREAD_NUM = 2;
const int REPEAT = 10;
const int SIM_TIMES = 100000;
int main () struct Task
{ {
Task ( int _lambda, double _p )
: lambda ( _lambda ), p ( _p )
{
}
int lambda; int lambda;
double p; double p;
cin >> lambda >> p; };
for ( int i = 0; i < 10; ++i ) {
cout << setprecision ( 13 ) << ( 1 - simulate_prob ( lambda, p, SIM_DAYS ) ) << endl; thread_safe_queue < Task > task_queue;
template < typename T >
vector < T > read_line_to_array ()
{
stringstream buf;
string str_buf;
getline ( cin, str_buf );
buf << str_buf;
vector < T > result;
T x;
while ( !buf.eof () ) buf >> x, result.push_back ( x );
return result;
}
void run_thread ( ofstream &RES, mutex &mut, ProgressBar &progress_bar )
{
while ( 1 ) {
Task current_task = task_queue.pop_front ();
if ( current_task.lambda == -1 ) break;
vector < double > result;
for ( int repeat = 0; repeat < REPEAT; ++repeat ) {
result.push_back ( simulate_prob ( current_task.lambda, current_task.p, SIM_TIMES ) );
++progress_bar;
}
{
lock_guard < mutex > lock ( mut );
RES << "---start" << endl;
RES << current_task.lambda << " " << current_task.p << endl;
for ( auto x : result ) {
RES << x << endl;
}
RES << "---end" << endl;
} }
}
}
int main ()
{
vector < int > lambdas = read_line_to_array < int > ();
vector < double > ps = read_line_to_array < double > ();
cout << "Number of lambdas: " << lambdas.size () << endl;
cout << "Number of Ps: " << ps.size () << endl;
ofstream RES ( "simulation.res" );
mutex mut;
ProgressBar progress_bar ( lambdas.size () * ps.size () * REPEAT );
progress_bar.set_desc ( "Simulating" );
progress_bar.start ();
for ( auto lambda : lambdas ) {
for ( auto p : ps ) {
task_queue.push_back ( Task ( lambda, p ) );
}
}
vector < thread > thrs;
for ( int i = 0; i < THREAD_NUM; ++i ) {
thrs.push_back ( thread ( run_thread, ref ( RES ), ref ( mut ), ref ( progress_bar ) ) );
task_queue.push_back ( Task ( -1, 0 ) );
}
for ( auto &x : thrs ) {
x.join ();
}
progress_bar.finish ();
RES.close ();
} }
\ No newline at end of file
...@@ -40,11 +40,11 @@ void State::pass_day ( int d ) ...@@ -40,11 +40,11 @@ void State::pass_day ( int d )
} }
} }
int State::use_coupon ( int c ) int State::use_coupon ( int c, int max_coupon )
{ {
int use_count = 0, current_use_count; int use_count = 0, current_use_count;
for ( int i = 0; i < EXPIRE_DAYS; ++i ) { for ( int i = 0; i < EXPIRE_DAYS; ++i ) {
current_use_count = min ( coupon_count[i], c / COUPON_COST ); current_use_count = min ( min ( coupon_count[i], c / COUPON_COST ), max_coupon - use_count );
c -= COUPON_COST * current_use_count; c -= COUPON_COST * current_use_count;
coupon_count[i] -= current_use_count; coupon_count[i] -= current_use_count;
use_count += current_use_count; use_count += current_use_count;
...@@ -71,7 +71,7 @@ double simulate_prob ( double lambda, double prob_day, int sim_times ) ...@@ -71,7 +71,7 @@ double simulate_prob ( double lambda, double prob_day, int sim_times )
current_state.pass_day ( day ); current_state.pass_day ( day );
int current_cost = poisson ( rand_gen ); int current_cost = poisson ( rand_gen );
total_cost += current_cost; total_cost += current_cost;
int current_coupon = current_state.use_coupon ( current_cost ); int current_coupon = current_state.use_coupon ( current_cost, static_cast < int > ( floor ( current_cost * COUPON_RATIO + 1e-9 ) ) / COUPON_VALUE );
used_coupon += current_coupon; used_coupon += current_coupon;
current_state.add_coupon ( ( current_cost - current_coupon * COUPON_VALUE ) / COUPON_COST ); current_state.add_coupon ( ( current_cost - current_coupon * COUPON_VALUE ) / COUPON_COST );
} }
......
...@@ -18,7 +18,7 @@ public: ...@@ -18,7 +18,7 @@ public:
void pass_day ( int d ); void pass_day ( int d );
int use_coupon ( int c ); int use_coupon ( int c, int max_count );
void add_coupon ( int c ); void add_coupon ( int c );
......
#pragma once
#include <iostream>
#include <iomanip>
#include <cmath>
#include <sstream>
#include <thread>
#include <chrono>
#include <mutex>
class ProgressBar
{
public:
ProgressBar ( int _total = 0 ) : total ( _total ), count ( 0 ), fill_char ( '#' ), width ( 50 ), desc ( "" ), unit ( "it" ), precision ( 2 ), flush_frequency ( 50 ), last_line_length ( 0 ), finished ( true )
{
}
void clear ()
{
if ( !finished ) {
finish ();
}
count = 0;
}
void start ()
{
clear ();
start_time = std::chrono::steady_clock::now ();
finished = false;
daemon = std::thread ( &ProgressBar::daemon_thread, this );
}
template < typename T >
ProgressBar & operator << ( T x )
{
std::lock_guard < std::mutex > lock ( output_buf_lock );
output_buf << x;
return *this;
}
void finish ()
{
if ( finished ) {
return;
}
finished = true;
daemon.join ();
std::cout << std::endl;
}
int operator = ( const int _count )
{
std::lock_guard < std::mutex > lock ( count_lock );
return count = _count;
}
void operator ++ ()
{
std::lock_guard < std::mutex > lock ( count_lock );
++count;
}
void operator ++ ( int _ )
{
std::lock_guard < std::mutex > lock ( count_lock );
++count;
}
int operator += ( int delta )
{
std::lock_guard < std::mutex > lock ( count_lock );
return ( count += delta );
}
int get_count () const
{
return count;
}
void set_total ( int _total )
{
total = _total;
}
int get_total () const
{
return total;
}
void set_fill_char ( char _fill_char )
{
fill_char = _fill_char;
}
char get_fill_char () const
{
return fill_char;
}
void set_width ( int _width )
{
width = _width;
}
int get_width () const
{
return width;
}
void set_desc ( std::string _desc )
{
desc = _desc;
}
std::string get_desc () const
{
return desc;
}
void set_unit ( std::string _unit )
{
unit = _unit;
}
std::string get_unit () const
{
return unit;
}
void set_precision ( int _precision )
{
precision = _precision;
}
int get_precision () const
{
return precision;
}
void set_flush_frequency ( int _flush_frequency )
{
flush_frequency = _flush_frequency;
}
int get_flush_frequency () const
{
return flush_frequency;
}
private:
void daemon_thread ()
{
while ( 1 ) {
bool current_finished = finished;
std::cout << "\r";
for ( int i = 0; i < last_line_length; ++i )
{
std::cout << " ";
}
std::cout << "\r";
{
std::lock_guard < std::mutex > lock ( output_buf_lock );
if ( output_buf.good () ) {
std::cout << output_buf.str ();
std::cout.flush ();
}
output_buf.clear ();
output_buf.str ( "" );
}
std::stringstream temp_buf;
if ( desc != "" ) {
temp_buf << desc << ": ";
}
double percent = static_cast < double > ( std::min ( count, total ) ) * 100 / total;
if ( precision ) {
percent = static_cast < int > ( floor ( percent * pow ( 10, precision ) ) ) / pow ( 10, precision );
if ( count >= total ) percent = 100;
temp_buf << std::setw ( precision + 4 ) << std::setprecision ( precision ) << std::fixed << percent << "%";
} else {
temp_buf << static_cast < int > ( floor ( percent ) ) << "%";
}
temp_buf << "|";
double char_width = 100.0 / width;
for ( int i = 1; i <= width; ++i ) {
if ( count >= total || percent >= i * char_width ) {
temp_buf << fill_char;
} else {
temp_buf << " ";
}
}
temp_buf << "| ";
temp_buf << count << "/" << total << " ";
temp_buf << "[";
auto time_used = std::chrono::steady_clock::now () - start_time;
long long time_count = std::chrono::duration_cast < std::chrono::seconds > ( time_used ).count ();
long long time_remain = count ? static_cast < long long > ( std::chrono::duration_cast < std::chrono::duration < double > > ( time_used ).count () * ( total - count ) / count ) : -1;
auto add_time = [&] ( long long x )
{
if ( x == -1 ) {
temp_buf << "??:??";
return;
}
if ( x / 60 / 60 > 0 ) {
temp_buf << std::setw ( 2 ) << std::setfill ( '0' ) << x / 60 / 60 << ":";
}
temp_buf << std::setw ( 2 ) << std::setfill ( '0' ) << x / 60 % 60 << ":";
temp_buf << std::setw ( 2 ) << std::setfill ( '0' ) << x % 60;
};
add_time ( time_count );
temp_buf << "<";
add_time ( time_remain );
temp_buf << ", ";
if ( count ) {
double speed = static_cast < double > ( count ) / std::chrono::duration_cast < std::chrono::duration < double > > ( time_used ).count ();
if ( speed >= 1 ) {
temp_buf << std::setprecision ( 2 ) << std::fixed << speed << unit << "/s";
} else {
temp_buf << std::setprecision ( 2 ) << std::fixed << 1 / speed << "s/" << unit;
}
} else {
temp_buf << "?.??" << unit << "/s";
}
temp_buf << "]";
std::cout << temp_buf.str ();
last_line_length = temp_buf.str ().size ();
std::cout.flush ();
if ( current_finished ) {
return;
}
std::this_thread::sleep_for ( std::chrono::milliseconds ( flush_frequency ) );
}
}
int count;
int total;
char fill_char;
int width;
std::string desc;
std::string unit;
int precision;
int flush_frequency;
std::chrono::steady_clock::time_point start_time;
std::stringstream output_buf;
mutable std::mutex count_lock;
mutable std::mutex output_buf_lock;
int last_line_length;
std::thread daemon;
bool finished;
};
\ No newline at end of file
/**
* utils/thread_safe_queue/thread_safe_queue.h
* thread-safe queue
*/
#pragma once
#include <queue>
#include <mutex>
#include <condition_variable>
template < typename T >
class thread_safe_queue
{
public:
void push_back ( T t );
void push_front ( T t );
T pop_back ();
T pop_front ();
bool empty ();
void clear ();
private:
std::deque < T > q;
mutable std::mutex mut;
std::condition_variable cv;
};
template<typename T>
void thread_safe_queue<T>::push_back ( T t )
{
std::unique_lock < std::mutex > lock ( mut );
q.push_back ( t );
cv.notify_one ();
}
template<typename T>
void thread_safe_queue<T>::push_front ( T t )
{
std::unique_lock < std::mutex > lock ( mut );
q.push_front ( t );
cv.notify_one ();
}
template<typename T>
T thread_safe_queue<T>::pop_back ()
{
std::unique_lock < std::mutex > lock ( mut );
while ( q.empty () ) {
cv.wait ( lock );
}
T return_value = q.back ();
q.pop_back ();
return return_value;
}
template<typename T>
T thread_safe_queue<T>::pop_front ()
{
std::unique_lock < std::mutex > lock ( mut );
while ( q.empty () ) {
cv.wait ( lock );
}
T return_value = q.front ();
q.pop_front ();
return return_value;
}
template<typename T>
bool thread_safe_queue<T>::empty ()
{
std::unique_lock < std::mutex > lock ( mut );
return q.empty ();
}
template<typename T>
inline void thread_safe_queue<T>::clear ()
{
std::unique_lock < std::mutex > lock ( mut );
cv.notify_all ();
q.clear ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment