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