Fault trees structure

Arturo Pérez Mulas arturo_perez at wanadoo.es
Tue Dec 12 14:16:32 EST 2000


Hi,

I have not left the discussion, only I have not yet have the time to read
you guys.
However, on a first look, it seems to me that Darrel's model is only
including 1 or 0
values, while a fault-tree uses probabilities for the limiting nodes (Basic
Events),
and the following arithmetic

Let A and B be nodes of probabilities P(A) and P(B) respectively

then

P(A AND B) = P(A) * P(B)
P(A OR B) = P(A) + P(B) - P(A)*P(B)

And also the following boolean logic (I use '+' for OR and '*' for AND):

A + (A * B) = A
A * (A + B) = A + A*B = A

And for logic '1' and '0', the usual

A + '0' = A
A * '0' = '0'

A + '1' = '1'
A * '1' = 'A'

However, this is not the main goal of the structure I want to develop
(believe me,
probability calculation of a FT is an exponential problem -NP- which
requires much
more evolved calculations methods, and approximations)

Also, you are not considering the 'links' issue (I think, sorry I did not
look at it in detail yet!).

Arturo.

"Darrell Gallion" <darrell at dorb.com> escribió en el mensaje
news:915pu2$6gf$1 at news.kodak.com...
> 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