Model.cpp
download
// Odwzorowanie analizowanego systemu
// Fragment pracy dyplomowej
// Dariusz Cieślak, cieslakd at gazeta.pl
#include <assert.h>
#include <iostream.h>
#include "Const.h"
#include "Predicate.h"
#include "Trigger.h"
#include "Model.h"
#include "Variable.h"
#include "FunctorExpression.h"
#include "ConstExpression.h"
#include "SymbolExpression.h"
#include "ConstExpression.h"
#include "Expression.h"
#include "Transition.h"
#include "AbstractState.h"
#include "Input.h"
#include "InputSubSet.h"
#include "RealTriggerGenerator.h"
#include "Scaner.h"
#include "Error.h"
#include "IIFExpression.h"
Model::Model()
: errorCondition(0)
{
}
Model::~Model()
{
}
void Model::add(Const* /*only*/ c)
{
consts.add(c);
}
void Model::add(Predicate* /*only*/ p)
{
predicates.add(p);
if(p->hasEqualOperator())
{
Predicate* /*only*/ p2 =
p->cloneWithNoEqualOperator();
predicates.add(p2);
}
}
void Model::add(Trigger* /*only*/ t)
{
assert(t->check());
triggerList.add(t);
}
void Model::setErrorCondition(Expression* /*only*/ expr)
{
assert(expr);
assert(!errorCondition);
errorCondition = expr;
}
const BitVector Model::computeAbstractState() const
{
if(errorCondition && errorCondition->eval())
return BitVector();
BitVector biState(predicates.getSize());
PtrList<Predicate>::iterator it(predicates);
int nrBit = 0;
while(it.next())
{
Predicate* pr = it.getValue();
int value = pr->eval();
if(value)
biState.setBit(nrBit);
// _LIN(cout << "predicate " << pr->asString() << "=" << value);
++ nrBit;
}
// _LIN(cout << "state= " << biState);
return biState;
}
void Model::createData()
{
{
RealTriggerGenerator rtg(*this);
}
do
{
BitVector biS1 = computeAbstractState();
PtrList<Trigger>::iterator it(triggerList);
while(it.next())
{
Trigger* /*shared*/ trg = it.getValue();
assert(trg->check());
variableList.saveVariables();
trg->compute();
Variable::select(1);
BitVector biS2 = computeAbstractState();
Variable::select(0);
addAction(biS1, biS2, trg);
}
}
while(variableList.nextState());
}
void Model::showAbstractState(ostream& os, AbstractState* /*shared*/ as) const
{
assert(as);
const char* sep = "";
BitVector bits = as->getBits();
if(!as->isErrorState())
{
PtrList<Predicate>::iterator it(predicates);
int nrBit = 0;
while(it.next())
{
Predicate* /*shared*/ p = it.getValue();
if(bits.getBit(nrBit))
{
os << sep << p->asString();
sep = ", ";
}
++ nrBit;
}
}
}
void Model::saveCxl(ostream& os)
{
Variable::select(1);
variableList.setInitialValues();
AbstractState initState(computeAbstractState());
Variable::select(0);
createData();
AbstractModel::saveCxl(os, initState);
}
/*----------------------------------------------------------------------*/
Expression* /*only*/ Model::parseValue(Scaner& scaner) const
{
Scaner::token_t token = scaner.getTokenType();
const char* sText = scaner.getTokenValue();
switch(token)
{
case Scaner::NOT:
{
scaner.next();
Expression* /*only*/ expr =
parseValue(scaner);
return new FunctorExpression(
FunctorExpression::NOT,
expr,
0);
}
case Scaner::NUMBER:
{
Expression* /*only*/ expr =
new ConstExpression(atoi(sText));
scaner.next();
return expr;
}
case Scaner::SYMBOL:
{
Expression* /*only*/ expr =
(variableList.exists(sText))?
new SymbolExpression(
variableList.find(sText)):
new SymbolExpression(
consts.find2(sText));
scaner.next();
return expr;
}
case Scaner::LP:
{
scaner.next();
Expression* /*only*/ expr = parse_log(scaner);
if(scaner.getTokenType() != Scaner::RP)
throw Error("right paren missing");
scaner.next();
return expr;
}
default:
throw Error("syntax error");
}
return NULL;
}
Expression* /*only*/ Model::parse_mul(Scaner& scaner) const
{
Expression* a = parseValue(scaner);
for(;;)
{
Scaner::token_t token = scaner.getTokenType();
switch(token)
{
case Scaner::MUL:
scaner.next();
a = new FunctorExpression(
FunctorExpression::MUL,
a,
parseValue(scaner));
break;
case Scaner::DIV:
scaner.next();
a = new FunctorExpression(
FunctorExpression::DIV,
a,
parseValue(scaner));
break;
default:
return a;
}
}
assert(0);
return 0;
}
Expression* /*only*/ Model::parse_sum(Scaner& scaner) const
{
Expression* a = parse_mul(scaner);
for(;;)
{
Scaner::token_t token = scaner.getTokenType();
switch(token)
{
case Scaner::ADD:
scaner.next();
a = new FunctorExpression(
FunctorExpression::ADD,
a,
parse_mul(scaner));
break;
case Scaner::SUB:
scaner.next();
a = new FunctorExpression(
FunctorExpression::SUB,
a,
parse_mul(scaner));
break;
default:
return a;
}
}
assert(0);
return 0;
}
Expression* /*only*/ Model::parse_rel(Scaner& scaner) const
{
Expression* a = parse_sum(scaner);
for(;;)
{
Scaner::token_t token = scaner.getTokenType();
switch(token)
{
case Scaner::EQ:
scaner.next();
a = new FunctorExpression(
FunctorExpression::EQ,
a,
parse_sum(scaner));
break;
case Scaner::NEQ:
scaner.next();
a = new FunctorExpression(
FunctorExpression::NEQ,
a,
parse_sum(scaner));
break;
case Scaner::GT:
scaner.next();
a = new FunctorExpression(
FunctorExpression::GT,
a,
parse_sum(scaner));
break;
case Scaner::LT:
scaner.next();
a = new FunctorExpression(
FunctorExpression::LT,
a,
parse_sum(scaner));
break;
case Scaner::GTE:
scaner.next();
a = new FunctorExpression(
FunctorExpression::GTE,
a,
parse_sum(scaner));
break;
case Scaner::LTE:
scaner.next();
a = new FunctorExpression(
FunctorExpression::LTE,
a,
parse_sum(scaner));
break;
case Scaner::IIF1:
{
scaner.next();
Expression* /*only*/ exprValue1 =
parse_sum(scaner);
if(scaner.getTokenType() !=
Scaner::IIF2)
throw Error("Syntax Error, need ':'");
scaner.next();
Expression* /*only*/ exprValue2 =
parse_sum(scaner);
return new IIFExpression(
a,
exprValue1,
exprValue2);
}
break;
default:
return a;
}
}
assert(0);
return 0;
}
Expression* /*only*/ Model::parse_log(Scaner& scaner) const
{
Expression* /*only*/ a = parse_rel(scaner);
for(;;)
{
Scaner::token_t token = scaner.getTokenType();
switch(token)
{
case Scaner::AND:
scaner.next();
a = new FunctorExpression(
FunctorExpression::AND,
a,
parse_rel(scaner));
break;
case Scaner::OR:
scaner.next();
a = new FunctorExpression(
FunctorExpression::OR,
a,
parse_rel(scaner));
break;
default:
return a;
}
}
assert(0);
return 0;
}
Expression* /*only*/ Model::parseExpression(Scaner& scaner) const
{
try
{
Expression* /*only*/ e = parse_log(scaner);
return e;
}
catch(Error err)
{
String sErr =
String(err.asString()) +
",token type='" + (char)scaner.getTokenType() +
"' ,token='" + scaner.getTokenValue() +
"'\n" +
scaner.asString();
throw Error(sErr);
}
return 0;
}
bool Model::checkExpressionResult(const char* sExpression,int iExpected) const
{
Scaner scaner(sExpression);
if(!scaner.next())
throw Error("empty expression");
Expression* /*only*/ e = parseExpression(scaner);
int iResult = -9999;
try
{
iResult = e->eval();
}
catch(Error err)
{
cerr << err.asString().c_str() << "\n";
delete e;
return false;
}
cerr << "expression=";
e->show(cerr);
cerr << "\n";
delete e;
if(iResult != iExpected)
{
cerr << "expected: " << iExpected << ", got: " << iResult
<< "\n";
return false;
}
return true;
}
/*----------------------------------------------------------------------*/
#ifndef NDEBUG
#include <iostream.h>
void Model::selfTest()
{
/* expression compiler */
{
Model model;
model.add(new Const("a",10));
model.add(new Const("b",20));
assert(model.checkExpressionResult("a",10));
assert(model.checkExpressionResult("!b",0));
assert(model.checkExpressionResult("2+1",3));
assert(model.checkExpressionResult("1+2*3",7));
assert(model.checkExpressionResult("1 = 2",0));
assert(model.checkExpressionResult("1 != 2",1));
assert(model.checkExpressionResult("a = 10",1));
assert(model.checkExpressionResult("a != 10",0));
assert(model.checkExpressionResult("2/2",1));
assert(model.checkExpressionResult("2-2",0));
assert(model.checkExpressionResult("3>(2+0)",1));
assert(model.checkExpressionResult("a>=b-10",1));
assert(model.checkExpressionResult("a>b-10",0));
assert(model.checkExpressionResult("a*b=200",1));
assert(model.checkExpressionResult("1?32:33",32));
assert(model.checkExpressionResult("0?32:33",33));
assert(model.checkExpressionResult("0?32:33+1",34));
assert(model.checkExpressionResult("(0?32:33+1) = 34",1));
assert(model.checkExpressionResult("3-2-1",0));
assert(model.checkExpressionResult("20/2",10));
assert(model.checkExpressionResult("20/4",5));
assert(model.checkExpressionResult("20/2/5",2));
assert(model.checkExpressionResult("20/5/2",2));
assert(model.checkExpressionResult("20/(5/2)",10));
}
/* one variable */
{
Model model;
/* first define all used variables */
Variable* a = new Variable("a", 0, 10, 0);
model.variableList.add(a);
/* then all predicates */
model.add(new Predicate("a_lte_0",
new FunctorExpression(
FunctorExpression::LTE,
new SymbolExpression(a),
new ConstExpression(0))));
/* inputs with few triggers */
model.inputList.add(new Input("inc_a"));
Trigger* inc_a = new Trigger(
model.inputList, model.variableList);
inc_a->addAndInput("inc_a");
inc_a->addVariable("a",
new FunctorExpression(
FunctorExpression::ADD,
new SymbolExpression(a),
new ConstExpression(1)));
model.add(inc_a);
/* (a == 0) => (a <= 0) */
assert(model.computeAbstractState() == BitVector(1,"1"));
/* computed value will be written to register 1 */
assert(a->eval() == 0);
inc_a->compute();
assert(a->eval() == 0);
/* after switching to register 1 new value is visible */
Variable::select(1);
assert(a->eval() == 1);
/* (a == 1) => !(a <= 0) */
assert(model.computeAbstractState() == BitVector(1,"0"));
Variable::select(0);
/* second time the same operatrion - the same results */
inc_a->compute();
assert(a->eval() == 0);
Variable::select(1);
assert(a->eval() == 1);
assert(model.computeAbstractState() == BitVector(1,"0"));
Variable::select(0);
}
/* one variable, more complicated example */
{
Model model;
/* first define all used variables */
Variable* a = new Variable("a", 0, 4, 0);
model.variableList.add(a);
/* when error should be raised ? */
model.setErrorCondition(
new FunctorExpression(
FunctorExpression::LT,
new SymbolExpression(a),
new ConstExpression(0)));
/* then all predicates */
model.add(new Predicate("a_lte_0",
new FunctorExpression(
FunctorExpression::LTE,
new SymbolExpression(a),
new ConstExpression(0))));
model.add(new Predicate("a_gt_2",
new FunctorExpression(
FunctorExpression::GT,
new SymbolExpression(a),
new ConstExpression(2))));
/* inputs with few triggers */
model.inputList.add(new Input("inc_a"));
model.inputList.add(new Input("dec_a"));
/* incremenet variable by one */
Trigger* inc_a = new Trigger(
model.inputList, model.variableList);
assert(!inc_a->check());
inc_a->addAndInput("inc_a");
inc_a->addVariable("a",
new FunctorExpression(
FunctorExpression::ADD,
new SymbolExpression(a),
new ConstExpression(1)));
assert(inc_a->check());
model.add(inc_a);
/* decrement variable by one */
Trigger* dec_a = new Trigger(
model.inputList, model.variableList);
dec_a->addAndInput("dec_a");
dec_a->addVariable("a",
new FunctorExpression(
FunctorExpression::SUB,
new SymbolExpression(a),
new ConstExpression(1)));
model.add(dec_a);
/* (a == 0) => (a <= 0) AND !(a >= 2) */
assert(model.computeAbstractState().check("10"));
assert(a->eval() == 0);
inc_a->compute();
assert(a->eval() == 0);
Variable::select(1);
assert(a->eval() == 1);
assert(model.computeAbstractState().check("00"));
Variable::select(0);
model.saveCxl(cout);
/* including ERR state */
assert(model.checkStatesCount(4));
#define CHECK_TR(biS1, biS2, sCond)\
assert(model.checkIfExists(biS1, biS2, sCond));
CHECK_TR("", "", "inc_a*!dec_a + !inc_a*dec_a");
CHECK_TR("01", "", "!inc_a*dec_a");
CHECK_TR("10", "00", "inc_a*!dec_a");
CHECK_TR("00", "00", "inc_a*!dec_a + !inc_a*dec_a");
CHECK_TR("00", "10", "!inc_a*dec_a");
CHECK_TR("00", "01", "inc_a*!dec_a");
CHECK_TR("01", "00", "!inc_a*dec_a");
CHECK_TR("01", "01", "inc_a*!dec_a + !inc_a*dec_a");
CHECK_TR("10", "10", "0");
assert(model.checkTransitionsCount(9));
}
/* two variables */
{
Model model;
Const* MAX = new Const("MAX", 10);
model.add(MAX);
/* variables */
Variable* a = new Variable("a", 0, 10, 0);
model.variableList.add(a);
Variable* b = new Variable("b", 0, 10, 0);
model.variableList.add(b);
/* predicates */
model.add(new Predicate("a_lt_b",
new FunctorExpression(
FunctorExpression::LT,
new SymbolExpression(a),
new SymbolExpression(b))));
model.add(new Predicate("a_lte_0",
new FunctorExpression(
FunctorExpression::LTE,
new SymbolExpression(a),
new ConstExpression(0))));
model.inputList.add(new Input("inc_a"));
model.inputList.add(new Input("inc_b"));
model.inputList.add(new Input("dec_a"));
model.inputList.add(new Input("dec_b"));
{
Trigger* trg = new Trigger(
model.inputList, model.variableList);
trg->addAndInput("inc_a");
trg->addVariable("a",
new FunctorExpression(
FunctorExpression::ADD,
new SymbolExpression(a),
new ConstExpression(1)));
model.add(trg);
}
{
Trigger* trg = new Trigger(
model.inputList, model.variableList);
trg->addAndInput("inc_b");
trg->addVariable("b",
new FunctorExpression(
FunctorExpression::ADD,
new SymbolExpression(b),
new ConstExpression(1)));
model.add(trg);
}
{
Trigger* trg = new Trigger(
model.inputList, model.variableList);
trg->addAndInput("dec_a");
trg->addVariable("a",
new FunctorExpression(
FunctorExpression::SUB,
new SymbolExpression(a),
new ConstExpression(1)));
model.add(trg);
}
{
Trigger* trg = new Trigger(
model.inputList, model.variableList);
trg->addAndInput("dec_b");
trg->addVariable("b",
new FunctorExpression(
FunctorExpression::SUB,
new SymbolExpression(b),
new ConstExpression(1)));
model.add(trg);
}
assert(model.computeAbstractState() == BitVector(2,"01"));
model.saveCxl(cout);
/* check if global real states match */
{
int i = 0;
do{
++ i;
}
while(model.variableList.nextState());
assert(i == 11*11);
}
}
/* add predicates for EQ,NEQ operators */
{
Model model;
/* variables */
Variable* a = new Variable("a", 0, 10, 0);
model.variableList.add(a);
/* predicates */
model.add(new Predicate("a_eq_5",
new FunctorExpression(
FunctorExpression::EQ,
new SymbolExpression(a),
new ConstExpression(5))));
}
}
#endif /* NDEBUG */