You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
853 lines
23 KiB
853 lines
23 KiB
//==============================================================================
|
|
//
|
|
// Copyright (c) 2004-2005, Andrew Hinton, Dave Parker
|
|
//
|
|
// This file is part of PRISM.
|
|
//
|
|
// PRISM is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// PRISM is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with PRISM; if not, write to the Free Software Foundation,
|
|
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
//
|
|
//==============================================================================
|
|
|
|
#include "simsampling.h"
|
|
#include "simpctl.h"
|
|
#include "simupdater.h"
|
|
#include "simreasoning.h"
|
|
#include "simstate.h"
|
|
#include "simutil.h"
|
|
#include "simlog.h"
|
|
#include <stdio.h>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
using std::cout;
|
|
using std::endl;
|
|
using std::vector;
|
|
|
|
//=============================================================================
|
|
// Description
|
|
//=============================================================================
|
|
|
|
/*
|
|
* This interface is used to perform approximate verification of properties
|
|
* via a Monte-Carlo based sampling technique.
|
|
*
|
|
* The vector registered_sample_holders can be populated to contain objects
|
|
* called CSampleHolders that simply make a number of samples to obtain an
|
|
* average (be it probability or reward) for the result of a CPathFormula for
|
|
* a given path.
|
|
*
|
|
* Once this vector has been populated, the Do_Sampling method can be run, which
|
|
* uses a cut-down loop detection handler (no path required) to perform the sampling
|
|
* algorithm.
|
|
*/
|
|
|
|
|
|
//=============================================================================
|
|
// Local Data
|
|
//=============================================================================
|
|
|
|
vector<CSampleHolder*> registered_sample_holders; //P=? or R=?
|
|
int no_sample_holders = 0; //size of registered_sample_holders
|
|
int no_iterations = 412000;
|
|
|
|
|
|
//=============================================================================
|
|
// Globals
|
|
//=============================================================================
|
|
|
|
bool should_stop_sampling = false; //used to stop the algorithm in its tracks
|
|
|
|
//=============================================================================
|
|
// Class Definitions
|
|
//=============================================================================
|
|
|
|
/*
|
|
* CSampleHolder
|
|
* =============
|
|
*
|
|
* The CSampleHolder class is responsible for storing a cumulative value of
|
|
* the property so far, together with the number of samples so that the mean
|
|
* value can be calculated.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Constructor for a CSampleHolder object.
|
|
*/
|
|
CSampleHolder::CSampleHolder()
|
|
{
|
|
cumulative_value = 0.0;
|
|
no_samples = 0;
|
|
no_reach_max = 0;
|
|
}
|
|
|
|
/*
|
|
* Adds the value of sample to the cumulative_value and increments the no_samples.
|
|
*/
|
|
void CSampleHolder::Sample(double sample)
|
|
{
|
|
if(sample == UNDEFINED_DOUBLE) //infinite detected
|
|
{
|
|
cumulative_value = UNDEFINED_DOUBLE;
|
|
}
|
|
else
|
|
{
|
|
cumulative_value += sample;
|
|
no_samples++;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* A sample where the maximum path length has been reached.
|
|
*/
|
|
void CSampleHolder::Sample_Maximum_Path_Reached()
|
|
{
|
|
no_reach_max++;
|
|
}
|
|
|
|
/*
|
|
* Reset for another sampling algorithm.
|
|
*/
|
|
void CSampleHolder::Reset()
|
|
{
|
|
cumulative_value = 0.0;
|
|
no_samples = 0;
|
|
no_reach_max = 0;
|
|
}
|
|
|
|
/*
|
|
* Give the number of times that the maximum path length was reached for
|
|
* the current sampling run.
|
|
*/
|
|
int CSampleHolder::Get_Number_Reached_Maximum_Path()
|
|
{
|
|
return no_reach_max;
|
|
}
|
|
|
|
|
|
/*
|
|
* CProbEqualsQuestion
|
|
* ===================
|
|
*
|
|
* The CProbEqualsQuestion class overrides CSampleHolder to provide functionality
|
|
* for properties of the form P=? [...]. These have a link to a registered
|
|
* CPathFormula, which is the path formula to be sampled.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Constructor for a CProbEqualsQuestion object.
|
|
*/
|
|
CProbEqualsQuestion::CProbEqualsQuestion(CPathFormula* formula) : CSampleHolder()
|
|
{
|
|
this->formula = formula;
|
|
required_runs = no_iterations;
|
|
|
|
}
|
|
|
|
/*
|
|
* Destructor for a CProbEqualsQuestion object.
|
|
*/
|
|
CProbEqualsQuestion::~CProbEqualsQuestion()
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Returns true if the number of samples taken is >= the amount required.
|
|
*/
|
|
bool CProbEqualsQuestion::Done()
|
|
{
|
|
return (no_samples >= required_runs);
|
|
}
|
|
|
|
/*
|
|
* Returns the mean value result(cumulative/no_samples)
|
|
*/
|
|
double CProbEqualsQuestion::Get_Result()
|
|
{
|
|
return cumulative_value / (double)no_samples;
|
|
}
|
|
|
|
/*
|
|
* Returns a pointer to the path formula
|
|
*/
|
|
CPathFormula* CProbEqualsQuestion::Get_Path_Formula()
|
|
{
|
|
return formula;
|
|
}
|
|
|
|
/*
|
|
* Method to set the number of iterations required to approximately verify this property.
|
|
*/
|
|
void CProbEqualsQuestion::Set_No_Iterations(int no_iterations_param)
|
|
{
|
|
required_runs = no_iterations_param;
|
|
}
|
|
|
|
void CProbEqualsQuestion::Write_Holder(int fd)
|
|
{
|
|
//write type
|
|
int holder_type = HOLDER_PROB;
|
|
write(fd, &holder_type, sizeof(int));
|
|
|
|
//Write the index of the path formula
|
|
int index = Index_Of_Path_Formula(formula);
|
|
write(fd, &index, sizeof(int));
|
|
|
|
//Write null byte
|
|
write(fd, "\0", 1);
|
|
}
|
|
|
|
|
|
/*
|
|
* CRewardEqualsQuestion
|
|
* =====================
|
|
*
|
|
* The CRewardEqualsQuestion class overrides CSampleHolder to provide functionality
|
|
* for properties of the form R=? [...]. These have a link to a registered
|
|
* CPathFormula, which is the reward formula to be sampled.
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* Constructor for a CRewardEqualsQuestion object.
|
|
*/
|
|
CRewardEqualsQuestion::CRewardEqualsQuestion(CPathFormula* formula) : CSampleHolder()
|
|
{
|
|
this->formula = formula;
|
|
required_runs = no_iterations;
|
|
}
|
|
|
|
/*
|
|
* Destructor for a CRewardEqualsQuestion object.
|
|
*/
|
|
CRewardEqualsQuestion::~CRewardEqualsQuestion()
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Returns true if the number of samples taken >= the number of samples required. Or
|
|
* if the cumulative_value is determined to be infinite... if which case the answer
|
|
* will always be infinite.
|
|
*/
|
|
bool CRewardEqualsQuestion::Done()
|
|
{
|
|
return (cumulative_value == UNDEFINED_DOUBLE || no_samples >= required_runs);
|
|
}
|
|
|
|
/*
|
|
* Returns the mean value result(cumulative/no_samples)
|
|
*/
|
|
double CRewardEqualsQuestion::Get_Result()
|
|
{
|
|
if(cumulative_value == UNDEFINED_DOUBLE)
|
|
return cumulative_value;
|
|
else
|
|
return cumulative_value / (double)no_samples;
|
|
}
|
|
|
|
/*
|
|
* Returns a pointer to the reward formula
|
|
*/
|
|
CPathFormula* CRewardEqualsQuestion::Get_Path_Formula()
|
|
{
|
|
return formula;
|
|
}
|
|
|
|
/*
|
|
* Method to set the number of iterations required to approximately verify this property.
|
|
*/
|
|
void CRewardEqualsQuestion::Set_No_Iterations(int no_iterations_param)
|
|
{
|
|
required_runs = no_iterations_param;
|
|
}
|
|
|
|
void CRewardEqualsQuestion::Write_Holder(int fd)
|
|
{
|
|
//write type
|
|
int holder_type = HOLDER_REWARD;
|
|
write(fd, &holder_type, sizeof(int));
|
|
|
|
//Write the index of the path formula
|
|
int index = Index_Of_Path_Formula(formula);
|
|
write(fd, &index, sizeof(int));
|
|
|
|
//Write null byte
|
|
write(fd, "\0", 1);
|
|
}
|
|
|
|
//Class CSamplingLoopDetectionHandler
|
|
|
|
CSamplingLoopDetectionHandler::CSamplingLoopDetectionHandler()
|
|
{
|
|
//start with a loop path of 10 as default
|
|
for(int i = 0; i < 10; i++)
|
|
{
|
|
CPathState* new_ps = new CPathState();
|
|
loop_path.push_back(new_ps);
|
|
}
|
|
exploring_deterministically = false;
|
|
proven_looping = false;
|
|
next_loop_index = 0;
|
|
deadlock = false;
|
|
}
|
|
|
|
CSamplingLoopDetectionHandler::~CSamplingLoopDetectionHandler()
|
|
{
|
|
for(int i = 0 ; i< loop_path.size(); i++)
|
|
{
|
|
delete loop_path[i];
|
|
}
|
|
|
|
loop_path.clear();
|
|
}
|
|
|
|
void CSamplingLoopDetectionHandler::Start_New_Deterministic_Path()
|
|
{
|
|
exploring_deterministically = true;
|
|
next_loop_index = 0;
|
|
proven_looping = false;
|
|
}
|
|
|
|
void CSamplingLoopDetectionHandler::Notify_State(int* state_variables)
|
|
{
|
|
if(next_loop_index >= loop_path.size()) //need to allocate some more path
|
|
{
|
|
debug(<<"Assigning more memory"<<endl);
|
|
//Add a path of 10 to loop_path
|
|
for(int i = 0; i < 10; i++)
|
|
{
|
|
CPathState* new_ps = new CPathState();
|
|
loop_path.push_back(new_ps);
|
|
}
|
|
}
|
|
loop_path[next_loop_index++]->Make_This_Current_State();
|
|
}
|
|
|
|
int* CSamplingLoopDetectionHandler::Path_At(int index)
|
|
{
|
|
return loop_path[index]->variables;
|
|
}
|
|
|
|
|
|
void CSamplingLoopDetectionHandler::Notify_Deterministic_Path_End()
|
|
{
|
|
exploring_deterministically = false;
|
|
next_loop_index = 0;
|
|
proven_looping = false;
|
|
}
|
|
|
|
void CSamplingLoopDetectionHandler::Reset()
|
|
{
|
|
exploring_deterministically = false;
|
|
next_loop_index = 0;
|
|
proven_looping = false;
|
|
deadlock = false;
|
|
}
|
|
|
|
int CSamplingLoopDetectionHandler::Path_Size()
|
|
{
|
|
return next_loop_index;
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// Functions
|
|
//=============================================================================
|
|
|
|
/*
|
|
* Deallocates memory for the sampling interface. All registered_sample_holders
|
|
* are removed from memory.
|
|
*/
|
|
void Deallocate_Sampling()
|
|
{
|
|
if(®istered_sample_holders != NULL)
|
|
{
|
|
for(int i = 0; i < registered_sample_holders.size(); i++)
|
|
{
|
|
delete registered_sample_holders[i];
|
|
}
|
|
registered_sample_holders.clear();
|
|
}
|
|
|
|
no_sample_holders = 0;
|
|
|
|
}
|
|
|
|
/*
|
|
* Assigns memory to store sample_holders
|
|
*/
|
|
void Allocate_Sampling()
|
|
{
|
|
registered_sample_holders.reserve(10);
|
|
no_sample_holders = 0;
|
|
}
|
|
|
|
/*
|
|
* Adds a CSampleHolder to the registered_sample_holders vector.
|
|
*/
|
|
int Register_Sample_Holder(CSampleHolder* sample_holder)
|
|
{
|
|
registered_sample_holders.push_back(sample_holder);
|
|
no_sample_holders++;
|
|
|
|
return no_sample_holders-1;
|
|
}
|
|
|
|
/*
|
|
* Returns true if each member of registered_sample_holders has done all
|
|
* of the necessary computation to get a result.
|
|
*/
|
|
bool All_Done_Sampling()
|
|
{
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
{
|
|
if(!registered_sample_holders[i]->Done()) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Returns true if for each path formula of each registered_sample_holder,
|
|
* the answer is known for the current execution path.
|
|
*/
|
|
bool All_PCTL_Answers_Known(CLoopDetectionHandler* loop_detection)
|
|
{
|
|
bool finished = true;
|
|
for(int j = 0; j < no_sample_holders && finished; j++)
|
|
{
|
|
CPathFormula * pf = registered_sample_holders[j]->Get_Path_Formula();
|
|
finished = finished && pf->Is_Answer_Known(loop_detection);
|
|
}
|
|
return finished;
|
|
}
|
|
|
|
/*
|
|
* Performs a sample according to the calculation on each CPathFormula of the
|
|
* CSampleHolders in registered_sample_holders. Each CPathFormula is reset
|
|
* for the next path.
|
|
*/
|
|
void Do_A_Sample(CLoopDetectionHandler* loop_detection)
|
|
{
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
{
|
|
CPathFormula * pf = registered_sample_holders[i]->Get_Path_Formula();
|
|
|
|
// store the current answer as a a sample
|
|
registered_sample_holders[i]->Sample(pf->Get_Answer_Double());
|
|
|
|
// if don't know the final answer (perhaps path length too short), register this fact...
|
|
if(!pf->Is_Answer_Known(loop_detection)) registered_sample_holders[i]->Sample_Maximum_Path_Reached();
|
|
|
|
pf->Reset();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Force the sampling algorithm to stop.
|
|
*/
|
|
void Stop_Sampling()
|
|
{
|
|
should_stop_sampling = true;
|
|
}
|
|
|
|
/*
|
|
* Print out the sampling results to the command line.
|
|
*/
|
|
void Print_Sampling_Results()
|
|
{
|
|
|
|
cout << "Sampling Results: " <<endl << endl;
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
{
|
|
cout << registered_sample_holders[i]->Get_Result() << "\t" <<
|
|
registered_sample_holders[i]->no_samples << "\t" <<
|
|
registered_sample_holders[i]->cumulative_value << "\t"
|
|
"\t" << registered_sample_holders[i]->Get_Path_Formula()->To_String() <<endl;
|
|
}
|
|
|
|
cout << endl << endl;
|
|
}
|
|
|
|
/*
|
|
* Get the calculated result of the CSampleHolder at the given index.
|
|
*/
|
|
double Get_Sampling_Result(int index)
|
|
{
|
|
return registered_sample_holders[index]->Get_Result();
|
|
}
|
|
|
|
/*
|
|
* Get the number of times the CSampleHolder at the given index had to be evaluated
|
|
* to the maximum path length in order to make a sample.
|
|
*/
|
|
int Get_Num_Reached_Max_Path(int index)
|
|
{
|
|
return registered_sample_holders[index]->Get_Number_Reached_Maximum_Path();
|
|
}
|
|
|
|
/*
|
|
* Get the total number of times any CSampleHolder at the given index had to be evaluated
|
|
* to the maximum path length in order to make a sample.
|
|
*/
|
|
int Get_Total_Num_Reached_Max_Path()
|
|
{
|
|
int count = 0;
|
|
for(int j = 0; j < no_sample_holders; j++)
|
|
{
|
|
count += Get_Num_Reached_Max_Path(j);
|
|
}
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* For each CSampleHolder in registered_sample_holders, this function sets the
|
|
* number of iterations for the sampling algorithm.
|
|
*/
|
|
void Set_No_Iterations(int no_iterations_param)
|
|
{
|
|
no_iterations = no_iterations_param;
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
registered_sample_holders[i]->Set_No_Iterations(no_iterations);
|
|
}
|
|
|
|
/*
|
|
* The sampling algorithm.
|
|
*/
|
|
void Do_Sampling(int path_length)
|
|
{
|
|
//#############################################
|
|
//#INITIALISE VARIABLES FOR SAMPLING ALGORITHM#
|
|
//#############################################
|
|
|
|
//Last state is required for the pctl/csl methods
|
|
CPathState* last_state = new CPathState();
|
|
|
|
//Loop detection requires that deterministic paths are
|
|
//stored, until that determinism is broken. This path
|
|
//is allocated dynamically, 10 steps at a time.
|
|
CSamplingLoopDetectionHandler* loop_detection = new CSamplingLoopDetectionHandler();
|
|
|
|
//Clone the starting state from state_variables
|
|
int* starting_variables = new int[no_state_variables];
|
|
for(int i = 0; i < no_state_variables; i++)
|
|
starting_variables[i] = state_variables[i];
|
|
|
|
//External flag set to false
|
|
should_stop_sampling = false;
|
|
|
|
//####################
|
|
//#MAIN SAMPLING LOOP#
|
|
//####################
|
|
|
|
int iteration_counter = 0;
|
|
int last_percentage_done = -1;
|
|
int percentage_done = -1;
|
|
double average_path_length = 0;
|
|
int min_path_length = 0, max_path_length = 0;
|
|
bool stopped_early = false;
|
|
bool deadlocks_found = false;
|
|
|
|
//Variables used within the sampling loop
|
|
//=======================================
|
|
|
|
//The current path
|
|
int current_index;
|
|
|
|
double* path_cost = new double[no_reward_structs];
|
|
double* total_state_cost = new double[no_reward_structs];
|
|
double* total_transition_cost = new double[no_reward_structs];
|
|
|
|
//Timers
|
|
clock_t start, start2, stop;
|
|
double time_taken;
|
|
|
|
start = start2 = clock();
|
|
|
|
Sim_Print_To_Main_Log("\nSampling progress: [");
|
|
|
|
//The loop continues until each pctl/csl formula is satisfied:
|
|
//E.g. usually, this is when the correct number of iterations
|
|
//has been performed, but for some, such as cumulative rewards
|
|
//this can be early if a loop is detected at any point, this
|
|
//is all handled by the All_Done_Sampling() function
|
|
while(!should_stop_sampling && !All_Done_Sampling()) //while there are more samples needed
|
|
{
|
|
// output of progress
|
|
percentage_done = ((10*(iteration_counter))/no_iterations)*10;
|
|
if (percentage_done > last_percentage_done) {
|
|
last_percentage_done = percentage_done;
|
|
//cout << " " << last_percentage_done << "%" << endl;
|
|
Sim_Print_To_Main_Log(" %d%%", last_percentage_done);
|
|
Sim_Flush_Main_Log();
|
|
}
|
|
//if (iteration_counter%100000 == 0) {
|
|
//cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\bIteration: " << iteration_counter;
|
|
//cout << "Iteration: " << iteration_counter << endl;
|
|
//}
|
|
|
|
if(((double)(clock()-start2)/ CLOCKS_PER_SEC) > 2) //do polling and feedback every 2 seconds
|
|
{
|
|
Write_Feedback(iteration_counter, no_iterations, false);
|
|
int poll = Poll_Control_File();
|
|
|
|
if(poll & STOP_SAMPLING == STOP_SAMPLING)
|
|
{
|
|
should_stop_sampling = true;
|
|
}
|
|
start2 = clock();
|
|
}
|
|
|
|
iteration_counter++;
|
|
|
|
//Start a (sample) new path for this iteration
|
|
//============================================
|
|
|
|
//Initialise variables for this loop
|
|
loop_detection->Reset();
|
|
for (int i = 0; i < no_reward_structs; i++) {
|
|
path_cost[i] = 0.0;
|
|
total_state_cost[i] = 0.0;
|
|
total_transition_cost[i] = 0.0;
|
|
}
|
|
|
|
//set the current state to the correct starting state
|
|
for(int i = 0; i < no_state_variables; i++)
|
|
state_variables[i] = starting_variables[i];
|
|
|
|
//Calculate initial state reward
|
|
Calculate_State_Reward(state_variables);
|
|
|
|
Notify_Path_Formulae(last_state, state_variables, loop_detection);
|
|
|
|
//====================================
|
|
//Generate a path of up to path_length
|
|
//====================================
|
|
|
|
for(current_index = 0;
|
|
!All_PCTL_Answers_Known(loop_detection) && //not got answers for all properties yet
|
|
//!loop_detection->Is_Proven_Looping() //not looping (removed this - e.g. cumul rewards can't stop yet)
|
|
current_index < path_length; //not exceeding path_length
|
|
current_index++)
|
|
{
|
|
last_state->Make_This_Current_State();
|
|
for (int i = 0; i < no_reward_structs; i++) {
|
|
last_state->state_instant_cost[i] = Get_State_Reward(i);
|
|
}
|
|
|
|
//Make an automatic choice for the current state
|
|
double dummy = 0.0;
|
|
Automatic_Update(loop_detection, dummy);
|
|
Calculate_State_Reward(state_variables);
|
|
|
|
//if(!loop_detection->Is_Proven_Looping()) { // removed this: for e.g. cumul rewards need to keep counting in loops...
|
|
|
|
if(model_type == STOCHASTIC)
|
|
{
|
|
double time_in_state = Get_Sampled_Time();
|
|
|
|
last_state->time_spent_in_state = time_in_state;
|
|
|
|
for (int i = 0; i < no_reward_structs; i++) {
|
|
last_state->state_cost[i] = last_state->state_instant_cost[i]*time_in_state;
|
|
last_state->transition_cost[i] = Get_Transition_Reward(i);
|
|
total_state_cost[i] += last_state->state_instant_cost[i]*time_in_state;
|
|
total_transition_cost[i] += last_state->transition_cost[i];
|
|
path_cost[i] = total_state_cost[i] + total_transition_cost[i];
|
|
last_state->path_cost_so_far[i] = path_cost[i];
|
|
}
|
|
|
|
Notify_Path_Formulae(last_state, state_variables, loop_detection);
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < no_reward_structs; i++) {
|
|
last_state->state_cost[i] = last_state->state_instant_cost[i];
|
|
last_state->transition_cost[i] = Get_Transition_Reward(i);
|
|
total_state_cost[i] += last_state->state_instant_cost[i];
|
|
total_transition_cost[i] += last_state->transition_cost[i];
|
|
path_cost[i] = total_state_cost[i] + total_transition_cost[i];
|
|
last_state->path_cost_so_far[i] = path_cost[i];
|
|
}
|
|
|
|
Notify_Path_Formulae(last_state, state_variables, loop_detection);
|
|
}
|
|
//}
|
|
|
|
} //end path generation for loop
|
|
|
|
// record if we found any deadlocks (can check this outside path gen loop because never escape deadlocks)
|
|
if (loop_detection->Is_Deadlock()) deadlocks_found = true;
|
|
|
|
// compute path length statistics so far
|
|
average_path_length = (average_path_length*(iteration_counter-1)+(current_index))/iteration_counter;
|
|
min_path_length = (iteration_counter == 1) ? current_index : ((current_index < min_path_length) ? current_index : min_path_length);
|
|
max_path_length = (iteration_counter == 1) ? current_index : ((current_index > max_path_length) ? current_index : max_path_length);
|
|
|
|
//Get samples and notify sample collectors
|
|
Do_A_Sample(loop_detection);
|
|
|
|
// stop early if any of the properties couldn't be sampled
|
|
if (Get_Total_Num_Reached_Max_Path() > 0) { stopped_early = true; break; }
|
|
|
|
}//end sampling while
|
|
|
|
if (!stopped_early) {
|
|
if (!should_stop_sampling) Sim_Print_To_Main_Log(" 100%% ]");
|
|
Sim_Print_To_Main_Log("\n");
|
|
stop = clock();
|
|
time_taken = (double)(stop - start)/CLOCKS_PER_SEC;
|
|
Sim_Print_To_Main_Log("\nSampling complete: %d iterations in %.2f seconds (average %.6f)\n", iteration_counter, time_taken, time_taken/iteration_counter);
|
|
Sim_Print_To_Main_Log("Path length statistics: average %.1f, min %d, max %d\n", average_path_length, min_path_length, max_path_length);
|
|
} else {
|
|
Sim_Print_To_Main_Log(" ...\n\nSampling terminated early after %d iterations.\n", iteration_counter);
|
|
}
|
|
|
|
// print a warning if deadlocks occured at any point
|
|
if (deadlocks_found) Sim_Print_To_Main_Log("\nWarning: Deadlocks were found during simulation: self-loops were added\n");
|
|
|
|
// print a warning if simulation was stopped by the user
|
|
if (should_stop_sampling) Sim_Print_To_Main_Log("\nWarning: Simulation was terminated before completion.\n");
|
|
|
|
//write to feedback file with true to indicate that we have finished sampling
|
|
Write_Feedback(iteration_counter, no_iterations, true);
|
|
|
|
//Print_Sampling_Results();
|
|
delete loop_detection;
|
|
delete[] starting_variables;
|
|
delete last_state;
|
|
delete[] path_cost;
|
|
delete[] total_state_cost;
|
|
delete[] total_transition_cost;
|
|
|
|
if (stopped_early) {
|
|
Report_Error("One or more of the properties being sampled could not be checked on a sample. Consider increasing the maximum path length");
|
|
throw 0;
|
|
}
|
|
}
|
|
|
|
//==============================================================================
|
|
// IO Functions
|
|
//==============================================================================
|
|
|
|
void Write_Sampling(int fd)
|
|
{
|
|
//sampling identifier
|
|
Write_Length_And_String("sp", fd);
|
|
|
|
//write no propeties
|
|
write(fd, &no_sample_holders, sizeof(int));
|
|
|
|
//Formulae table
|
|
//==============
|
|
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
{
|
|
registered_sample_holders[i]->Write_Holder(fd);
|
|
}
|
|
|
|
//write null byte
|
|
write(fd, "\0", 1);
|
|
}
|
|
|
|
void Read_Sampling(int fd)
|
|
{
|
|
char buf_str[256];
|
|
//cout << "read_sampling called" << endl;
|
|
int int_buf;
|
|
//read model header
|
|
read(fd, &int_buf, sizeof(int));
|
|
read(fd, &buf_str, int_buf+1);
|
|
if(strcmp(buf_str, "sp") != 0)
|
|
{
|
|
throw "Error when importing binary file: sampling header not found";
|
|
}
|
|
//cout << "done reading header" << endl;
|
|
//read no properties
|
|
read(fd, &int_buf, sizeof(int));
|
|
//cout << "There should be " << int_buf << "sample holders" << endl;
|
|
|
|
//read in the properties
|
|
for(int i = 0; i < int_buf; i++)
|
|
{
|
|
CSampleHolder* holder = Read_Sample_Holder(fd);
|
|
//cout << "this is the holder loaded" << endl;
|
|
//cout << holder->Get_Path_Formula()->To_String() << endl;
|
|
Register_Sample_Holder(holder);
|
|
}
|
|
|
|
//read off null byte
|
|
read(fd, &buf_str, 1);
|
|
if(strcmp(buf_str, "") != 0)
|
|
{
|
|
throw "Error when importing binary file: state space not terminated correctly";
|
|
}
|
|
}
|
|
|
|
CSampleHolder* Read_Sample_Holder(int fd)
|
|
{
|
|
char buf_str[256];
|
|
int int_buf;
|
|
|
|
//read type of holder
|
|
|
|
read(fd, &int_buf, sizeof(int));
|
|
|
|
int value;
|
|
|
|
switch(int_buf)
|
|
{
|
|
case HOLDER_PROB:
|
|
//read the index
|
|
read(fd, &value, sizeof(int));
|
|
//read off null byte
|
|
read(fd, &buf_str, 1);
|
|
if(strcmp(buf_str, "") != 0)
|
|
{
|
|
throw "Error when importing binary file: state space not terminated correctly";
|
|
}
|
|
return new CProbEqualsQuestion(Get_Path_Formula(value));
|
|
case HOLDER_REWARD:
|
|
//read the index
|
|
read(fd, &value, sizeof(int));
|
|
//read off null byte
|
|
read(fd, &buf_str, 1);
|
|
if(strcmp(buf_str, "") != 0)
|
|
{
|
|
throw "Error when importing binary file: state space not terminated correctly";
|
|
}
|
|
return new CRewardEqualsQuestion(Get_Path_Formula(value));
|
|
default:
|
|
throw "error: unexpected sample holder type";
|
|
}
|
|
}
|
|
|
|
void Write_Sampling_Results(int fd)
|
|
{
|
|
char str[256];
|
|
for(int i = 0; i < no_sample_holders; i++)
|
|
{
|
|
sprintf(str, "%d", i);
|
|
write(fd, str, strlen(str));
|
|
write(fd, "\t", 1);
|
|
sprintf(str, "%d", registered_sample_holders[i]->no_samples);
|
|
write(fd, str, strlen(str));
|
|
write(fd, "\t", 1);
|
|
sprintf(str, "%lf", registered_sample_holders[i]->cumulative_value);
|
|
write(fd, str, strlen(str));
|
|
write(fd, "\n", 1);
|
|
}
|
|
}
|
|
|