9 Commits

Author SHA1 Message Date
582b6ade6d Version bump for release 0.1.7 2018-04-08 20:44:43 +02:00
e64b2e70de Remove unused captured lambda reference 2018-04-08 20:44:43 +02:00
d7e4af98d7 Update copyright year in license file 2018-04-08 20:35:03 +02:00
a406cb43bd Update graph coloring example with placeholders
This replaces the former graph coloring example with a new formulation
that makes use of the newly supported placeholders.
2018-04-08 20:28:57 +02:00
c294a29cb2 Support placeholders with #external declarations
This adds support for declaring predicates as placeholders through the
“#external” directive in the input language of clingo.

Placeholders are not subject to completion. This prevents predicates
that represent instance-specific facts from being assumed as universally
false by default negation when translating an encoding.

This stretches clingo’s usual syntax a bit to make the implementation
lightweight. In order to declare a predicate with a specific arity as a
placeholder, the following statement needs to be added to the program:

    #external <predicate name>(<arity>).

Multiple unit tests cover cases where placeholders are used or not as
well as a more complex graph coloring example.
2018-04-08 20:28:57 +02:00
c91cbaf58b Update Catch to 2.2.2 2018-04-07 00:22:01 +02:00
2a2fec0eac Update change log with dependency change
This adds the dependency change from Boost (for program options) to
cxxopts to the change log.
2018-04-06 23:08:57 +02:00
09e56c3bce Format change log sections with proper headings
This makes the change log sections have proper headings, which were just
normal text before.
2018-04-06 22:53:59 +02:00
e2c0d6b705 Update cxxopts to 2.0.0+3+gabe9ebd
With cxxopts 2.0.0, positional arguments weren’t recognized when other
command-line options were passed before. This has been fixed in the
meantime, but there is no release with the bug fix yet.

This updates cxxopts to a newer commit to ship anthem with this fix.
2018-04-06 22:44:14 +02:00
14 changed files with 165 additions and 99 deletions

View File

@@ -1,14 +1,18 @@
# Change Log
## 0.1.7 (2018-04-05)
## 0.1.7 (2018-04-08)
Features:
### Features
* support for declaring placeholders with the `#external` directive
### Internal
* drops Boost dependency in favor of the header-only command-line option library [cxxopts](https://github.com/jarro2783/cxxopts)
## 0.1.6 (2017-06-12)
Features:
### Features
* unique IDs for all variables (user-defined variables are renamed)
* support for hiding predicates from completed output by using `#show` statements
@@ -16,7 +20,7 @@ Features:
* command-line option `--parentheses` to fully parenthesize the output
* adds multiple example instances for experimenting
Bug Fixes:
### Bug Fixes
* adds missing error message when attempting to read inaccessible file
* removes unnecessary parentheses after simplification
@@ -24,52 +28,52 @@ Bug Fixes:
## 0.1.5 (2017-05-04)
Bug Fixes:
### Bug Fixes
* fixes lost signs with negated 0-ary predicates
## 0.1.4 (2017-04-12)
Features:
### Features
* completion of input programs (optional)
* command-line option `--complete` to turn on completion
## 0.1.3 (2017-03-30)
Features:
### Features
* support for anonymous variables
Bug Fixes:
### Bug Fixes
* fixes incorrectly simplified rules with comparisons
* fixes misleading error message concerning negated, unsupported body literals
## 0.1.2 (2017-03-23)
Features:
### Features
* simplification of output formulas (optional)
* command-line option `--simplify` to turn on simplification
Bug Fixes:
### Bug Fixes
* fixes incorrectly translated choice rules with multiple elements in the head aggregate
Internal:
### Internal
* explicit syntax tree representation for first-order formulas
## 0.1.1 (2017-03-06)
Features:
### Features
* support for choice rules (without guards)
## 0.1.0 (2016-11-24)
Features:
### Features
* initial support for translating rules in *Essential Gringo* (excluding aggregates) to first-order logic formulas
* command-line option `--color` to autodetect, enable, or disable color output

View File

@@ -1,6 +1,6 @@
# The MIT License (MIT)
Copyright © 20162017 Patrick Lühne
Copyright © 20162018 Patrick Lühne
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

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

View File

@@ -1,12 +1,9 @@
colored(V, red) :- vertex(V), not colored(V, green), not colored(V, blue).
colored(V, green) :- vertex(V), not colored(V, red), not colored(V, blue).
colored(V, blue) :- vertex(V), not colored(V, red), not colored(V, green).
#external color(1).
#external edge(2).
#external vertex(1).
#show color/2.
:- edge(V1, V2), colored(V1, C), colored(V2, C).
vertex(a).
vertex(b).
vertex(c).
edge(a, b).
edge(a, c).
{color(V,C)} :- vertex(V), color(C).
covered(V) :- color(V, _).
:- vertex(V), not covered(V).
:- color(V1,C), color(V2,C), edge(V1,V2).

View File

@@ -5,6 +5,7 @@
#include <anthem/AST.h>
#include <anthem/ASTVisitors.h>
#include <anthem/Context.h>
namespace anthem
{
@@ -40,7 +41,7 @@ class VariableStack
bool matches(const Predicate &lhs, const Predicate &rhs);
bool matches(const Predicate &predicate, const PredicateSignature &signature);
bool matches(const PredicateSignature &lhs, const PredicateSignature &rhs);
void collectPredicateSignatures(const Formula &formula, std::vector<PredicateSignature> &predicateSignatures);
void collectPredicateSignatures(const Formula &formula, std::vector<PredicateSignature> &predicateSignatures, Context &context);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Replacing Variables

View File

@@ -16,6 +16,14 @@ namespace anthem
//
////////////////////////////////////////////////////////////////////////////////////////////////////
struct PredicateSignatureMeta
{
ast::PredicateSignature predicateSignature;
bool used{false};
};
////////////////////////////////////////////////////////////////////////////////////////////////////
struct Context
{
Context() = default;
@@ -30,8 +38,8 @@ struct Context
bool performSimplification = false;
bool performCompletion = false;
std::optional<std::vector<ast::PredicateSignature>> visiblePredicateSignatures;
std::optional<std::vector<ast::PredicateSignature>> externalPredicateSignatures;
std::optional<std::vector<PredicateSignatureMeta>> visiblePredicateSignatures;
std::optional<std::vector<PredicateSignatureMeta>> externalPredicateSignatures;
ast::ParenthesisStyle parenthesisStyle = ast::ParenthesisStyle::Normal;
};

View File

@@ -176,7 +176,8 @@ struct StatementVisitor
context.logger.log(output::Priority::Debug, statement.location) << "showing “" << signature.name() << "/" << signature.arity() << "";
context.visiblePredicateSignatures.value().emplace_back(std::string(signature.name()), signature.arity());
auto predicateSignature = ast::PredicateSignature{std::string(signature.name()), signature.arity()};
context.visiblePredicateSignatures.value().emplace_back(PredicateSignatureMeta{std::move(predicateSignature)});
}
void visit(const Clingo::AST::ShowTerm &, const Clingo::AST::Statement &statement, std::vector<ast::ScopedFormula> &, Context &)
@@ -213,12 +214,13 @@ struct StatementVisitor
if (aritySymbol.type() != Clingo::SymbolType::Number)
fail();
const auto &arity = arityArgument.data.get<Clingo::Symbol>().number();
const size_t arity = arityArgument.data.get<Clingo::Symbol>().number();
if (!context.externalPredicateSignatures)
context.externalPredicateSignatures.emplace();
context.externalPredicateSignatures->emplace_back(std::string(predicate.name), arity);
auto predicateSignature = ast::PredicateSignature{std::string(predicate.name), arity};
context.externalPredicateSignatures->emplace_back(PredicateSignatureMeta{std::move(predicateSignature)});
}
template<class T>

View File

@@ -59,7 +59,7 @@ bool VariableStack::contains(const VariableDeclaration &variableDeclaration) con
};
const auto layerContainsVariableDeclaration =
[&variableDeclaration, &variableDeclarationMatches](const auto &layer)
[&variableDeclarationMatches](const auto &layer)
{
return (std::find_if(layer->cbegin(), layer->cend(), variableDeclarationMatches) != layer->cend());
};
@@ -194,7 +194,7 @@ struct CollectFreeVariablesVisitor
struct CollectPredicateSignaturesVisitor : public RecursiveFormulaVisitor<CollectPredicateSignaturesVisitor>
{
static void accept(const Predicate &predicate, const Formula &, std::vector<PredicateSignature> &predicateSignatures)
static void accept(const Predicate &predicate, const Formula &, std::vector<PredicateSignature> &predicateSignatures, Context &context)
{
const auto predicateSignatureMatches =
[&predicate](const auto &predicateSignature)
@@ -206,12 +206,35 @@ struct CollectPredicateSignaturesVisitor : public RecursiveFormulaVisitor<Collec
return;
// TODO: avoid copies
predicateSignatures.emplace_back(std::string(predicate.name), predicate.arity());
auto predicateSignature = PredicateSignature(std::string(predicate.name), predicate.arity());
// Ignore predicates that are declared #external
if (context.externalPredicateSignatures)
{
const auto matchesPredicateSignature =
[&](const auto &otherPredicateSignature)
{
return ast::matches(predicateSignature, otherPredicateSignature.predicateSignature);
};
auto &externalPredicateSignatures = context.externalPredicateSignatures.value();
const auto matchingExternalPredicateSignature =
std::find_if(externalPredicateSignatures.begin(), externalPredicateSignatures.end(), matchesPredicateSignature);
if (matchingExternalPredicateSignature != externalPredicateSignatures.end())
{
matchingExternalPredicateSignature->used = true;
return;
}
}
predicateSignatures.emplace_back(std::move(predicateSignature));
}
// Ignore all other types of expressions
template<class T>
static void accept(const T &, const Formula &, std::vector<PredicateSignature> &)
static void accept(const T &, const Formula &, std::vector<PredicateSignature> &, const Context &)
{
}
};
@@ -240,10 +263,10 @@ bool matches(const PredicateSignature &lhs, const PredicateSignature &rhs)
////////////////////////////////////////////////////////////////////////////////////////////////////
// TODO: remove const_cast
void collectPredicateSignatures(const Formula &formula, std::vector<PredicateSignature> &predicateSignatures)
void collectPredicateSignatures(const Formula &formula, std::vector<PredicateSignature> &predicateSignatures, Context &context)
{
auto &formulaMutable = const_cast<Formula &>(formula);
formulaMutable.accept(CollectPredicateSignaturesVisitor(), formulaMutable, predicateSignatures);
formulaMutable.accept(CollectPredicateSignaturesVisitor(), formulaMutable, predicateSignatures, context);
}
////////////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -165,7 +165,7 @@ std::vector<ast::Formula> complete(std::vector<ast::ScopedFormula> &&scopedFormu
// Get a list of all predicates
for (const auto &scopedFormula : scopedFormulas)
ast::collectPredicateSignatures(scopedFormula.formula, predicateSignatures);
ast::collectPredicateSignatures(scopedFormula.formula, predicateSignatures, context);
std::sort(predicateSignatures.begin(), predicateSignatures.end(),
[](const auto &lhs, const auto &rhs)
@@ -180,47 +180,9 @@ std::vector<ast::Formula> complete(std::vector<ast::ScopedFormula> &&scopedFormu
std::vector<ast::Formula> completedFormulas;
// Warn about incorrect #external declarations
if (context.externalPredicateSignatures)
for (const auto &externalPredicateSignature : *context.externalPredicateSignatures)
{
// TODO: avoid code duplication
const auto matchesPredicateSignature =
[&](const auto &otherPredicateSignature)
{
return ast::matches(externalPredicateSignature, otherPredicateSignature);
};
const auto matchingPredicateSignature =
std::find_if(predicateSignatures.cbegin(), predicateSignatures.cend(), matchesPredicateSignature);
if (matchingPredicateSignature == predicateSignatures.cend())
context.logger.log(output::Priority::Warning) << "#external declaration of “" << externalPredicateSignature.name << "/" << externalPredicateSignature.arity <<"” does not match any known predicate";
}
// Complete predicates
for (const auto &predicateSignature : predicateSignatures)
{
// Dont complete predicates that are declared #external
if (context.externalPredicateSignatures)
{
const auto matchesPredicateSignature =
[&](const auto &otherPredicateSignature)
{
return ast::matches(predicateSignature, otherPredicateSignature);
};
const auto &externalPredicateSignatures = context.externalPredicateSignatures.value();
const auto matchingExternalPredicateSignature =
std::find_if(externalPredicateSignatures.cbegin(), externalPredicateSignatures.cend(), matchesPredicateSignature);
if (matchingExternalPredicateSignature != externalPredicateSignatures.cend())
continue;
}
completedFormulas.emplace_back(completePredicate(predicateSignature, scopedFormulas));
}
// Complete integrity constraints
for (auto &scopedFormula : scopedFormulas)

View File

@@ -194,23 +194,7 @@ void eliminateHiddenPredicates(const std::vector<ast::PredicateSignature> &predi
return;
}
const auto &visiblePredicateSignatures = context.visiblePredicateSignatures.value();
// Check for undeclared predicates that are requested to be shown
for (const auto &visiblePredicateSignature : visiblePredicateSignatures)
{
const auto matchesPredicateSignature =
[&](const auto &predicateSignature)
{
return ast::matches(predicateSignature, visiblePredicateSignature);
};
const auto matchingPredicateSignature =
std::find_if(predicateSignatures.cbegin(), predicateSignatures.cend(), matchesPredicateSignature);
if (matchingPredicateSignature == predicateSignatures.cend())
context.logger.log(output::Priority::Warning) << "cannot show undeclared predicate “" << visiblePredicateSignature.name << "/" << visiblePredicateSignature.arity <<"";
}
auto &visiblePredicateSignatures = context.visiblePredicateSignatures.value();
// Replace all occurrences of hidden predicates
for (size_t i = 0; i < predicateSignatures.size(); i++)
@@ -220,15 +204,18 @@ void eliminateHiddenPredicates(const std::vector<ast::PredicateSignature> &predi
const auto matchesPredicateSignature =
[&](const auto &otherPredicateSignature)
{
return ast::matches(predicateSignature, otherPredicateSignature);
return ast::matches(predicateSignature, otherPredicateSignature.predicateSignature);
};
const auto matchingVisiblePredicateSignature =
std::find_if(visiblePredicateSignatures.cbegin(), visiblePredicateSignatures.cend(), matchesPredicateSignature);
std::find_if(visiblePredicateSignatures.begin(), visiblePredicateSignatures.end(), matchesPredicateSignature);
// If the predicate ought to be visible, dont eliminate it
if (matchingVisiblePredicateSignature != visiblePredicateSignatures.cend())
if (matchingVisiblePredicateSignature != visiblePredicateSignatures.end())
{
matchingVisiblePredicateSignature->used = true;
continue;
}
// Check that the predicate is not declared #external
if (context.externalPredicateSignatures)

View File

@@ -85,6 +85,26 @@ void translate(const char *fileName, std::istream &stream, Context &context)
// Perform completion
auto completedFormulas = complete(std::move(scopedFormulas), context);
// Check for #show statements with undeclared predicates
if (context.visiblePredicateSignatures)
for (const auto &predicateSignature : context.visiblePredicateSignatures.value())
if (!predicateSignature.used)
context.logger.log(output::Priority::Warning)
<< "#show declaration of “"
<< predicateSignature.predicateSignature.name
<< "/" << predicateSignature.predicateSignature.arity
<< "” does not match any eligible predicate";
// Check for #external statements with undeclared predicates
if (context.externalPredicateSignatures)
for (const auto &predicateSignature : context.externalPredicateSignatures.value())
if (!predicateSignature.used)
context.logger.log(output::Priority::Warning)
<< "#external declaration of “"
<< predicateSignature.predicateSignature.name
<< "/" << predicateSignature.predicateSignature.arity
<< "” does not match any eligible predicate";
// Simplify output if specified
if (context.performSimplification)
for (auto &completedFormula : completedFormulas)

View File

@@ -0,0 +1,62 @@
#include <catch.hpp>
#include <sstream>
#include <anthem/AST.h>
#include <anthem/Context.h>
#include <anthem/Translation.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
TEST_CASE("[placeholders] Programs with placeholders are correctly completed", "[placeholders]")
{
std::stringstream input;
std::stringstream output;
std::stringstream errors;
anthem::output::Logger logger(output, errors);
anthem::Context context(std::move(logger));
context.performSimplification = true;
context.performCompletion = true;
SECTION("no placeholders")
{
input <<
"colored(V, red) :- vertex(V), not colored(V, green), not colored(V, blue).";
anthem::translate("input", input, context);
CHECK(output.str() ==
"forall V1, V2 (colored(V1, V2) <-> (V2 = red and vertex(V1) and not colored(V1, green) and not colored(V1, blue)))\n"
"forall V3 not vertex(V3)\n");
}
SECTION("single placeholder")
{
input <<
"#external vertex(1).\n"
"colored(V, red) :- vertex(V), not colored(V, green), not colored(V, blue).";
anthem::translate("input", input, context);
CHECK(output.str() ==
"forall V1, V2 (colored(V1, V2) <-> (V2 = red and vertex(V1) and not colored(V1, green) and not colored(V1, blue)))\n");
}
SECTION("complex example: graph coloring")
{
input <<
"#external color(1).\n"
"#external edge(2).\n"
"#external vertex(1).\n"
"#show color/2.\n"
"{color(V, C)} :- vertex(V), color(C).\n"
"covered(V) :- color(V, _).\n"
":- vertex(V), not covered(V).\n"
":- color(V1, C), color(V2, C), edge(V1, V2).";
anthem::translate("input", input, context);
CHECK(output.str() ==
"forall V1, V2 (color(V1, V2) <-> (vertex(V1) and color(V2) and color(V1, V2)))\n"
"forall U1 not (vertex(U1) and not exists U2 color(U1, U2))\n"
"forall U3, U4, U5 not (color(U3, U4) and color(U5, U4) and edge(U3, U5))\n");
}
}