#!/usr/bin/env python3 """Export the Slipnet structure to a JSON file. This script is self-contained to avoid Python version compatibility issues with the main copycat package. """ import json class Slipnode: """Minimal Slipnode for export purposes.""" def __init__(self, slipnet, name, depth, length=0.0): self.slipnet = slipnet self.name = name self.conceptualDepth = depth self.intrinsicLinkLength = length self.shrunkLinkLength = length * 0.4 self.codelets = [] self.categoryLinks = [] self.instanceLinks = [] self.propertyLinks = [] self.lateralSlipLinks = [] self.lateralNonSlipLinks = [] self.incomingLinks = [] self.outgoingLinks = [] class Sliplink: """Minimal Sliplink for export purposes.""" def __init__(self, source, destination, label=None, length=0.0): self.source = source self.destination = destination self.label = label self.fixedLength = length source.outgoingLinks.append(self) destination.incomingLinks.append(self) class SlipnetExporter: """Recreates the Slipnet structure for export.""" def __init__(self): self.slipnodes = [] self.sliplinks = [] self._addInitialNodes() self._addInitialLinks() def _addNode(self, name, depth, length=0): slipnode = Slipnode(self, name, depth, length) self.slipnodes.append(slipnode) return slipnode def _addLink(self, source, destination, label=None, length=0.0): link = Sliplink(source, destination, label=label, length=length) self.sliplinks.append(link) return link def _addSlipLink(self, source, destination, label=None, length=0.0): link = self._addLink(source, destination, label, length) source.lateralSlipLinks.append(link) def _addNonSlipLink(self, source, destination, label=None, length=0.0): link = self._addLink(source, destination, label, length) source.lateralNonSlipLinks.append(link) def _addBidirectionalLink(self, source, destination, length): self._addNonSlipLink(source, destination, length=length) self._addNonSlipLink(destination, source, length=length) def _addCategoryLink(self, source, destination, length): link = self._addLink(source, destination, None, length) source.categoryLinks.append(link) def _addInstanceLink(self, source, destination, length=100.0): categoryLength = source.conceptualDepth - destination.conceptualDepth self._addCategoryLink(destination, source, categoryLength) link = self._addLink(source, destination, None, length) source.instanceLinks.append(link) def _addPropertyLink(self, source, destination, length): link = self._addLink(source, destination, None, length) source.propertyLinks.append(link) def _addOppositeLink(self, source, destination): self._addSlipLink(source, destination, label=self.opposite) self._addSlipLink(destination, source, label=self.opposite) def _link_items_to_their_neighbors(self, items): previous = items[0] for item in items[1:]: self._addNonSlipLink(previous, item, label=self.successor) self._addNonSlipLink(item, previous, label=self.predecessor) previous = item def _addInitialNodes(self): self.letters = [] for c in 'abcdefghijklmnopqrstuvwxyz': slipnode = self._addNode(c, 10.0) self.letters.append(slipnode) self.numbers = [] for c in '12345': slipnode = self._addNode(c, 30.0) self.numbers.append(slipnode) # string positions self.leftmost = self._addNode('leftmost', 40.0) self.rightmost = self._addNode('rightmost', 40.0) self.middle = self._addNode('middle', 40.0) self.single = self._addNode('single', 40.0) self.whole = self._addNode('whole', 40.0) # alphabetic positions self.first = self._addNode('first', 60.0) self.last = self._addNode('last', 60.0) # directions self.left = self._addNode('left', 40.0) self.left.codelets += ['top-down-bond-scout--direction'] self.left.codelets += ['top-down-group-scout--direction'] self.right = self._addNode('right', 40.0) self.right.codelets += ['top-down-bond-scout--direction'] self.right.codelets += ['top-down-group-scout--direction'] # bond types self.predecessor = self._addNode('predecessor', 50.0, 60.0) self.predecessor.codelets += ['top-down-bond-scout--category'] self.successor = self._addNode('successor', 50.0, 60.0) self.successor.codelets += ['top-down-bond-scout--category'] self.sameness = self._addNode('sameness', 80.0) self.sameness.codelets += ['top-down-bond-scout--category'] # group types self.predecessorGroup = self._addNode('predecessorGroup', 50.0) self.predecessorGroup.codelets += ['top-down-group-scout--category'] self.successorGroup = self._addNode('successorGroup', 50.0) self.successorGroup.codelets += ['top-down-group-scout--category'] self.samenessGroup = self._addNode('samenessGroup', 80.0) self.samenessGroup.codelets += ['top-down-group-scout--category'] # other relations self.identity = self._addNode('identity', 90.0) self.opposite = self._addNode('opposite', 90.0, 80.0) # objects self.letter = self._addNode('letter', 20.0) self.group = self._addNode('group', 80.0) # categories self.letterCategory = self._addNode('letterCategory', 30.0) self.stringPositionCategory = self._addNode('stringPositionCategory', 70.0) self.stringPositionCategory.codelets += ['top-down-description-scout'] self.alphabeticPositionCategory = self._addNode('alphabeticPositionCategory', 80.0) self.alphabeticPositionCategory.codelets += ['top-down-description-scout'] self.directionCategory = self._addNode('directionCategory', 70.0) self.bondCategory = self._addNode('bondCategory', 80.0) self.groupCategory = self._addNode('groupCategory', 80.0) self.length = self._addNode('length', 60.0) self.objectCategory = self._addNode('objectCategory', 90.0) self.bondFacet = self._addNode('bondFacet', 90.0) self.initiallyClampedSlipnodes = [ self.letterCategory, self.stringPositionCategory, ] def _addInitialLinks(self): self._link_items_to_their_neighbors(self.letters) self._link_items_to_their_neighbors(self.numbers) # letter categories for letter in self.letters: self._addInstanceLink(self.letterCategory, letter, 97.0) self._addCategoryLink(self.samenessGroup, self.letterCategory, 50.0) # lengths for number in self.numbers: self._addInstanceLink(self.length, number) groups = [self.predecessorGroup, self.successorGroup, self.samenessGroup] for group in groups: self._addNonSlipLink(group, self.length, length=95.0) opposites = [ (self.first, self.last), (self.leftmost, self.rightmost), (self.left, self.right), (self.successor, self.predecessor), (self.successorGroup, self.predecessorGroup), ] for a, b in opposites: self._addOppositeLink(a, b) # properties self._addPropertyLink(self.letters[0], self.first, 75.0) self._addPropertyLink(self.letters[-1], self.last, 75.0) links = [ # object categories (self.objectCategory, self.letter), (self.objectCategory, self.group), # string positions (self.stringPositionCategory, self.leftmost), (self.stringPositionCategory, self.rightmost), (self.stringPositionCategory, self.middle), (self.stringPositionCategory, self.single), (self.stringPositionCategory, self.whole), # alphabetic positions (self.alphabeticPositionCategory, self.first), (self.alphabeticPositionCategory, self.last), # direction categories (self.directionCategory, self.left), (self.directionCategory, self.right), # bond categories (self.bondCategory, self.predecessor), (self.bondCategory, self.successor), (self.bondCategory, self.sameness), # group categories (self.groupCategory, self.predecessorGroup), (self.groupCategory, self.successorGroup), (self.groupCategory, self.samenessGroup), # bond facets (self.bondFacet, self.letterCategory), (self.bondFacet, self.length), ] for a, b in links: self._addInstanceLink(a, b) # link bonds to their groups self._addNonSlipLink(self.sameness, self.samenessGroup, label=self.groupCategory, length=30.0) self._addNonSlipLink(self.successor, self.successorGroup, label=self.groupCategory, length=60.0) self._addNonSlipLink(self.predecessor, self.predecessorGroup, label=self.groupCategory, length=60.0) # link bond groups to their bonds self._addNonSlipLink(self.samenessGroup, self.sameness, label=self.bondCategory, length=90.0) self._addNonSlipLink(self.successorGroup, self.successor, label=self.bondCategory, length=90.0) self._addNonSlipLink(self.predecessorGroup, self.predecessor, label=self.bondCategory, length=90.0) # letter category to length self._addSlipLink(self.letterCategory, self.length, length=95.0) self._addSlipLink(self.length, self.letterCategory, length=95.0) # letter to group self._addSlipLink(self.letter, self.group, length=90.0) self._addSlipLink(self.group, self.letter, length=90.0) # direction-position, direction-neighbor, position-neighbor self._addBidirectionalLink(self.left, self.leftmost, 90.0) self._addBidirectionalLink(self.right, self.rightmost, 90.0) self._addBidirectionalLink(self.right, self.leftmost, 100.0) self._addBidirectionalLink(self.left, self.rightmost, 100.0) self._addBidirectionalLink(self.leftmost, self.first, 100.0) self._addBidirectionalLink(self.rightmost, self.first, 100.0) self._addBidirectionalLink(self.leftmost, self.last, 100.0) self._addBidirectionalLink(self.rightmost, self.last, 100.0) # other self._addSlipLink(self.single, self.whole, length=90.0) self._addSlipLink(self.whole, self.single, length=90.0) def export_slipnet(): """Export slipnet nodes and links to a JSON structure.""" slipnet = SlipnetExporter() # Build node data nodes = [] node_to_id = {} for node in slipnet.slipnodes: node_to_id[node] = node.name node_data = { "name": node.name, "conceptualDepth": node.conceptualDepth, "intrinsicLinkLength": node.intrinsicLinkLength, "shrunkLinkLength": node.shrunkLinkLength, } if node.codelets: node_data["codelets"] = node.codelets nodes.append(node_data) # Build link data with type classification links = [] for link in slipnet.sliplinks: link_data = { "source": node_to_id[link.source], "destination": node_to_id[link.destination], "fixedLength": link.fixedLength, } if link.label: link_data["label"] = node_to_id[link.label] # Determine link type if link in link.source.lateralSlipLinks: link_data["type"] = "slip" elif link in link.source.lateralNonSlipLinks: link_data["type"] = "nonSlip" elif link in link.source.categoryLinks: link_data["type"] = "category" elif link in link.source.instanceLinks: link_data["type"] = "instance" elif link in link.source.propertyLinks: link_data["type"] = "property" links.append(link_data) # Identify initially clamped nodes initially_clamped = [node_to_id[n] for n in slipnet.initiallyClampedSlipnodes] # Create the full structure data = { "description": "Copycat Slipnet - A semantic network for analogical reasoning", "nodeCount": len(nodes), "linkCount": len(links), "initiallyClampedNodes": initially_clamped, "nodes": nodes, "links": links, } return data if __name__ == '__main__': data = export_slipnet() output_file = 'slipnet.json' with open(output_file, 'w') as f: json.dump(data, f, indent=2) print(f"Exported {data['nodeCount']} nodes and {data['linkCount']} links to {output_file}")