
    e!hf1                     "   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZmZ dd	lmZ dd
lmZmZmZ ddlmZ  G d dej,                  ej.                  e      Z G d dej,                  ej2                  ej.                  e      Z G d dej,                  ej2                  ej.                  e      Z G d dej,                  ej2                  e      Z G d dej,                  e      Z G d dej,                  ej2                  e      Zy)z
RETE nodes implementation.

This are the node types needed by this RETE implementation. Some node
types (like `The One-input Node for Testing Variable Bindings) are not
needed in this implementation.

    )Mapping)suppress)chain)
Activation)Rule)MATCHERMATCH   )mixins)NodeOneInputNodeTwoInputNode)Tokenc                       e Zd ZdZd Zd Zy)BusNodea  
    The Bus Node.

    The node that reports working memory changes to the rest of the
    network.

    This node cannot be activated in the same manner as the other nodes.
    No tokens can be sent to it since this is the node where the first
    tokens are built.
    c                     t        j                  |      }t        j                  d|       | j                  D ]  }|j                  |        y)z1Create a VALID token and send it to all children.<BusNode> added %rN)r   validr   debugchildrencallbackselffacttokenchilds       c/var/www/html/diagnosisapp-backend/venv/lib/python3.12/site-packages/experta/matchers/rete/nodes.pyaddzBusNode.add$   s>    D!*E2]] 	"ENN5!	"    c                     t        j                  |      }t        j                  d|       | j                  D ]  }|j                  |        y)z4Create an INVALID token and send it to all children.r   N)r   invalidr   r   r   r   r   s       r   removezBusNode.remove+   s>    d#*E2]] 	"ENN5!	"r   N)__name__
__module____qualname____doc__r   r"    r   r   r   r      s    	""r   r   c                       e Zd ZdZd Zy)	WhereNodez6
    Check some conditions over a token context.

    c                     | j                  |j                        r#| j                  D ]  }|j                  |        y y )N)matchercontextr   r   )r   r   r   s      r   	_activatezWhereNode._activate;   s6    <<& &u%& 'r   Nr#   r$   r%   r&   r-   r'   r   r   r)   r)   3   s    &r   r)   c                       e Zd ZdZd Zy)FeatureTesterNodea  
    Feature Tester Node.

    This node implementation represents two different nodes in the
    original paper: `The One-input Node for Testing Constant Features`
    and `The One-input Node for Testing Variable Bindings`.

    The trick here is this node receives a callable object at
    initilization time and uses it for testing the received tokens on
    activation. The given callable can return one of the following
    things:

      - Boolean:

        - `True`: The test pass. The token will be sent to the children
          nodes.

        - `False`: The test failed. Do nothing.

      - Mapping (dict):

        - With content: The test pass. In addition the pairs key-value
          will be added to the token context.

        - Empty: The test failed. Do nothing.

    The only exception here is when the callable returns a mapping with
    some key and some value, and the current context of the token also
    have an entry for this key but with a different value. In this case
    the test do not pass.
    c                    	 t        |j                        dk(  sJ 	 t        |j                        d   }| j                  |      }|rt        |t              r|j                         D ]  \  }}t        |t              r*|d   |j                  v s(|j                  |d      |k(  s> y|j                  j                  ||      |k7  r yd|f|j                  v sr|j                  d|f   |k(  s y |j                  j                  |       | j                  D ]  }|j                  |        yy# t        $ r}t	        |      |d}~ww xY w)z
        Activate this node.

        Test the given token with this token matcher function and iff
        the test pass update the token and pass to all children.

        r
   r   NF)lendatalistAssertionError
ValueErrorr+   
isinstancer   itemstupler,   getupdater   r   )r   r   r   excmatchkeyvaluer   s           r   r-   zFeatureTesterNode._activatee   s2   	'uzz?a''' 

#A&DT"%)"'++- 
)JC!#u-q6U]]2$)MM#a&$9U$B#( ==,,S%8EA#(!3<5==8$)MM5#,$?5$H#(
) $$U+ &u%&   	+S/s*	+s   D1 1	E:EENr.   r'   r   r   r0   r0   A   s    @ &r   r0   c                   ,    e Zd ZdZd Z	 ddZd Zd Zy)OrdinaryMatchNodea"  
    Ordinary Two-input Node.

    This kind of node receive tokens at two ports (left and right) and
    try to match them.

    The matching function is a callable given as a parameter to __init__
    and stored internally. This functions will receive two contexts, one
    from the left and other from the right, and decides if they match
    together (returning True or False).

    Matching pairs will be combined in one token containing facts from
    both and a combined context. This combined tokens will be sent to
    all children.
    c                 @    t               | _        t               | _        y)zWipe node memory.N)r4   left_memoryright_memoryr   s    r   _resetzOrdinaryMatchNode._reset       6 Fr   c           	         |j                         r |j                  |j                                n7t        t              5  |j                  |j                                ddd       |D ]O  \  }}t        |      }|r|j                  }|}n|}|j                  }| j                  ||      }	|	rt        j                  d| j                  j                  ||       |j                  j                         D 
ci c]  \  }
}t        |
t              r|
| }}
}|j                         D ]  \  }
}t        |
t               r|||
<    t#        |j$                  |j&                  |z  |      }| j(                  D ]  }|j+                  |        $t        j,                  d| j                  j                  ||       R y# 1 sw Y   `xY wc c}}
w )a  
        Node activation internal function.

        This is a generalization of both activation functions.

        The given token is added or removed from `branch_memory`
        depending of its tag.

        For any other data in `matching_memory` the match function will
        be called and if a match occurs a new token will be produced and
        sent to all children.

        Nz%s (%s | %s) = Truez%s (%s | %s) = False)is_validappendto_infor   r6   r"   dictr,   r+   r	   info	__class__r#   r8   r7   strr9   r   tagr3   r   r   r   )r   r   branch_memorymatching_memoryis_left
other_dataother_contextleft_contextright_contextr=   kv
newcontextnewtokenr   s                  r   __activationzOrdinaryMatchNode.__activation   s    >>  1*% 6$$U]]_56 *9 #	+%J /M$}} -, %LL}=E

0>>22'(*
 05}}/B/B/D 5tq!!+As!3  d 5
 5 *//1 *DAq%a/()
1*
 !!&j!8!+- "]] -ENN8,- 2 NN33()+A#	+6 6(5s     F>8G>Gc                 V    | j                  || j                  | j                  d       y)zNode left activation.TrS   N)_OrdinaryMatchNode__activationrC   rD   r   r   s     r   _activate_leftz OrdinaryMatchNode._activate_left   s,    %**++"& 	 	(r   c                 V    | j                  || j                  | j                  d       y)zNode right activation.Fr^   N)r_   rD   rC   r`   s     r   _activate_rightz!OrdinaryMatchNode._activate_right   s,    %++**"' 	 	)r   N)T)r#   r$   r%   r&   rF   r_   ra   rc   r'   r   r   rA   rA      s!     # "8+t()r   rA   c                   :     e Zd ZdZ fdZd Zd Zd Zd Z xZ	S )ConflictSetNodea  
    Conflict Set Change Node.

    This node is the final step in the network. Any token activating
    this node will produce an activation (VALID token) or deactivation
    (INVALID token) of the internal `rule` with the token context and
    facts.
    c                     	 t        |t              sJ 	 || _        t               | _        t               | _        t        | %          y# t        $ r}t	        |      |d}~ww xY w)z*Initialize the node with the given `rule`.N)
r7   r   ruler5   	TypeErrorsetaddedremovedsuper__init__)r   rg   r<   rN   s      r   rm   zConflictSetNode.__init__   s\    	dD))) DIU
u  	*C.c)	*s   A
 
	A$AA$c                 "    t               | _        y)zWipe the node internal memory.N)ri   memoryrE   s    r   rF   zConflictSetNode._reset  s    er   c                    |j                         }t        | j                  t        |j                        |j
                  D ci c]  \  }}t        |t              s|| c}}      }|j                         rp|| j                  vra| j                  j                  |       || j                  v r| j                  j                  |       y| j                  j                  |       yy	 | j                  j                  |       || j                  v r| j                  j                  |       y| j                  j                  |       yc c}}w # t        $ r Y yw xY w)z'Activate this node for the given token.N)rK   r   rg   	frozensetr3   r,   r7   rO   rI   ro   r   rk   r"   rj   r6   )r   r   rM   rX   rY   
activations         r   r-   zConflictSetNode._activate  s    }}IIdii "llAdajC.@QTAC

 >>4;;&%-LL''
3JJNN:. '1""4( +JJ%%j1LL$$Z0% B  s   EE+E 	EEc                 r    | j                   | j                  f}t               | _         t               | _        |S )zReturn a list of activations.)rj   rk   ri   )r   ress     r   get_activationszConflictSetNode.get_activations"  s+    zz4<<(U
u
r   c                 `    | j                   j                  d| j                  j                  S )Nz: )rN   r#   rg   rE   s    r   __str__zConflictSetNode.__str__+  s!    >>22DII4F4FGGr   )
r#   r$   r%   r&   rm   rF   r-   ru   rw   __classcell__)rN   s   @r   re   re      s"    18Hr   re   c                   "    e Zd ZdZd Zd Zd Zy)NotNodeaa  
    Not Node.

    This is a special kind of node representing the absence of some
    fact/condition.

    This node is similar to `OrdinaryMatchNode` in the sense it has two
    input ports and try to match tokens arriving in both of them. But
    pass VALID tokens to the children when no matches are found and
    INVALID tokens when they are.
    c                 @    t               | _        t               | _        y)zWipe node internal memory.N)rL   rC   r4   rD   rE   s    r   rF   zNotNode._reset>  rG   r   c                 (   | j                   sl|j                         rd| j                  |j                         <   n| j                  |j                         = | j                  D ]  }|j                  |        y|j                         rd}| j                   D ]0  \  }}| j                  |j                  t        |            s,|dz  }2 |dk(  r"| j                  D ]  }|j                  |        || j                  |j                         <   yd}| j                   D ]1  \  }}| j                  |j                  t        |            s,|dz  } n |dk(  r"| j                  D ]  }|j                  |        | j                  |j                         = y)aW  
        Activate from the left.

        In case of a valid token this activations test the right memory
        with the given token and looks for the number of matches. The
        token and the number of occurences are stored in the left
        memory.

        If the number of matches is zero the token activates all children.

        r   r
   N)	rD   rI   rC   rK   r   r   r+   r,   rL   )r   r   r   count_rW   s         r   ra   zNotNode._activate_leftC  sk      ~~45  1$$U]]_5 &u%& ^^E$($5$5  =<<tM/BCQJE z!]] *ENN5)* 16DU]]_-E$($5$5  =<<tM/BCQJE
 z!]] *ENN5)*   1r   c                 \   |j                         r,| j                  j                  |j                                d}n+d}| j                  j	                  |j                                | j
                  D ]  }| j                  t        |j                        |j                        s3| j
                  |xx   |z  cc<   | j
                  |   }|dk(  r|dk(  s|dk(  si|dk(  so|dk(  r|j                         }n|j                         }| j                  D ]  }|j                  |         y)a=  
        Activate from the right.

        Go over the left memory and find matching data, when found
        update the counter (substracting if the given token is invalid
        and adding otherwise). Depending on the result of this operation
        a new token is generated and passing to all children.

        r
   r   N)rI   rD   rJ   rK   r"   rC   r+   rL   r,   to_valid_tokento_invalid_tokenr   r   )r   r   incleftnewcountr[   r   s          r   rc   zNotNode._activate_rightq  s     >>$$U]]_5CC$$U]]_5$$ 	1D||D.>  &#-&++D1McRi!Q3!8by#'#6#6#8#'#8#8#:!% 1x01	1r   N)r#   r$   r%   r&   rF   ra   rc   r'   r   r   rz   rz   /  s    
#
,2\1r   rz   N)r&   collections.abcr   
contextlibr   	itertoolsr   experta.activationr   experta.ruler   experta.watchersr   r	    r   abstractr   r   r   r   r   AnyChildNoMemoryr   
HasMatcherr)   r0   rA   re   rz   r'   r   r   <module>r      s    $   )  +  6 6 "foooo":&!!&D&))$D&N^)))$^)BCHfoo"CHL_1foo_1r   