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.
 
 
 
 
 
 

1254 lines
30 KiB

//==============================================================================
//
// Copyright (c) 2002-
// Authors:
// * Andrew Hinton <ug60axh@cs.bham.ac.uk> (University of Birmingham)
// * Dave Parker <david.parker@comlab.ox.ac.uk> (University of Oxford, formerly University of Birmingham)
//
//------------------------------------------------------------------------------
//
// 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 <stdio.h>
#include "simpctl.h"
#include "simutil.h"
#include "simstate.h"
#include "simmodel.h"
#include "simreasoning.h"
#include "simupdater.h"
#include <math.h>
#include <iostream>
#include <string>
#include <cstring>
#include <vector>
using std::cout;
using std::endl;
using std::string;
using std::vector;
//=============================================================================
// Description
//=============================================================================
/*
* This interface provides the means of reasoning about executions through
* models. It stores a collection of CPathFormula or CRewardFormula objects.
* These objects should be notified about any updates in the state, so that
* they can reason about the path as a whole. These updates should be notified
* in order and each object can be reset to look at a new path.
*/
//TODO integrate path formulae.cc stuff
//==============================================================================
//Class Definitions
//==============================================================================
/*
* CPathFormula
* ===========
*
* The CPathFormula class is used to represent any form of reasoning about
* paths. Primarily, this is used for (bounded/unbounded) untils and
* next operators, but is also overridden for specific support for rewards
* based operators.
*
* The important method is the Notify_State() method which should be overridden
* by each type of path operator to deal with an addition to the execution
* path. When the answer for a particular path is known, answer_known is
* set to true and the result is stored in answer. At this point no more
* evaluation of the path property is necessary.
*/
/*
* Constructor for CPathFormula object.
*/
CPathFormula::CPathFormula()
{
answer_known = false;
answer = false;
negate = false;
}
/*
* Set whether or not the value of this formula should be negated
*/
void CPathFormula::Set_Negate(bool b)
{
negate = b;
}
/*
* Access to the calculated answer for this CPathFormula object.
*/
bool CPathFormula::Get_Answer()
{
return (negate)?(!answer):(answer);
}
/*
* Access to a real number version of the answer for this CPathFormula
* object.
*/
double CPathFormula::Get_Answer_Double()
{
if(Get_Answer()) return 1.0;
else return 0.0;
}
/*
* Resets this CPathFormula object for use in future calcuations.
*/
void CPathFormula::Reset()
{
answer_known = false;
answer = false;
}
/*
* This method should be overridden by all reward subclasses to return
* true.
*/
bool CPathFormula::Is_Reward()
{
return false;
}
/*
* CRewardFormula
* ==============
*
* The CRewardFormula class overrides CPathFormula to provide specific
* support for reward operators. Essentially it provides an extra
* variables answer_double which is used to store the calculated reward
* for an execution path. This can be queried by Get_Answer_Double().
*
*/
/*
* Constructor for a CRewardFormula object.
*/
CRewardFormula::CRewardFormula() : CPathFormula()
{
answer_double = 0.0;
}
/*
* Returns the calculated reward for this CRewardFormula.
*/
double CRewardFormula::Get_Answer_Double()
{
return answer_double;
}
/*
* Returns the reward structure index for this CRewardFormula.
*/
int CRewardFormula::Get_Reward_Struct_Index()
{
return reward_struct_index;
}
/*
* Resets this CRewardFormula object for use in future calcuations.
*/
void CRewardFormula::Reset()
{
answer_known = false;
answer_double = 0.0;
answer = false;
}
/*
* Overridden to state that this object should be treated as a reward
* formulae.
*/
bool CRewardFormula::Is_Reward()
{
return true;
}
/*
* CBoundedUntil
* ==============
*
* The CBoundedUntil class is used to store and deal with path formulae of the form:
* [ leftExpression U[lower_bound, upper_bound] rightExpression ].
* i.e. leftExpression must hold true until rightExpression is satisfied within
* the lower and upper time bounds. For CTMCs, the time bounds refer to real time
* but for DTMCs, this bound refers to time steps.
*
*/
/*
* Constructor for a CBoundedUntil object.
*/
CBoundedUntil::CBoundedUntil(CExpression* leftExpression, CExpression* rightExpression, double lower_bound, double upper_bound) : CPathFormula()
{
this->leftExpression = leftExpression;
this->rightExpression = rightExpression;
this->upper_bound = upper_bound;
this->lower_bound = lower_bound;
this->counter = -1;
this->time_so_far = 0.0;
}
/*
* Destructor for a CBoundedUntil object. Deletes the left and right expression
* structures.
*/
CBoundedUntil::~CBoundedUntil()
{
if(leftExpression != NULL)
delete leftExpression;
if(rightExpression != NULL)
delete rightExpression;
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CBoundedUntil::Notify_State(CPathState* last_state, int* current_state)
{
counter++;
if(model_type == STOCHASTIC)
{
if(counter > 0)
{
double time_last_state = last_state->time_spent_in_state;
time_so_far += time_last_state;
if(time_so_far > upper_bound)
{
//must take into account the possibility of missing
//lower bound
//could have missed out evaluation of rightExpression
if(time_so_far-time_last_state <= lower_bound)
{
int* vars = last_state->variables;
if(rightExpression->Evaluate(vars))
{
answer_known = true;
answer = true;
}
else
{
answer_known = true;
answer = false;
}
}
else
{
answer_known = true;
answer = false;
}
}
else if(time_so_far <= lower_bound)
{
if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
else
{
if(rightExpression->Evaluate(current_state))
{
answer_known = true;
answer = true;
}
else if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
}
else
{
if(lower_bound == 0.0)
{
if(rightExpression->Evaluate(current_state))
{
answer_known = true;
answer = true;
}
}
else
{
if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
}
}
else
{
if(!answer_known)
{
if(counter > (int)upper_bound)
{
answer_known = true;
answer = false;
}
else if(counter < (int)lower_bound)
{
if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
else
{
if(rightExpression->Evaluate(current_state))
{
answer_known = true;
answer = true;
}
else if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
}
}
}
/*
* Determines whether the answer is already known for this path formula. This
* will *only* be if the answer has been proven, *not* if the path is looping.
*/
bool CBoundedUntil::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
return answer_known;
}
/*
* Returns a string representation of this CBoundedUntil object.
*/
string CBoundedUntil::To_String()
{
return leftExpression->To_String() + " U<= "+ Double_To_String(upper_bound)+ " " + rightExpression->To_String();
}
/*
* Resets the counter and time_so_far variables, and calls the superclass Reset method.
*/
void CBoundedUntil::Reset()
{
CPathFormula::Reset();
counter = -1;
time_so_far = 0.0;
}
void CBoundedUntil::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_BOUNDED_UNTIL;
write(fd, &form_type, sizeof(int));
//lower bound
write(fd, &lower_bound, sizeof(double));
//upper bound
write(fd, &upper_bound, sizeof(double));
//Left Expression
leftExpression->Write_Expression(fd);
//Right Expression
rightExpression->Write_Expression(fd);
//write null byte
write(fd, "\0", 1);
}
/*
* CUntil
* ======
*
* The CUntil class is used to store and deal with path formulae of the form:
* [ leftExpression U rightExpression ].
* i.e. leftExpression must hold true until rightExpression is satisfied.
*
*/
/*
* Constructor for a CUntil object.
*/
CUntil::CUntil(CExpression* leftExpression, CExpression* rightExpression) : CPathFormula()
{
this->leftExpression = leftExpression;
this->rightExpression = rightExpression;
}
/*
* Destructor for a CBoundedUntil object. Deletes the left and right expression
* structures.
*/
CUntil::~CUntil()
{
if(leftExpression != NULL)
delete leftExpression;
if(rightExpression != NULL)
delete rightExpression;
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CUntil::Notify_State(CPathState* last_state, int* current_state)
{
if(!answer_known)
{
if(rightExpression->Evaluate(current_state))
{
answer_known = true;
answer = true;
}
else if(!leftExpression->Evaluate(current_state))
{
answer_known = true;
answer = false;
}
}
}
/*
* Determines whether the answer is already known for this path formula. This
* will either be if the answer has been proven, or if the answer has not been
* determined but the path is looping.
*/
bool CUntil::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
return answer_known || loop_detection->Is_Proven_Looping() || loop_detection->Is_Deadlock();
}
/*
* Returns a string representation of this CUntil object.
*/
string CUntil::To_String()
{
return leftExpression->To_String() + " U "+ rightExpression->To_String();
}
void CUntil::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_UNTIL;
write(fd, &form_type, sizeof(int));
//Left Expression
leftExpression->Write_Expression(fd);
//Right Expression
rightExpression->Write_Expression(fd);
//write null byte
write(fd, "\0", 1);
}
/*
* CNext
* =====
*
* The CNext class is used to store and deal with path formulae of the form:
* [ X expression ].
* i.e. expression must hold true in the state following the original state.
*
*/
/*
* Constructor for a CNext object.
*/
CNext::CNext(CExpression* expression) : CPathFormula()
{
this->expression = expression;
}
/*
* Destructor for a CNextUntil object. Deletes the expression
* structure.
*/
CNext::~CNext()
{
if(expression != NULL)
delete expression;
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CNext::Notify_State(CPathState* last_state, int* current_state)
{
counter++;
if(!answer_known)
{
if(counter == 1) // if in 'Next' state
{
answer_known = true;
if(expression->Evaluate(current_state))
answer = true;
else
answer = false;
}
}
}
/*
* Returns a string representation of this CNext object.
*/
string CNext::To_String()
{
return "X "+expression->To_String();
}
/*
* Determines whether the answer is already known for this path formula. This
* will either be if the answer has been proven, or if the answer has not been
* determined but the path is looping.
*/
bool CNext::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
return answer_known || loop_detection->Is_Proven_Looping() || loop_detection->Is_Deadlock();
}
/*
* Resets the counter for this CNext object and calls the superclass Reset method.
*/
void CNext::Reset()
{
CPathFormula::Reset();
counter = -1;
}
void CNext::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_NEXT;
write(fd, &form_type, sizeof(int));
//Write Expression
expression->Write_Expression(fd);
//write null byte
write(fd, "\0", 1);
}
/*
* CRewardCumulative
* =================
*
* The CRewardCumulative class is used to store and deal with rewards formulae
* of the form:
* [ C<=time ].
* i.e. What is the reward accumulated before the time bound
*
*/
/*
* Constructor for a CRewardCumulative object.
*/
CRewardCumulative::CRewardCumulative(int rsi, double time) : CRewardFormula()
{
this->reward_struct_index = rsi;
this->time = time;
this->counter = -1;
time_so_far = 0;
answer_double = 0.0;
}
/*
* Destructor for a CRewardCumulative object.
*/
CRewardCumulative::~CRewardCumulative()
{
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CRewardCumulative::Notify_State(CPathState* last_state, int* current_state)
{
counter++;
if(model_type == STOCHASTIC)
{
if(counter > 0)
{
double time_last_state = last_state->time_spent_in_state;
time_so_far += time_last_state;
if(time_so_far > time)
{
//time occured in last state
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double =
last_state->cumulative_state_cost[reward_struct_index] + last_state->cumulative_transition_cost[reward_struct_index] -
last_state->transition_cost[reward_struct_index] +
last_state->state_instant_cost[reward_struct_index] * (time - time_so_far);
} else {
answer_double = 0.0;
}
}
else if(time_so_far == time) //unlikely, but just in case
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double =
last_state->cumulative_state_cost[reward_struct_index] + last_state->cumulative_transition_cost[reward_struct_index];
} else {
answer_double = 0.0;
}
}
}
}
else
{
if(counter > 0)
{
if(counter >= time)
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = last_state->cumulative_state_cost[reward_struct_index] + last_state->cumulative_transition_cost[reward_struct_index];
} else {
answer_double = 0.0;
}
}
}
}
}
/*
* Returns a string representation of this CRewardCumulative object.
*/
string CRewardCumulative::To_String()
{
return "[ C <= "+Double_To_String(time)+" ]";
}
/*
* Resets the counter, time_so_far and answer_double and calls the superclass
* Reset() method.
*/
void CRewardCumulative::Reset()
{
CRewardFormula::Reset();
counter = -1;
time_so_far = 0;
answer_double =0.0;
}
/*
* Determines whether the answer is already known for this path formula. This
* will *only* be if the answer has been proven, *not* if the path is looping.
*/
bool CRewardCumulative::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
return answer_known;
}
void CRewardCumulative::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_CUMULATIVE;
write(fd, &form_type, sizeof(int));
//rsi
write(fd, &reward_struct_index, sizeof(int));
//time
write(fd, &time, sizeof(double));
//write null byte
write(fd, "\0", 1);
}
/*
* CRewardInstantanious
* ====================
*
* The CRewardCumulative class is used to store and deal with rewards formulae
* of the form:
* [ I time ].
* i.e. What is the instantaneous state reward at the given time.
*
*/
/*
* Constructor for a CRewardInstantaneous object...and yes it does set the
* time_so_far variable to 0.0 now... ooops
*/
CRewardInstantanious::CRewardInstantanious(int rsi, double time) : CRewardFormula()
{
this->reward_struct_index = rsi;
this->time = time;
this->counter = -1;
time_so_far = 0;
answer_double = 0.0;
}
/*
* Destructor for a CRewardInstantaneous object.
*/
CRewardInstantanious::~CRewardInstantanious()
{
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CRewardInstantanious::Notify_State(CPathState* last_state, int* current_state)
{
counter++;
if(model_type == STOCHASTIC)
{
if(counter > 0)
{
double time_last_state = last_state->time_spent_in_state;
time_so_far += time_last_state;
if(time_so_far > time)
{
//time occured in last state
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = last_state->state_instant_cost[reward_struct_index];
} else {
answer_double = 0.0;
}
}
else if(time_so_far == time) //unlikely, but just in case
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = Get_State_Reward(reward_struct_index);
} else {
answer_double = 0.0;
}
}
}
else
{
if(time == 0)
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = Get_State_Reward(reward_struct_index);
} else {
answer_double = 0.0;
}
}
}
}
else
{
if(counter > 0)
{
if(counter >= time)
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = Get_State_Reward(reward_struct_index);
} else {
answer_double = 0.0;
}
}
}
else
{
if(time == 0)
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = Get_State_Reward(reward_struct_index);
} else {
answer_double = 0.0;
}
}
}
}
}
/*
* Returns a string representation of this CRewardInstantaneous object.
*/
string CRewardInstantanious::To_String()
{
return "[ I ="+Double_To_String(time)+" ] answer_known = "+Bool_To_String(answer_known);
}
/*
* Resets the counter, time_so_far and answer_double variables and calls the superclass
* Reset() method.
*/
void CRewardInstantanious::Reset()
{
CRewardFormula::Reset();
counter = -1;
time_so_far = 0;
answer_double = 0.0;
}
/*
* Determines whether the answer is already known for this path formula. This
* will *only* be if the answer has been proven, *not* if the path is looping.
*/
bool CRewardInstantanious::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
return answer_known;
}
void CRewardInstantanious::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_INSTANTANEOUS;
write(fd, &form_type, sizeof(int));
//rsi
write(fd, &reward_struct_index, sizeof(int));
//time
write(fd, &time, sizeof(double));
//write null byte
write(fd, "\0", 1);
}
/*
* CRewardReachability
* ===================
*
* The CRewardReachability class is used to store and deal with rewards formulae
* of the form:
* [ F expression ].
* i.e. What is the accumulated reward when expression is satisfied.
*
*/
/*
* Constructor for a CRewardReachability object.
*/
CRewardReachability::CRewardReachability(int rsi, CExpression* expression) : CRewardFormula()
{
this->reward_struct_index = rsi;
this->expression = expression;
}
/*
* Destructor for a CRewardReachability object.
*/
CRewardReachability::~CRewardReachability()
{
if(expression != NULL)
delete expression;
}
/*
* This method should be called for each update to the current state. This
* method determines whether the answer can be determined for this update
* and if, so calculates the answer and puts it in the answer member variable.
*/
void CRewardReachability::Notify_State(CPathState* last_state, int* current_state)
{
if(expression->Evaluate(current_state))
{
answer_known = true;
if (reward_struct_index >= 0 && reward_struct_index < no_reward_structs) {
answer_double = last_state->cumulative_state_cost[reward_struct_index] + last_state->cumulative_transition_cost[reward_struct_index];//Get_Path_Cost_No_Path();
} else {
answer_double = 0.0;
}
}
}
/*
* Determines whether the answer is already known for this path formula. This
* will either be if the answer has been proven, or if the path is looping.
* If the path is looping, this method also sets the answer_double to undefined
* because the reward is infinite.
*/
bool CRewardReachability::Is_Answer_Known(CLoopDetectionHandler* loop_detection)
{
if (!answer_known) if(loop_detection->Is_Proven_Looping() || loop_detection->Is_Deadlock()) answer_double = UNDEFINED_DOUBLE;
return answer_known || loop_detection->Is_Proven_Looping() || loop_detection->Is_Deadlock();
}
/*
* Returns a string representation of this CRewardReachability object.
*/
string CRewardReachability::To_String()
{
return "[ F "+expression->To_String()+" ]";
}
void CRewardReachability::Write_Formula(int fd)
{
//write formula type
int form_type = FORMULA_REACHABILITY;
write(fd, &form_type, sizeof(int));
//rsi
write(fd, &reward_struct_index, sizeof(int));
//Write Expression
expression->Write_Expression(fd);
//write null byte
write(fd, "\0", 1);
}
//==============================================================================
// Local Data
//==============================================================================
vector<CPathFormula*> registered_path_formulae; //all path and reward formulae
int no_path_formulae; //size of registered_path_formulae
//==============================================================================
//Function Definitions
//==============================================================================
/**
* This function removes all registered path formulae
* from memory.
*/
void Deallocate_PCTL_Core()
{
//cout << "Deallocate_PCTL_Core 1" << endl;
if(&registered_path_formulae !=NULL)
{
//cout << "Deallocate_PCTL_Core 2" << endl;
for(int i = 0; i < no_path_formulae; i++)
{
//cout << "Deallocate_PCTL_Core 3" << endl;
//cout << registered_path_formulae[i]->To_String();
if(registered_path_formulae[i] != NULL)
delete registered_path_formulae[i];
registered_path_formulae[i] = NULL;
}
//cout << "Deallocate_PCTL_Core 4" << endl;
registered_path_formulae.clear();
}
//cout << "Deallocate_PCTL_Core 5" << endl;
no_path_formulae = 0;
//cout << "Deallocate_PCTL_Core 6" << endl;
}
/*
* Allocates storage for path formulae to be registered.
*/
void Allocate_PCTL_Core()
{
registered_path_formulae.reserve(10);
no_path_formulae = 0;
}
/*
* Adds the given path formula to registered_path_formula.
*/
int Register_Path_Formula(CPathFormula* formula)
{
//cout << "Registering formula " << formula->To_String() << endl;
registered_path_formulae.push_back(formula);
no_path_formulae++;
return no_path_formulae-1;
}
/*
* Returns the index of the formula parameter in registered_path_formula
*/
int Index_Of_Path_Formula(CPathFormula* formula)
{
for(int i = 0; i < registered_path_formulae.size(); i++)
{
if(registered_path_formulae[i] == formula)
return i;
}
return -1;
}
/*
* Calls the Notify_State method of each path or reward formula in
* registered_path_formulae.
*/
void Notify_Path_Formulae(CPathState* last_state, int* current_state, CLoopDetectionHandler* loop_detection)
{
for(int i = 0; i< no_path_formulae; i++)
{
if(!registered_path_formulae[i]->Is_Answer_Known(loop_detection))
registered_path_formulae[i]->Notify_State(last_state, current_state);
}
}
//TODO move this to path PCTL manager
/*
void Recalculate_Path_Formulae()
{
//first rest each path formula
Reset_Path_Formulae();
for(int i = 0; i < no_path_formulae; i++)
{
for(int j = 0; j<=thePath->currentIndex; j++)
{
registered_path_formulae[i]->Notify_State(j);
}
}
}*/
/*
* Resets each path or reward formula in registered_path_formulae for
* new calculations.
*/
void Reset_Path_Formulae()
{
for(int i = 0; i< no_path_formulae; i++)
registered_path_formulae[i]->Reset();
}
/*
* Outputs the contents of registered_path_formulae to the command line.
*/
void Print_Formulae()
{
cout << endl;
cout << "Status of loaded PCTL path formulae:" << endl << endl;
cout << "Known\tAnswer\tFormulae" << endl;
cout << "===================================================================" << endl;
for(int i = 0; i < no_path_formulae; i++)
{
CPathFormula* form = registered_path_formulae[i];
/*cout << form->Is_Answer_Known() << "\t";
if(form->Is_Answer_Known())
cout << form->Get_Answer() << "\t";
else
cout << "\t"; */
cout << form->To_String() << endl;
}
cout << endl;
}
/*
* Method for direct querying of a registered path formula.
* Returns -1 if the answer is not known (or an error)
* Returns 0 if the answer is known as false
* Returns 1 if the answer is known as true
* Returns 2 if the answer is numeric.
*/
int Query_Path_Formula(int index)
{
if(index >= no_path_formulae) return -1;
if(registered_path_formulae[index] == NULL) return -1;
if(!registered_path_formulae[index]->answer_known) return -1;
//check for numeric
if(registered_path_formulae[index]->Is_Reward()) return 2;
if (registered_path_formulae[index]->Get_Answer()) return 1;
else return 0;
}
/*
* If the path formula at the index is numeric, this returns the answer
*/
double Query_Path_Formula_Numeric(int index)
{
if(index >= no_path_formulae) return -1;
return registered_path_formulae[index]->Get_Answer_Double();
}
CPathFormula* Get_Path_Formula(int index)
{
return registered_path_formulae[index];
}
//==============================================================================
// IO Functions
//==============================================================================
void Write_Pctl_Manager(int fd)
{
//model identifier
Write_Length_And_String("pctl", fd);
//write no formulae
write(fd, &no_path_formulae, sizeof(int));
//Formulae table
//==============
for(int i = 0; i < no_path_formulae; i++)
{
registered_path_formulae[i]->Write_Formula(fd);
}
//write null byte
write(fd, "\0", 1);
}
void Read_Pctl(int fd)
{
char buf_str[256];
int int_buf;
//read model header
read(fd, &int_buf, sizeof(int));
read(fd, &buf_str, int_buf+1);
if(strcmp(buf_str, "pctl") != 0)
{
throw "Error when importing binary file: pctl header not found";
}
read(fd, &int_buf, sizeof(int));
for(int i = 0 ; i < int_buf; i++)
{
CPathFormula* formula = Read_Path_Formula(fd);
Register_Path_Formula(formula);
}
//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";
}
}
CPathFormula* Read_Path_Formula(int fd)
{
int int_buf;
char buf_str[256];
//read formula type
read(fd, &int_buf, sizeof(int));
CExpression* expr;
CExpression* expr1;
CExpression* expr2;
double value1, value2;
int rsi;
switch(int_buf)
{
case FORMULA_BOUNDED_UNTIL:
read(fd, &value1, sizeof(double));
read(fd, &value2, sizeof(double));
expr1 = Read_Expression(fd);
expr2 = Read_Expression(fd);
//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 CBoundedUntil(expr1, expr2, value1, value2);
case FORMULA_UNTIL:
expr1 = Read_Expression(fd);
expr2 = Read_Expression(fd);
//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 CUntil(expr1, expr2);
case FORMULA_NEXT:
expr= Read_Expression(fd);
//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 CNext(expr);
case FORMULA_CUMULATIVE:
read(fd, &rsi, sizeof(int));
read(fd, &value1, sizeof(double));
//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 CRewardCumulative(rsi, value1);
case FORMULA_REACHABILITY:
read(fd, &rsi, sizeof(int));
expr= Read_Expression(fd);
//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 CRewardReachability(rsi, expr);
case FORMULA_INSTANTANEOUS:
read(fd, &rsi, sizeof(int));
read(fd, &value1, sizeof(double));
//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 CRewardInstantanious(rsi, value1);
default:
throw "unexpected formula type when loading pctl formula";
}
}