class Wongi::Engine::Overlay

Attributes

generator_tracker[R]
hidden_ncc_tokens[R]
hidden_parent_tokens[R]
hidden_parent_wme_manual[R]
hidden_parent_wmes[R]
indexes[R]
ncc_tokens[R]
ncc_tokens_owner[R]
neg_join_results[R]
opt_join_results[R]
parent[R]
queue[R]
rete[R]
tokens[R]
wme_manual[R]
wmes[R]

Public Class Methods

new(rete, parent = nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 19
def initialize(rete, parent = nil)
  @rete = rete
  @parent = parent

  @wmes = Set.new
  @indexes = [
    nil,
    AlphaIndex.new(%i[object]),
    AlphaIndex.new(%i[predicate]),
    AlphaIndex.new(%i[predicate object]),
    AlphaIndex.new(%i[subject]),
    AlphaIndex.new(%i[subject object]),
    AlphaIndex.new(%i[subject predicate]),
    nil,
  ]
  @hidden_parent_wmes = {}

  @tokens = Hash.new { |h, k| h[k] = [] }
  @hidden_parent_tokens = Set.new

  @generator_tracker = GeneratorTracker.new

  @wme_manual = {}
  @hidden_parent_wme_manual = {}

  @neg_join_results = JoinResults.new
  @opt_join_results = JoinResults.new

  @ncc_tokens = Hash.new { |h, k| h[k] = [] }
  @ncc_tokens_owner = {}
  @hidden_ncc_tokens = Hash.new { |h, k| h[k] = {} }

  @queue = []
end

Public Instance Methods

<<(thing) click to toggle source
# File lib/wongi-engine/overlay.rb, line 65
def <<(thing)
  case thing
  when Array
    assert(WME.new(*thing))
  when WME
    assert(thing)
  else
    raise Error, "overlays can only accept data"
  end

  self
end
add_ncc_token(owner, ncc) click to toggle source
# File lib/wongi-engine/overlay.rb, line 438
def add_ncc_token(owner, ncc)
  if hidden_ncc_tokens.key?(owner) && hidden_ncc_tokens[token].include?(ncc)
    hidden_ncc_tokens[owner].delete(ncc)
    if hidden_ncc_tokens[owner].empty?
      hidden_ncc_tokens.delete(owner)
    end
    return
  end

  ncc_tokens[owner] << ncc
  ncc_tokens_owner[ncc] = owner
end
add_neg_join_result(njr) click to toggle source
# File lib/wongi-engine/overlay.rb, line 385
def add_neg_join_result(njr)
  neg_join_results.add(njr)
end
add_opt_join_result(ojr) click to toggle source
# File lib/wongi-engine/overlay.rb, line 403
def add_opt_join_result(ojr)
  opt_join_results.add(ojr)
end
add_token(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 304
def add_token(token)
  # p add_token: {token:}
  # TODO: is this really likely to happen? we don't normally restore deleted tokens but rather create new ones in the activation
  if hidden_token?(token)
    puts "odd case"
    unhide_token(token)
    return
  end

  tokens[token.node.object_id].push(token) # unless tokens.include?(token) # TODO: pretty unlikely to somehow trigger a repeated evaluation for the same token?..
end
ancestor?(other) click to toggle source
# File lib/wongi-engine/overlay.rb, line 58
def ancestor?(other)
  return false if parent.nil?
  return true if parent == other

  parent.ancestor?(other)
end
assert(wme, generator: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 78
def assert(wme, generator: nil)
  operation = [:assert, wme, { generator: generator }]
  queue.push(operation)

  run_queue if queue.length == 1

  self
end
default?() click to toggle source
# File lib/wongi-engine/overlay.rb, line 124
def default?
  self == rete.default_overlay
end
each(*args, &block) click to toggle source
# File lib/wongi-engine/overlay.rb, line 135
def each(*args, &block)
  template = nil
  case args.length
  when 0
    template = Template.new(:_, :_, :_)
  when 1
    arg = args.first
    case arg
    when Array
      template = Template.new(*arg)
    when Template
      template = arg
    when WME
      template = Template.new(arg.subject, arg.predicate, arg.object)
    else
      raise ArgumentError
    end
  when 3
    template = Template.new(*args)
  else
    raise ArgumentError
  end

  each_by_template(template).each(&block)
end
each_by_template(template) click to toggle source
# File lib/wongi-engine/overlay.rb, line 229
def each_by_template(template)
  Enumerator.new do |y|
    each_own_wme_by_template(template, y)
    each_parent_wme_by_template(template, y)
  end
end
entity(subject) click to toggle source
# File lib/wongi-engine/overlay.rb, line 161
def entity(subject)
  # 4 is the bitmap for <s _ _>
  EntityIterator.new(subject, indexes[4].collection_for_wme(Template.new(subject, :_, :_)))
end
find(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 128
def find(wme)
  if wme.is_a?(Array)
    wme = WME.new(*wme)
  end
  find_wme(wme)
end
find_ignoring_hidden(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 222
def find_ignoring_hidden(wme)
  find_own_wme(wme) ||
    if parent
      parent.find_ignoring_hidden(wme)
    end
end
generated?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 173
def generated?(wme)
  generators(wme).any?
end
generated_wmes(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 186
def generated_wmes(token)
  Enumerator.new do |y|
    generator_tracker.for_token(token).each { y << _1 }
    if parent && !hidden_token?(token)
      parent.generated_wmes(token).reject { hidden_wme?(_1) }.each { y << _1 }
    end
  end
end
generators(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 177
def generators(wme)
  Enumerator.new do |y|
    generator_tracker.for_wme(wme).each {  y << _1 }
    if parent
      parent.generators(wme).reject { hidden_token?(_1) }.each { y << _1 }
    end
  end
end
manual?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 166
def manual?(wme)
  wme_manual.key?(wme) ||
    if parent
      parent.manual?(wme) && !hidden_parent_wme_manual.key?(wme)
    end
end
ncc_owner(ncc) click to toggle source
# File lib/wongi-engine/overlay.rb, line 451
def ncc_owner(ncc)
  ncc_tokens_owner[ncc]
end
ncc_tokens_for(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 455
def ncc_tokens_for(token)
  own_ncc_tokens_for(token) + parent_ncc_tokens_for(token)
end
neg_join_results_for(wme: nil, token: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 393
def neg_join_results_for(wme: nil, token: nil)
  if wme
    neg_join_results.for(wme: wme) + parent_neg_join_results_for(wme: wme)
  elsif token
    neg_join_results.for(token: token) + parent_neg_join_results_for(token: token)
  else
    []
  end
end
new_child() click to toggle source
# File lib/wongi-engine/overlay.rb, line 54
def new_child
  Overlay.new(rete, self)
end
node_tokens(beta) click to toggle source
# File lib/wongi-engine/overlay.rb, line 367
def node_tokens(beta)
  parents = parents_node_tokens(beta)
  own = own_node_tokens(beta)
  parents + own
end
opt_join_results_for(wme: nil, token: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 412
def opt_join_results_for(wme: nil, token: nil)
  if wme
    opt_join_results.for(wme: wme) + parent_opt_join_results_for(wme: wme)
  elsif token
    opt_join_results.for(token: token) + parent_opt_join_results_for(token: token)
  else
    []
  end
end
remove_neg_join_result(njr) click to toggle source
# File lib/wongi-engine/overlay.rb, line 389
def remove_neg_join_result(njr)
  neg_join_results.remove(njr)
end
remove_opt_join_result(ojr) click to toggle source
# File lib/wongi-engine/overlay.rb, line 407
def remove_opt_join_result(ojr)
  # p remove_opt_join_result: {ojr:}
  opt_join_results.remove(ojr)
end
remove_own_token(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 342
def remove_own_token(token)
  # p remove_own_token: {token:}
  tokens[token.node.object_id].delete(token)
  neg_join_results.remove_token(token)
  opt_join_results.remove_token(token)
  generator_tracker.remove_token(token)

  # if this is an NCC partner token
  if (owner = ncc_tokens_owner[token])
    if ncc_tokens.key?(owner)
      ncc_tokens[owner].delete(token)
    end
    if hidden_ncc_tokens.key?(owner)
      hidden_ncc_tokens[owner].delete(token)
    end
  end

  # if this is an NCC owner token
  own_ncc_tokens_for(token).each do |ncc|
    ncc_tokens_owner.delete(ncc)
  end
  ncc_tokens.delete(token)
  hidden_ncc_tokens.delete(token)
end
remove_token(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 316
def remove_token(token)
  # p remove_token: {token:}

  # capture the entire enumerated state
  wmes = generated_wmes(token).to_a

  if own_node_tokens(token.node).find { _1.equal?(token) }.nil?
    if parents_node_tokens(token.node).find { _1.equal?(token) }
      hide_token(token)

      # do not hide JRs from the WME side: it will be done in the alpha deactivation and the JRs have to stay visible until then
      parent_neg_join_results_for(token: token).each { neg_join_results.hide(_1) }
      parent_opt_join_results_for(token: token).each { opt_join_results.hide(_1) }

      parent_ncc_tokens_for(token).each do |ncc|
        hidden_ncc_tokens[token][ncc] = true
      end
    end
  else
    remove_own_token(token)
  end

  wmes.each { retract(_1, generator: token) }

end
retract(wme, options = {}) click to toggle source
# File lib/wongi-engine/overlay.rb, line 87
def retract(wme, options = {})
  if wme.is_a?(Array)
    wme = WME.new(*wme)
  end

  operation = [:retract, wme, options]
  queue.push(operation)

  run_queue if queue.length == 1

  self
end

Private Instance Methods

add_wme(wme, generator:) click to toggle source
# File lib/wongi-engine/overlay.rb, line 253
        def add_wme(wme, generator:)
  # p add_wme: { wme:, generator: !!generator }

  # if we previously hid this locally, unhide it
  hidden_parent_wmes.delete(wme)

  unless has_own_wme?(wme)
    wmes.add(wme)
    indexes[1..6].each { _1.add(wme) }
  end

  if generator
    generator_tracker.add(wme, generator)
  else
    hidden_parent_wme_manual.delete(wme)
    wme_manual[wme] = true
  end
end
each_own_wme_by_template(template, y) click to toggle source
# File lib/wongi-engine/overlay.rb, line 236
        def each_own_wme_by_template(template, y)
  if template.concrete?
    wme = find_own_wme(WME.from_concrete_template(template))
    y << wme if wme
  elsif template.root?
    wmes.each { y << _1 }
  else
    indexes[template.bitmap].collection_for_wme(template).each { y << _1 }
  end
end
each_parent_wme_by_template(template, y) click to toggle source
# File lib/wongi-engine/overlay.rb, line 247
        def each_parent_wme_by_template(template, y)
  if parent
    parent.each_by_template(template).reject { hidden_wme?(_1) }.each { y << _1 }
  end
end
find_own_wme(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 207
        def find_own_wme(wme)
  has_own_wme?(wme) ? wme : nil
end
find_parents_wme(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 215
        def find_parents_wme(wme)
  return unless parent

  parent_wme = parent.find(wme)
  parent_wme unless hidden_wme?(parent_wme)
end
find_wme(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 203
        def find_wme(wme)
  find_own_wme(wme) || find_parents_wme(wme)
end
has_own_wme?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 211
        def has_own_wme?(wme)
  wmes.include?(wme)
end
hidden_token?(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 477
        def hidden_token?(token)
  hidden_parent_tokens.include?(token.object_id)
end
hidden_wme?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 473
        def hidden_wme?(wme)
  hidden_parent_wmes.key?(wme)
end
hide_token(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 481
        def hide_token(token)
  hidden_parent_tokens.add(token.object_id)
end
own_generated?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 199
        def own_generated?(wme)
  generator_tracker.for_wme(wme).any?
end
own_manual?(wme) click to toggle source
# File lib/wongi-engine/overlay.rb, line 195
        def own_manual?(wme)
  wme_manual.key?(wme)
end
own_ncc_tokens_for(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 459
        def own_ncc_tokens_for(token)
  ncc_tokens.key?(token) ? ncc_tokens[token] : []
end
own_node_tokens(beta) click to toggle source
# File lib/wongi-engine/overlay.rb, line 373
        def own_node_tokens(beta)
  tokens[beta.object_id]
end
parent_ncc_tokens_for(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 463
        def parent_ncc_tokens_for(token)
  if parent
    parent.ncc_tokens_for(token).reject { |parent_token|
      hidden_ncc_tokens.key?(token) && hidden_ncc_tokens[token].key?(parent_token)
    }
  else
    []
  end
end
parent_neg_join_results_for(wme: nil, token: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 430
        def parent_neg_join_results_for(wme: nil, token: nil)
  if parent
    parent.neg_join_results_for(wme: wme, token: token).reject { neg_join_results.hidden?(_1) }
  else
    []
  end
end
parent_opt_join_results_for(wme: nil, token: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 422
        def parent_opt_join_results_for(wme: nil, token: nil)
  if parent
    parent.opt_join_results_for(wme: wme, token: token).reject { opt_join_results.hidden?(_1) }
  else
    []
  end
end
parents_node_tokens(beta) click to toggle source
# File lib/wongi-engine/overlay.rb, line 377
        def parents_node_tokens(beta)
  if parent
    parent.node_tokens(beta).reject { hidden_token?(_1) }
  else
    []
  end
end
remove_wme(wme, generator: nil) click to toggle source
# File lib/wongi-engine/overlay.rb, line 272
        def remove_wme(wme, generator: nil)
  # p remove_wme: { wme:, generator: !!generator }

  if find_own_wme(wme)
    wme_manual.delete(wme) if generator.nil?

    # no remaining reasons to keep this WME around
    if !own_generated?(wme) && !own_manual?(wme)
      wmes.delete(wme)
      indexes[1..6].each { _1.remove(wme) }
    end

    neg_join_results.remove_wme(wme)
    opt_join_results.remove_wme(wme)
  end

  # did we also have an unshadowed parent version?
  return unless find_parents_wme(wme)

  # must be parents' then

  if generator.nil?
    wme_manual.delete(wme)
    # if still manual, it must be from the parent
    hidden_parent_wme_manual[wme] = true if manual?(wme)
  end

  if !manual?(wme) && !generated?(wme)
    hidden_parent_wmes[wme] = true
  end
end
run_queue() click to toggle source
# File lib/wongi-engine/overlay.rb, line 100
        def run_queue
  until queue.empty?
    operation, wme, options = queue.shift

    case operation
    when :assert
      existing_wme = find_ignoring_hidden(wme)
      wme = existing_wme || wme
      visible = !find(wme).nil?
      add_wme(wme, **options)
      rete.real_assert(wme) unless visible

    when :retract
      wme = find_ignoring_hidden(wme)
      if wme # it's perhaps better to return quietly, because complicated cascades may delete a WME while we're going through the queue
        visible = !find(wme).nil?
        remove_wme(wme, **options)
        rete.real_retract(wme) if visible
      end

    end
  end
end
unhide_token(token) click to toggle source
# File lib/wongi-engine/overlay.rb, line 485
        def unhide_token(token)
  hidden_parent_tokens.delete(token.object_id)
end