@@ -531,6 +531,11 @@ def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr:
531531 # y >= x => not(x < y) => not(x - y < 0) => not r < 0
532532 return sp .Heaviside (root )
533533
534+ # rewrite n-ary XOR to OR to be handled below:
535+ trigger = trigger .replace (sp .Xor , _xor_to_or )
536+
537+ # TODO: x == y
538+
534539 # or(x,y) = not(and(not(x),not(y))
535540 if isinstance (trigger , sp .Or ):
536541 return sp .Integer (1 ) - sp .Mul (
@@ -540,8 +545,6 @@ def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr:
540545 ]
541546 )
542547
543- # TODO: x XOR y = (A & ~B) | (~A & B)
544- # TODO: x == y
545548 if isinstance (trigger , sp .And ):
546549 return sp .Mul (* [_parse_heaviside_trigger (arg ) for arg in trigger .args ])
547550
@@ -551,6 +554,25 @@ def _parse_heaviside_trigger(trigger: sp.Expr) -> sp.Expr:
551554 )
552555
553556
557+ def _xor_to_or (* args ):
558+ """
559+ Replace XOR by OR expression.
560+
561+ ``xor(x, y, ...) = (x & ~y & ...) | (~x & y & ...) | ...``.
562+
563+ to be used in ``trigger = trigger.replace(sp.Xor, _xor_to_or)``.
564+ """
565+ res = sp .false
566+ for i in range (len (args )):
567+ res = sp .Or (
568+ res ,
569+ sp .And (
570+ * (arg if i == j else sp .Not (arg ) for j , arg in enumerate (args ))
571+ ),
572+ )
573+ return res .simplify ()
574+
575+
554576def grouper (
555577 iterable : Iterable , n : int , fillvalue : Any = None
556578) -> Iterable [tuple [Any ]]:
0 commit comments