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 */


(...) Nie ma bowiem łatwych odpowiedzi. Nie istnieje nic takiego jak najlepsze rozwiązanie - zarówno jeśli chodzi o narzędzia, jak i języki czy systemy operacyjne. Są jedynie systemy, które mogą być bardziej odpowiednie w konkretnych okolicznościach.

I tu właśnie do gry wchodzi pragmatyzm. Nie należy przywiązywać się do żadnej określonej metody, ale mieć na tyle rozległą wiedzę i doświadczenie, by w danej sytuacji wybrać dobre rozwiązanie. (...)

Andrew Hunt, David Thomas "Pragmatyczny Programista"