1 Commits

Author SHA1 Message Date
53c96f0fe7 Version bump for release 0.1.9 RC 1 2018-04-20 16:39:54 +02:00
12 changed files with 400 additions and 577 deletions

View File

@@ -1,13 +1,11 @@
# Change Log # Change Log
## 0.1.9 RC 2 (2018-04-21) ## 0.1.9 RC 1 (2018-04-20)
### Features ### Features
* optional detection of integer variables and integer predicate parameters * optional detection of integer variables and integer predicate parameters
* command-line option `--detect-integers` to enable integer variable detection * command-line option `--detect-integers` to enable integer variable detection
* support for declaring functions integer with the `#external` directive
* new simplification rule applying to integer variables
## 0.1.8 (2018-04-20) ## 0.1.8 (2018-04-20)

View File

@@ -72,7 +72,7 @@ int main(int argc, char **argv)
if (version) if (version)
{ {
std::cout << "anthem version 0.1.9-rc.2" << std::endl; std::cout << "anthem version 0.1.9-rc.1" << std::endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -3,6 +3,7 @@
#include <anthem/ASTForward.h> #include <anthem/ASTForward.h>
#include <anthem/Domain.h> #include <anthem/Domain.h>
#include <anthem/Tristate.h>
namespace anthem namespace anthem
{ {

View File

@@ -1,262 +0,0 @@
#ifndef __ANTHEM__ARITHMETICS_H
#define __ANTHEM__ARITHMETICS_H
#include <anthem/Utils.h>
namespace anthem
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Arithmetics
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct DefaultVariableDomainAccessor
{
ast::Domain operator()(const ast::Variable &variable)
{
return variable.declaration->domain;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template <class VariableDomainAccessor = DefaultVariableDomainAccessor, class... Arguments>
EvaluationResult isArithmetic(const ast::Term &term, Arguments &&...);
////////////////////////////////////////////////////////////////////////////////////////////////////
template <class VariableDomainAccessor = DefaultVariableDomainAccessor>
struct IsTermArithmeticVisitor
{
template <class... Arguments>
static EvaluationResult visit(const ast::BinaryOperation &binaryOperation, Arguments &&... arguments)
{
const auto isLeftArithemtic = isArithmetic<VariableDomainAccessor>(binaryOperation.left, std::forward<Arguments>(arguments)...);
const auto isRightArithmetic = isArithmetic<VariableDomainAccessor>(binaryOperation.right, std::forward<Arguments>(arguments)...);
if (isLeftArithemtic == EvaluationResult::Error || isRightArithmetic == EvaluationResult::Error)
return EvaluationResult::Error;
if (isLeftArithemtic == EvaluationResult::False || isRightArithmetic == EvaluationResult::False)
return EvaluationResult::Error;
if (isLeftArithemtic == EvaluationResult::Unknown || isRightArithmetic == EvaluationResult::Unknown)
return EvaluationResult::Unknown;
return EvaluationResult::True;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Boolean &, Arguments &&...)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Function &function, Arguments &&...)
{
switch (function.declaration->domain)
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Integer &, Arguments &&...)
{
return EvaluationResult::True;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Interval &interval, Arguments &&... arguments)
{
const auto isFromArithmetic = isArithmetic<VariableDomainAccessor>(interval.from, std::forward<Arguments>(arguments)...);
const auto isToArithmetic = isArithmetic<VariableDomainAccessor>(interval.to, std::forward<Arguments>(arguments)...);
if (isFromArithmetic == EvaluationResult::Error || isToArithmetic == EvaluationResult::Error)
return EvaluationResult::Error;
if (isFromArithmetic == EvaluationResult::False || isToArithmetic == EvaluationResult::False)
return EvaluationResult::Error;
if (isFromArithmetic == EvaluationResult::Unknown || isToArithmetic == EvaluationResult::Unknown)
return EvaluationResult::Unknown;
return EvaluationResult::True;
}
template <class... Arguments>
static EvaluationResult visit(const ast::SpecialInteger &, Arguments &&...)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::String &, Arguments &&...)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::UnaryOperation &unaryOperation, Arguments &&... arguments)
{
const auto isArgumentArithmetic = isArithmetic<VariableDomainAccessor>(unaryOperation.argument, std::forward<Arguments>(arguments)...);
switch (unaryOperation.operator_)
{
case ast::UnaryOperation::Operator::Absolute:
return (isArgumentArithmetic == EvaluationResult::False ? EvaluationResult::Error : isArgumentArithmetic);
}
return EvaluationResult::Unknown;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Variable &variable, Arguments &&... arguments)
{
const auto domain = VariableDomainAccessor()(variable, std::forward<Arguments>(arguments)...);
switch (domain)
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
template <class VariableDomainAccessor, class... Arguments>
EvaluationResult isArithmetic(const ast::Term &term, Arguments &&... arguments)
{
return term.accept(IsTermArithmeticVisitor<VariableDomainAccessor>(), std::forward<Arguments>(arguments)...);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
EvaluationResult isInteger(const ast::Term &term);
////////////////////////////////////////////////////////////////////////////////////////////////////
struct IsTermIntegerVisitor
{
static EvaluationResult visit(const ast::BinaryOperation &binaryOperation)
{
const auto isLeftArithemtic = isArithmetic(binaryOperation.left);
const auto isRightArithmetic = isArithmetic(binaryOperation.right);
if (isLeftArithemtic == EvaluationResult::Error || isRightArithmetic == EvaluationResult::Error)
return EvaluationResult::Error;
if (isLeftArithemtic == EvaluationResult::False || isRightArithmetic == EvaluationResult::False)
return EvaluationResult::Error;
if (binaryOperation.operator_ == ast::BinaryOperation::Operator::Division)
return EvaluationResult::False;
if (isLeftArithemtic == EvaluationResult::Unknown || isRightArithmetic == EvaluationResult::Unknown)
return EvaluationResult::Unknown;
return EvaluationResult::True;
}
static EvaluationResult visit(const ast::Boolean &)
{
return EvaluationResult::False;
}
static EvaluationResult visit(const ast::Function &function)
{
switch (function.declaration->domain)
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
}
static EvaluationResult visit(const ast::Integer &)
{
return EvaluationResult::True;
}
template <class... Arguments>
static EvaluationResult visit(const ast::Interval &)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::SpecialInteger &)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::String &)
{
return EvaluationResult::False;
}
template <class... Arguments>
static EvaluationResult visit(const ast::UnaryOperation &unaryOperation)
{
const auto isArgumentArithmetic = isArithmetic(unaryOperation.argument);
switch (unaryOperation.operator_)
{
case ast::UnaryOperation::Operator::Absolute:
return (isArgumentArithmetic == EvaluationResult::False ? EvaluationResult::Error : isArgumentArithmetic);
}
return EvaluationResult::Unknown;
}
static EvaluationResult visit(const ast::Variable &variable)
{
switch (variable.declaration->domain)
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
inline EvaluationResult isInteger(const ast::Term &term)
{
return term.accept(IsTermIntegerVisitor());
}
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -3,7 +3,7 @@
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/ASTUtils.h> #include <anthem/ASTUtils.h>
#include <anthem/Utils.h> #include <anthem/Tristate.h>
namespace anthem namespace anthem
{ {

View File

@@ -12,6 +12,14 @@ namespace anthem
// //
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
enum class SimplificationResult
{
Simplified,
Unchanged,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
void simplify(ast::Formula &formula); void simplify(ast::Formula &formula);
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -3,7 +3,6 @@
#include <anthem/AST.h> #include <anthem/AST.h>
#include <anthem/Simplification.h> #include <anthem/Simplification.h>
#include <anthem/Utils.h>
namespace anthem namespace anthem
{ {
@@ -20,96 +19,96 @@ template<class T>
struct FormulaSimplificationVisitor struct FormulaSimplificationVisitor
{ {
template <class... Arguments> template <class... Arguments>
OperationResult visit(And &and_, Formula &formula, Arguments &&... arguments) SimplificationResult visit(And &and_, Formula &formula, Arguments &&... arguments)
{ {
for (auto &argument : and_.arguments) for (auto &argument : and_.arguments)
if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Biconditional &biconditional, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Biconditional &biconditional, Formula &formula, Arguments &&... arguments)
{ {
if (biconditional.left.accept(*this, biconditional.left, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (biconditional.left.accept(*this, biconditional.left, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
if (biconditional.right.accept(*this, biconditional.right, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (biconditional.right.accept(*this, biconditional.right, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Boolean &, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Boolean &, Formula &formula, Arguments &&... arguments)
{ {
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Comparison &, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Comparison &, Formula &formula, Arguments &&... arguments)
{ {
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Exists &exists, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Exists &exists, Formula &formula, Arguments &&... arguments)
{ {
if (exists.argument.accept(*this, exists.argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (exists.argument.accept(*this, exists.argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(ForAll &forAll, Formula &formula, Arguments &&... arguments) SimplificationResult visit(ForAll &forAll, Formula &formula, Arguments &&... arguments)
{ {
if (forAll.argument.accept(*this, forAll.argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (forAll.argument.accept(*this, forAll.argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Implies &implies, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Implies &implies, Formula &formula, Arguments &&... arguments)
{ {
if (implies.antecedent.accept(*this, implies.antecedent, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (implies.antecedent.accept(*this, implies.antecedent, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
if (implies.consequent.accept(*this, implies.consequent, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (implies.consequent.accept(*this, implies.consequent, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(In &, Formula &formula, Arguments &&... arguments) SimplificationResult visit(In &, Formula &formula, Arguments &&... arguments)
{ {
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Not &not_, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Not &not_, Formula &formula, Arguments &&... arguments)
{ {
if (not_.argument.accept(*this, not_.argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (not_.argument.accept(*this, not_.argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Or &or_, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Or &or_, Formula &formula, Arguments &&... arguments)
{ {
for (auto &argument : or_.arguments) for (auto &argument : or_.arguments)
if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Predicate &, Formula &formula, Arguments &&... arguments) SimplificationResult visit(Predicate &, Formula &formula, Arguments &&... arguments)
{ {
return T::accept(formula, std::forward<Arguments>(arguments)...); return T::accept(formula, std::forward<Arguments>(arguments)...);
} }
@@ -117,69 +116,69 @@ struct FormulaSimplificationVisitor
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class T, class OperationResult = void> template<class T, class SimplificationResult = void>
struct TermSimplificationVisitor struct TermSimplificationVisitor
{ {
template <class... Arguments> template <class... Arguments>
OperationResult visit(BinaryOperation &binaryOperation, Term &term, Arguments &&... arguments) SimplificationResult visit(BinaryOperation &binaryOperation, Term &term, Arguments &&... arguments)
{ {
if (binaryOperation.left.accept(*this, binaryOperation.left, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (binaryOperation.left.accept(*this, binaryOperation.left, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
if (binaryOperation.right.accept(*this, binaryOperation.right, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (binaryOperation.right.accept(*this, binaryOperation.right, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Boolean &, Term &term, Arguments &&... arguments) SimplificationResult visit(Boolean &, Term &term, Arguments &&... arguments)
{ {
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Function &function, Term &term, Arguments &&... arguments) SimplificationResult visit(Function &function, Term &term, Arguments &&... arguments)
{ {
for (auto &argument : function.arguments) for (auto &argument : function.arguments)
if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (argument.accept(*this, argument, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Integer &, Term &term, Arguments &&... arguments) SimplificationResult visit(Integer &, Term &term, Arguments &&... arguments)
{ {
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Interval &interval, Term &term, Arguments &&... arguments) SimplificationResult visit(Interval &interval, Term &term, Arguments &&... arguments)
{ {
if (interval.from.accept(*this, interval.from, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (interval.from.accept(*this, interval.from, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
if (interval.to.accept(*this, interval.to, std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (interval.to.accept(*this, interval.to, std::forward<Arguments>(arguments)...) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(SpecialInteger &, Term &term, Arguments &&... arguments) SimplificationResult visit(SpecialInteger &, Term &term, Arguments &&... arguments)
{ {
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(String &, Term &term, Arguments &&... arguments) SimplificationResult visit(String &, Term &term, Arguments &&... arguments)
{ {
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }
template <class... Arguments> template <class... Arguments>
OperationResult visit(Variable &, Term &term, Arguments &&... arguments) SimplificationResult visit(Variable &, Term &term, Arguments &&... arguments)
{ {
return T::accept(term, std::forward<Arguments>(arguments)...); return T::accept(term, std::forward<Arguments>(arguments)...);
} }

24
include/anthem/Tristate.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef __ANTHEM__TRISTATE_H
#define __ANTHEM__TRISTATE_H
namespace anthem
{
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tristate
//
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Tristate
{
True,
False,
Unknown,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
}
#endif

View File

@@ -23,33 +23,6 @@ constexpr const auto UserVariablePrefix = "U";
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
enum class Tristate
{
True,
False,
Unknown,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class EvaluationResult
{
True,
False,
Unknown,
Error,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class OperationResult
{
Unchanged,
Changed,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
} }
#endif #endif

View File

@@ -1,12 +1,10 @@
#include <anthem/IntegerVariableDetection.h> #include <anthem/IntegerVariableDetection.h>
#include <anthem/Arithmetics.h>
#include <anthem/ASTCopy.h> #include <anthem/ASTCopy.h>
#include <anthem/ASTUtils.h> #include <anthem/ASTUtils.h>
#include <anthem/ASTVisitors.h> #include <anthem/ASTVisitors.h>
#include <anthem/Exception.h> #include <anthem/Exception.h>
#include <anthem/Simplification.h> #include <anthem/Simplification.h>
#include <anthem/Utils.h>
#include <anthem/output/AST.h> #include <anthem/output/AST.h>
namespace anthem namespace anthem
@@ -45,11 +43,125 @@ void clearVariableDomainMap(VariableDomainMap &variableDomainMap)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
struct VariableDomainMapAccessor enum class OperationResult
{ {
ast::Domain operator()(const ast::Variable &variable, VariableDomainMap &variableDomainMap) Unchanged,
Changed,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
enum class EvaluationResult
{
True,
False,
Unknown,
Error,
};
////////////////////////////////////////////////////////////////////////////////////////////////////
EvaluationResult isArithmetic(const ast::Term &term, VariableDomainMap &variableDomainMap);
////////////////////////////////////////////////////////////////////////////////////////////////////
struct IsTermArithmeticVisitor
{
static EvaluationResult visit(const ast::BinaryOperation &binaryOperation, VariableDomainMap &variableDomainMap)
{ {
return domain(variable, variableDomainMap); const auto isLeftArithemtic = isArithmetic(binaryOperation.left, variableDomainMap);
const auto isRightArithmetic = isArithmetic(binaryOperation.right, variableDomainMap);
if (isLeftArithemtic == EvaluationResult::Error || isRightArithmetic == EvaluationResult::Error)
return EvaluationResult::Error;
if (isLeftArithemtic == EvaluationResult::False || isRightArithmetic == EvaluationResult::False)
return EvaluationResult::Error;
if (isLeftArithemtic == EvaluationResult::Unknown || isRightArithmetic == EvaluationResult::Unknown)
return EvaluationResult::Unknown;
return EvaluationResult::True;
}
static EvaluationResult visit(const ast::Boolean &, VariableDomainMap &)
{
return EvaluationResult::False;
}
static EvaluationResult visit(const ast::Function &function, VariableDomainMap &)
{
switch (function.declaration->domain)
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
}
static EvaluationResult visit(const ast::Integer &, VariableDomainMap &)
{
return EvaluationResult::True;
}
static EvaluationResult visit(const ast::Interval &interval, VariableDomainMap &variableDomainMap)
{
const auto isFromArithmetic = isArithmetic(interval.from, variableDomainMap);
const auto isToArithmetic = isArithmetic(interval.to, variableDomainMap);
if (isFromArithmetic == EvaluationResult::Error || isToArithmetic == EvaluationResult::Error)
return EvaluationResult::Error;
if (isFromArithmetic == EvaluationResult::False || isToArithmetic == EvaluationResult::False)
return EvaluationResult::Error;
if (isFromArithmetic == EvaluationResult::Unknown || isToArithmetic == EvaluationResult::Unknown)
return EvaluationResult::Unknown;
return EvaluationResult::True;
}
static EvaluationResult visit(const ast::SpecialInteger &, VariableDomainMap &)
{
return EvaluationResult::False;
}
static EvaluationResult visit(const ast::String &, VariableDomainMap &)
{
return EvaluationResult::False;
}
static EvaluationResult visit(const ast::UnaryOperation &unaryOperation, VariableDomainMap &variableDomainMap)
{
const auto isArgumentArithmetic = isArithmetic(unaryOperation.argument, variableDomainMap);
switch (unaryOperation.operator_)
{
case ast::UnaryOperation::Operator::Absolute:
return (isArgumentArithmetic == EvaluationResult::False ? EvaluationResult::Error : isArgumentArithmetic);
}
return EvaluationResult::Unknown;
}
static EvaluationResult visit(const ast::Variable &variable, VariableDomainMap &variableDomainMap)
{
switch (domain(variable, variableDomainMap))
{
case ast::Domain::General:
return EvaluationResult::False;
case ast::Domain::Integer:
return EvaluationResult::True;
case ast::Domain::Unknown:
return EvaluationResult::Unknown;
}
return EvaluationResult::Unknown;
} }
}; };
@@ -57,7 +169,7 @@ struct VariableDomainMapAccessor
EvaluationResult isArithmetic(const ast::Term &term, VariableDomainMap &variableDomainMap) EvaluationResult isArithmetic(const ast::Term &term, VariableDomainMap &variableDomainMap)
{ {
return isArithmetic<VariableDomainMapAccessor>(term, variableDomainMap); return term.accept(IsTermArithmeticVisitor(), variableDomainMap);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -269,220 +381,199 @@ EvaluationResult evaluate(const ast::Formula &formula, VariableDomainMap &variab
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template <class Functor> OperationResult detectIntegerVariables(ast::Formula &formula, ast::Formula &definition, VariableDomainMap &variableDomainMap);
struct ForEachVariableDeclarationVisitor
////////////////////////////////////////////////////////////////////////////////////////////////////
struct DetectIntegerVariablesVisitor
{ {
template <class... Arguments> static OperationResult visit(ast::And &and_, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::And &and_, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
for (auto &argument : and_.arguments) for (auto &argument : and_.arguments)
if (argument.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(argument, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::Biconditional &biconditional, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::Biconditional &biconditional, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
if (biconditional.left.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(biconditional.left, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
if (biconditional.right.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(biconditional.right, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::Boolean &, ast::Formula &, VariableDomainMap &)
static OperationResult visit(ast::Boolean &, Arguments &&...)
{ {
return OperationResult::Unchanged; return OperationResult::Unchanged;
} }
template <class... Arguments> static OperationResult visit(ast::Comparison &, ast::Formula &, VariableDomainMap &)
static OperationResult visit(ast::Comparison &, Arguments &&...)
{ {
return OperationResult::Unchanged; return OperationResult::Unchanged;
} }
template <class... Arguments> static OperationResult visit(ast::Exists &exists, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::Exists &exists, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
if (exists.argument.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(exists.argument, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
for (auto &variableDeclaration : exists.variables) for (auto &variableDeclaration : exists.variables)
if (Functor()(*variableDeclaration, exists.argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) {
if (variableDeclaration->domain != ast::Domain::Unknown)
continue;
clearVariableDomainMap(variableDomainMap);
auto argumentResult = evaluate(exists.argument, variableDomainMap);
auto definitionResult = evaluate(definition, variableDomainMap);
if (argumentResult == EvaluationResult::Error || argumentResult == EvaluationResult::False
|| definitionResult == EvaluationResult::Error || definitionResult == EvaluationResult::False)
{
continue;
}
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[variableDeclaration.get()] = ast::Domain::General;
argumentResult = evaluate(exists.argument, variableDomainMap);
definitionResult = evaluate(definition, variableDomainMap);
if (argumentResult == EvaluationResult::Error || argumentResult == EvaluationResult::False
|| definitionResult == EvaluationResult::Error || definitionResult == EvaluationResult::False)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
variableDeclaration->domain = ast::Domain::Integer;
}
}
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::ForAll &forAll, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::ForAll &forAll, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
if (forAll.argument.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(forAll.argument, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
for (auto &variableDeclaration : forAll.variables) for (auto &variableDeclaration : forAll.variables)
if (Functor()(*variableDeclaration, forAll.argument, std::forward<Arguments>(arguments)...) == OperationResult::Changed) {
if (variableDeclaration->domain != ast::Domain::Unknown)
continue;
clearVariableDomainMap(variableDomainMap);
auto argumentResult = evaluate(forAll.argument, variableDomainMap);
auto definitionResult = evaluate(definition, variableDomainMap);
if (argumentResult == EvaluationResult::Error || argumentResult == EvaluationResult::False
|| definitionResult == EvaluationResult::Error || definitionResult == EvaluationResult::False)
{
continue;
}
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[variableDeclaration.get()] = ast::Domain::General;
argumentResult = evaluate(forAll.argument, variableDomainMap);
definitionResult = evaluate(definition, variableDomainMap);
if (argumentResult == EvaluationResult::Error || argumentResult == EvaluationResult::False
|| definitionResult == EvaluationResult::Error || definitionResult == EvaluationResult::False)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
variableDeclaration->domain = ast::Domain::Integer;
}
}
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::Implies &implies, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::Implies &implies, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
if (implies.antecedent.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(implies.antecedent, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
if (implies.consequent.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(implies.consequent, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::In &, ast::Formula &, VariableDomainMap &)
static OperationResult visit(ast::In &, Arguments &&...)
{ {
return OperationResult::Unchanged; return OperationResult::Unchanged;
} }
template <class... Arguments> static OperationResult visit(ast::Not &not_, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::Not &not_, Arguments &&... arguments)
{ {
return not_.argument.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...); return detectIntegerVariables(not_.argument, definition, variableDomainMap);
} }
template <class... Arguments> static OperationResult visit(ast::Or &or_, ast::Formula &definition, VariableDomainMap &variableDomainMap)
static OperationResult visit(ast::Or &or_, Arguments &&... arguments)
{ {
auto operationResult = OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
for (auto &argument : or_.arguments) for (auto &argument : or_.arguments)
if (argument.accept(ForEachVariableDeclarationVisitor(), std::forward<Arguments>(arguments)...) == OperationResult::Changed) if (detectIntegerVariables(argument, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
return operationResult; return operationResult;
} }
template <class... Arguments> static OperationResult visit(ast::Predicate &predicate, ast::Formula &, VariableDomainMap &)
static OperationResult visit(ast::Predicate &, Arguments &&...)
{ {
return OperationResult::Unchanged; auto operationResult = OperationResult::Unchanged;
assert(predicate.arguments.size() == predicate.declaration->arity());
// Propagate integer domains from predicates to variables
for (size_t i = 0; i < predicate.arguments.size(); i++)
{
auto &variableArgument = predicate.arguments[i];
auto &parameter = predicate.declaration->parameters[i];
if (parameter.domain != ast::Domain::Integer)
continue;
if (!variableArgument.is<ast::Variable>())
continue;
auto &variable = variableArgument.get<ast::Variable>();
if (variable.declaration->domain == ast::Domain::Integer)
continue;
operationResult = OperationResult::Changed;
variable.declaration->domain = ast::Domain::Integer;
}
return operationResult;
} }
}; };
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
struct CheckIfDefinitionFalseFunctor OperationResult detectIntegerVariables(ast::Formula &formula, ast::Formula &definition, VariableDomainMap &variableDomainMap)
{ {
OperationResult operator()(ast::VariableDeclaration &variableDeclaration, return formula.accept(DetectIntegerVariablesVisitor(), definition, variableDomainMap);
ast::Formula &, ast::Formula &definition, VariableDomainMap &variableDomainMap) }
{
if (variableDeclaration.domain != ast::Domain::Unknown)
return OperationResult::Unchanged;
clearVariableDomainMap(variableDomainMap);
auto result = evaluate(definition, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
return OperationResult::Unchanged;
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[&variableDeclaration] = ast::Domain::General;
result = evaluate(definition, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
variableDeclaration.domain = ast::Domain::Integer;
return OperationResult::Changed;
}
return OperationResult::Unchanged;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct CheckIfQuantifiedFormulaFalseFunctor
{
OperationResult operator()(ast::VariableDeclaration &variableDeclaration,
ast::Formula &quantifiedFormula, VariableDomainMap &variableDomainMap)
{
if (variableDeclaration.domain != ast::Domain::Unknown)
return OperationResult::Unchanged;
clearVariableDomainMap(variableDomainMap);
auto result = evaluate(quantifiedFormula, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
return OperationResult::Unchanged;
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[&variableDeclaration] = ast::Domain::General;
result = evaluate(quantifiedFormula, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
variableDeclaration.domain = ast::Domain::Integer;
return OperationResult::Changed;
}
return OperationResult::Unchanged;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct CheckIfCompletedFormulaTrueFunctor
{
OperationResult operator()(ast::VariableDeclaration &variableDeclaration,
ast::Formula &, ast::Formula &completedFormula, VariableDomainMap &variableDomainMap)
{
if (variableDeclaration.domain != ast::Domain::Unknown)
return OperationResult::Unchanged;
clearVariableDomainMap(variableDomainMap);
auto result = evaluate(completedFormula, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::True)
return OperationResult::Unchanged;
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[&variableDeclaration] = ast::Domain::General;
result = evaluate(completedFormula, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::True)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
variableDeclaration.domain = ast::Domain::Integer;
return OperationResult::Changed;
}
return OperationResult::Unchanged;
}
};
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -499,10 +590,7 @@ void detectIntegerVariables(std::vector<ast::Formula> &completedFormulas)
for (auto &completedFormula : completedFormulas) for (auto &completedFormula : completedFormulas)
{ {
if (completedFormula.accept(ForEachVariableDeclarationVisitor<CheckIfQuantifiedFormulaFalseFunctor>(), variableDomainMap) == OperationResult::Changed) if (detectIntegerVariables(completedFormula, completedFormula, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed;
if (completedFormula.accept(ForEachVariableDeclarationVisitor<CheckIfCompletedFormulaTrueFunctor>(), completedFormula, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed; operationResult = OperationResult::Changed;
if (!completedFormula.is<ast::ForAll>()) if (!completedFormula.is<ast::ForAll>())
@@ -521,11 +609,11 @@ void detectIntegerVariables(std::vector<ast::Formula> &completedFormulas)
auto &predicate = biconditional.left.get<ast::Predicate>(); auto &predicate = biconditional.left.get<ast::Predicate>();
auto &definition = biconditional.right; auto &definition = biconditional.right;
if (completedFormula.accept(ForEachVariableDeclarationVisitor<CheckIfDefinitionFalseFunctor>(), definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed;
assert(predicate.arguments.size() == predicate.declaration->arity()); assert(predicate.arguments.size() == predicate.declaration->arity());
if (detectIntegerVariables(definition, definition, variableDomainMap) == OperationResult::Changed)
operationResult = OperationResult::Changed;
for (size_t i = 0; i < predicate.arguments.size(); i++) for (size_t i = 0; i < predicate.arguments.size(); i++)
{ {
auto &variableArgument = predicate.arguments[i]; auto &variableArgument = predicate.arguments[i];
@@ -535,7 +623,28 @@ void detectIntegerVariables(std::vector<ast::Formula> &completedFormulas)
auto &variable = variableArgument.get<ast::Variable>(); auto &variable = variableArgument.get<ast::Variable>();
parameter.domain = variable.declaration->domain; if (parameter.domain != ast::Domain::Unknown)
continue;
clearVariableDomainMap(variableDomainMap);
auto result = evaluate(definition, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
continue;
// As a hypothesis, make the parameters domain noninteger
variableDomainMap[variable.declaration] = ast::Domain::General;
result = evaluate(definition, variableDomainMap);
if (result == EvaluationResult::Error || result == EvaluationResult::False)
{
// If making the variable noninteger leads to a false or erroneous result, its proven to be integer
operationResult = OperationResult::Changed;
variable.declaration->domain = ast::Domain::Integer;
parameter.domain = ast::Domain::Integer;
}
} }
} }
} }

View File

@@ -2,11 +2,10 @@
#include <optional> #include <optional>
#include <anthem/Arithmetics.h>
#include <anthem/ASTCopy.h> #include <anthem/ASTCopy.h>
#include <anthem/Equality.h> #include <anthem/Equality.h>
#include <anthem/SimplificationVisitors.h>
#include <anthem/output/AST.h> #include <anthem/output/AST.h>
#include <anthem/SimplificationVisitors.h>
namespace anthem namespace anthem
{ {
@@ -101,7 +100,7 @@ struct ReplaceVariableInFormulaVisitor : public ast::RecursiveFormulaVisitor<Rep
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class SimplificationRule> template<class SimplificationRule>
OperationResult simplify(ast::Formula &formula) SimplificationResult simplify(ast::Formula &formula)
{ {
return SimplificationRule::apply(formula); return SimplificationRule::apply(formula);
} }
@@ -109,10 +108,10 @@ OperationResult simplify(ast::Formula &formula)
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
template<class FirstSimplificationRule, class SecondSimplificationRule, class... OtherSimplificationRules> template<class FirstSimplificationRule, class SecondSimplificationRule, class... OtherSimplificationRules>
OperationResult simplify(ast::Formula &formula) SimplificationResult simplify(ast::Formula &formula)
{ {
if (simplify<FirstSimplificationRule>(formula) == OperationResult::Changed) if (simplify<FirstSimplificationRule>(formula) == SimplificationResult::Simplified)
return OperationResult::Changed; return SimplificationResult::Simplified;
return simplify<SecondSimplificationRule, OtherSimplificationRules...>(formula); return simplify<SecondSimplificationRule, OtherSimplificationRules...>(formula);
} }
@@ -123,19 +122,19 @@ struct SimplificationRuleExistsWithoutQuantifiedVariables
{ {
static constexpr const auto Description = "exists () (F) === F"; static constexpr const auto Description = "exists () (F) === F";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Exists>()) if (!formula.is<ast::Exists>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &exists = formula.get<ast::Exists>(); auto &exists = formula.get<ast::Exists>();
if (!exists.variables.empty()) if (!exists.variables.empty())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = std::move(exists.argument); formula = std::move(exists.argument);
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -145,20 +144,20 @@ struct SimplificationRuleTrivialAssignmentInExists
{ {
static constexpr const auto Description = "exists X (X = Y) === #true"; static constexpr const auto Description = "exists X (X = Y) === #true";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Exists>()) if (!formula.is<ast::Exists>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
const auto &exists = formula.get<ast::Exists>(); const auto &exists = formula.get<ast::Exists>();
if (!exists.argument.is<ast::Comparison>()) if (!exists.argument.is<ast::Comparison>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
const auto &comparison = exists.argument.get<ast::Comparison>(); const auto &comparison = exists.argument.get<ast::Comparison>();
if (comparison.operator_ != ast::Comparison::Operator::Equal) if (comparison.operator_ != ast::Comparison::Operator::Equal)
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
const auto matchingAssignment = std::find_if(exists.variables.cbegin(), exists.variables.cend(), const auto matchingAssignment = std::find_if(exists.variables.cbegin(), exists.variables.cend(),
[&](const auto &variableDeclaration) [&](const auto &variableDeclaration)
@@ -168,11 +167,11 @@ struct SimplificationRuleTrivialAssignmentInExists
}); });
if (matchingAssignment == exists.variables.cend()) if (matchingAssignment == exists.variables.cend())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = ast::Formula::make<ast::Boolean>(true); formula = ast::Formula::make<ast::Boolean>(true);
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -182,20 +181,20 @@ struct SimplificationRuleAssignmentInExists
{ {
static constexpr const auto Description = "exists X (X = t and F(X)) === exists () (F(t))"; static constexpr const auto Description = "exists X (X = t and F(X)) === exists () (F(t))";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Exists>()) if (!formula.is<ast::Exists>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &exists = formula.get<ast::Exists>(); auto &exists = formula.get<ast::Exists>();
if (!exists.argument.is<ast::And>()) if (!exists.argument.is<ast::And>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &and_ = exists.argument.get<ast::And>(); auto &and_ = exists.argument.get<ast::And>();
auto &arguments = and_.arguments; auto &arguments = and_.arguments;
auto simplificationResult = OperationResult::Unchanged; auto simplificationResult = SimplificationResult::Unchanged;
for (auto i = exists.variables.begin(); i != exists.variables.end();) for (auto i = exists.variables.begin(); i != exists.variables.end();)
{ {
@@ -226,7 +225,7 @@ struct SimplificationRuleAssignmentInExists
arguments.erase(j); arguments.erase(j);
wasVariableReplaced = true; wasVariableReplaced = true;
simplificationResult = OperationResult::Changed; simplificationResult = SimplificationResult::Simplified;
break; break;
} }
@@ -250,19 +249,19 @@ struct SimplificationRuleEmptyConjunction
{ {
static constexpr const auto Description = "[empty conjunction] === #true"; static constexpr const auto Description = "[empty conjunction] === #true";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::And>()) if (!formula.is<ast::And>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &and_ = formula.get<ast::And>(); auto &and_ = formula.get<ast::And>();
if (!and_.arguments.empty()) if (!and_.arguments.empty())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = ast::Formula::make<ast::Boolean>(true); formula = ast::Formula::make<ast::Boolean>(true);
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -272,19 +271,19 @@ struct SimplificationRuleOneElementConjunction
{ {
static constexpr const auto Description = "[conjunction of only F] === F"; static constexpr const auto Description = "[conjunction of only F] === F";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::And>()) if (!formula.is<ast::And>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &and_ = formula.get<ast::And>(); auto &and_ = formula.get<ast::And>();
if (and_.arguments.size() != 1) if (and_.arguments.size() != 1)
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = std::move(and_.arguments.front()); formula = std::move(and_.arguments.front());
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -294,19 +293,19 @@ struct SimplificationRuleTrivialExists
{ {
static constexpr const auto Description = "exists ... ([#true/#false]) === [#true/#false]"; static constexpr const auto Description = "exists ... ([#true/#false]) === [#true/#false]";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Exists>()) if (!formula.is<ast::Exists>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &exists = formula.get<ast::Exists>(); auto &exists = formula.get<ast::Exists>();
if (!exists.argument.is<ast::Boolean>()) if (!exists.argument.is<ast::Boolean>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = std::move(exists.argument); formula = std::move(exists.argument);
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -316,21 +315,21 @@ struct SimplificationRuleInWithPrimitiveArguments
{ {
static constexpr const auto Description = "[primitive A] in [primitive B] === A = B"; static constexpr const auto Description = "[primitive A] in [primitive B] === A = B";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::In>()) if (!formula.is<ast::In>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &in = formula.get<ast::In>(); auto &in = formula.get<ast::In>();
assert(ast::isPrimitive(in.element)); assert(ast::isPrimitive(in.element));
if (!ast::isPrimitive(in.element) || !ast::isPrimitive(in.set)) if (!ast::isPrimitive(in.element) || !ast::isPrimitive(in.set))
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
formula = ast::Comparison(ast::Comparison::Operator::Equal, std::move(in.element), std::move(in.set)); formula = ast::Comparison(ast::Comparison::Operator::Equal, std::move(in.element), std::move(in.set));
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -340,10 +339,10 @@ struct SimplificationRuleSubsumptionInBiconditionals
{ {
static constexpr const auto Description = "(F <-> (F and G)) === (F -> G)"; static constexpr const auto Description = "(F <-> (F and G)) === (F -> G)";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Biconditional>()) if (!formula.is<ast::Biconditional>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &biconditional = formula.get<ast::Biconditional>(); auto &biconditional = formula.get<ast::Biconditional>();
@@ -354,7 +353,7 @@ struct SimplificationRuleSubsumptionInBiconditionals
const auto rightIsAnd = biconditional.right.is<ast::And>(); const auto rightIsAnd = biconditional.right.is<ast::And>();
if (!(leftIsPredicate && rightIsAnd) && !(rightIsPredicate && leftIsAnd)) if (!(leftIsPredicate && rightIsAnd) && !(rightIsPredicate && leftIsAnd))
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &predicateSide = (leftIsPredicate ? biconditional.left : biconditional.right); auto &predicateSide = (leftIsPredicate ? biconditional.left : biconditional.right);
auto &andSide = (leftIsPredicate ? biconditional.right : biconditional.left); auto &andSide = (leftIsPredicate ? biconditional.right : biconditional.left);
@@ -368,13 +367,13 @@ struct SimplificationRuleSubsumptionInBiconditionals
}); });
if (matchingPredicate == and_.arguments.cend()) if (matchingPredicate == and_.arguments.cend())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
and_.arguments.erase(matchingPredicate); and_.arguments.erase(matchingPredicate);
formula = ast::Formula::make<ast::Implies>(std::move(predicateSide), std::move(andSide)); formula = ast::Formula::make<ast::Implies>(std::move(predicateSide), std::move(andSide));
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -384,21 +383,21 @@ struct SimplificationRuleDoubleNegation
{ {
static constexpr const auto Description = "not not F === F"; static constexpr const auto Description = "not not F === F";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Not>()) if (!formula.is<ast::Not>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &not_ = formula.get<ast::Not>(); auto &not_ = formula.get<ast::Not>();
if (!not_.argument.is<ast::Not>()) if (!not_.argument.is<ast::Not>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &notNot = not_.argument.get<ast::Not>(); auto &notNot = not_.argument.get<ast::Not>();
formula = std::move(notNot.argument); formula = std::move(notNot.argument);
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -408,15 +407,15 @@ struct SimplificationRuleDeMorganForConjunctions
{ {
static constexpr const auto Description = "(not (F and G)) === (not F or not G)"; static constexpr const auto Description = "(not (F and G)) === (not F or not G)";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Not>()) if (!formula.is<ast::Not>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &not_ = formula.get<ast::Not>(); auto &not_ = formula.get<ast::Not>();
if (!not_.argument.is<ast::And>()) if (!not_.argument.is<ast::And>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &and_ = not_.argument.get<ast::And>(); auto &and_ = not_.argument.get<ast::And>();
@@ -425,7 +424,7 @@ struct SimplificationRuleDeMorganForConjunctions
formula = ast::Formula::make<ast::Or>(std::move(and_.arguments)); formula = ast::Formula::make<ast::Or>(std::move(and_.arguments));
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -435,21 +434,21 @@ struct SimplificationRuleImplicationFromDisjunction
{ {
static constexpr const auto Description = "(not F or G) === (F -> G)"; static constexpr const auto Description = "(not F or G) === (F -> G)";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Or>()) if (!formula.is<ast::Or>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &or_ = formula.get<ast::Or>(); auto &or_ = formula.get<ast::Or>();
if (or_.arguments.size() != 2) if (or_.arguments.size() != 2)
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
const auto leftIsNot = or_.arguments[0].is<ast::Not>(); const auto leftIsNot = or_.arguments[0].is<ast::Not>();
const auto rightIsNot = or_.arguments[1].is<ast::Not>(); const auto rightIsNot = or_.arguments[1].is<ast::Not>();
if (leftIsNot == rightIsNot) if (leftIsNot == rightIsNot)
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &negativeSide = leftIsNot ? or_.arguments[0] : or_.arguments[1]; auto &negativeSide = leftIsNot ? or_.arguments[0] : or_.arguments[1];
auto &positiveSide = leftIsNot ? or_.arguments[1] : or_.arguments[0]; auto &positiveSide = leftIsNot ? or_.arguments[1] : or_.arguments[0];
@@ -461,7 +460,7 @@ struct SimplificationRuleImplicationFromDisjunction
formula = ast::Formula::make<ast::Implies>(std::move(negativeSideArgument), std::move(positiveSide)); formula = ast::Formula::make<ast::Implies>(std::move(negativeSideArgument), std::move(positiveSide));
return OperationResult::Changed; return SimplificationResult::Simplified;
} }
}; };
@@ -471,15 +470,15 @@ struct SimplificationRuleNegatedComparison
{ {
static constexpr const auto Description = "(not F [comparison] G) === (F [negated comparison] G)"; static constexpr const auto Description = "(not F [comparison] G) === (F [negated comparison] G)";
static OperationResult apply(ast::Formula &formula) static SimplificationResult apply(ast::Formula &formula)
{ {
if (!formula.is<ast::Not>()) if (!formula.is<ast::Not>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &not_ = formula.get<ast::Not>(); auto &not_ = formula.get<ast::Not>();
if (!not_.argument.is<ast::Comparison>()) if (!not_.argument.is<ast::Comparison>())
return OperationResult::Unchanged; return SimplificationResult::Unchanged;
auto &comparison = not_.argument.get<ast::Comparison>(); auto &comparison = not_.argument.get<ast::Comparison>();
@@ -507,32 +506,7 @@ struct SimplificationRuleNegatedComparison
formula = std::move(comparison); formula = std::move(comparison);
return OperationResult::Changed; return SimplificationResult::Simplified;
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct SimplificationRuleIntegerSetInclusion
{
static constexpr const auto Description = "(F in G) === (F = G) if F and G are integer variables";
static OperationResult apply(ast::Formula &formula)
{
if (!formula.is<ast::In>())
return OperationResult::Unchanged;
auto &in = formula.get<ast::In>();
const auto isElementInteger = isInteger(in.element);
const auto isSetInteger = isInteger(in.set);
if (isElementInteger != EvaluationResult::True || isSetInteger != EvaluationResult::True)
return OperationResult::Unchanged;
formula = ast::Formula::make<ast::Comparison>(ast::Comparison::Operator::Equal, std::move(in.element), std::move(in.set));
return OperationResult::Changed;
} }
}; };
@@ -552,8 +526,7 @@ const auto simplifyWithDefaultRules =
SimplificationRuleSubsumptionInBiconditionals, SimplificationRuleSubsumptionInBiconditionals,
SimplificationRuleDeMorganForConjunctions, SimplificationRuleDeMorganForConjunctions,
SimplificationRuleImplicationFromDisjunction, SimplificationRuleImplicationFromDisjunction,
SimplificationRuleNegatedComparison, SimplificationRuleNegatedComparison
SimplificationRuleIntegerSetInclusion
>; >;
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -562,7 +535,7 @@ const auto simplifyWithDefaultRules =
struct SimplifyFormulaVisitor : public ast::FormulaSimplificationVisitor<SimplifyFormulaVisitor> struct SimplifyFormulaVisitor : public ast::FormulaSimplificationVisitor<SimplifyFormulaVisitor>
{ {
// Do nothing for all other types of expressions // Do nothing for all other types of expressions
static OperationResult accept(ast::Formula &formula) static SimplificationResult accept(ast::Formula &formula)
{ {
return simplifyWithDefaultRules(formula); return simplifyWithDefaultRules(formula);
} }
@@ -572,7 +545,7 @@ struct SimplifyFormulaVisitor : public ast::FormulaSimplificationVisitor<Simplif
void simplify(ast::Formula &formula) void simplify(ast::Formula &formula)
{ {
while (formula.accept(SimplifyFormulaVisitor(), formula) == OperationResult::Changed); while (formula.accept(SimplifyFormulaVisitor(), formula) == SimplificationResult::Simplified);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -154,7 +154,7 @@ void translate(const char *fileName, std::istream &stream, Context &context)
<< output::Keyword("int") << output::Keyword("int")
<< "(" << predicateDeclaration->name << "(" << predicateDeclaration->name
<< "/" << output::Number(predicateDeclaration->arity()) << "/" << output::Number(predicateDeclaration->arity())
<< "@" << output::Number(i + 1) << "@" << output::Number(i)
<< ")." << std::endl; << ")." << std::endl;
} }
} }