Page Menu
Home
Xreate
Search
Configure Global Search
Log In
Docs
Questions
Repository
Issues
Patches
Internal API
Files
F3999965
transcendlayer.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Thu, Jul 9, 3:24 AM
Size
14 KB
Mime Type
text/x-c++
Expires
Sat, Jul 11, 3:24 AM (1 d, 6 h)
Engine
blob
Format
Raw Data
Handle
272868
Attached To
rXR Xreate
transcendlayer.cpp
View Options
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Author: pgess <v.melnychenko@xreate.org>
* File: transcendlayer.cpp
*/
/**
* \file transcendlayer.h
* \brief Reasoner. Wrapper over the external Clasp reasoner library
*/
#include "transcendlayer.h"
#include "analysis/utils.h"
#include "utils.h"
#include <gringo/scripts.hh>
#include <boost/format.hpp>
#include <boost/algorithm/string/join.hpp>
#include <iostream>
#include <memory>
#include <boost/variant/detail/apply_visitor_binary.hpp>
using namespace std;
//TODO escape identifiers started with upper case symbol
namespace xreate{
bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) {
return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed;
}
struct VisitorSymbolNodeHash : public boost::static_visitor<size_t>{
std::size_t operator()(const xreate::SymbolPacked& node) const noexcept {
return 2 * (node.identifier + 3 * node.scope + 5 * std::abs(node.version));
}
std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept {
return 7 * node.id;
}
} ;
}
namespace std{
std::size_t
hash<xreate::SymbolNode>::operator()(xreate::SymbolNode const& s) const noexcept {
return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s);
}
std::size_t
hash<xreate::SymbolGeneralized>::operator()(xreate::SymbolGeneralized const& s) const noexcept {
return xreate::AttachmentsId<xreate::SymbolGeneralized>::getId(s);
}
}
namespace xreate{
void
TranscendLayer::printWarnings(std::ostream& out) {
const std::string warningTag = "warning";
auto warningsModel = query(warningTag);
if(warningsModel.size())
for(auto warning : warningsModel) {
unsigned int warningId;
Gringo::Symbol params;
std::tie(warningId, params) = parse<unsigned int, Gringo::Symbol>(warning.second);
cout << "Warning: " << __warnings.at(warningId) << " ";
params.print(out);
out << params;
}
}
bool
TranscendLayer::processSolution(Gringo::Model const &model) {
cout << "Model: " << endl;
const string& atomBindVar = Config::get("transcend.bindings.variable");
const string& atomBindFunc = Config::get("transcend.bindings.function");
const string& atomBindScope = Config::get("transcend.bindings.scope");
for(Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) {
atom.print(cout);
cout << " | " << endl;
string atomName(atom.name().c_str());
if(atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope) {
string atomAlias = std::get<1>(parse<Gringo::Symbol, Gringo::Symbol>(atom)).name().c_str();
__model.emplace(atomAlias, atom);
continue;
}
__model.emplace(atomName, atom);
}
return true;
}
void
TranscendLayer::registerReport(IAnalysisReport * report) {
__reports.push_back(report);
}
void
TranscendLayer::printReports() {
for(IAnalysisReport* report : __reports) {
report->print(__partGeneral);
}
}
void
TranscendLayer::deleteReports(){
for(IAnalysisReport* report : __reports) {
delete report;
}
__reports.clear();
}
void
TranscendLayer::addRuleWarning(const RuleWarning & rule) {
//__partGeneral << rule << endl;
list<string> domains;
boost::format formatDef("%1%(%2%)");
std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()),
[&formatDef](const std::pair<std::string, DomainAnnotation> &argument) {
string domain;
switch(argument.second) {
case DomainAnnotation::FUNCTION:
domain = "function";
break;
case DomainAnnotation::VARIABLE:
domain = "variable";
break;
}
return boost::str(formatDef % domain % argument.first);
});
list<string> vars;
std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()),
[](const std::pair<std::string, DomainAnnotation> &argument) {
return argument.first.c_str();
});
list<list < string>> guardsRaw;
std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()),
[this](const Expression & guard) {
return xreate::analysis::compile(guard);
});
const list<string>& guards = xreate::analysis::multiplyLists(std::move(guardsRaw));
list<string> &&branches = xreate::analysis::compileNeg(rule.__condition);
boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%.");
for(const string &guardsJoined : guards)
for(const string &branch : branches) {
unsigned int hook = registerWarning(string(rule.__message));
__partGeneral << formatWarning
% (hook)
% (boost::algorithm::join(vars, ", "))
% (branch)
% (guardsJoined)
% (boost::algorithm::join(domains, ", "))
<< endl;
}
}
unsigned int
TranscendLayer::registerWarning(std::string && message) {
static int warningId = 0;
__warnings.emplace(warningId, message);
return warningId++;
}
void
TranscendLayer::involveImports() {
ostream &out = __partGeneral;
if(ast)
for(string fn : ast->__rawImports) {
std::ifstream file(fn);
if(!file) {
std::cout << "Can't process script file: " << fn << std::endl;
assert(false);
}
while(!file.eof()) {
string line;
std::getline(file, line);
out << line << endl;
}
}
}
void
TranscendLayer::addRawScript(std::string && script) {
__partGeneral << script;
}
void
TranscendLayer::run() {
involveImports();
printReports();
ostringstream program;
program << __partTags.str() << __partGeneral.str();
cout << FYEL(program.str()) << endl;
std::vector<char const *> args{"clingo", nullptr};
DefaultGringoModule moduleDefault;
Gringo::Scripts scriptsDefault(moduleDefault);
ClingoLib ctl(scriptsDefault, 0, args.data(), { }, 0);
ctl.add("base",{}, program.str());
ctl.ground({
{"base",
{}}
}, nullptr);
// solve
Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) {
this->processSolution(model);
return true;
},
{
});
if(result.satisfiable() == Gringo::SolveResult::Satisfiable) {
cout << FGRN("SUCCESSFULLY") << endl;
} else {
cout << FRED("UNSUCCESSFULLY") << endl;
}
// invoke all query plugins to process solution
for(auto q : __queries) {
q.second->init(this);
}
}
TranscendLayer::TranscendLayer() : ast(nullptr) { }
StaticModel
TranscendLayer::query(const std::string & atom) const {
StaticModel result;
if (! __model.count(atom)) {
return result;
}
auto currentDataRange = __model.equal_range(atom);
std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end()));
return result;
}
ScopePacked
TranscendLayer::pack(const CodeScope * const scope) {
auto pos = __indexScopes.emplace(scope, __indexScopes.size());
if(pos.second)
__registryScopes.push_back(scope);
return pos.first->second;
}
size_t
TranscendLayer::getScopesCount() const {
return __registryScopes.size();
}
SymbolPacked
TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) {
SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope));
__indexSymbolNameHints.emplace(result, hintSymbolName);
return result;
}
Symbol
TranscendLayer::unpack(const SymbolPacked & symbol) const {
return Symbol{ScopedSymbol
{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]};
};
std::string
TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) {
auto result = __indexSymbolNameHints.find(symbol);
return(result == __indexSymbolNameHints.end()) ? "" : result->second;
}
IQuery *
TranscendLayer::registerQuery(IQuery *query, const QueryId & id) {
return __queries.emplace(id, query).first->second;
}
IQuery *
TranscendLayer::getQuery(const QueryId & id) {
assert(__queries.count(id) && "Undefined query");
return __queries.at(id);
}
class VisitorUnpackSymbol : public boost::static_visitor<SymbolGeneralized>{
public:
VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { }
SymbolGeneralized operator()(const SymbolPacked& symbol) const {
return __transcend->unpack(symbol);
}
SymbolGeneralized operator()(const SymbolAnonymous& symbol) const {
return symbol;
}
private:
const TranscendLayer* __transcend;
} ;
class VisitorPackSymbol : public boost::static_visitor<SymbolNode>{
public:
VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName)
: __transcend(transcend), __hint(hintSymbolName) { }
SymbolNode operator()(const Symbol& symbol) const {
return __transcend->pack(symbol, __hint);
}
SymbolNode operator()(const SymbolAnonymous& symbol) const {
return symbol;
}
private:
TranscendLayer* __transcend;
std::string __hint;
} ;
SymbolNode
TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) {
return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol);
}
SymbolGeneralized
TranscendLayer::unpack(const SymbolNode & symbol) const {
return boost::apply_visitor(VisitorUnpackSymbol(this), symbol);
}
bool
operator==(const SymbolPacked& s1, const SymbolPacked & s2) {
return s1.identifier == s2.identifier && s1.scope == s2.scope;
}
bool
operator<(const SymbolPacked& s1, const SymbolPacked & s2) {
return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier);
}
Expression
ParseImplAtom<Expression>
::get(const Gringo::Symbol & atom) {
switch(atom.type()) {
case Gringo::SymbolType::Num: return Expression(atom.num());
case Gringo::SymbolType::Str: return Expression(Atom<String_t>(std::string(atom.string().c_str())));
case Gringo::SymbolType::Fun:
{
//FUNC
Expression result(Operator::CALL,{Expression(Atom<Identifier_t>(std::string(atom.name().c_str())))});
for(const Gringo::Symbol& arg : atom.args()) {
result.addArg(ParseImplAtom<Expression>::get(arg));
}
return result;
}
default:
{
assert(false);
}
}
}
int
ParseImplAtom<int>
::get(const Gringo::Symbol & atom) {
switch(atom.type()) {
case Gringo::SymbolType::Num: return atom.num();
default: break;
}
assert(false && "Inappropriate symbol type");
}
std::string
ParseImplAtom<std::string>
::get(const Gringo::Symbol & atom) {
switch(atom.type()) {
case Gringo::SymbolType::Str: return atom.string().c_str();
case Gringo::SymbolType::Fun: return atom.name().c_str();
default: break;
}
assert(false && "Inappropriate symbol type");
}
SymbolPacked
ParseImplAtom<SymbolPacked>
::get(const Gringo::Symbol & atom) {
auto result = TranscendLayer::parse<int, int, int>(atom);
return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result));
};
Gringo::Symbol
ParseImplAtom<Gringo::Symbol>
::get(const Gringo::Symbol & atom) {
return atom;
}
SymbolNode
ParseImplAtom<SymbolNode>
::get(const Gringo::Symbol & atom) {
assert(atom.type() == Gringo::SymbolType::Fun
&& "Inappropriate symbol type");
if(atom.name() == "a") {
return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse<int>(atom))};
} else if(atom.name() == "s") {
return ParseImplAtom<SymbolPacked>::get(atom);
}
assert(false && "Wrong symbol format");
}
class VisitorSymbolId : public boost::static_visitor<unsigned int>{
public:
unsigned int operator()(const Symbol& symbol) const {
return AttachmentsId<Symbol>::getId(symbol);
}
unsigned int operator()(const SymbolAnonymous& symbol) const {
return symbol.id;
}
} ;
unsigned int
AttachmentsId<SymbolGeneralized>
::getId(const SymbolGeneralized & symbol) {
return boost::apply_visitor(VisitorSymbolId(), symbol);
}
} //end of xreate namespace
/**
* \class xreate::TranscendLayer
* \brief Reasoning and logic Solver.
*
* Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/)
*
* For building *logic program* for reasoning TranscendLayer takes input from:
* - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript()
* - Includes. There is possibility to specify external files with ASP scripts
* to append to _logic program_. \ref involveImports() (private member)
* - Diagnostic rules. Rules that produce diagnostic messages during
* compilation(warnings) or even able to halt compilation with errors.
* addRuleWarning(), \ref registerWarning()
* - DFA data. \ref setDFAData()
* - CFA data. \ref setCFAData()
* - Dominators Analysis. See xreate::dominators::DominatorsAnalysisProvider.
* Executed by \ref run()
* - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context)
*
* Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories:
* - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by
* useful insights about data, structure and algorithms of a program
* - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by
* annotations Developer specifically provides manually
* - *External* data. Raw scripts and includes feed reasoner with third-party data
* related to a different aspects of a program possibly produced by external analyzers
*
* Once TranscendLayer got input from all providers and logic program is fully constructed
* it runs external Clasp reasoner and receives back desired solutions.
*
* Output of the external Clasp reasoner is recognized and accessed via *queries*.
* IQuery represents an interface between reasoner's output and rest of Xreate.
* Each query inherits xreate::IQuery interface. Currently there are queries as follows:
* - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers)
* - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context)
*
* \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsAnalysisProvider
*/
Event Timeline
Log In to Comment