| /******************************************************************************* |
| * Copyright (c) 2016 CEA LIST. |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Arnault Lapitre (CEA LIST) arnault.lapitre@cea.fr |
| * - Initial API and implementation |
| ******************************************************************************/ |
| |
| #include "OmegaSolver.h" |
| |
| /* |
| * Here because "SolverDef.h" could define this macro |
| */ |
| #if defined( _AVM_SOLVER_OMEGA_ ) |
| |
| |
| #include <common/BF.h> |
| |
| #include <fml/executable/ExecutableForm.h> |
| #include <fml/executable/InstanceOfData.h> |
| |
| #include <fml/expression/AvmCode.h> |
| #include <fml/builtin/Boolean.h> |
| #include <fml/builtin/Character.h> |
| #include <fml/expression/ExpressionSimplifier.h> |
| #include <fml/numeric/Float.h> |
| #include <fml/numeric/Integer.h> |
| #include <fml/numeric/Rational.h> |
| |
| #include <fml/operator/Operator.h> |
| |
| #include <fml/runtime/ExecutionContext.h> |
| #include <fml/runtime/ExecutionData.h> |
| #include <fml/runtime/RuntimeForm.h> |
| #include <fml/runtime/RuntimeID.h> |
| |
| #include <fml/workflow/Query.h> |
| #include <fml/workflow/WObject.h> |
| |
| #include <sew/Configuration.h> |
| |
| |
| namespace sep |
| { |
| |
| /* |
| *************************************************************************** |
| * ID |
| *************************************************************************** |
| */ |
| std::string OmegaSolver::ID = "OMEGA"; |
| |
| std::string OmegaSolver::DESCRIPTION = "OMEGA 'Solver of quantifier-free " |
| "problems in Presburger Arithmetic at CS.UMD.EDU, version 2.1'"; |
| |
| avm_uint64_t OmegaSolver::SOLVER_SESSION_ID = 0; |
| |
| |
| |
| /** |
| * CONFIGURE |
| */ |
| bool OmegaSolver::configure( |
| Configuration & aConfiguration, WObject * wfFilterObject, |
| ListOfPairMachineData & listOfSelectedVariable) |
| { |
| isConfigureFlag = true; |
| |
| if( not SatSolver::configure( |
| aConfiguration, wfFilterObject, listOfSelectedVariable) ) |
| { |
| return( false ); |
| } |
| |
| setSelectedVariable( |
| aConfiguration.getMainExecutionData(), |
| listOfSelectedVariable ); |
| |
| return( true ); |
| } |
| |
| |
| /** |
| * RESET VARIABLE or PARAMETER |
| */ |
| void OmegaSolver::resetVariableTable() |
| { |
| getSelectedVariable().clear(); |
| |
| // Attention Omega compte de 1 à n |
| mTableOfVariableInstance.clear(); |
| mTableOfVariableInstance.append( NULL ); |
| |
| mTableOfVar4ParamInstance.clear(); |
| } |
| |
| |
| void OmegaSolver::resetParameterTable() |
| { |
| // Initialisation du tableau des parametres |
| mTableOfVariableID.clear(); |
| |
| VectorOfInstanceOfData::iterator it = mTableOfParameterInstance.begin(); |
| VectorOfInstanceOfData::iterator itEnd = mTableOfParameterInstance.end(); |
| for( ; it != itEnd ; ++it ) |
| { |
| (*it)->setMark(0); |
| } |
| mTableOfParameterInstance.clear(); |
| |
| // Attention: Omega compte de 1 à n |
| mTableOfParameterID.clear(); |
| omega::Variable_ID sentinelID; |
| mTableOfParameterID.push_back(sentinelID); |
| } |
| |
| |
| /** |
| * SET VARIABLE or PARAMETER |
| */ |
| void OmegaSolver::setSelectedVariable(const ExecutionData & anED) |
| { |
| resetVariableTable(); |
| |
| TableOfInstanceOfData::const_raw_iterator itData; |
| TableOfInstanceOfData::const_raw_iterator endData; |
| |
| TableOfRuntimeT::const_iterator itRF = anED.getTableOfRuntime().begin(); |
| TableOfRuntimeT::const_iterator endRF = anED.getTableOfRuntime().end(); |
| for( RuntimeID itRID ; itRF != endRF ; ++itRF ) |
| { |
| itRID = (*itRF)->getRID(); |
| |
| if( itRID.getExecutable()->hasData() || |
| itRID.getExecutable()->hasBuffer() ) |
| { |
| PairMachineData tmpListOfOffset( itRID ); |
| |
| itData = itRID.getExecutable()->getBasicData().begin(); |
| endData = itRID.getExecutable()->getBasicData().end(); |
| for( ; itData != endData ; ++itData ) |
| { |
| tmpListOfOffset.second().append( (itData) ); |
| |
| mTableOfVariableInstance.append( (itData) ); |
| |
| //AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_TRACE << TAB << "Omega Relation variable : " |
| // << str_header( *itData ) << std::endl; |
| //AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| } |
| |
| if( tmpListOfOffset.second().nonempty() ) |
| { |
| getSelectedVariable().append(tmpListOfOffset); |
| } |
| } |
| } |
| } |
| |
| |
| void OmegaSolver::setSelectedVariable(const ExecutionData & anED, |
| ListOfPairMachineData & listOfSelectedVariable) |
| { |
| resetVariableTable(); |
| |
| SatSolver::setSelectedVariable(listOfSelectedVariable); |
| |
| ListOfPairMachineData::iterator itPairMachineData = listOfSelectedVariable.begin(); |
| ListOfPairMachineData::iterator endPairMachineData = listOfSelectedVariable.end(); |
| for( ; itPairMachineData != endPairMachineData ; ++itPairMachineData ) |
| { |
| if( (*itPairMachineData).second().nonempty() ) |
| { |
| ListOfInstanceOfData::iterator itVar = (*itPairMachineData).second().begin(); |
| ListOfInstanceOfData::iterator endVar = (*itPairMachineData).second().end(); |
| |
| for( ; itVar != endVar ; ++itVar ) |
| { |
| mTableOfVariableInstance.append( *itVar ); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << "Omega Relation variable : " |
| << str_header( *itVar ) << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| } |
| } |
| } |
| } |
| |
| |
| void OmegaSolver::setSelectedVariable(const ExecutionData & anED, |
| ListOfInstanceOfData & aLisOfAdditionnalVar) |
| { |
| setSelectedVariable(anED); |
| |
| mTableOfVar4ParamInstance.append(aLisOfAdditionnalVar); |
| } |
| |
| |
| |
| /** |
| * PROVER |
| */ |
| bool OmegaSolver::isSubSet( |
| const ExecutionContext & newEC, const ExecutionContext & oldEC) |
| { |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| oldEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation oldRelation( mTableOfVariableInstance.size() - 1 ); |
| toRelation(oldEC.refExecutionData(), oldRelation); |
| |
| |
| if( ((& newEC) != mCacheForNewEC) || isCurrentPathScope() ) |
| { |
| mCacheForNewEC = (& newEC); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| newEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation newRelation( mTableOfVariableInstance.size() - 1 ); |
| toRelation(newEC.refExecutionData(), newRelation); |
| |
| mCacheForNewRelation = newRelation; |
| |
| |
| return( isSubSet(newRelation, oldRelation) ); |
| } |
| else |
| { |
| omega::Relation newRelation = mCacheForNewRelation; |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << "ED cpy : " |
| << newRelation.print_with_subs_to_string() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| |
| return( isSubSet(newRelation, oldRelation) ); |
| } |
| } |
| |
| |
| bool OmegaSolver::isEqualSet( |
| const ExecutionContext & newEC, const ExecutionContext & oldEC) |
| { |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| oldEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation oldRelation( mTableOfVariableInstance.size() - 1 ); |
| toRelation(oldEC.refExecutionData(), oldRelation); |
| |
| |
| if( (& newEC) != mCacheForNewEC ) |
| { |
| mCacheForNewEC = (& newEC); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| newEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation newRelation( mTableOfVariableInstance.size() - 1 ); |
| toRelation(newEC.refExecutionData(), newRelation); |
| |
| mCacheForNewRelation = newRelation; |
| |
| |
| return( isEqualSet(newRelation, oldRelation) ); |
| } |
| else |
| { |
| omega::Relation newRelation = mCacheForNewRelation; |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << "ED cpy : " |
| << newRelation.print_with_subs_to_string() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| return( isEqualSet(newRelation, oldRelation) ); |
| } |
| } |
| |
| |
| bool OmegaSolver::isEmptyIntersection( |
| const ExecutionContext & newEC, const ExecutionContext & oldEC) |
| { |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| oldEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation oldRelation( mTableOfVariableInstance.size() - 1 + |
| mTableOfVar4ParamInstance.size() ); |
| setParameterUple(oldRelation); |
| toRelation(oldEC.refExecutionData(), oldRelation); |
| |
| |
| if( (& newEC) != mCacheForNewEC ) |
| { |
| mCacheForNewEC = (& newEC); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| newEC.traceDefault(AVM_OS_TRACE << TAB); |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // Creation de la relation Omega |
| // Attention: Omega compte de 1 à n |
| omega::Relation newRelation( mTableOfVariableInstance.size() - 1 + |
| mTableOfVar4ParamInstance.size() ); |
| setParameterUple(newRelation); |
| toRelation(newEC.refExecutionData(), newRelation); |
| |
| mCacheForNewRelation = newRelation; |
| |
| |
| return( isEmptyIntersection(newRelation, oldRelation) ); |
| } |
| else |
| { |
| omega::Relation newRelation = mCacheForNewRelation; |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << "ED cpy : " |
| << newRelation.print_with_subs_to_string() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| return( isEmptyIntersection(newRelation, oldRelation) ); |
| } |
| } |
| |
| |
| |
| SolverDef::SATISFIABILITY_RING OmegaSolver::isSatisfiable(const BF & aCondition) |
| { |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << "OmegaSolver::isSatisfiable(...) " |
| ":" << SOLVER_SESSION_ID << ">" << std::endl |
| << "\t" << aCondition.str() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| BF valCondition = ExpressionSimplifier::simplif( aCondition ); |
| |
| // Initialisation du tableau des parametres |
| mTableOfVariableID.clear(); |
| mTableOfParameterInstance.clear(); |
| |
| // Attention: Omega compte de 1 à n |
| mTableOfParameterID.clear(); |
| omega::Variable_ID sentinelID; |
| mTableOfParameterID.push_back(sentinelID); |
| |
| omega::Relation aRelation(0); |
| |
| // Creation du quantificateur Exist associe aux parametres |
| registerExistQuantifier = aRelation.add_and()->add_exists(); |
| omega::F_And * andRootNode = registerExistQuantifier->add_and(); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_COUT << "aCondition : " << aCondition->str() << std::flush; |
| AVM_OS_TRACE << "v::isSatisfiable(...) " |
| ":" << SOLVER_SESSION_ID << ">" << std::endl; |
| AVM_OS_TRACE << TAB << aCondition.str() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| toConjonction(andRootNode, valCondition); |
| |
| // Simplification de la Relation |
| aRelation.finalize(); |
| |
| aRelation.simplify(2,4); |
| |
| |
| //AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_TRACE << TAB << "the Relation : " |
| // << newRelation.print_with_subs_to_string() << std::endl; |
| //AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| |
| SolverDef::SATISFIABILITY_RING satisfiability = |
| aRelation.is_satisfiable() ? |
| SolverDef::SATISFIABLE : SolverDef::UNSATISFIABLE; |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << "result :" << SOLVER_SESSION_ID << "> " |
| << SolverDef::strSatisfiability(satisfiability) << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| aRelation = omega::Relation::Null(); |
| |
| resetParameterTable(); |
| |
| return( satisfiability ); |
| } |
| |
| |
| /** |
| * TOOLS |
| */ |
| bool OmegaSolver::isSubSet(omega::Relation & Rel1, omega::Relation & Rel2) |
| { |
| return( Must_Be_Subset(Rel1, Rel2) ); |
| } |
| |
| bool OmegaSolver::isEqualSet(omega::Relation & Rel1, omega::Relation & Rel2) |
| { |
| return( Must_Be_Subset(copy(Rel1), copy(Rel2)) && Must_Be_Subset(Rel2, Rel1) ); |
| } |
| |
| |
| bool OmegaSolver::isEmptyIntersection(omega::Relation & Rel1, omega::Relation & Rel2) |
| { |
| omega::Relation interRelation = Intersection(Rel2, Rel1); |
| |
| bool isEmpty = (! interRelation.is_satisfiable() ); |
| |
| interRelation = omega::Relation::Null(); |
| |
| return( isEmpty ); |
| } |
| |
| |
| bool OmegaSolver::setParameterUple(omega::Relation & aRelation) |
| { |
| std::ostringstream oss; |
| |
| VectorOfInstanceOfData::iterator it = mTableOfVar4ParamInstance.begin(); |
| VectorOfInstanceOfData::iterator itEnd = mTableOfVar4ParamInstance.end(); |
| avm_offset_t paramOffset = 1; |
| for( ; it != itEnd ; ++it , ++paramOffset ) |
| { |
| oss.str(""); |
| oss << "VP_" << paramOffset; |
| |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << oss.str() << " << " << (*it)->getFullyQualifiedNameID() |
| << " >> --> is a Symbolic Parameter" << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| (*it)->setOffset(mTableOfParameterID.size()); |
| mTableOfParameterInstance.push_back( (*it) ); |
| |
| omega::Variable_ID aVarID = aRelation.set_var(paramOffset); |
| mTableOfParameterID.push_back( aVarID ); |
| aRelation.name_set_var(paramOffset, oss.str().c_str()); |
| } |
| |
| return( true ); |
| } |
| |
| bool OmegaSolver::toRelation( |
| const ExecutionData & anED, omega::Relation & aRelation) |
| { |
| // Creation du quantificateur Exist associe aux parametres |
| registerExistQuantifier = aRelation.add_and()->add_exists(); |
| omega::F_And * andRootNode = registerExistQuantifier->add_and(); |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << TAB << "aPC : " << anED.getPathCondition().str() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| toConjonction(andRootNode, anED.getPathCondition()); |
| |
| std::ostringstream oss; |
| |
| ListOfPairMachineData::iterator itPairMachineData = getSelectedVariable().begin(); |
| ListOfPairMachineData::iterator endPairMachineData = getSelectedVariable().end(); |
| avm_offset_t varOffset = mTableOfVar4ParamInstance.size() + 1; |
| for( ; itPairMachineData != endPairMachineData ; ++itPairMachineData ) |
| { |
| if( (*itPairMachineData).second().nonempty() ) |
| { |
| ListOfInstanceOfData::iterator itVar = (*itPairMachineData).second().begin(); |
| ListOfInstanceOfData::iterator endVar = (*itPairMachineData).second().end(); |
| |
| const RuntimeForm & aRF = anED.getRuntime( (*itPairMachineData).first() ); |
| |
| for( ; itVar != endVar ; ++itVar , ++varOffset ) |
| { |
| oss.str(""); |
| oss << "V_" << varOffset; |
| |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| // AVM_OS_COUT << oss.str() << " <-- " << aRF.getData(*itVar).str() << std::endl; |
| AVM_OS_TRACE << TAB << oss.str() << " <-- " |
| << aRF.getData(*itVar).str() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| |
| |
| omega::Variable_ID aVarID = aRelation.set_var(varOffset); |
| mTableOfVariableID.push_back(aVarID); |
| aRelation.name_set_var(varOffset, oss.str().c_str()); |
| |
| omega::EQ_Handle eqNode = andRootNode->add_EQ(); |
| eqNode.update_coef(aVarID, -1); |
| |
| if( (*itVar)->isTypedBoolean() ) |
| { |
| if( aRF.getData(*itVar).isEqualTrue() ) |
| { |
| eqNode.update_const( 1 ); |
| } |
| else if( aRF.getData(*itVar).isEqualFalse() ) |
| { |
| eqNode.update_const( 0 ); |
| } |
| else |
| { |
| eqNode.update_coef(aVarID, 1); |
| } |
| } |
| else |
| { |
| toConstraint(eqNode, 1, aRF.getData(*itVar)); |
| } |
| } |
| } |
| } |
| |
| // Simplification de la Relation |
| aRelation.finalize(); |
| |
| |
| //AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_COUT << "FINALIZE : "; |
| // aRelation.prefix_print(); AVM_OS_COUT << std::flush; |
| //AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| |
| aRelation.simplify(2,4); |
| |
| |
| AVM_IF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| // AVM_OS_COUT << "SIMPLIF : " << std::endl |
| // << "ED : " << aRelation.print_with_subs_to_string() << std::endl; |
| AVM_OS_TRACE << TAB << "ED : " |
| << aRelation.print_with_subs_to_string() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( HIGH , SMT_SOLVING ) |
| |
| |
| resetParameterTable(); |
| |
| return( true ); |
| } |
| |
| |
| omega::Variable_ID OmegaSolver::getParameterID(InstanceOfData * aParameter) |
| { |
| if( aParameter->getMark() == 0 ) |
| { |
| // if( aParameter->isTypedBoolean() ) |
| // { |
| // } |
| // else if( aParameter->isTypedInteger() ) |
| // { |
| // } |
| // else if( aParameter->isTypedRational() ) |
| // { |
| // } |
| // else if( aParameter->isTypedFloat() ) |
| // { |
| // } |
| // else if( aParameter->isTypedReal() ) |
| // { |
| // } |
| // else |
| // { |
| // AVM_OS_ERROR_ALERT << "Unexpected an instance type << " |
| // << aParameter->getFullyQualifiedNameID() << " : " << paramFormType->getFullyQualifiedNameID() |
| // << ">> !!!" |
| // << SEND_ALERT; |
| // } |
| |
| aParameter->setMark(mTableOfParameterID.size()); |
| mTableOfParameterInstance.push_back(aParameter); |
| |
| std::ostringstream oss; |
| oss.str(""); |
| oss << "P_" << mTableOfParameterID.size(); |
| |
| |
| //AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_COUT << "\t" << oss.str() << " <- " << aParameter->getFullyQualifiedNameID() << std::endl; |
| // AVM_OS_TRACE << TAB << oss.str() << " <- " << aParameter->getFullyQualifiedNameID() << std::endl; |
| //AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| mTableOfParameterID.push_back( |
| registerExistQuantifier->declare( oss.str().c_str() ) ); |
| } |
| |
| //return( mTableOfParameterID[ aParameter->getMark() ] ); |
| |
| omega::Variable_ID varID = mTableOfParameterID[ aParameter->getMark() ]; |
| |
| |
| //AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| // AVM_OS_TRACE << TAB << "varID: "; |
| // const char * c = varID->char_name(); |
| // while( isalnum(*c) ) { AVM_OS_TRACE << *c; ++c; } |
| // AVM_OS_TRACE << TAB << " <- " << str_header( aParameter ) << std::endl; |
| //AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| return( varID ); |
| } |
| |
| |
| void OmegaSolver::toConjonction(omega::F_And * andNode, const BF & exprForm) |
| { |
| AVM_OS_ASSERT_FATAL_NULL_SMART_POINTER_EXIT( exprForm ) << "expression !!!" |
| << SEND_EXIT; |
| |
| switch( exprForm.classKind() ) |
| { |
| case FORM_AVMCODE_KIND: |
| { |
| AvmCode * aCode = exprForm.to_ptr< AvmCode >(); |
| |
| switch( aCode->getAvmOpCode() ) |
| { |
| case AVM_OPCODE_EQ: // - first + second == 0 |
| { |
| BFCode exprCond; |
| avm_integer_t exprInt; |
| |
| if( aCode->first().is< AvmCode >() ) |
| { |
| exprCond = aCode->first().bfCode(); |
| |
| if( aCode->second().isInteger() ) |
| { |
| exprInt = aCode->second().toInteger(); |
| } |
| } |
| else if( aCode->first().isInteger() ) |
| { |
| exprInt = aCode->first().toInteger(); |
| |
| if( aCode->second().is< AvmCode >() ) |
| { |
| exprCond = aCode->second().bfCode(); |
| } |
| } |
| |
| if( exprCond.valid() ) |
| { |
| switch( exprCond->getAvmOpCode() ) |
| { |
| case AVM_OPCODE_EQ: |
| case AVM_OPCODE_NEQ: |
| case AVM_OPCODE_LT: |
| case AVM_OPCODE_LTE: |
| case AVM_OPCODE_GT: |
| case AVM_OPCODE_GTE: |
| case AVM_OPCODE_NOT: |
| case AVM_OPCODE_AND: |
| case AVM_OPCODE_NAND: |
| case AVM_OPCODE_XAND: |
| case AVM_OPCODE_OR: |
| case AVM_OPCODE_NOR: |
| case AVM_OPCODE_XOR: |
| case AVM_OPCODE_XNOR: |
| { |
| omega::F_And * andEQ = andNode; |
| |
| if( exprInt == 0 ) |
| { |
| andEQ = andNode->add_not()->add_and(); |
| } |
| |
| toConjonction(andEQ, exprCond); |
| |
| return; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| } |
| else |
| { |
| omega::EQ_Handle eqNode = andNode->add_EQ(); |
| toConstraint(eqNode, -1, aCode->first()); |
| toConstraint(eqNode, 1, aCode->second()); |
| } |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_NEQ: // NOT( - first + second == 0 ) |
| { |
| BFCode exprCond; |
| avm_integer_t exprInt; |
| |
| if( aCode->first().is< AvmCode >() ) |
| { |
| exprCond = aCode->first().bfCode(); |
| |
| if( aCode->second().isInteger() ) |
| { |
| exprInt = aCode->second().toInteger(); |
| } |
| } |
| else if( aCode->first().isInteger() ) |
| { |
| exprInt = aCode->first().toInteger(); |
| |
| if( aCode->second().is< AvmCode >() ) |
| { |
| exprCond = aCode->second().bfCode(); |
| } |
| } |
| |
| if( exprCond.valid() ) |
| { |
| switch( exprCond->getAvmOpCode() ) |
| { |
| case AVM_OPCODE_EQ: |
| case AVM_OPCODE_NEQ: |
| case AVM_OPCODE_LT: |
| case AVM_OPCODE_LTE: |
| case AVM_OPCODE_GT: |
| case AVM_OPCODE_GTE: |
| case AVM_OPCODE_NOT: |
| case AVM_OPCODE_AND: |
| case AVM_OPCODE_NAND: |
| case AVM_OPCODE_XAND: |
| case AVM_OPCODE_OR: |
| case AVM_OPCODE_NOR: |
| case AVM_OPCODE_XOR: |
| case AVM_OPCODE_XNOR: |
| { |
| omega::F_And * andEQ = andNode; |
| |
| if( exprInt != 0 ) |
| { |
| andEQ = andNode->add_not()->add_and(); |
| } |
| |
| toConjonction(andEQ, exprCond); |
| |
| return; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| } |
| else |
| { |
| omega::EQ_Handle eqNode = |
| andNode->add_not()->add_and()->add_EQ(); |
| |
| toConstraint(eqNode, -1, aCode->first()); |
| toConstraint(eqNode, 1, aCode->second()); |
| } |
| |
| break; |
| } |
| |
| |
| |
| case AVM_OPCODE_LT: // - first + second - 1 >= 0 |
| { |
| omega::GEQ_Handle geqNode = andNode->add_GEQ(); |
| toConstraint(geqNode, -1, aCode->first()); |
| toConstraint(geqNode, 1, aCode->second()); |
| geqNode.update_const(-1); |
| |
| break; |
| } |
| |
| case AVM_OPCODE_LTE: // - first + second >= 0 |
| { |
| omega::GEQ_Handle geqNode = andNode->add_GEQ(); |
| toConstraint(geqNode, -1, aCode->first()); |
| toConstraint(geqNode, 1, aCode->second()); |
| |
| break; |
| } |
| |
| case AVM_OPCODE_GT: // first - second - 1 >= 0 |
| { |
| omega::GEQ_Handle geqNode = andNode->add_GEQ(); |
| toConstraint(geqNode, 1, aCode->first()); |
| toConstraint(geqNode, -1, aCode->second()); |
| geqNode.update_const(-1); |
| |
| break; |
| } |
| |
| case AVM_OPCODE_GTE: // first - second >= 0 |
| { |
| BFCode exprCond; |
| avm_integer_t exprInt; |
| |
| if( aCode->first().is< AvmCode >() ) |
| { |
| exprCond = aCode->first().bfCode(); |
| |
| if( aCode->second().isInteger() ) |
| { |
| exprInt = aCode->second().toInteger(); |
| } |
| } |
| else if( aCode->first().isInteger() ) |
| { |
| exprInt = aCode->first().toInteger(); |
| |
| if( aCode->second().is< AvmCode >() ) |
| { |
| exprCond = aCode->second().bfCode(); |
| } |
| } |
| |
| if( exprCond.valid() ) |
| { |
| switch( exprCond->getAvmOpCode() ) |
| { |
| case AVM_OPCODE_EQ: |
| case AVM_OPCODE_NEQ: |
| case AVM_OPCODE_LT: |
| case AVM_OPCODE_LTE: |
| case AVM_OPCODE_GT: |
| case AVM_OPCODE_GTE: |
| case AVM_OPCODE_NOT: |
| case AVM_OPCODE_AND: |
| case AVM_OPCODE_NAND: |
| case AVM_OPCODE_XAND: |
| case AVM_OPCODE_OR: |
| case AVM_OPCODE_NOR: |
| case AVM_OPCODE_XOR: |
| case AVM_OPCODE_XNOR: |
| { |
| omega::F_And * andEQ = andNode; |
| |
| if( exprInt < 1 ) |
| { |
| andEQ = andNode->add_not()->add_and(); |
| } |
| |
| toConjonction(andEQ, exprCond); |
| |
| return; |
| } |
| |
| default: |
| { |
| break; |
| } |
| } |
| } |
| else |
| { |
| omega::GEQ_Handle geqNode = andNode->add_GEQ(); |
| toConstraint(geqNode, 1, aCode->first()); |
| toConstraint(geqNode, -1, aCode->second()); |
| } |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_CONTAINS: |
| { |
| BuiltinCollection * aCollection = |
| aCode->first().to_ptr< BuiltinCollection >(); |
| |
| if( aCollection->singleton() ) |
| { |
| omega::EQ_Handle eqNode = andNode->add_EQ(); |
| toConstraint(eqNode, -1, aCollection->at(0)); |
| toConstraint(eqNode, 1, aCode->second()); |
| } |
| else if( aCollection->populated() ) |
| { |
| omega::F_Or * orNode = andNode->add_or(); |
| |
| std::size_t colSize = aCollection->size(); |
| for( std::size_t offset = 0 ; offset < colSize ; ++offset ) |
| { |
| omega::EQ_Handle eqNode = orNode->add_and()->add_EQ(); |
| toConstraint(eqNode, -1, aCollection->at(offset)); |
| toConstraint(eqNode, 1, aCode->second()); |
| } |
| } |
| else |
| { |
| andNode->add_EQ().update_const( |
| exprForm.to_ptr< Boolean >()->getValue() ? 0 : 1 ); |
| } |
| break; |
| } |
| |
| |
| case AVM_OPCODE_NOT: |
| { |
| if( aCode->first().is< InstanceOfData >() ) // arg0 == 0 |
| { |
| andNode->add_EQ().update_coef(getParameterID( |
| aCode->first().to_ptr< InstanceOfData >()), 1); |
| } |
| else // NOT( arg0 ) |
| { |
| toConjonction(andNode->add_not()->add_and(), aCode->first()); |
| } |
| |
| break; |
| } |
| |
| case AVM_OPCODE_AND: // AND args |
| { |
| AvmCode::iterator it = aCode->begin(); |
| AvmCode::iterator itEnd = aCode->end(); |
| for( ; it != itEnd ; ++it ) |
| { |
| toConjonction(andNode, *it); |
| } |
| |
| break; |
| } |
| |
| case AVM_OPCODE_NAND: // NAND first second |
| { |
| omega::F_And * nandNode = andNode->add_not()->add_and(); |
| toConjonction(nandNode, aCode->first()); |
| toConjonction(nandNode, aCode->second()); |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_XAND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported boolean expression << XAND >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_OR: // OR args |
| { |
| omega::F_Or * orNode = andNode->add_or(); |
| AvmCode::iterator it = aCode->begin(); |
| AvmCode::iterator itEnd = aCode->end(); |
| for( ; it != itEnd ; ++it ) |
| { |
| toConjonction(orNode->add_and(), *it); |
| } |
| |
| break; |
| } |
| |
| case AVM_OPCODE_NOR: // NOR first second |
| { |
| omega::F_And * norNode = andNode->add_not()->add_or()->add_and(); |
| toConjonction(norNode, aCode->first()); |
| toConjonction(norNode, aCode->second()); |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_XOR: |
| case AVM_OPCODE_XNOR: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported boolean expression " |
| "<< XOR | XNOR >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| |
| case AVM_OPCODE_PLUS: |
| case AVM_OPCODE_UMINUS: |
| case AVM_OPCODE_MINUS: |
| case AVM_OPCODE_MULT: |
| case AVM_OPCODE_DIV: |
| case AVM_OPCODE_POW: |
| case AVM_OPCODE_MOD: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected arithmetic expression Operator !!!" |
| << SEND_EXIT; |
| break; |
| } |
| |
| |
| default: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected BASEFORM KIND for execution !!!\n" |
| << aCode->toString( AVM_TAB1_INDENT ) |
| << SEND_EXIT; |
| break; |
| } |
| } |
| |
| break; |
| } |
| |
| case FORM_INSTANCE_DATA_KIND: |
| { |
| // andNode->add_not()->add_and()->add_EQ().update_coef( |
| // getParameterID( exprForm.to_ptr< InstanceOfData >() ) ); |
| |
| omega::EQ_Handle eqNode = andNode->add_and()->add_EQ(); |
| eqNode.update_coef( getParameterID(exprForm.to_ptr< InstanceOfData >()), 1); |
| eqNode.update_const(-1); |
| |
| break; |
| } |
| |
| |
| case FORM_BUILTIN_BOOLEAN_KIND: // true <=> (0 == 0) ; false <=> (1 == 0) |
| { |
| andNode->add_EQ().update_const( |
| exprForm.to_ptr< Boolean >()->getValue() ? 0 : 1 ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_INTEGER_KIND: |
| { |
| andNode->add_EQ().update_const( |
| exprForm.to_ptr< Integer >()->isZero() ? 0 : 1 ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_RATIONAL_KIND: |
| { |
| andNode->add_EQ().update_const( |
| exprForm.to_ptr< Rational >()->isZero() ? 0 : 1 ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_FLOAT_KIND: |
| { |
| andNode->add_EQ().update_const( |
| exprForm.to_ptr< Float >()->isZero() ? 0 : 1 ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_CHARACTER_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in Character !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_STRING_KIND: |
| case FORM_BUILTIN_QUALIFIED_IDENTIFIER_KIND: |
| case FORM_BUILTIN_IDENTIFIER_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in String " |
| "< STRING | UFI | IDENTIFIER > or Operator !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| case FORM_OPERATOR_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported Operator expression !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| |
| case FORM_INSTANCE_BUFFER_KIND: |
| case FORM_INSTANCE_CONNECTOR_KIND: |
| case FORM_INSTANCE_MACHINE_KIND: |
| case FORM_INSTANCE_PORT_KIND: |
| |
| default: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected BASEFORM KIND as expression << " |
| << exprForm.str() << " >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| } |
| } |
| |
| |
| void OmegaSolver::toConstraint(omega::Constraint_Handle & constraintNode, |
| int coefficient, const BF & exprForm) |
| { |
| AVM_OS_ASSERT_FATAL_NULL_SMART_POINTER_EXIT( exprForm ) << "expression !!!" |
| << SEND_EXIT; |
| |
| switch( exprForm.classKind() ) |
| { |
| case FORM_AVMCODE_KIND: |
| { |
| AvmCode * aCode = exprForm.to_ptr< AvmCode >(); |
| |
| switch( aCode->getAvmOpCode() ) |
| { |
| case AVM_OPCODE_PLUS: |
| { |
| AvmCode::iterator it = aCode->begin(); |
| AvmCode::iterator itEnd = aCode->end(); |
| for( ; it != itEnd ; ++it ) |
| { |
| toConstraint(constraintNode, coefficient, *it); |
| } |
| |
| break; |
| } |
| |
| case AVM_OPCODE_UMINUS: |
| { |
| toConstraint(constraintNode, - coefficient, aCode->first()); |
| |
| break; |
| } |
| |
| case AVM_OPCODE_MINUS: |
| { |
| toConstraint(constraintNode, coefficient, aCode->first()); |
| toConstraint(constraintNode, - coefficient, aCode->second()); |
| |
| break; |
| } |
| |
| case AVM_OPCODE_MULT: |
| { |
| if( aCode->size() == 2 ) |
| { |
| if( aCode->first().isInteger() ) |
| { |
| coefficient = coefficient * aCode->first().toInteger(); |
| toConstraint(constraintNode, coefficient, aCode->second()); |
| } |
| else if( aCode->second().isInteger() ) |
| { |
| coefficient = coefficient * aCode->second().toInteger(); |
| toConstraint(constraintNode, coefficient, aCode->first()); |
| } |
| else |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported non linear multiplication !!!" |
| << SEND_EXIT; |
| } |
| } |
| else |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported non binary multiplication !!!" |
| << SEND_EXIT; |
| } |
| |
| break; |
| } |
| |
| case AVM_OPCODE_DIV: |
| case AVM_OPCODE_POW: |
| case AVM_OPCODE_MOD: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported arithmetic expression Operator " |
| "<< DIV | EXP | MOD >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| case AVM_OPCODE_EQ: |
| case AVM_OPCODE_NEQ: |
| case AVM_OPCODE_LT: |
| case AVM_OPCODE_LTE: |
| case AVM_OPCODE_GT: |
| case AVM_OPCODE_GTE: |
| case AVM_OPCODE_NOT: |
| case AVM_OPCODE_AND: |
| case AVM_OPCODE_NAND: |
| case AVM_OPCODE_XAND: |
| case AVM_OPCODE_OR: |
| case AVM_OPCODE_NOR: |
| case AVM_OPCODE_XOR: |
| case AVM_OPCODE_XNOR: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected boolean expression Operator << " |
| << aCode->str() << " >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| default: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected BASEFORM KIND for execution\n" |
| << aCode->toString( AVM_TAB1_INDENT ) |
| << SEND_EXIT; |
| break; |
| } |
| } |
| |
| break; |
| } |
| |
| case FORM_INSTANCE_DATA_KIND: |
| { |
| constraintNode.update_coef( |
| getParameterID(exprForm.to_ptr< InstanceOfData >()) , |
| coefficient ); |
| |
| break; |
| } |
| |
| |
| case FORM_BUILTIN_BOOLEAN_KIND: // true <=> 1 ; false <=> 0 |
| { |
| constraintNode.update_const( |
| ( exprForm.to_ptr< Boolean >()->getValue() ) ? 1 : 0 ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_INTEGER_KIND: |
| { |
| constraintNode.update_const( |
| coefficient * exprForm.to_ptr< Integer >()->toInteger() ); |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_RATIONAL_KIND: |
| { |
| AVM_OS_WARNING_ALERT << "Unsupported builtin Rational !!!" |
| << SEND_ALERT; |
| |
| if( exprForm.to_ptr< Rational >()->isInteger() ) |
| { |
| constraintNode.update_const( |
| coefficient * exprForm.to_ptr< Rational >()->toInteger() ); |
| } |
| else |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in Rational !!!" |
| << SEND_EXIT; |
| } |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_FLOAT_KIND: |
| { |
| AVM_OS_WARNING_ALERT << "Unsupported built-in Float !!!" |
| << SEND_ALERT; |
| |
| if( exprForm.to_ptr< Float >()->isInteger() ) |
| { |
| constraintNode.update_const( |
| coefficient * exprForm.to_ptr< Float >()->toInteger() ); |
| } |
| else |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in Float !!!" |
| << SEND_EXIT; |
| } |
| |
| break; |
| } |
| |
| |
| case FORM_RUNTIME_ID_KIND: |
| { |
| constraintNode.update_const( coefficient * exprForm.bfRID().getRid() ); |
| |
| break; |
| } |
| |
| |
| case FORM_BUILTIN_CHARACTER_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in Character !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| case FORM_BUILTIN_STRING_KIND: |
| case FORM_BUILTIN_QUALIFIED_IDENTIFIER_KIND: |
| case FORM_BUILTIN_IDENTIFIER_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported built-in String " |
| "< STRING | UFI | IDENTIFIER > or Operator !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| case FORM_OPERATOR_KIND: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unsupported Operator expression !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| |
| |
| case FORM_INSTANCE_BUFFER_KIND: |
| case FORM_INSTANCE_CONNECTOR_KIND: |
| case FORM_INSTANCE_MACHINE_KIND: |
| case FORM_INSTANCE_PORT_KIND: |
| |
| default: |
| { |
| AVM_OS_FATAL_ERROR_EXIT |
| << "Unexpected BASEFORM KIND as expression << " |
| << exprForm.str() << " >> !!!" |
| << SEND_EXIT; |
| |
| break; |
| } |
| } |
| } |
| |
| |
| /** |
| * SOLVER |
| */ |
| bool OmegaSolver::solveImpl(const BF & aCondition, |
| BFVector & dataVector, BFVector & valuesVector) |
| { |
| AVM_IF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| AVM_OS_TRACE << "OmegaSolver::solve(...) " |
| ":" << SOLVER_SESSION_ID << ">" << std::endl |
| << "\t" << aCondition.str() << std::endl; |
| AVM_ENDIF_DEBUG_LEVEL_FLAG( MEDIUM , SMT_SOLVING ) |
| |
| // !!!! NE FAIT RIEN POUR L'INSTANT |
| |
| return(false); |
| } |
| |
| |
| } |
| |
| |
| #endif /* _AVM_SOLVER_OMEGA_ */ |