Merge pull request #3 from jtauber/master
improved PEP compliance and fixed errors preventing it from running
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
co.py.cat
|
||||
=========
|
||||
|
||||
An implementation of the [Douglas Hofstadter](http://prelectur.stanford.edu/lecturers/hofstadter/)'s [copycat](https://en.wikipedia.org/wiki/Copycat_%28software%29) [algorithm](http://www.al-got-rhythm.net)
|
||||
An implementation of [Douglas Hofstadter](http://prelectur.stanford.edu/lecturers/hofstadter/)'s [copycat](https://en.wikipedia.org/wiki/Copycat_%28software%29) [algorithm](http://www.al-got-rhythm.net)
|
||||
|
||||
This implementation is a copycat of Scott Boland's [Java implementation](http://itee.uq.edu.au/~scottb/_Copycat/), but re-written into Python. It's not a direct translation - but based on his code. I did not carry over the GUI, as this version can more usefully be run from command line, or imported for use by other Python scripts.
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ from workspaceStructure import WorkspaceStructure
|
||||
from slipnet import slipnet
|
||||
from workspace import workspace
|
||||
|
||||
|
||||
class Bond(WorkspaceStructure):
|
||||
def __init__(self, source, destination, bondCategory, bondFacet, sourceDescriptor, destinationDescriptor):
|
||||
WorkspaceStructure.__init__(self)
|
||||
@ -164,6 +165,7 @@ class Bond(WorkspaceStructure):
|
||||
def set_source(self, value):
|
||||
self.source = value
|
||||
|
||||
|
||||
def possibleGroupBonds(bondCategory, directionCategory, bondFacet, bonds):
|
||||
result = []
|
||||
for bond in bonds:
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
#import utils
|
||||
import random
|
||||
|
||||
from coderack import coderack
|
||||
from workspaceObject import WorkspaceObject
|
||||
@ -10,6 +10,7 @@ from group import Group
|
||||
from bond import Bond, possibleGroupBonds
|
||||
from correspondence import Correspondence
|
||||
|
||||
|
||||
# some methods common to the codelets
|
||||
def __showWhichStringObjectIsFrom(structure):
|
||||
if not structure:
|
||||
@ -21,6 +22,7 @@ def __showWhichStringObjectIsFrom(structure):
|
||||
whence = 'initial'
|
||||
print 'object chosen = %s from %s string' % (structure, whence)
|
||||
|
||||
|
||||
def __getScoutSource(slipnode, relevanceMethod, typeName):
|
||||
initialRelevance = relevanceMethod(workspace.initial, slipnode)
|
||||
targetRelevance = relevanceMethod(workspace.target, slipnode)
|
||||
@ -29,7 +31,7 @@ def __getScoutSource(slipnode,relevanceMethod,typeName):
|
||||
logging.info('initial : relevance = %d, unhappiness=%d' % (initialRelevance, int(initialUnhappiness)))
|
||||
logging.info('target : relevance = %d, unhappiness=%d' % (targetRelevance, int(targetUnhappiness)))
|
||||
string = workspace.initial
|
||||
if utils.random() * (initialRelevance + initialUnhappiness+targetRelevance+targetUnhappiness) > (initialRelevance + initialUnhappiness):
|
||||
if random.random() * (initialRelevance + initialUnhappiness + targetRelevance + targetUnhappiness) > (initialRelevance + initialUnhappiness):
|
||||
string = workspace.target
|
||||
logging.info('target string selected: %s for %s' % (workspace.target, typeName))
|
||||
else:
|
||||
@ -37,29 +39,34 @@ def __getScoutSource(slipnode,relevanceMethod,typeName):
|
||||
source = chooseUnmodifiedObject('intraStringSalience', string.objects)
|
||||
return source
|
||||
|
||||
|
||||
def __getBondFacet(source, destination):
|
||||
bondFacet = chooseBondFacet(source, destination)
|
||||
assert bondFacet
|
||||
return bondFacet
|
||||
|
||||
|
||||
def __getDescriptors(bondFacet, source, destination):
|
||||
sourceDescriptor = source.getDescriptor(bondFacet)
|
||||
destinationDescriptor = destination.getDescriptor(bondFacet)
|
||||
assert sourceDescriptor and destinationDescriptor
|
||||
return sourceDescriptor, destinationDescriptor
|
||||
|
||||
|
||||
def __allOppositeMappings(mappings):
|
||||
return len([m for m in mappings if m.label != slipnet.opposite]) == 0
|
||||
|
||||
|
||||
def __structureVsStructure(structure1, weight1, structure2, weight2):
|
||||
structure1.updateStrength()
|
||||
structure2.updateStrength()
|
||||
weightedStrength1 = temperatureAdjustedValue(structure1.totalStrength * weight1)
|
||||
weightedStrength2 = temperatureAdjustedValue(structure2.totalStrength * weight2)
|
||||
rhs = (weightedStrength1 + weightedStrength2) * utils.random()
|
||||
rhs = (weightedStrength1 + weightedStrength2) * random.random()
|
||||
logging.info('%d > %d' % (weightedStrength1, rhs))
|
||||
return weightedStrength1 > rhs
|
||||
|
||||
|
||||
def __fightItOut(structure, structureWeight, incompatibles, incompatibleWeight):
|
||||
if not (incompatibles and len(incompatibles)):
|
||||
return True
|
||||
@ -70,6 +77,7 @@ def __fightItOut(structure, structureWeight, incompatibles, incompatibleWeight):
|
||||
logging.info('won fight with %s' % incompatible)
|
||||
return True
|
||||
|
||||
|
||||
def __fightIncompatibles(incompatibles, structure, name, structureWeight, incompatibleWeight):
|
||||
if len(incompatibles):
|
||||
if __fightItOut(structure, structureWeight, incompatibles, incompatibleWeight):
|
||||
@ -80,6 +88,7 @@ def __fightIncompatibles(incompatibles,structure,name,structureWeight,incompatib
|
||||
logging.info('no incompatible %s' % name)
|
||||
return True
|
||||
|
||||
|
||||
def __slippability(conceptMappings):
|
||||
for mapping in conceptMappings:
|
||||
slippiness = mapping.slipability() / 100.0
|
||||
@ -88,6 +97,7 @@ def __slippability(conceptMappings):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
# start the actual codelets
|
||||
def breaker():
|
||||
probabilityOfFizzle = (100.0 - Temperature) / 100.0
|
||||
@ -98,7 +108,7 @@ def breaker():
|
||||
isinstance(s, Bond) or
|
||||
isinstance(s, Correspondence)]
|
||||
assert len(structures)
|
||||
structure = utils.choice(structures)
|
||||
structure = random.choice(structures)
|
||||
__showWhichStringObjectIsFrom(structure)
|
||||
breakObjects = [structure]
|
||||
if isinstance(structure, Bond):
|
||||
@ -112,6 +122,7 @@ def breaker():
|
||||
for structure in breakObjects:
|
||||
structure.break_the_structure()
|
||||
|
||||
|
||||
def bottom_up_description_scout(codelet):
|
||||
chosenObject = chooseUnmodifiedObject('totalSalience', workspace.objects)
|
||||
assert chosenObject
|
||||
@ -126,6 +137,7 @@ def bottom_up_description_scout(codelet):
|
||||
chosenProperty = chosen.destination
|
||||
coderack.proposeDescription(chosenObject, chosenProperty.category(), chosenProperty, codelet)
|
||||
|
||||
|
||||
def top_down_description_scout(codelet):
|
||||
descriptionType = codelet.arguments[0]
|
||||
chosenObject = chooseUnmodifiedObject('totalSalience', workspace.objects)
|
||||
@ -138,6 +150,7 @@ def top_down_description_scout(codelet):
|
||||
chosenProperty = descriptions[i]
|
||||
coderack.proposeDescription(chosenObject, chosenProperty.category(), chosenProperty, codelet)
|
||||
|
||||
|
||||
def description_strength_tester(codelet):
|
||||
description = codelet.arguments[0]
|
||||
description.descriptor.buffer = 100.0
|
||||
@ -147,6 +160,7 @@ def description_strength_tester(codelet):
|
||||
assert formulas.coinFlip(probability)
|
||||
coderack.newCodelet('description-builder', codelet, strength)
|
||||
|
||||
|
||||
def description_builder(codelet):
|
||||
description = codelet.arguments[0]
|
||||
assert description.object in workspace.objects
|
||||
@ -156,6 +170,7 @@ def description_builder(codelet):
|
||||
else:
|
||||
description.build()
|
||||
|
||||
|
||||
def bottom_up_bond_scout(codelet):
|
||||
source = chooseUnmodifiedObject('intraStringSalience', workspace.objects)
|
||||
__showWhichStringObjectIsFrom(source)
|
||||
@ -175,6 +190,7 @@ def bottom_up_bond_scout(codelet):
|
||||
logging.info('proposing %s bond ' % category.name)
|
||||
coderack.proposeBond(source, destination, category, bondFacet, sourceDescriptor, destinationDescriptor, codelet)
|
||||
|
||||
|
||||
def rule_scout(codelet):
|
||||
assert workspace.numberOfUnreplacedObjects() == 0
|
||||
changedObjects = [o for o in workspace.initial.objects if o.changed]
|
||||
@ -230,17 +246,19 @@ def rule_scout(codelet):
|
||||
relation = objectList[i]
|
||||
coderack.proposeRule(slipnet.letterCategory, descriptor, slipnet.letter, relation, codelet)
|
||||
|
||||
|
||||
def rule_strength_tester(codelet):
|
||||
rule = codelet.arguments[0]
|
||||
rule.updateStrength()
|
||||
probability = temperatureAdjustedProbability(rule.totalStrength / 100.0)
|
||||
assert utils.random() <= probability
|
||||
assert random.random() <= probability
|
||||
coderack.newCodelet('rule-builder', codelet, rule.totalStrength, rule)
|
||||
|
||||
|
||||
def replacement_finder():
|
||||
# choose random letter in initial string
|
||||
letters = [o for o in workspace.initial.objects if isinstance(o, Letter)]
|
||||
letterOfInitialString = utils.choice(letters)
|
||||
letterOfInitialString = random.choice(letters)
|
||||
logging.info('selected letter in initial string = %s' % letterOfInitialString)
|
||||
if letterOfInitialString.replacement:
|
||||
logging.info("Replacement already found for %s, so fizzling" % letterOfInitialString)
|
||||
@ -266,6 +284,7 @@ def replacement_finder():
|
||||
workspace.changedObject = letterOfInitialString
|
||||
logging.info('building replacement')
|
||||
|
||||
|
||||
def top_down_bond_scout__category(codelet):
|
||||
logging.info('top_down_bond_scout__category')
|
||||
category = codelet.arguments[0]
|
||||
@ -287,6 +306,7 @@ def top_down_bond_scout__category(codelet):
|
||||
else:
|
||||
coderack.proposeBond(destination, source, category, bondFacet, destinationDescriptor, sourceDescriptor, codelet)
|
||||
|
||||
|
||||
def top_down_bond_scout__direction(codelet):
|
||||
direction = codelet.arguments[0]
|
||||
source = __getScoutSource(direction, localDirectionCategoryRelevance, 'bond')
|
||||
@ -301,6 +321,7 @@ def top_down_bond_scout__direction(codelet):
|
||||
category = slipnet.sameness
|
||||
coderack.proposeBond(source, destination, category, bondFacet, sourceDescriptor, destinationDescriptor, codelet)
|
||||
|
||||
|
||||
def bond_strength_tester(codelet):
|
||||
bond = codelet.arguments[0]
|
||||
__showWhichStringObjectIsFrom(bond)
|
||||
@ -315,6 +336,7 @@ def bond_strength_tester(codelet):
|
||||
logging.info("succeeded: posting bond-builder")
|
||||
coderack.newCodelet('bond-builder', codelet, strength)
|
||||
|
||||
|
||||
def bond_builder(codelet):
|
||||
bond = codelet.arguments[0]
|
||||
__showWhichStringObjectIsFrom(bond)
|
||||
@ -352,6 +374,7 @@ def bond_builder(codelet):
|
||||
logging.info('building bond %s' % bond)
|
||||
bond.buildBond()
|
||||
|
||||
|
||||
def top_down_group_scout__category(codelet):
|
||||
groupCategory = codelet.arguments[0]
|
||||
category = groupCategory.getRelatedNode(slipnet.bondCategory)
|
||||
@ -383,7 +406,7 @@ def top_down_group_scout__category(codelet):
|
||||
if category == slipnet.sameness and isinstance(source, Letter):
|
||||
group = Group(source.string, slipnet.samenessGroup, None, slipnet.letterCategory, [source], [])
|
||||
probability = group.singleLetterGroupProbability()
|
||||
assert utils.random() >= probability
|
||||
assert random.random() >= probability
|
||||
coderack.proposeSingleLetterGroup(source, codelet)
|
||||
return
|
||||
direction = firstBond.directionCategory
|
||||
@ -422,6 +445,7 @@ def top_down_group_scout__category(codelet):
|
||||
source = source.rightBond.rightObject
|
||||
coderack.proposeGroup(objects, bonds, groupCategory, direction, bondFacet, codelet)
|
||||
|
||||
|
||||
def top_down_group_scout__direction(codelet):
|
||||
direction = codelet.arguments[0]
|
||||
source = __getScoutSource(direction, localDirectionCategoryRelevance, 'direction')
|
||||
@ -500,10 +524,11 @@ def top_down_group_scout__direction(codelet):
|
||||
source = source.rightBond.rightObject
|
||||
coderack.proposeGroup(objects, bonds, groupCategory, direction, bondFacet, codelet)
|
||||
|
||||
|
||||
#noinspection PyStringFormat
|
||||
def group_scout__whole_string(codelet):
|
||||
string = workspace.initial
|
||||
if utils.random() > 0.5:
|
||||
if random.random() > 0.5:
|
||||
string = workspace.target
|
||||
logging.info('target string selected: %s' % workspace.target)
|
||||
else:
|
||||
@ -528,7 +553,7 @@ def group_scout__whole_string(codelet):
|
||||
objects += [leftmost]
|
||||
assert leftmost.rightmost
|
||||
# choose a random bond from list
|
||||
chosenBond = utils.choice(bonds)
|
||||
chosenBond = random.choice(bonds)
|
||||
category = chosenBond.category
|
||||
directionCategory = chosenBond.directionCategory
|
||||
bondFacet = chosenBond.facet
|
||||
@ -537,6 +562,7 @@ def group_scout__whole_string(codelet):
|
||||
groupCategory = category.getRelatedNode(slipnet.groupCategory)
|
||||
coderack.proposeGroup(objects, bonds, groupCategory, directionCategory, bondFacet, codelet)
|
||||
|
||||
|
||||
def group_strength_tester(codelet):
|
||||
# update strength value of the group
|
||||
group = codelet.arguments[0]
|
||||
@ -544,13 +570,14 @@ def group_strength_tester(codelet):
|
||||
group.updateStrength()
|
||||
strength = group.totalStrength
|
||||
probability = temperatureAdjustedProbability(strength / 100.0)
|
||||
assert utils.random() <= probability
|
||||
assert random.random() <= probability
|
||||
# it is strong enough - post builder & activate nodes
|
||||
group.groupCategory.getRelatedNode(slipnet.bondCategory).buffer = 100.0
|
||||
if group.directionCategory:
|
||||
group.directionCategory.buffer = 100.0
|
||||
coderack.newCodelet('group-builder', codelet, strength)
|
||||
|
||||
|
||||
def group_builder(codelet):
|
||||
# update strength value of the group
|
||||
group = codelet.arguments[0]
|
||||
@ -618,6 +645,7 @@ def group_builder(codelet):
|
||||
group.activateDescriptions()
|
||||
logging.info('building group')
|
||||
|
||||
|
||||
def rule_builder(codelet):
|
||||
rule = codelet.arguments[0]
|
||||
if rule.ruleEqual(workspace.rule):
|
||||
@ -630,6 +658,7 @@ def rule_builder(codelet):
|
||||
assert __structureVsStructure(rule, 1.0, workspace.rule, 1.0)
|
||||
workspace.buildRule(rule)
|
||||
|
||||
|
||||
def __getCutOff(density):
|
||||
if density > 0.8:
|
||||
distribution = [5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]
|
||||
@ -641,7 +670,7 @@ def __getCutOff(density):
|
||||
distribution = [1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0, 1.0]
|
||||
else:
|
||||
distribution = [1.0, 1.0, 1.0, 2.0, 5.0, 150.0, 5.0, 2.0, 1.0, 1.0]
|
||||
stop = sum(distribution) * utils.random()
|
||||
stop = sum(distribution) * random.random()
|
||||
total = 0.0
|
||||
for i in range(0, len(distribution)):
|
||||
total += distribution[i]
|
||||
@ -649,6 +678,7 @@ def __getCutOff(density):
|
||||
return i + 1
|
||||
return len(distribution)
|
||||
|
||||
|
||||
def rule_translator():
|
||||
assert workspace.rule
|
||||
if len(workspace.initial) == 1 and len(workspace.target) == 1:
|
||||
@ -668,6 +698,7 @@ def rule_translator():
|
||||
temperature.clamped = True
|
||||
formulas.Temperature = 100.0
|
||||
|
||||
|
||||
def bottom_up_correspondence_scout(codelet):
|
||||
objectFromInitial = chooseUnmodifiedObject('interStringSalience', workspace.initial.objects)
|
||||
objectFromTarget = chooseUnmodifiedObject('interStringSalience', workspace.target.objects)
|
||||
@ -691,6 +722,7 @@ def bottom_up_correspondence_scout(codelet):
|
||||
flipTargetObject = True
|
||||
coderack.proposeCorrespondence(objectFromInitial, objectFromTarget, conceptMappings, flipTargetObject, codelet)
|
||||
|
||||
|
||||
def important_object_correspondence_scout(codelet):
|
||||
objectFromInitial = chooseUnmodifiedObject('relativeImportance', workspace.initial.objects)
|
||||
descriptors = objectFromInitial.relevantDistinguishingDescriptors()
|
||||
@ -725,6 +757,7 @@ def important_object_correspondence_scout(codelet):
|
||||
flipTargetObject = True
|
||||
coderack.proposeCorrespondence(objectFromInitial, objectFromTarget, conceptMappings, flipTargetObject, codelet)
|
||||
|
||||
|
||||
def correspondence_strength_tester(codelet):
|
||||
correspondence = codelet.arguments[0]
|
||||
objectFromInitial = correspondence.objectFromInitial
|
||||
@ -733,7 +766,7 @@ def correspondence_strength_tester(codelet):
|
||||
correspondence.updateStrength()
|
||||
strength = correspondence.totalStrength
|
||||
probability = temperatureAdjustedProbability(strength / 100.0)
|
||||
assert utils.random() <= probability
|
||||
assert random.random() <= probability
|
||||
# activate some concepts
|
||||
for mapping in correspondence.conceptMappings:
|
||||
mapping.initialDescriptionType.buffer = 100.0
|
||||
@ -742,6 +775,7 @@ def correspondence_strength_tester(codelet):
|
||||
mapping.targetDescriptor.buffer = 100.0
|
||||
coderack.newCodelet('correspondence-builder', codelet, strength, correspondence)
|
||||
|
||||
|
||||
def correspondence_builder(codelet):
|
||||
correspondence = codelet.arguments[0]
|
||||
objectFromInitial = correspondence.objectFromInitial
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
import re, inspect, math, logging
|
||||
import re
|
||||
import inspect
|
||||
import math
|
||||
import logging
|
||||
import random
|
||||
|
||||
import utils
|
||||
import formulas
|
||||
import workspaceFormulas
|
||||
from slipnet import slipnet
|
||||
@ -12,6 +15,7 @@ MAX_NUMBER_OF_CODELETS = 100
|
||||
|
||||
codeletsUsed = {}
|
||||
|
||||
|
||||
class CodeRack(object):
|
||||
def __init__(self):
|
||||
#logging.debug('coderack.__init__()')
|
||||
@ -66,12 +70,12 @@ class CodeRack(object):
|
||||
howMany = workspaceFormulas.howManyToPost(codeletName)
|
||||
#print '%s:%d' % (codeletName,howMany)
|
||||
for unused in range(0, howMany):
|
||||
if utils.random() < probability:
|
||||
if random.random() < probability:
|
||||
urgency = self.getUrgencyBin(node.activation * node.conceptualDepth / 100.0)
|
||||
codelet = Codelet(codeletName, urgency, self.codeletsRun)
|
||||
codelet.arguments += [node]
|
||||
logging.info('Post top down: %s, with urgency: %d' % (codelet.name, urgency))
|
||||
#logging.info("From slipnode %s, activation: %s, depth: %s" %(node.get_name(),node.activation,node.conceptual_depth) )
|
||||
#logging.info("From slipnode %s, activation: %s, depth: %s" %(node.get_name(),node.activation,node.conceptualDepth) )
|
||||
self.post(codelet)
|
||||
|
||||
def postBottomUpCodelets(self):
|
||||
@ -101,7 +105,7 @@ class CodeRack(object):
|
||||
if formulas.Temperature < 25.0 and 'translator' in codeletName:
|
||||
urgency = 5
|
||||
for unused in range(0, howMany):
|
||||
if utils.random() < probability:
|
||||
if random.random() < probability:
|
||||
codelet = Codelet(codeletName, urgency, self.codeletsRun)
|
||||
self.post(codelet)
|
||||
|
||||
@ -196,7 +200,7 @@ class CodeRack(object):
|
||||
for codelet in self.codelets:
|
||||
urgency = (coderack.codeletsRun - codelet.timeStamp) * (7.5 - codelet.urgency)
|
||||
urgencies += [urgency]
|
||||
threshold = utils.random() * sum(urgencies)
|
||||
threshold = random.random() * sum(urgencies)
|
||||
sumOfUrgencies = 0.0
|
||||
for i in range(0, len(self.codelets)):
|
||||
sumOfUrgencies += urgencies[i]
|
||||
@ -255,7 +259,7 @@ class CodeRack(object):
|
||||
for codeletName in knownCodeletNames:
|
||||
methodName = re.sub('[ -]', '_', codeletName)
|
||||
if methodName not in self.codeletMethodsDir:
|
||||
raise NotImplementedError, 'Cannot find %s in codeletMethods' % methodName
|
||||
raise NotImplementedError('Cannot find %s in codeletMethods' % methodName)
|
||||
method = getattr(codeletMethods, methodName)
|
||||
self.methods[methodName] = method
|
||||
|
||||
@ -271,12 +275,12 @@ class CodeRack(object):
|
||||
return None
|
||||
temp = formulas.Temperature
|
||||
scale = (100.0 - temp + 10.0) / 15.0
|
||||
# threshold = sum( [ c.urgency ** scale for c in self.codelets ] ) * utils.random()
|
||||
# threshold = sum( [ c.urgency ** scale for c in self.codelets ] ) * random.random()
|
||||
urgsum = 0.0
|
||||
for codelet in self.codelets:
|
||||
urg = codelet.urgency ** scale
|
||||
urgsum += urg
|
||||
r = utils.random()
|
||||
r = random.random()
|
||||
threshold = r * urgsum
|
||||
chosen = None
|
||||
urgencySum = 0.0
|
||||
@ -321,9 +325,9 @@ class CodeRack(object):
|
||||
#if not self.codeletMethodsDir:
|
||||
method = self.methods[methodName]
|
||||
if not method:
|
||||
raise ValueError, 'Found %s in codeletMethods, but cannot get it' % methodName
|
||||
raise ValueError('Found %s in codeletMethods, but cannot get it' % methodName)
|
||||
if not callable(method):
|
||||
raise RuntimeError, 'Cannot call %s()' % methodName
|
||||
raise RuntimeError('Cannot call %s()' % methodName)
|
||||
args, varargs, varkw, defaults = inspect.getargspec(method)
|
||||
#global codeletsUsed
|
||||
#codeletsUsed[methodName] = codeletsUsed.get(methodName,0) + 1
|
||||
|
||||
@ -2,6 +2,7 @@ import logging
|
||||
from formulas import Temperature
|
||||
from slipnet import slipnet
|
||||
|
||||
|
||||
class CoderackPressure(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
@ -11,6 +12,7 @@ class CoderackPressure(object):
|
||||
self.values = []
|
||||
self.codelets = []
|
||||
|
||||
|
||||
class CoderackPressures(object):
|
||||
def __init__(self):
|
||||
#logging.debug('coderackPressures.__init__()')
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
from slipnet import slipnet
|
||||
|
||||
|
||||
class ConceptMapping(object):
|
||||
def __init__(self, initialDescriptionType, targetDescriptionType, initialDescriptor, targetDescriptor, initialObject, targetObject):
|
||||
logging.info('make a map: %s-%s' % (initialDescriptionType.get_name(), targetDescriptionType.get_name()))
|
||||
|
||||
@ -15,6 +15,7 @@ from temperature import temperature
|
||||
from coderack import coderack
|
||||
from coderackPressure import coderackPressures
|
||||
|
||||
|
||||
def updateEverything():
|
||||
workspace.updateEverything()
|
||||
coderack.updateCodelets()
|
||||
@ -53,6 +54,7 @@ def runTrial():
|
||||
for answer, count in answers.iteritems():
|
||||
print '%s:%d' % (answer, count)
|
||||
|
||||
|
||||
def run(initial, modified, target):
|
||||
workspace.setStrings(initial, modified, target)
|
||||
runTrial()
|
||||
|
||||
@ -2,6 +2,7 @@ from workspace import workspace
|
||||
from workspaceStructure import WorkspaceStructure
|
||||
from formulas import getMappings
|
||||
|
||||
|
||||
class Correspondence(WorkspaceStructure):
|
||||
def __init__(self, objectFromInitial, objectFromTarget, conceptMappings, flipTargetObject):
|
||||
WorkspaceStructure.__init__(self)
|
||||
@ -186,4 +187,3 @@ class Correspondence(WorkspaceStructure):
|
||||
workspace.structures.remove(self)
|
||||
self.objectFromInitial.correspondence = None
|
||||
self.objectFromTarget.correspondence = None
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import logging
|
||||
from workspaceStructure import WorkspaceStructure
|
||||
|
||||
|
||||
class Description(WorkspaceStructure):
|
||||
def __init__(self, workspaceObject, descriptionType, descriptor):
|
||||
WorkspaceStructure.__init__(self)
|
||||
@ -52,5 +53,3 @@ class Description(WorkspaceStructure):
|
||||
if self in workspace.structures:
|
||||
workspace.structures.remove(self)
|
||||
self.object.descriptions.remove(self)
|
||||
|
||||
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
import math #, random
|
||||
import math
|
||||
import logging
|
||||
|
||||
import utils
|
||||
import random
|
||||
|
||||
from temperature import temperature
|
||||
|
||||
actualTemperature = Temperature = 100.0
|
||||
|
||||
|
||||
def selectListPosition(probabilities):
|
||||
total = sum(probabilities)
|
||||
#logging.info('total: %s' % total)
|
||||
r = utils.random()
|
||||
r = random.random()
|
||||
stopPosition = total * r
|
||||
#logging.info('stopPosition: %s' % stopPosition)
|
||||
total = 0
|
||||
@ -22,6 +22,7 @@ def selectListPosition(probabilities):
|
||||
index += 1
|
||||
return 0
|
||||
|
||||
|
||||
def weightedAverage(values):
|
||||
total = 0.0
|
||||
totalWeights = 0.0
|
||||
@ -32,11 +33,13 @@ def weightedAverage(values):
|
||||
return 0.0
|
||||
return total / totalWeights
|
||||
|
||||
|
||||
def temperatureAdjustedValue(value):
|
||||
#logging.info('Temperature: %s' % Temperature)
|
||||
#logging.info('actualTemperature: %s' % actualTemperature)
|
||||
return value ** (((100.0 - Temperature) / 30.0) + 0.5)
|
||||
|
||||
|
||||
def temperatureAdjustedProbability(value):
|
||||
if not value or value == 0.5 or not temperature.value:
|
||||
return value
|
||||
@ -51,8 +54,10 @@ def temperatureAdjustedProbability(value):
|
||||
f = 1.0 - e
|
||||
return max(f, 0.5)
|
||||
|
||||
|
||||
def coinFlip(chance=0.5):
|
||||
return utils.random() < chance
|
||||
return random.random() < chance
|
||||
|
||||
|
||||
def blur(value):
|
||||
root = math.sqrt(value)
|
||||
@ -60,6 +65,7 @@ def blur(value):
|
||||
return value + root
|
||||
return value - root
|
||||
|
||||
|
||||
def chooseObjectFromList(objects, attribute):
|
||||
if not objects:
|
||||
return None
|
||||
@ -73,6 +79,7 @@ def chooseObjectFromList(objects,attribute):
|
||||
logging.info("Selected: %d" % index)
|
||||
return objects[index]
|
||||
|
||||
|
||||
def chooseRelevantDescriptionByActivation(workspaceObject):
|
||||
descriptions = workspaceObject.relevantDescriptions()
|
||||
if not descriptions:
|
||||
@ -81,6 +88,7 @@ def chooseRelevantDescriptionByActivation(workspaceObject):
|
||||
index = selectListPosition(activations)
|
||||
return descriptions[index]
|
||||
|
||||
|
||||
def similarPropertyLinks(slip_node):
|
||||
result = []
|
||||
for slip_link in slip_node.propertyLinks:
|
||||
@ -90,6 +98,7 @@ def similarPropertyLinks(slip_node):
|
||||
result += [slip_link]
|
||||
return result
|
||||
|
||||
|
||||
def chooseSlipnodeByConceptualDepth(slip_nodes):
|
||||
if not slip_nodes:
|
||||
return None
|
||||
@ -97,12 +106,15 @@ def chooseSlipnodeByConceptualDepth(slip_nodes):
|
||||
i = selectListPosition(depths)
|
||||
return slip_nodes[i]
|
||||
|
||||
|
||||
def __relevantCategory(objekt, slipnode):
|
||||
return objekt.rightBond and objekt.rightBond.category == slipnode
|
||||
|
||||
|
||||
def __relevantDirection(objekt, slipnode):
|
||||
return objekt.rightBond and objekt.rightBond.directionCategory == slipnode
|
||||
|
||||
|
||||
def __localRelevance(string, slipnode, relevance):
|
||||
numberOfObjectsNotSpanning = numberOfMatches = 0.0
|
||||
#logging.info("find relevance for a string: %s" % string);
|
||||
@ -118,14 +130,17 @@ def __localRelevance(string,slipnode,relevance):
|
||||
return 100.0 * numberOfMatches
|
||||
return 100.0 * numberOfMatches / (numberOfObjectsNotSpanning - 1.0)
|
||||
|
||||
|
||||
def localBondCategoryRelevance(string, category):
|
||||
if len(string.objects) == 1:
|
||||
return 0.0
|
||||
return __localRelevance(string, category, __relevantCategory)
|
||||
|
||||
|
||||
def localDirectionCategoryRelevance(string, direction):
|
||||
return __localRelevance(string, direction, __relevantDirection)
|
||||
|
||||
|
||||
def getMappings(objectFromInitial, objectFromTarget, initialDescriptions, targetDescriptions):
|
||||
mappings = []
|
||||
from conceptMapping import ConceptMapping
|
||||
@ -143,4 +158,3 @@ def getMappings(objectFromInitial,objectFromTarget, initialDescriptions, targetD
|
||||
)
|
||||
mappings += [mapping]
|
||||
return mappings
|
||||
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
import utils, logging
|
||||
import logging
|
||||
import random
|
||||
|
||||
from workspace import workspace
|
||||
from workspaceObject import WorkspaceObject
|
||||
from slipnet import slipnet
|
||||
import formulas
|
||||
|
||||
|
||||
class Group(WorkspaceObject):
|
||||
def __init__(self, string, groupCategory, directionCategory, facet, objectList, bondList):
|
||||
WorkspaceObject.__init__(self, string)
|
||||
@ -36,7 +38,6 @@ class Group(WorkspaceObject):
|
||||
self.clampSalience = False
|
||||
self.name = ''
|
||||
|
||||
|
||||
from description import Description
|
||||
if self.bondList and len(self.bondList):
|
||||
firstFacet = self.bondList[0].facet
|
||||
@ -62,7 +63,7 @@ class Group(WorkspaceObject):
|
||||
|
||||
#check whether or not to add length description category
|
||||
probability = self.lengthDescriptionProbability()
|
||||
if utils.random() < probability:
|
||||
if random.random() < probability:
|
||||
length = len(self.objectList)
|
||||
if length < 6:
|
||||
self.addDescription(slipnet.length, slipnet.numbers[length - 1])
|
||||
@ -233,5 +234,3 @@ class Group(WorkspaceObject):
|
||||
if description.descriptor == descriptor:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
from workspace import workspace
|
||||
|
||||
|
||||
class GroupRun(object):
|
||||
def __init__(self):
|
||||
self.name = 'xxx'
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from workspaceObject import WorkspaceObject
|
||||
from slipnet import slipnet
|
||||
|
||||
|
||||
class Letter(WorkspaceObject):
|
||||
def __init__(self, string, position, length):
|
||||
WorkspaceObject.__init__(self, string)
|
||||
@ -30,7 +31,7 @@ class Letter(WorkspaceObject):
|
||||
return ''
|
||||
i = self.leftStringPosition - 1
|
||||
if len(self.string) <= i:
|
||||
raise ValueError, 'len(self.string) <= self.leftStringPosition :: %d <= %d' % (len(self.string),self.leftStringPosition)
|
||||
raise ValueError('len(self.string) <= self.leftStringPosition :: %d <= %d' % (len(self.string), self.leftStringPosition))
|
||||
return self.string[i]
|
||||
|
||||
def distinguishingDescriptor(self, descriptor):
|
||||
@ -45,4 +46,3 @@ class Letter(WorkspaceObject):
|
||||
if description.descriptor == descriptor:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
from workspaceStructure import WorkspaceStructure
|
||||
|
||||
|
||||
class Replacement(WorkspaceStructure):
|
||||
def __init__(self, objectFromInitial, objectFromModified, relation):
|
||||
WorkspaceStructure.__init__(self)
|
||||
self.objectFromInitial = objectFromInitial
|
||||
self.objectFromModified = objectFromModified
|
||||
self.relation = relation
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ from workspace import workspace
|
||||
from workspaceStructure import WorkspaceStructure
|
||||
from formulas import *
|
||||
|
||||
|
||||
class Rule(WorkspaceStructure):
|
||||
def __init__(self, facet, descriptor, category, relation):
|
||||
WorkspaceStructure.__init__(self)
|
||||
@ -131,4 +132,3 @@ class Rule(WorkspaceStructure):
|
||||
endString = self.finalAnswer[right:]
|
||||
self.finalAnswer = startString + middleString + endString
|
||||
return True
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#from slipnode import Slipnode
|
||||
|
||||
|
||||
class Sliplink(object):
|
||||
def __init__(self, source, destination, label=None, length=0.0):
|
||||
self.source = source
|
||||
|
||||
@ -3,6 +3,7 @@ import logging
|
||||
from slipnode import Slipnode
|
||||
from sliplink import Sliplink
|
||||
|
||||
|
||||
class SlipNet(object):
|
||||
def __init__(self):
|
||||
logging.debug("SlipNet.__init__()")
|
||||
|
||||
@ -1,17 +1,20 @@
|
||||
import math
|
||||
import utils
|
||||
import logging
|
||||
import random
|
||||
|
||||
|
||||
def full_activation():
|
||||
return 100
|
||||
|
||||
|
||||
def jump_threshold():
|
||||
return 55.0
|
||||
|
||||
|
||||
class Slipnode(object):
|
||||
def __init__(self, name, depth, length=0.0):
|
||||
# logging.info('depth to %s for %s' % (depth,name))
|
||||
self.conceptual_depth = depth
|
||||
self.conceptualDepth = depth
|
||||
self.usualConceptualDepth = depth
|
||||
self.name = name
|
||||
self.intrinsicLinkLength = length
|
||||
@ -47,7 +50,7 @@ class Slipnode(object):
|
||||
|
||||
def setConceptualDepth(self, depth):
|
||||
logging.info('set depth to %s for %s' % (depth, self.name))
|
||||
self.conceptual_depth = depth
|
||||
self.conceptualDepth = depth
|
||||
|
||||
def category(self):
|
||||
if not len(self.categoryLinks):
|
||||
@ -79,7 +82,7 @@ class Slipnode(object):
|
||||
def update(self):
|
||||
act = self.activation
|
||||
self.oldActivation = act
|
||||
self.buffer -= self.activation * ( 100.0 - self.conceptual_depth) / 100.0
|
||||
self.buffer -= self.activation * (100.0 - self.conceptualDepth) / 100.0
|
||||
|
||||
def linked(self, other):
|
||||
"""Whether the other is among the outgoing links"""
|
||||
@ -152,7 +155,7 @@ class Slipnode(object):
|
||||
def jump(self):
|
||||
value = (self.activation / 100.0) ** 3
|
||||
#logging.info('jumping for %s at activation %s' % (self.name,self.activation))
|
||||
if self.activation > jump_threshold() and utils.random() < value and not self.clamped:
|
||||
if self.activation > jump_threshold() and random.random() < value and not self.clamped:
|
||||
self.activate_fully()
|
||||
|
||||
def get_name(self):
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
|
||||
|
||||
class Temperature(object):
|
||||
def __init__(self):
|
||||
self.value = 100.0
|
||||
|
||||
140
copycat/utils.py
140
copycat/utils.py
@ -1,140 +0,0 @@
|
||||
|
||||
def any(things):
|
||||
"""Return True if any of the things are True.
|
||||
|
||||
things should be iterable.
|
||||
|
||||
If the things are empty, then we can't say any are True
|
||||
>>> any([])
|
||||
False
|
||||
|
||||
If all the things are False, then we can't say any are True
|
||||
>>> any([False,False,False])
|
||||
False
|
||||
|
||||
If all the things are equivalent to False, then we can't say any are True
|
||||
>>> any([0,[],''])
|
||||
False
|
||||
|
||||
The type of the true thing should not matter
|
||||
>>> any([1,[],''])
|
||||
True
|
||||
>>> any([0,(2,),''])
|
||||
True
|
||||
>>> any([0,[],'foo'])
|
||||
True
|
||||
>>> any([0,[],True,''])
|
||||
True
|
||||
|
||||
It should not matter where the True thing is
|
||||
>>> any((True,False,False,False,False,))
|
||||
True
|
||||
>>> any((False,False,True,False,False,))
|
||||
True
|
||||
>>> any((False,False,False,False,True,))
|
||||
True
|
||||
|
||||
The size of the sequence should not matter
|
||||
>>> True == any((True,)) == any((True,True,)) == any((True,True,True,True,))
|
||||
True
|
||||
|
||||
Any string is True
|
||||
>>> any('foo')
|
||||
True
|
||||
|
||||
Except an empty string
|
||||
>>> any('')
|
||||
False
|
||||
|
||||
The function cannot be applied to ints
|
||||
>>> any(7)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: iteration over non-sequence
|
||||
"""
|
||||
for thing in things:
|
||||
if thing:
|
||||
return True
|
||||
return False
|
||||
|
||||
def all(things):
|
||||
"""Return True if all of the things are True.
|
||||
|
||||
things should be iterable.
|
||||
|
||||
If the things are empty, then we can't say all are True
|
||||
>>> all([])
|
||||
False
|
||||
|
||||
If all the things are False, then we can't say all are True
|
||||
>>> all([False,False,False])
|
||||
False
|
||||
|
||||
If all the things are equivalent to False, then we can't say all are True
|
||||
>>> all([0,[],''])
|
||||
False
|
||||
|
||||
The type of the false thing should not matter
|
||||
>>> all([0,True,True,])
|
||||
False
|
||||
>>> all([True,(),True,])
|
||||
False
|
||||
>>> all([True,True,'',])
|
||||
False
|
||||
|
||||
Position of the false thing should not matter
|
||||
>>> all((False,True,True,))
|
||||
False
|
||||
>>> all((True,False,True,))
|
||||
False
|
||||
>>> all((True,True,False,))
|
||||
False
|
||||
|
||||
any string is True
|
||||
>>> all('foo')
|
||||
True
|
||||
|
||||
Except an empty string
|
||||
>>> all('')
|
||||
False
|
||||
|
||||
The function cannot be applied to ints
|
||||
>>> all(7)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: iteration over non-sequence
|
||||
"""
|
||||
for thing in things:
|
||||
if not thing:
|
||||
return False
|
||||
return len(things) > 0
|
||||
|
||||
import logging
|
||||
|
||||
seed = 999.0
|
||||
count = 0
|
||||
testably_random = True
|
||||
def random():
|
||||
global testably_random
|
||||
if testably_random:
|
||||
from random import random
|
||||
return random()
|
||||
global seed
|
||||
global count
|
||||
seed += 1.0
|
||||
count += 1
|
||||
if seed > 1999:
|
||||
seed = 0.0
|
||||
logging.info("count: %d" % count)
|
||||
#if seed == 998:
|
||||
# sys.exit(1)
|
||||
return seed / 2000.0
|
||||
|
||||
def choice(aList):
|
||||
i = int(random() * len(aList))
|
||||
return aList[i]
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
@ -4,6 +4,7 @@ from workspaceString import WorkspaceString
|
||||
|
||||
unknownAnswer = '?'
|
||||
|
||||
|
||||
class Workspace(object):
|
||||
def __init__(self):
|
||||
#logging.debug('workspace.__init__()')
|
||||
@ -155,4 +156,3 @@ class Workspace(object):
|
||||
|
||||
|
||||
workspace = Workspace()
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ from temperature import temperature
|
||||
from slipnet import slipnet
|
||||
import formulas
|
||||
|
||||
|
||||
class WorkspaceFormulas(object):
|
||||
def __init__(self):
|
||||
self.clampTemperature = False
|
||||
@ -16,7 +17,7 @@ class WorkspaceFormulas(object):
|
||||
if workspace.rule:
|
||||
workspace.rule.updateStrength()
|
||||
ruleWeakness = 100.0 - workspace.rule.totalStrength
|
||||
values = ( (workspace.totalUnhappiness, 0.8), (ruleWeakness, 0.2), )
|
||||
values = ((workspace.totalUnhappiness, 0.8), (ruleWeakness, 0.2))
|
||||
slightly_above_actual_temperature = formulas.actualTemperature + 0.001
|
||||
logging.info('actualTemperature: %f' % slightly_above_actual_temperature)
|
||||
formulas.actualTemperature = formulas.weightedAverage(values)
|
||||
@ -32,15 +33,18 @@ class WorkspaceFormulas(object):
|
||||
|
||||
workspaceFormulas = WorkspaceFormulas()
|
||||
|
||||
|
||||
def numberOfObjects():
|
||||
return len(workspace.objects)
|
||||
|
||||
|
||||
def chooseUnmodifiedObject(attribute, inObjects):
|
||||
objects = [o for o in inObjects if o.string != workspace.modified]
|
||||
if not len(objects):
|
||||
print 'no objects available in initial or target strings'
|
||||
return formulas.chooseObjectFromList(objects, attribute)
|
||||
|
||||
|
||||
def chooseNeighbour(source):
|
||||
objects = []
|
||||
for objekt in workspace.objects:
|
||||
@ -52,6 +56,7 @@ def chooseNeighbour(source):
|
||||
objects += [objekt]
|
||||
return formulas.chooseObjectFromList(objects, "intraStringSalience")
|
||||
|
||||
|
||||
def chooseDirectedNeighbor(source, direction):
|
||||
if direction == slipnet.left:
|
||||
logging.info('Left')
|
||||
@ -59,6 +64,7 @@ def chooseDirectedNeighbor(source,direction):
|
||||
logging.info('Right')
|
||||
return __chooseRightNeighbor(source)
|
||||
|
||||
|
||||
def __chooseLeftNeighbor(source):
|
||||
objects = []
|
||||
for o in workspace.objects:
|
||||
@ -71,6 +77,7 @@ def __chooseLeftNeighbor(source):
|
||||
logging.info('Number of left objects: %s' % len(objects))
|
||||
return formulas.chooseObjectFromList(objects, 'intraStringSalience')
|
||||
|
||||
|
||||
def __chooseRightNeighbor(source):
|
||||
objects = [o for o in workspace.objects if
|
||||
o.string == source.string and
|
||||
@ -78,6 +85,7 @@ def __chooseRightNeighbor(source):
|
||||
]
|
||||
return formulas.chooseObjectFromList(objects, 'intraStringSalience')
|
||||
|
||||
|
||||
def chooseBondFacet(source, destination):
|
||||
sourceFacets = [d.descriptionType for d in source.descriptions if d.descriptionType in slipnet.bondFacets]
|
||||
bondFacets = [d.descriptionType for d in destination.descriptions if d.descriptionType in sourceFacets]
|
||||
@ -87,9 +95,11 @@ def chooseBondFacet(source, destination):
|
||||
i = formulas.selectListPosition(supports)
|
||||
return bondFacets[i]
|
||||
|
||||
|
||||
def __supportForDescriptionType(descriptionType, string):
|
||||
return (descriptionType.activation + __descriptionTypeSupport(descriptionType, string)) / 2
|
||||
|
||||
|
||||
def __descriptionTypeSupport(descriptionType, string):
|
||||
"""The proportion of objects in the string that have a description with this descriptionType"""
|
||||
numberOfObjects = totalNumberOfObjects = 0.0
|
||||
@ -101,6 +111,7 @@ def __descriptionTypeSupport(descriptionType,string):
|
||||
numberOfObjects += 1.0
|
||||
return numberOfObjects / totalNumberOfObjects
|
||||
|
||||
|
||||
def probabilityOfPosting(codeletName):
|
||||
if codeletName == 'breaker':
|
||||
return 1.0
|
||||
@ -126,6 +137,7 @@ def probabilityOfPosting(codeletName):
|
||||
return 1.0
|
||||
return result
|
||||
|
||||
|
||||
def howManyToPost(codeletName):
|
||||
if codeletName == 'breaker':
|
||||
return 1
|
||||
@ -156,5 +168,3 @@ def howManyToPost(codeletName):
|
||||
if number < formulas.blur(4.0):
|
||||
return 2
|
||||
return 3
|
||||
|
||||
|
||||
|
||||
@ -4,6 +4,7 @@ from description import Description
|
||||
from slipnet import slipnet
|
||||
from workspaceStructure import WorkspaceStructure
|
||||
|
||||
|
||||
class WorkspaceObject(WorkspaceStructure):
|
||||
def __init__(self, workspaceString):
|
||||
WorkspaceStructure.__init__(self)
|
||||
@ -223,4 +224,3 @@ class WorkspaceObject(WorkspaceStructure):
|
||||
if self.leftStringPosition == other.rightStringPosition + 1:
|
||||
return True
|
||||
return other.leftStringPosition == self.rightStringPosition + 1
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import logging
|
||||
from letter import Letter
|
||||
from slipnet import slipnet
|
||||
|
||||
|
||||
class WorkspaceString(object):
|
||||
def __init__(self, s):
|
||||
self.string = s
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import formulas
|
||||
|
||||
|
||||
class WorkspaceStructure(object):
|
||||
def __init__(self):
|
||||
self.string = None
|
||||
@ -24,14 +25,14 @@ class WorkspaceStructure(object):
|
||||
|
||||
def updateInternalStrength(self):
|
||||
"""How internally cohesive the structure is"""
|
||||
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.updateInternalStrength()'
|
||||
raise NotImplementedError('call of abstract method: WorkspaceStructure.updateInternalStrength()')
|
||||
|
||||
def updateExternalStrength(self):
|
||||
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.updateExternalStrength()'
|
||||
raise NotImplementedError('call of abstract method: WorkspaceStructure.updateExternalStrength()')
|
||||
|
||||
def break_the_structure(self):
|
||||
"""Break this workspace structure
|
||||
|
||||
Exactly what is broken depends on sub-class
|
||||
"""
|
||||
raise NotImplementedError, 'call of abstract method: WorkspaceStructure.break_the_structure()'
|
||||
raise NotImplementedError('call of abstract method: WorkspaceStructure.break_the_structure()')
|
||||
|
||||
Reference in New Issue
Block a user