class Porolog::Instantiation
A Porolog::Instantiation
implements an instantiation of a Variable
of a Goal
. An Instantiation
joins two expressions. At least one expression must have a variable. An index may be provided to index into the value of either expression, or both may have an index. Thus, an element of each list could be instantiated without reference to the other elements:
x = [a,b,c,d,e] | y = [p,q,r,s]
@author Luis Esteban
@!attribute variable1
@return [Variable,Object] one end of the instantiation.
@!attribute variable2
@return [Variable,Object] the other end of the instantiation.
@!attribute index1
@return [Object,nil] the index into the value of variable1.
@!attribute index2
@return [Object,nil] the index into the value of variable2.
Attributes
Public Class Methods
@return [Hash{Array => Porolog::Instantiation}] all Instantiations
# File lib/porolog/instantiation.rb, line 50 def self.instantiations @@instantiations end
Finds or creates a new instantiation. At least one of the variables must be a Variable
. @param variable1 [Porolog::Variable,Porolog::Value,Object] one end of the instantiation to be made. @param variable2 [Porolog::Variable,Porolog::Value,Object] the other end of the instantiation to be made. @param index1 [Integer,Symbol,nil] index into the value of variable1. @param index2 [Integer,Symbol,nil] index into the value of variable2. @return [Porolog::Instantiation] the found or created Instantiation
.
# File lib/porolog/instantiation.rb, line 60 def self.new(variable1, index1, variable2, index2) raise NoVariableError, "Cannot instantiate non-variables: #{variable1.inspect} and #{variable2.inspect}" unless variable1.is_a?(Variable) || variable2.is_a?(Variable) variable1 = Value.new variable1, variable2.goal unless variable1.is_a?(Variable) || variable1.is_a?(Value) variable2 = Value.new variable2, variable1.goal unless variable2.is_a?(Variable) || variable2.is_a?(Value) instantiation = \ @@instantiations[[variable1, index1, variable2, index2]] || @@instantiations[[variable2, index2, variable1, index1]] || super instantiation end
Initializes and registers a new Instantiation
. At least one of the variables must be a Variable
. @param variable1 [Porolog::Variable,Porolog::Value,Object] one end of the instantiation to be made. @param variable2 [Porolog::Variable,Porolog::Value,Object] the other end of the instantiation to be made. @param index1 [Integer,Symbol,nil] index into the value of variable1. @param index2 [Integer,Symbol,nil] index into the value of variable2. @return [Porolog::Instantiation] the found or created Instantiation
.
# File lib/porolog/instantiation.rb, line 80 def initialize(variable1, index1, variable2, index2) @variable1 = variable1 @variable2 = variable2 @index1 = index1 @index2 = index2 @variable1.instantiations << self @variable2.instantiations << self @@instantiations[signature] = self end
Clears all instantiations. @return [Boolean] success
# File lib/porolog/instantiation.rb, line 42 def self.reset @@instantiations = {} true end
Public Instance Methods
@param goal [Porolog::Goal] the provided Goal
. @return [Boolean] whether the Instantiation
attaches to a variable in the provided Goal
.
# File lib/porolog/instantiation.rb, line 337 def belongs_to?(goal) [ @variable1.goal, @variable2.goal, ].include?(goal) end
@return [Boolean] whether the Instantiation
has been deleted (memoized).
# File lib/porolog/instantiation.rb, line 330 def deleted? @deleted ||= @variable1.goal.deleted? || @variable2.goal.deleted? @deleted end
@return [Array<Porolog::Goal>] the Goals of the Variables of the Instantiation
.
# File lib/porolog/instantiation.rb, line 128 def goals [@variable1.goal,@variable2.goal] end
@return [String] pretty representation.
# File lib/porolog/instantiation.rb, line 99 def inspect(indent = 0) index1 = @index1 ? "[#{@index1.inspect}]" : '' index2 = @index2 ? "[#{@index2.inspect}]" : '' "#{' ' * indent}#{@variable1.inspect}#{index1} = #{@variable2.inspect}#{index2}" end
Returns the Goal
of the other Variable
to the one provided. @param variable [Porolog::Variable] the provided Variable
. @return [Porolog::Goal,nil] the Goal
of the other Variable
.
# File lib/porolog/instantiation.rb, line 120 def other_goal_to(variable) return nil unless variables.include?(variable) other_variable = (variables - [variable]).first other_variable&.goal end
Removes itself from its variables' Instantiations and unregisters itself. @return [Boolean] success
# File lib/porolog/instantiation.rb, line 108 def remove @variable1.instantiations.delete(self) if @variable1.is_a?(Variable) || @variable1.is_a?(Value) @variable2.instantiations.delete(self) if @variable2.is_a?(Variable) || @variable2.is_a?(Value) @deleted = true @@instantiations.delete(signature) @deleted end
@return [Array] the signature of the Instantiation
, which aids in avoiding duplication instantiations.
# File lib/porolog/instantiation.rb, line 93 def signature @signature ||= [@variable1, @index1, @variable2, @index2].freeze @signature end
@param value [Object] the known value. @param index [Integer,Symbol,Array] the known index. @return [Array] an Array
where the known value is at the known index.
# File lib/porolog/instantiation.rb, line 280 def value_at_index(value, index) value && case index when Integer result = [] result[index] = value result << UNKNOWN_TAIL result when Symbol case index when :flathead [*value, UNKNOWN_TAIL] when :head [value, UNKNOWN_TAIL] when :tail [nil, *value] when :flattail value else raise UnhandledIndexError, "Unhandled index: #{index.inspect} for #{value.inspect}" end when Array if index.empty? [nil, *value] else [value, UNKNOWN_TAIL] end else if index raise UnhandledIndexError, "Unhandled index: #{index.inspect} for #{value.inspect}" else value end end end
@param value [Object] the provided value. @param index [Integer,Symbol,Array<Integer>] the index. @param visited [Array] prevents infinite recursion. @return [Object] the indexed value of the provided value.
# File lib/porolog/instantiation.rb, line 152 def value_indexed(value, index, visited = []) return nil unless value return nil if value.type == :variable return nil if value == [] && index == :tail visit = [value, index] return nil if visited.include?(visit) visited = visited + [visit] case index when Integer if value.respond_to?(:last) && value.last == UNKNOWN_TAIL if index >= value.length - 1 UNKNOWN_TAIL else value[index] end elsif value.is_a?(Numeric) value else value[index] end when Symbol value_value = value.value(visited) if index == :flathead # value_value = [..., 4, 5, 6] if value_value.first == UNKNOWN_TAIL UNKNOWN_ARRAY else nil end elsif index == :flattail # value_value = [1, 2, 3, ...] if value_value.first == UNKNOWN_TAIL nil elsif value_value.last == UNKNOWN_TAIL UNKNOWN_ARRAY end elsif value_value.respond_to?(index) value_value.send(index) else value end when Array if index.empty? value[1..-1] else value[0...index.first] end else if index raise UnhandledIndexError, "Unhandled index: #{index.inspect} of #{value.inspect}" else value end end end
@param visited [Array] prevents infinite recursion. @return [Array] the values of the Variables of the Instantiation
.
# File lib/porolog/instantiation.rb, line 139 def values(visited = []) return [] if visited.include?(self) values_for_variable1 = values_for(@variable1, visited) values_for_variable2 = values_for(@variable2, visited) (values_for_variable1 + values_for_variable2).uniq end
@param variable [Porolog::Variable,Porolog::Value] the specified variable (or end of the Instantiation
). @param visited [Array] prevents infinite recursion. @return [Array<Object>] the values for the specified variable by finding the values of the other variable (i.e. the other end) and applying any indexes.
# File lib/porolog/instantiation.rb, line 216 def values_for(variable, visited = []) return [] if visited.include?(self) visited = visited + [self] if variable == @variable1 if @index1 == :flathead flathead = value_at_index(value_indexed(@variable2.value(visited), @index2, visited), @index1).value.value if flathead return [[*flathead]] else return [] end end if @index1 == :flattail flattail = value_at_index(value_indexed(@variable2.value(visited), @index2, visited), @index1).value.value if flattail return [[UNKNOWN_TAIL, *flattail]] else return [] end end if @index1 [value_at_index(value_indexed(@variable2.value(visited), @index2, visited), @index1)] else if @variable2.is_a?(Variable) [value_indexed(@variable2.value(visited), @index2, visited)] else [value_indexed(@variable2, @index2, visited)] end end elsif variable == @variable2 if @index2 == :flathead flathead = value_at_index(value_indexed(@variable1.value(visited), @index1, visited), @index2).value.value if flathead return [[*flathead]] else return [] end end if @index2 == :flattail flattail = value_at_index(value_indexed(@variable1.value(visited), @index1, visited), @index2).value.value if flattail return [[UNKNOWN_TAIL, *flattail]] else return [] end end if @index2 [value_at_index(value_indexed(@variable1.value(visited), @index1, visited), @index2)] else if @variable1.is_a?(Variable) [value_indexed(@variable1.value(visited), @index1, visited)] else [value_indexed(@variable1, @index1, visited)] end end else [] end.compact end
@return [Array<Porolog::Variable,Object>] the Variables of the Instantiation
.
# File lib/porolog/instantiation.rb, line 133 def variables [@variable1,@variable2] end
@param variable [Porolog::Variable,Porolog::Value] the specified variable. @return [Boolean] whether the specified variable is not indexed.
# File lib/porolog/instantiation.rb, line 320 def without_index_on?(variable) [ [@variable1,@index1], [@variable2,@index2], ].any?{|pair| pair.first == variable && pair.last.nil? } end