Class: Chemicalml::Cml::ReferenceResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/chemicalml/cml/reference_resolver.rb

Overview

Walks a CML document and resolves id-based references to the actual target wire instances. Useful for callers that need to follow CML references programmatically (e.g. bond → atoms, atomParity → atoms, map → molecules).

References are attribute values like atomRefs2="a1 a2", atomRefs4="a1 a2 a3 a4", bondRefs="b1 b2", ref="m1". The values are whitespace-separated lists of ids.

The resolver is opt-in: it does not modify the wire tree. Callers use it to perform lookups; unresolved refs are reported in a list (a constraint turns this list into warnings).

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ ReferenceResolver

Returns a new instance of ReferenceResolver.

Parameters:

  • document (Lutaml::Model::Serializable)

    the CML document to walk. Must include Chemicalml::Cml::Visitable (the standard wire classes do).



23
24
25
26
27
# File 'lib/chemicalml/cml/reference_resolver.rb', line 23

def initialize(document)
  @document = document
  @atom_index = nil
  @bond_index = nil
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



18
19
20
# File 'lib/chemicalml/cml/reference_resolver.rb', line 18

def document
  @document
end

Instance Method Details

#atom_indexObject

Lazily-built => Atom index. Speeds up find_atom and reference-resolution lookups from O(n) to O(1).



31
32
33
34
35
36
37
# File 'lib/chemicalml/cml/reference_resolver.rb', line 31

def atom_index
  @atom_index ||= begin
    hash = {}
    document.each_atom { |a| hash[a.id] = a if a.id }
    hash
  end
end

#bond_indexObject

Lazily-built => Bond index.



40
41
42
43
44
45
46
# File 'lib/chemicalml/cml/reference_resolver.rb', line 40

def bond_index
  @bond_index ||= begin
    hash = {}
    document.each_bond { |b| hash[b.id] = b if b.id }
    hash
  end
end

#find_atom(_molecule, atom_id) ⇒ Object

Returns the Atom with the given id within the given molecule, or nil if not found.



50
51
52
53
54
# File 'lib/chemicalml/cml/reference_resolver.rb', line 50

def find_atom(_molecule, atom_id)
  return nil unless atom_id

  atom_index[atom_id]
end

#find_bond(_molecule, bond_id) ⇒ Object

Returns the Bond with the given id within the given molecule, or nil if not found.



58
59
60
61
62
# File 'lib/chemicalml/cml/reference_resolver.rb', line 58

def find_bond(_molecule, bond_id)
  return nil unless bond_id

  bond_index[bond_id]
end

#resolve_atom_refs2(bond, molecule = containing_molecule(bond)) ⇒ Object

Resolves bond.atom_refs2 to a pair of [Atom, Atom]. Returns nils for missing atoms so callers can detect partial misses.



66
67
68
69
70
71
72
# File 'lib/chemicalml/cml/reference_resolver.rb', line 66

def resolve_atom_refs2(bond, molecule = containing_molecule(bond))
  ids = parse_refs(bond&.atom_refs2)
  return [] if ids.empty?
  return [nil, nil] if ids.size != 2

  ids.map { |id| find_atom(molecule, id) }
end

#unresolved_refsObject

Walks the whole document and reports every reference attribute whose target id is missing. Returns a list of hashes:

{ node: <Bond>, attr: :atom_refs2, missing: ["a99"] }


78
79
80
81
82
83
84
# File 'lib/chemicalml/cml/reference_resolver.rb', line 78

def unresolved_refs
  results = []
  visit(@document) do |node|
    results.concat(unresolved_for(node))
  end
  results
end