Skip to content
Snippets Groups Projects
Commit 80a044ce authored by Adam Wardynski's avatar Adam Wardynski
Browse files

Groundwork for WCCL rules: Rule, Action, ActionExecContext.

Rule - user-level class encapsulating WCCL rule.
Action - internal class for Rule's actions
ActionExecContext - helper class for execution of actions.
parent 167e2406
Branches
Tags
No related merge requests found
#ifndef LIBWCCL_OPS_ACTION_H
#define LIBWCCL_OPS_ACTION_H
#include <boost/shared_ptr.hpp>
#include <boost/assert.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <libwccl/ops/expression.h>
#include <libwccl/values/value.h>
#include <libwccl/ops/actionexeccontext.h>
namespace Wccl {
/**
* Abstract base class for actions in WCCL rules
*/
class Action : public Expression
{
public:
/**
* @returns Name of the action.
*/
virtual std::string name(const Corpus2::Tagset&) const = 0;
/**
* Executes the action for the given execution context.
*/
virtual Bool execute(const ActionExecContext& context) const = 0;
};
} /* end ns Wccl */
#endif // LIBWCCL_OPS_ACTION_H
#ifndef LIBWCCL_OPS_ACTIONEXECCONTEXT_H
#define LIBWCCL_OPS_ACTIONEXECCONTEXT_H
#include <boost/noncopyable.hpp>
#include <libwccl/variables.h>
#include <libwccl/sentencecontext.h>
namespace Wccl {
/**
* Class holding execution context of an action
* i.e. state that the action should operate on.
*/
class ActionExecContext : boost::noncopyable {
public:
ActionExecContext(
SentenceContext& sentence_context,
const boost::shared_ptr<Variables>& vars)
: sentence_context_(sentence_context), vars_(vars)
{
}
/**
* @returns Context of a sentence the action is executed on.
*/
SentenceContext& sentence_context() const {
return sentence_context_;
}
/**
* @returns Pointer to variables the operator should operate with.
* @note Variables should be accesible to modifications, but overall
* object should not get replaced, hence the const pointer.
*/
const boost::shared_ptr<Variables>& variables() const {
return vars_;
}
private:
SentenceContext& sentence_context_;
const boost::shared_ptr<Variables> vars_;
};
} /* end ns Wccl */
#endif // LIBWCCL_OPS_ACTIONEXECCONTEXT_H
#include <libwccl/ops/rule.h>
#include <sstream>
namespace Wccl {
Bool Rule::execute(SentenceContext &sentence_context)
{
if(sentence_context.size() == 0) {
throw InvalidArgument(
"sentence_context",
"Received an empty sentence.");
}
if(!sentence_context.is_current_inside()) {
throw InvalidArgument(
"sentence_context",
"Current position is outside boundaries of the sentence.");
}
Bool changed(false);
if(condition_->apply(FunExecContext(sentence_context, variables_))->get_value()) {
ActionExecContext aec(sentence_context, variables_);
foreach(const boost::shared_ptr<Action>& action, *actions_) {
if(action->execute(aec).get_value()) {
changed.set_value(true);
}
}
}
return changed;
}
const boost::shared_ptr<const Function<Bool> > Rule::TrueCondition()
{
static boost::shared_ptr<const Function<Bool> > true_constant(
new Constant<Bool>(Bool(true)));
return true_constant;
}
std::string Rule::to_string(const Corpus2::Tagset &tagset) const
{
std::ostringstream os;
os << "rule(\"" << name_ << "\", " << condition_->to_string(tagset);
foreach(const boost::shared_ptr<Action>& action, *actions_) {
os << ", " << action->to_string(tagset);
}
os << ")";
return os.str();
}
std::ostream& Rule::write_to(std::ostream& os) const {
os << "rule(\"" << name_ << "\", " << *condition_;
foreach(const boost::shared_ptr<Action>& action, *actions_) {
os << ", " << *action;
}
os << ")";
return os;
}
} /* end ns Wccl */
#ifndef LIBWCCL_OPS_RULE_H
#define LIBWCCL_OPS_RULE_H
#include <boost/scoped_ptr.hpp>
#include <libwccl/ops/parsedexpression.h>
#include <libwccl/ops/functions/constant.h>
#include <libwccl/ops/action.h>
namespace Wccl {
/**
* Represents a parsed WCCL Rule that executes some actions.
* @note The class methods are not thread-safe, but you can use clone method
* to acquire a separate copy of the Rule, and the copy can be used concurrently.
*/
class Rule : public ParsedExpression
{
public:
Rule(
const std::string& name,
const Variables& variables,
const boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > >& actions,
const boost::shared_ptr<const Function<Bool> >& condition = TrueCondition());
/**
* Evaluates condition and if it is true, executes the actions sequentially. Does
* not execute any of the rules if condition is false.
* @returns True if any of the actions made a change, False otherwise.
* @param sentence_context SentenceContext of the Sentence to execute the Rule on.
* @see execute() - equivalent method; the \link operator()() operator() \endlink allows
* more convenient functional notation, however if you only have a pointer
* you might prefer the apply method as shown below. The choice is yours.
* \code
* Bool res;
* res = rule(sc);
* // versus
* res = rule.execute(sc);
* // or if you have a pointer...
* res = (*rule_ptr)(sc);
* // versus
* res = rule_ptr->apply(sc);
* \endcode
*/
Bool operator()(SentenceContext& sentence_context);
/**
* Evaluates condition and if it is true, executes the actions sequentially. Does
* not execute any of the rules if condition is false.
* @returns True if any of the actions made a change, False otherwise.
* @param sentence_context SentenceContext of the Sentence to execute the Rule on.
* @note The result is conciously marked as const, so a copy of Rule data
* is not created unless necessary.
* @see \link operator()() operator() \endlink - an equivalent of this method that allows
* functional notation, treating Rule directly as a function
*/
Bool execute(SentenceContext& sentence_context);
/**
* @returns Name of the Rule.
*/
std::string name() const;
/**
* Makes a copy of the Rule, having its own space for Variables.
* This allows the copy to be run concurrently (otherwise methods
* of this class are not thread-safe; concurrent executions
* on the same object would share Variables so don't do that).
* @returns A copy of the Rule, including copy of Variables' values.
* @note The values of the Variables are copied as they are, which is
* a usable feature. If that is not what you want, use clone_clean()
* or call clean() when you need it.
* @see clone_clean - a convenience version that returns a copy with
* all Variables set to their default values.
* @see clone_ptr - a version that returns a copy wrapped in a shared
* pointer
* @see clone_clean_ptr - a version that returns a copy wrapped
* in a shared pointer, and also having its Variables cleaned.
* @see \link Rule(const Rule&, bool) copy constructor \endlink -
* another way to create a copy
* @see \link operator=(const Rule&) operator= \endlink - assignment
* Rule, yet another way to create a copy.
*/
Rule clone() const;
/**
* Makes a copy of the Rule, having its own space for Variables.
* This allows the copy to be run concurrently (otherwise methods
* of this class are not thread-safe; concurrent executions
* on the same object would share Variables so don't do that).
* All the Variables in the copy will have default values.
* @returns A copy of the Rule with Variables that have default
* values.
* @see clone - a version that returns a copy without cleaning Variables.
* @see clone_ptr - a version that returns a copy wrapped in a shared
* pointer
* @see clone_clean_ptr - a version that returns a copy wrapped
* in a shared pointer, and also having its Variables cleaned.
*/
Rule clone_clean() const;
/**
* @returns A copy of the expression, with values of the variables
* copied as well.
* @see clone_clean_ptr - convenience version that returns clean copy.
*/
boost::shared_ptr<Rule> clone_ptr() const;
/**
* @returns A copy of the expression, with values of the variables
* set to their defaults.
* @see clone_ptr - a version that keeps values of the variables.
*/
boost::shared_ptr<Rule> clone_clean_ptr() const;
/**
* Copy constructor, creates a copy with new set of values for
* variables, allowing concurrent run of semantically same Rule
* (running same physical Rule object is inherently not thread safe).
* @param other - the Rule to copy.
* @param clean - true if copy needs to have its variables
* set to default values, false to keep the values; false is default
*/
Rule(const Rule& other, bool clean = false);
/**
* Default constructor. Produces Rule that returns False.
*/
Rule();
/**
* Assignment operator to create a workable copy of other Rule
* (workable means it has a new set of values for variables, allowing
* concurrent run of semantically same Rule; running same physical
* Rule object is inherently not thread safe).
* @note The values for variables are kept as in the original Rule.
* @param other - Rule to copy
* @returns A reference to the current object, after assignment.
*/
Rule& operator=(const Rule& other);
std::string to_string(const Corpus2::Tagset& tagset) const;
protected:
Rule* clone_internal() const;
std::ostream& write_to(std::ostream& ostream) const;
private:
static const boost::shared_ptr<const Function<Bool> > TrueCondition();
boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > > actions_;
boost::shared_ptr<const Function<Bool> > condition_;
std::string name_;
};
//
//--- implementation details ---
//
inline
Rule::Rule(
const std::string& name,
const Variables& variables,
const boost::shared_ptr<const std::vector<boost::shared_ptr<Action> > >& actions,
const boost::shared_ptr<const Function<Bool> >& condition)
: ParsedExpression(variables),
actions_(actions),
condition_(condition),
name_(name) {
BOOST_ASSERT(actions_);
BOOST_ASSERT(condition_);
}
inline
Bool Rule::operator()(SentenceContext& sc) {
return execute(sc);
}
inline
std::string Rule::name() const {
return name_;
}
inline
Rule* Rule::clone_internal() const {
return new Rule(name_, *variables_, actions_, condition_);
}
inline
Rule::Rule(const Rule &other, bool clean)
: ParsedExpression(*other.variables_),
actions_(other.actions_),
condition_(other.condition_),
name_(other.name_)
{
BOOST_ASSERT(actions_);
BOOST_ASSERT(condition_);
if(clean) {
this->clean();
}
}
inline
Rule Rule::clone() const {
return *this;
}
inline
Rule Rule::clone_clean() const {
return Rule(*this, true);
}
inline
Rule& Rule::operator=(const Rule& other) {
BOOST_ASSERT(other.actions_);
BOOST_ASSERT(other.condition_);
actions_ = other.actions_;
condition_ = other.condition_;
name_ = other.name_;
variables_.reset(other.variables_->clone());
return *this;
}
inline
Rule::Rule()
: ParsedExpression((Variables())),
actions_(boost::make_shared<std::vector<boost::shared_ptr<Action> > >()),
condition_(detail::DefaultFunction<Bool>()),
name_()
{
BOOST_ASSERT(actions_);
BOOST_ASSERT(condition_);
}
inline
boost::shared_ptr<Rule> Rule::clone_ptr() const {
return boost::shared_ptr<Rule>(clone_internal());
}
inline
boost::shared_ptr<Rule> Rule::clone_clean_ptr() const {
boost::shared_ptr<Rule> copy(clone_internal());
BOOST_ASSERT(copy);
copy->clean();
return copy;
}
} /* end ns Wccl */
#endif // LIBWCCL_OPS_RULE_H
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment