From 80a044cea7d518ddbba73c7912dd0fbf43d3910b Mon Sep 17 00:00:00 2001 From: Adam Wardynski <award@.(B-4.4.46a)> Date: Tue, 11 Jan 2011 17:56:46 +0100 Subject: [PATCH] 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. --- libwccl/ops/action.h | 33 +++++ libwccl/ops/actionexeccontext.h | 46 ++++++ libwccl/ops/rule.cpp | 58 ++++++++ libwccl/ops/rule.h | 250 ++++++++++++++++++++++++++++++++ 4 files changed, 387 insertions(+) create mode 100644 libwccl/ops/action.h create mode 100644 libwccl/ops/actionexeccontext.h create mode 100644 libwccl/ops/rule.cpp create mode 100644 libwccl/ops/rule.h diff --git a/libwccl/ops/action.h b/libwccl/ops/action.h new file mode 100644 index 0000000..666030c --- /dev/null +++ b/libwccl/ops/action.h @@ -0,0 +1,33 @@ +#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 diff --git a/libwccl/ops/actionexeccontext.h b/libwccl/ops/actionexeccontext.h new file mode 100644 index 0000000..27115e5 --- /dev/null +++ b/libwccl/ops/actionexeccontext.h @@ -0,0 +1,46 @@ +#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 diff --git a/libwccl/ops/rule.cpp b/libwccl/ops/rule.cpp new file mode 100644 index 0000000..0ff6262 --- /dev/null +++ b/libwccl/ops/rule.cpp @@ -0,0 +1,58 @@ +#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 */ diff --git a/libwccl/ops/rule.h b/libwccl/ops/rule.h new file mode 100644 index 0000000..6b7a242 --- /dev/null +++ b/libwccl/ops/rule.h @@ -0,0 +1,250 @@ +#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 -- GitLab