lib/pione/model/feature-expr.rb in pione-0.1.1 vs lib/pione/model/feature-expr.rb in pione-0.1.2

- old
+ new

@@ -2,36 +2,50 @@ module Pione::Model # Feature is selection system between task and task worker. module Feature class << self - # Returns feature conjunction. - # @param [Array<Expr>] exprs + # Return feature conjunction. + # + # @param exprs [Array<Expr>] # feature expression list # @return [Expr] # conjuncted expression + # + # @example + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # Feature.and(x, y) #=> +X & +Y def and(*exprs) AndExpr.new(*exprs) end - # Returns feature disjunction. - # @param [Array<Expr>] exprs + # Return feature disjunction. + # + # @param exprs [Array<Expr>] # feature expression list # @return [Expr] # disjuncted expression + # + # @example + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # Feature.or(x, y) #=> +X | +Y def or(*exprs) OrExpr.new(*exprs) end - # Returns empty feature. + # Return empty feature. + # # @return [Expr] # empty feature def empty empty ||= EmptyFeature.new end - # Returns boundless feature + # Return boundless feature. + # # @return [Expr] # boundless feature def boundless boundless ||= BoundlessFeature.new end @@ -39,32 +53,34 @@ # Expr is a super class for all feature expressions. class Expr < BasicModel set_pione_model_type TypeFeature - # Returns itself. + # Return simplified expression. + # # @return [Expr] - # itself + # simplified expression def simplify return self end - # Returns true if the feature is empty. + # Return true if the feature is empty. + # # @return [Boolean] - # false + # true if the feature is empty def empty? return false end - # Returns true if the other matches the feature. + # Return true if the other matches the feature. + # # @return [Boolean] # true if the other matches the feature def match(other) raise ArgumentError.new(other) unless other.kind_of?(Expr) Sentence.new(self, other).decide end - alias :=== :match end # SpecialFeature is a class for empty feature and boundless feature. class SpecialFeature < Expr @@ -73,18 +89,17 @@ "Feature::SpecialFeature<#{symbol}>" end # @api private def textize - "#{symbol}" + symbol end # @api private def ==(other) other.kind_of?(self.class) - end - + end alias :eql? :== # @api private def hash true.hash @@ -94,18 +109,20 @@ # EmptyFeature is a class for empty feature that is one of special # features. This is written as '*', that means the worker has no specific # ability in provider expression and the task has no specific request in # request expression. class EmptyFeature < SpecialFeature - # Returns "*". - # return [Boolean] + # Return the symbol of empty feature. + # + # return [String] # "*" def symbol "*" end - # Returns true because empty feature is empty. + # Return true because empty feature is empty. + # # @return [Boolean] # true def empty? true end @@ -120,23 +137,33 @@ # BoundlessFeature is a class for whole feature that is one of special # features. This is written as '@', that means the worker has boundless # ability in provider expression and the task has boundless ability request # in request expression. class BoundlessFeature < SpecialFeature + # Return the symbol of bundless feature. + # + # return [String] + # "@" def symbol "@" end + + # @api private + def ==(other) + other.kind_of?(BoundlessFeature) + end end # Operator is superclass of all operator classes. class Operator < Expr; end # UnaryOperator is a class for provider opeators and request operator. class UnaryOperator < Operator attr_reader :symbol - # Returns the operator symbol. + # Return the operator symbol. + # # @return [String] # operator symbol # @example # # requisite feature # + @@ -154,11 +181,12 @@ # ! def self.operator @operator end - # Creates a new operator. + # Create a new operator. + # # @param [Symbol] symbol # feature symbol def initialize(symbol) @symbol = symbol super() @@ -181,11 +209,10 @@ # @api private def ==(other) other.kind_of?(self.class) and @symbol == other.symbol end - alias :eql? :== # @api private def hash @symbol.hash @@ -201,10 +228,11 @@ class PossibleExpr < ProviderExpr @operator = "^" end # RestrictiveExpr is a class for restrictive feature expression. + # # @example # !X class RestrictiveExpr < ProviderExpr @operator = "!" end @@ -213,82 +241,106 @@ class RequestExpr < UnaryOperator; end # Requisite Operator is a class for requisite feature expressions. Requisite # Feature are written like as "+X", these represent feature's requiste # ability. + # # @example # +X class RequisiteExpr < RequestExpr @operator = "+" end # BlockingExpr is a class for blocking feature expressions. Blocking Feature # are written like as "-X", these represent the ability that block to # execute the task. + # # @example - # -X + # BlockingExpr.new("X") #=> -X class BlockingExpr < RequestExpr @operator = "-" end # PreferredExpr is a class for preferred feature expressions. Preferred # Feature are written like as "?X", these represent that task workers what # the feature have take the task. + # + # @example + # PreferredExpr.new("X") #=> ?X class PreferredExpr < RequestExpr @operator = "?" end # Connective is a superclass of AndExpr and OrExpr. This represents - # connection of some features. + # connection of feature expressions. class Connective < Expr + # @return [Set] + # feature expressions included in the connective attr_reader :elements - # Creates a new connective. - # @param [Array<Expr>] elements - # feature list + # Create a new connective. + # + # @param elements [Array<Expr>] + # feature expressions def initialize(*elements) @elements = Set.new elements.each {|elt| add(elt) } super() end - # Adds the element from the connective set and unifies by it. - # @param [Expr] elt + # Add the feature expression as elements of the connective and unify it. + # + # @param expr [Expr] # feature element # @return [void] - def add(elt) - if elt.kind_of?(self.class) - elt.elements.each {|e| unify(e) } + # + # @example AND expression + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # AndExpr.new(x).add(y) #=> +X & +Y + # @example OR expression + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # OrExpr.new(x, y).add(x) #=> +X | +Y + def add(expr) + if expr.kind_of?(self.class) + expr.elements.each {|e| unify(e) } else - unify(elt) + unify(expr) end end - # Deletes the element from the connective set. - # @param [Expr] elt + # Delete the element from the connective set. + # + # @param elt [Expr] # feature element # @return [void] def delete(elt) @elements.delete(elt) if @elements.empty? @elements.add(EmptyFeature.new) end end - # Unifies connective set by the element. + # Unify connective set by the element. + # # @param [Expr] elt # feature element # @return [void] def unify(elt) unless self.class::UNIFICATIONS.any?{|name| __send__(name, elt)} @elements.add(elt) end end - # Simplifies the connective by unifing and up-rising single element. + # Simplify the connective by unifing and up-rising single element. + # # @return [Expr] # simplified feature + # + # @example + # AndExpr.new(RequisiteExpr.new("X")).simplify #=> +X def simplify if @elements.size == 1 return @elements.first.simplify else elements = @elements.map{|e| e.simplify} @@ -296,11 +348,12 @@ elements.each {|e| add(e)} return self end end - # Returns true if the connective set is empty. + # Return true if the connective set is empty. + # # @return [Boolean] # true if the connective set is empty def empty? return true if @elements.empty? return true if @elements == Set.new([Feature.empty]) @@ -315,51 +368,64 @@ ] end # @api private def textize - "#{self.class.name}(%s)" % [ - @elements.map{|elt| elt.textize}.join(",") - ] + "#{self.class.name}(%s)" % @elements.map{|elt| elt.textize}.join(",") end # @api private def ==(other) return true if empty? and other.kind_of?(Expr) and other.empty? other.kind_of?(self.class) and @elements == other.elements end + alias :eql? :"==" - alias :eql? :== - # @api private def hash @elements.hash end # Clone with cloning the elements set. + # # @api private def clone obj = super elements = @elements.clone obj.instance_eval { @elements = elements } return obj end end + # AndExpr represents conjunction of feature expressions. + # + # @example + # AndExpr.new(RequisiteExpr.new("X"), RequisiteExpr.new("Y")) #=> +X & +Y class AndExpr < Connective UNIFICATIONS = [ :unify_redundant_feature, :summarize_or, :background_preferred_feature, :unify_by_restrictive_feature ] module UnificationMethod - def unify_redundant_feature(elt) - # Γ & Γ -> Γ - # Δ & Δ -> Δ - return @elements.include?(elt) + # Unify redundant feature. This unification rule is described as + # follows: + # + # - Γ & Γ -> Γ + # - Δ & Δ -> Δ + # + # @param expr [Expr] + # feature expression + # + # @example + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # AndExpr.new(x,y).unify_redundant_feature(x) #=> true + def unify_redundant_feature(expr) + return @elements.include?(expr) end def summarize_or(elt) if elt.kind_of?(OrExpr) if target = @elements.find {|e| @@ -447,11 +513,11 @@ end end include UnificationMethod - # Makes an expander for response test. + # Make an expander for response test. def expander # convert or-clause into expander elements = @elements.map do |elt| elt.kind_of?(OrExpr) ? elt.expander : elt end @@ -461,11 +527,11 @@ private require 'fiber' - # Chooses a concrete expression that expand or-clause. + # Choose a concrete expression that expand or-clause. def choose_concrete_expr(y, orig, list, fiber, i) if orig.size == i # when reach the terminateion of elements, yield a concrete expression y << AndExpr.new(*convert_cons_list_into_array(list)) else @@ -501,32 +567,55 @@ def convert_cons_list_into_array(input) input == [] ? [] : convert_cons_list_into_array(input[1]) << input.first end end + # OrExpr represents disjunction of feature expressions. + # + # @example + # OrExpr.new(RequisiteExpr.new("X"), RequisiteExpr.new("Y")) #=> +X | +Y class OrExpr < Connective + # unification list UNIFICATIONS = [ :unify_redundant_feature, :summarize_and, :foreground_preferred_feature, :unify_by_possible_feature, :neutralize ] + # OrExpr's unification methods. module UnificationMethod - def unify_redundant_feature(elt) - # Γ | Γ -> Γ - # Δ | Δ -> Δ - return @elements.include?(elt) + # Return true if elements include the feature. This unification rule is + # described as follows: + # + # - Γ | Γ -> Γ + # - Δ | Δ -> Δ + # + # @param expr [Expr] + # feature expression + # + # @example + # x = RequisiteExpr.new("X") + # y = RequisiteExpr.new("Y") + # OrExpr.new(x, y).unify_redundant_feature(x) #=> true + def unify_redundant_feature(expr) + return @elements.include?(expr) end + # Return true if the expression is summarized by AND connective. This + # rule is described as follows: + # + # - (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3) + # - Γ1 | (Γ1 & Γ3) -> Γ1 + # - (Γ1 & Γ2) | Γ1 -> Γ1 def summarize_and(elt) if elt.kind_of?(AndExpr) + # (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3) if target = @elements.find {|e| e.kind_of?(AndExpr) && not((e.elements & elt.elements).empty?) } - # (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3) @elements.delete(target) union = target.elements & elt.elements union_expr = if union.length > 1 AndExpr.new(*union.to_a) else @@ -614,10 +703,10 @@ end end include UnificationMethod - # Makes an expander for response test. + # Make an expander for response test. def expander Enumerator.new do |y| @elements.each do |elt| elt.kind_of?(AndExpr) ? elt.expander.each {|e| y << e } : y << elt end