Fault trees structure

Darrell Gallion darrell at dorb.com
Tue Dec 12 13:18:58 EST 2000


Alex Martelli wrote:
> def connectInput(self, name):
>     self.__dict__.setdefault('_input',{})[name] = None
>
> is a possible alternative (also in other cases), but
> not very readable.  It would seem best to just set
> empty dictionaries in __init__ for _input and _output,
> so as to avoid having test for them at every connect,
> and possibly having errors lurking elsewhere, too:
>
Sounds good.
This wasn't required once I moved the __init__ into NodeBase by your
suggestion.

[snip]
>
> Of course, giving NodeBase an __init__ means having
> to call it in lieu, or from, specific subclasses'
> ones, but that seems OK; right now OrNode and
> AndNode sport identical __init__ methods, so why
> not factor them out of the subclasses and up into
> the NodeBase common baseclass.
>
Done.

>
>
> >     def logic(self, collection):
> >         cc= reduce(lambda x,y: x and y, self._input.values())
> >         self.propagate(collection, cc)
>
> If the values are constrained to "boolean" (0 and 1), then
> using operator.and_ as the first argument to reduce might
> well be faster, and perhaps more readable (similarly for
> or-nodes).
>
Not sure that values will be constrained to boolean.

When I tried this something odd happened.
None isn't valid for and_ while it is for "and"

>>> and_(1, 1)
1
>>> and_(None, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: bad operand type(s) for &
>>> None and 1
>>>

Made some other changes as well.
Thanks for taking the time to look this over.
Maybe I'll have find a use for this code :)

--Darrell


class NodeBase:
    def __init__(self, name, logicFunc):
        self._name=name
        self._previousOutputValue=None
        self._logicFunc=logicFunc
        self._output={}
        self._input={}

    def name(self):
        return self._name

    def connectInput(self, name):
        self._input[name] = None

    def connectOutput(self, otherNode, name):
        self._output[otherNode.name()] = name
        otherNode.connectInput(name)

    def signal(self, collection, name, value=1):
        self._input[name]=value
        self.logic(collection)

    def propagate(self, collection, value):
        if value==self._previousOutputValue:
            # No point in propagating the same value
            return
        for nodeName, inputName in self._output.items():
            try:
                node=getattr(collection, nodeName)
                node.signal(collection, inputName, value)
            except:
                print self._name
                print nodeName
                print collection
                raise

    def logic(self, collection):
        cc= self._logicFunc(self, collection)
        self.propagate(collection, cc)

def andFunc(self, collection):
        return reduce(lambda x,y: x and y, self._input.values())

def announceFunc(self, collection):
        cc= reduce(lambda x,y: x or y, self._input.values())
        if cc:
            print self._name, self._input
        else:
            # Noise on the input, but nothing to report
            print '.',
        return cc

def sourceFunc(self, collection):
    assert(0)

class SourceNode(NodeBase):
    def __init__(self, name):
        NodeBase.__init__(self, name, sourceFunc)

    def __call__(self, collection, value):
        self.propagate(collection, value)


class FaultTree:#(UserDict.UserDict): Not sure about this
    def __init__(self, *nodes):
        for n in nodes:
            setattr(self, n.name(), n)

ft=FaultTree(NodeBase("and1", andFunc), NodeBase("and2", andFunc),
NodeBase("and3", andFunc),
            NodeBase("fail", announceFunc))

ft.and1.connectOutput(ft.and3,"one")
ft.and2.connectOutput(ft.and3,"two")
ft.and3.connectOutput(ft.fail,"who cares")

    # Setup some signal sources
drivers=[]
for x in range(3):
    s1=SourceNode(x)
    drivers.append(s1)
    s1.connectOutput(ft.and1, x)

    # Setup some signal sources
for x in range(3):
    s1=SourceNode(x)
    drivers.append(s1)
    s1.connectOutput(ft.and2, x)

    # Make it go
for i in drivers:
    i(ft, 1)







More information about the Python-list mailing list