def vector(self): """ :return: if this distribution contains only a single vector, return that vector; otherwise, throw exception :rtype: KeyedVector """ vector = KeyedVector() for substate, distribution in self.distributions.items(): assert len( distribution ) == 1, 'Cannot return vector from uncertain distribution' vector.update(distribution.domain()[0]) return vector
def __str__(self): certain = [ dist for dist in self.distributions.values() if len(dist) == 1 ] vector = KeyedVector() for dist in certain: vector.update({ key: value for key, value in dist.first().items() if key != keys.CONSTANT }) return '%s\n%s' % (vector.sortedString(), '\n---\n'.join([ str(dist) for dist in self.distributions.values() if len(dist) > 1 ]))
def collapseDynamics(tree,effects,variables={}): effects.reverse() present = tree.getKeysIn() tree.makeFuture(present) for stage in effects: subtree = None for key,dynamics in stage.items(): if dynamics and makeFuture(key) in tree.getKeysIn(): assert len(dynamics) == 1 if subtree is None: subtree = dynamics[0] else: subtree += dynamics[0] if subtree: if tree is None: tree = subtree else: for key in tree.getKeysIn(): if not key in subtree.getKeysOut(): fun = lambda m: KeyedMatrix(list(m.items())+[(key,KeyedVector({key: 1.}))]) subtree = subtree.map(fun) tree = tree*subtree future = [key for key in tree.getKeysIn() if isFuture(key)] if future: tree.makePresent(future) return tree.prune(variables=variables)
def parse(self, element): assert element.tagName == 'plane' node = element.firstChild self.planes = [] while node: if node.nodeType == node.ELEMENT_NODE: assert node.tagName == 'vector' vector = KeyedVector(node) text = node.getAttribute('threshold') if text[0] == '[': if '.' in text: threshold = [float(t) for t in text[1:-1].split(',')] else: threshold = [int(t) for t in text[1:-1].split(',')] elif text[0] == '{': if '.' in text: threshold = {float(t) for t in text[1:-1].split(',')} else: threshold = {int(t) for t in text[1:-1].split(',')} elif '.' in text: threshold = float(text) else: threshold = int(text) try: comparison = int(node.getAttribute('comparison')) except ValueError: comparison = str(node.getAttribute('comparison')) self.planes.append((vector, threshold, comparison)) node = node.nextSibling
def select(self, maximize=False, incremental=False): """ Reduce distribution to a single element, sampled according to the given distribution :param incremental: if C{True}, then select each key value in series (rather than picking out a joint vector all at once, default is C{False}) :return: the probability of the selection made """ if incremental: prob = KeyedVector() else: prob = 1 for distribution in self.distributions.values(): if incremental: prob.update(distribution.select(maximize, incremental)) else: prob *= distribution.select(maximize, incremental) return prob
def subDistribution(self, key): """ :return: the minimal joint distribution containing this key """ substate = self.keyMap[key] if substate is None: return VectorDistribution( {KeyedVector({key: self.certain[key]}): 1}) else: return self.distributions[substate]
def andRow(trueKeys=[], falseKeys=[]): """ :param trueKeys: list of keys which must be C{True} (default is empty list) :type trueKeys: str[] :param falseKeys: list of keys which must be C{False} (default is empty list) :type falseKeys: str[] :return: a plane testing whether all boolean keyed values are set as desired :rtype: L{KeyedPlane} """ weights = {} for key in trueKeys: weights[key] = 1 for key in falseKeys: weights[key] = -1 return KeyedPlane(KeyedVector(weights), len(trueKeys) - 0.5)
def parse(self,element): assert element.tagName == 'tree' node = element.firstChild plane = None children = {} while node: if node.nodeType == node.ELEMENT_NODE: if node.tagName == 'vector': if node.getAttribute('key'): # Vector leaf key = eval(node.getAttribute('key')) children[key] = KeyedVector(node) else: # Branch plane = KeyedPlane(node) elif node.tagName == 'plane': plane = KeyedPlane(node) elif node.tagName == 'matrix': key = eval(node.getAttribute('key')) children[key] = KeyedMatrix(node) elif node.tagName == 'tree': key = eval(node.getAttribute('key')) children[key] = KeyedTree(node) elif node.tagName == 'distribution': children = TreeDistribution(node) elif node.tagName == 'bool': key = eval(node.getAttribute('key')) children[key] = eval(node.getAttribute('value')) elif node.tagName == 'action': key = eval(node.getAttribute('key')) children[key] = Action(node) elif node.tagName == 'str': key = eval(node.getAttribute('key')) children[key] = str(node.firstChild.data).strip() elif node.tagName == 'int': key = int(node.getAttribute('key')) children[key] = KeyedTree(node) elif node.tagName == 'none': key = eval(node.getAttribute('key')) children[key] = None node = node.nextSibling if plane: self.makeBranch(plane,children) elif isinstance(children,Distribution): self.makeProbabilistic(children) else: self.makeLeaf(children[None])
def join(self, key, value, substate=None): """ Modifies the distribution over vectors to have the given value for the given key :param key: the key to the column to modify :type key: str :param value: either a single value to apply to all vectors, or else a L{Distribution} over possible values :substate: name of substate vector distribution to join with, ignored if the key already exists in this state. By default, find a new substate """ if key in self.keyMap: substate = self.keyMap[key] else: if substate is None: substate = 0 while substate in self.distributions: substate += 1 self.keyMap[key] = substate if not substate in self.distributions: self.distributions[substate] = VectorDistribution( {KeyedVector({keys.CONSTANT: 1}): 1}) return self.distributions[substate].join(key, value)
def worlds(self): """ :return: iterator through all possible joint vectors (i.e., possible worlds) and their probabilities :rtype: KeyedVector,float """ # Convert to lists now to ensure same ordering throughout substates = list(self.distributions.keys()) domains = { substate: self.distributions[substate].domain() for substate in substates } for index in range(len(self)): vector = {} prob = 1 for substate in substates: subindex = index % len(self.distributions[substate]) subvector = domains[substate][subindex % len(domains[substate])] vector.update(subvector) prob *= self.distributions[substate][subvector] index = index // len(self.distributions[substate]) yield KeyedVector(vector), prob
def ceil(self,key,hi): """ Modify this tree to make sure the new computed value never goes higher than the given ceiling @warning: may introduce redundant checks """ if self.isLeaf(): fMatrix = self.children[None] assert len(fMatrix) == 1,'Unable to handle dynamics of more than one feature' assert makeFuture(key) in fMatrix,'Are you sure you should be ceiling me on a key I don\'t have?' del self.children[None] tMatrix = setToConstantMatrix(key,hi) branch = KeyedPlane(KeyedVector(fMatrix[makeFuture(key)]),hi) self.makeBranch(branch,{True: KeyedTree(tMatrix), False: KeyedTree(fMatrix)}) elif self.branch: for child in self.children.values(): child.ceil(key,hi) else: for child in self.children.domain(): prob = self.children[child] del self.children[child] self[child.ceil(key,hi)] = prob return self
def equalFeatureRow(key1, key2): """ :return: a plane testing whether the values of the two given features are equal :rtype: L{KeyedPlane} """ return KeyedPlane(KeyedVector({key1: 1, key2: -1}), 0, 0)
def equalRow(key, value): """ :return: a plane testing whether the given keyed value equals the given target value :rtype: L{KeyedPlane} """ return KeyedPlane(KeyedVector({key: 1}), value, 0)
def falseRow(key): """ :return: a plane testing whether a boolean keyed value is False :rtype: L{KeyedPlane} """ return KeyedPlane(KeyedVector({key: 1}), 0.5, -1)
def differenceRow(key1, key2, threshold): """ :return: a plane testing whether the difference between the first and second keyed values exceeds the given threshold :rtype: L{KeyedPlane} """ return KeyedPlane(KeyedVector({key1: 1, key2: -1}), threshold)
def thresholdRow(key, threshold): """ :return: a plane testing whether the given keyed value exceeds the given threshold :rtype: L{KeyedPlane} """ return KeyedPlane(KeyedVector({key: 1}), threshold)