+
    iZL                         R t ^ RIHt ^ RIHt ^RIHtHtHtH	t	 R t
R tR tR tR tR	 t ! R
 R]4      t ! R R4      t ! R R4      t ! R R]4      t ! R R]4      tR# )a>  This is rule-based deduction system for SymPy

The whole thing is split into two parts

 - rules compilation and preparation of tables
 - runtime inference

For rule-based inference engines, the classical work is RETE algorithm [1],
[2] Although we are not implementing it in full (or even significantly)
it's still worth a read to understand the underlying ideas.

In short, every rule in a system of rules is one of two forms:

 - atom                     -> ...      (alpha rule)
 - And(atom1, atom2, ...)   -> ...      (beta rule)


The major complexity is in efficient beta-rules processing and usually for an
expert system a lot of effort goes into code that operates on beta-rules.


Here we take minimalistic approach to get something usable first.

 - (preparation)    of alpha- and beta- networks, everything except
 - (runtime)        FactRules.deduce_all_facts

             _____________________________________
            ( Kirr: I've never thought that doing )
            ( logic stuff is that difficult...    )
             -------------------------------------
                    o   ^__^
                     o  (oo)\_______
                        (__)\       )\/\
                            ||----w |
                            ||     ||


Some references on the topic
----------------------------

[1] https://en.wikipedia.org/wiki/Rete_algorithm
[2] http://reports-archive.adm.cs.cmu.edu/anon/1995/CMU-CS-95-113.pdf

https://en.wikipedia.org/wiki/Propositional_formula
https://en.wikipedia.org/wiki/Inference_rule
https://en.wikipedia.org/wiki/List_of_rules_of_inference
)defaultdict)Iterator)LogicAndOrNotc                J    \        V \        4      '       d   V P                  # V # )z\Return the literal fact of an atom.

Effectively, this merely strips the Not around a fact.

isinstancer   argatoms   &N/var/www/html/photoedit/myenv/lib/python3.14/site-packages/sympy/core/facts.py
_base_factr   7   s    
 $xx    c                 R    \        V \        4      '       d   V P                  R 3# V R3# )FTr	   r   s   &r   _as_pairr   B   s(    $%  d|r   c                    \        V 4      p\        4       P                  ! \        \         V4      !  pV F;  pV F2  pWC3V9   g   K  V F  pW53V9   g   K  VP                  WE34       K!  	  K4  	  K=  	  V# )z
Computes the transitive closure of a list of implications

Uses Warshall's algorithm, as described at
http://www.cs.hope.edu/~cusack/Notes/Notes/DiscreteMath/Warshall.pdf.
)setunionmapadd)implicationsfull_implicationsliteralskijs   &     r   transitive_closurer   K   ss     L)u{{C%678HAv**!Av!22)--qf5 "   r   c           	        Y  UUu. uF  w  r\        V4      \        V4      3NK  	  upp,           p \        \        4      p\        V 4      pV F$  w  rVWV8X  d   K  W5,          P	                  V4       K&  	  VP                  4        F>  w  rWVP                  V4       \        V4      pW9   g   K)  \        RV: RV: RV: 24      h	  V# u uppi )zdeduce all implications

Description by example
----------------------

given set of logic rules:

  a -> b
  b -> c

we deduce all possible rules:

  a -> b, c
  b -> c


implications: [] of (a,b)
return:       {} of a -> set([b, c, ...])
zimplications are inconsistent: z ->  )r   r   r   r   r   itemsdiscard
ValueError)	r   r   r   resr   abimplnas	   &        r   deduce_alpha_implicationsr)   _   s    (  ,"O,CFCF#3,"OOL
c
C*<8!6

1	 " 99;QV:@A2tLN N	  J# #Ps   !C	c                  aa / pV P                  4        F  p\        W,          4      . 3W#&   K  	  V F/  w  poVP                   F  pWR9   d   K  \        4       . 3W%&   K  	  K1  	  RpV'       d   RpV F  w  po\        V\        4      '       g   \        R4      h\        VP                  4      oVP                  4        Fj  w  pw  rxWs0,          p	SV	9  g   K  SP                  V	4      '       g   K3  VP                  S4       VP                  S4      p
V
e   Wz^ ,          ,          pRpKl  	  K  	  K  \        V4       F  w  pw  po\        VP                  4      oVP                  4        F  w  pw  rxWs0,          p	SV	9   d   K  \        ;QJ d     VV3R lV	 4       F  '       g   K   RM	  RM! VV3R lV	 4       4      '       d   K^  SV	,          '       g   Ko  VP                  V4       K  	  K  	  V# )a~  apply additional beta-rules (And conditions) to already-built
alpha implication tables

   TODO: write about

   - static extension of alpha-chains
   - attaching refs to beta-nodes to alpha chains


   e.g.

   alpha_implications:

   a  ->  [b, !c, d]
   b  ->  [d]
   ...


   beta_rules:

   &(b,d) -> e


   then we'll extend a's rule to the following

   a  ->  [b, !c, d, e]
TFzCond is not Andc              3   l   <"   T F)  p\        V4      S9   ;'       g    \        V4      S8H  x  K+  	  R # 5iN)r   ).0xibargsbimpls   & r   	<genexpr>,apply_beta_to_alpha_route.<locals>.<genexpr>   s.     H%B3r7e#77s2w%'77%s   44)keysr   argsr
   r   	TypeErrorr!   issubsetr   get	enumerateanyappend)alpha_implications
beta_rulesx_implxbcondbkseen_static_extensionximplsbbx_all
bimpl_implbidxr/   r0   s   &&          @@r   apply_beta_to_alpha_routerG      s   8 F$$&+./4	 '"u**B|%FJ  # !
 %&LE5eS)) 122

OE#)<<><F%%..*?*?JJu% "(E!2J!-Q-/,0) $2	 '$ !** 5nueEJJ%||~OA|SLE~ sH%HsssH%HHHu}}		$  . !6 Mr   c                D   \        \        4      pV P                  4        F|  w  w  r#p\        V\        4      '       d   VP
                  ^ ,          pV FE  w  rS\        V\        4      '       d   VP
                  ^ ,          pW,          P                  V4       KG  	  K~  	  V# )a  build prerequisites table from rules

Description by example
----------------------

given set of logic rules:

  a -> b, c
  b -> c

we build prerequisites (from what points something can be deduced):

  b <- a
  c <- a, b

rules:   {} of a -> [b, c, ...]
return:  {} of c <- [a, b, ...]

Note however, that this prerequisites may be *not* enough to prove a
fact. An example is 'a -> b' rule, where prereq(a) is b, and prereq(b)
is a. That's because a=T -> b=T, and b=F -> a=F, but a=F -> b=?
)r   r   r!   r
   r   r4   r   )rulesprereqr%   _r'   r   s   &     r   rules_2prereqrL      sy    . Faq	AFQ!S!!FF1IIMM!  & Mr   c                       ] tR t^tRtRtR# )TautologyDetectedz:(internal) Prover uses it for reporting detected tautology N)__name__
__module____qualname____firstlineno____doc____static_attributes__rO   r   r   rN   rN      s    Dr   rN   c                   \   a  ] tR tRt o RtR tR t]R 4       t]R 4       t	R t
R tR	tV tR
# )Proveri  a  ai - prover of logic rules

given a set of initial rules, Prover tries to prove all possible rules
which follow from given premises.

As a result proved_rules are always either in one of two forms: alpha or
beta:

Alpha rules
-----------

This are rules of the form::

  a -> b & c & d & ...


Beta rules
----------

This are rules of the form::

  &(a,b,...) -> c & d & ...


i.e. beta rules are join conditions that say that something follows when
*several* facts are true at the same time.
c                2    . V n         \        4       V n        R # r,   )proved_rulesr   _rules_seenselfs   &r   __init__Prover.__init__  s    5r   c                    . p. pV P                    FA  w  r4\        V\        4      '       d   VP                  W434       K/  VP                  W434       KC  	  W3# )z-split proved rules into alpha and beta chains)rY   r
   r   r:   )r\   rules_alpha
rules_betar%   r&   s   &    r   split_alpha_betaProver.split_alpha_beta"  sV    
%%DA!S!!!!1&)""A6*	 &
 &&r   c                0    V P                  4       ^ ,          # )    rb   r[   s   &r   r`   Prover.rules_alpha-      $$&q))r   c                0    V P                  4       ^,          # )   rf   r[   s   &r   ra   Prover.rules_beta1  rh   r   c                   V'       d   \        V\        4      '       d   R# \        V\        4      '       d   R# W3V P                  9   d   R# V P                  P                  W34        V P	                  W4       R#   \
         d     R# i ; i)zprocess a -> b ruleN)r
   boolrZ   r   _process_rulerN   )r\   r%   r&   s   &&&r   process_ruleProver.process_rule5  sr    jD))a6T%%%  !(	q$  		s   *A= =BBc           
        \        V\        4      '       d8   \        VP                  \        R 7      pV F  pV P                  W4       K  	  R# \        V\        4      '       d   \        VP                  \        R 7      p\        V\        4      '       g   W9   d   \        WR4      hT P                  \        VP                   Uu. uF  p\        V4      NK  	  up!  \        V4      4       \        \        V4      4       FL  pW5,          pVRV W5^,           R ,           pV P                  \        V\        V4      4      \        V!  4       KN  	  R# \        V\        4      '       dL   \        VP                  \        R 7      pW'9   d   \        WR4      hV P                  P                  W34       R# \        V\        4      '       dJ   \        VP                  \        R 7      pW'9   d   \        WR4      hV F  pV P                  W4       K  	  R# V P                  P                  W34       V P                  P                  \        V4      \        V4      34       R# u upi ))keyza -> a|c|...Nz
a & b -> az
a | b -> a)r
   r   sortedr4   strro   r   r   rN   r   rangelenrY   r:   )	r\   r%   r&   sorted_bargsbargrF   brestsorted_aargsaargs	   &&&      r   rn   Prover._process_ruleF  s    a!!&&c2L$!!!* % 2!!&&c2La''$+A.AAc!&&#A&$CI&#ABCFKc,/0#)$Ud+l!89.EE!!#aT"3RZ@ 1 3!!&&c2L 'l;;$$aV, 2!!&&c2L 'l;;$!!$* %
 $$aV,$$c!fc!f%569 $Bs   I)rZ   rY   N)rP   rQ   rR   rS   rT   r]   rb   propertyr`   ra   ro   rn   rU   __classdictcell____classdict__s   @r   rW   rW     sK     8!	' * * * *"17 17r   rW   c                      a  ] tR tRt o RtR tV 3R lR lt]V 3R lR l4       tR t	R	 t
R
 tR tV 3R lR ltRtV tR# )	FactRulesi|  a  Rules that describe how to deduce facts in logic space

When defined, these rules allow implications to quickly be determined
for a set of facts. For this precomputed deduction tables are used.
see `deduce_all_facts`   (forward-chaining)

Also it is possible to gather prerequisites for a fact, which is tried
to be proven.    (backward-chaining)


Definition Syntax
-----------------

a -> b       -- a=T -> b=T  (and automatically b=F -> a=F)
a -> !b      -- a=T -> b=F
a == b       -- a -> b & b -> a
a -> b & c   -- a=T -> b=T & c=T
# TODO b | c


Internals
---------

.full_implications[k, v]: all the implications of fact k=v
.beta_triggers[k, v]: beta rules that might be triggered when k=v
.prereq  -- {} k <- [] of k's prerequisites

.defined_facts -- set of defined fact names
c           	        \        V\        4      '       d   VP                  4       p\        4       pV F  pVP	                  R^4      w  rEp\
        P                  ! V4      p\
        P                  ! V4      pVR8X  d   VP                  WF4       K^  VR8X  d%   VP                  WF4       VP                  Wd4       K  \        RV,          4      h	  . V n	        VP                   FN  w  rxV P                  P                  VP                   Uu0 uF  p\        V4      kK  	  up\        V4      34       KP  	  \        VP                  4      p	\!        WP                  4      p
V
P#                  4        Uu0 uF  p\%        V4      kK  	  upV n        \)        \*        4      p\)        \*        4      pV
P-                  4        F<  w  pw  rV Uu0 uF  p\        V4      kK  	  upV\        V4      &   W\        V4      &   K>  	  Wn        Wn        \)        \*        4      p\3        V4      pVP-                  4        F  w  ppVV;;,          V,          uu&   K  	  VV n        R# u upi u upi u upi )z)Compile rules into internal lookup tablesNz->z==zunknown op %r)r
   rt   
splitlinesrW   splitr   
fromstringro   r#   r<   ra   r:   r4   r   r)   r`   rG   r3   r   defined_factsr   r   r!   r   beta_triggersrL   rJ   )r\   rI   Pruler%   opr&   r?   r0   impl_aimpl_abr   r   r   r'   betaidxsr   rJ   
rel_prereqpitemss   &&                  r   r]   FactRules.__init__  s    eS!!$$&E HDzz$*HA1  #A  #ATzq$tq$q$ 2!566   LLLEOO""',zz2z!(1+z2HUODF )
 +1==9 ,FLLA 6=\\^D^jm^D (,#C(#*==?ACG-H4ahqk4-Hhqk*)1(1+& $3 "3* S!"#45
#))+IAv1II ,; 3 E .Is   I
1II#c                    < V ^8  d   QhRS[ /#    return)rt   )formatr   s   "r   __annotate__FactRules.__annotate__  s     - -C -r   c                @    RP                  V P                  4       4      # )zCGenerate a string with plain python representation of the instance 
)joinprint_rulesr[   s   &r   
_to_pythonFactRules._to_python  s    yy))+,,r   c                    < V ^8  d   QhRS[ /# )r   data)dict)r   r   s   "r   r   r     s     
 
 
r   c                    V ! R4      pR F5  p\        \        4      pVP                  W,          4       \        W#V4       K7  	  VR,          Vn        \        VR,          4      Vn        V# )z:Generate an instance from the plain python representation  r<   r   )r   r   rJ   )r   r   updatesetattrr<   r   )clsr   r\   rr   ds   &&   r   _from_pythonFactRules._from_python  s_     2wCC#AHHTYDq! D |, o!67r   c              #  h   "   R x  \        V P                  4       F  pRV: R2x  K  	  Rx  R# 5i)zdefined_facts = [    ,z] # defined_factsN)rs   r   )r\   facts   & r   _defined_facts_linesFactRules._defined_facts_lines  s5     !!4--.D"" /!!s   02c              #    "   R x  \        V P                  4       F[  pR FR  pRV RV R2x  RV: RV: R2x  V P                  W3,          p\        V4       F  pRV: R2x  K  	  R	x  R
x  KT  	  K]  	  Rx  R# 5i)zfull_implications = dict( [z    # Implications of  = :z    ((, z	), set( (        r   z       ) ),z     ),z ] ) # full_implicationsN)TF)rs   r   r   )r\   r   valuer   implieds   &    r   _full_implications_lines"FactRules._full_implications_lines  s     ++4--.D&.tfCwa@@thb	;;#55tmD%l3G$WKq11  4## ' / )(s   A?Bc              #     "   R x  Rx  \        V P                  4       FG  pRV 2x  RV: R2x  \        V P                  V,          4       F  pRV: R2x  K  	  Rx  Rx  KI  	  Rx  R	# 5i)
z
prereq = {r   z.    # facts that could determine the value of r   z: {r   r   z    },z
} # prereqN)rs   rJ   )r\   r   pfacts   &  r   _prereq_linesFactRules._prereq_lines  sx     4;;'DB4&II%%D 12 	++ 3NH ( s   A/A1c           
   #    "   \        \        4      p\        V P                  4       F   w  pw  r4W,          P	                  W234       K"  	  R x  Rx  Rx  ^ p/ p\        V4       Fl  pVw  rxRV RV 2x  W,           FK  w  r2WVV&   V^,          pRP                  \        \        \        V4      4      4      p	RV	 R2x  RV: R	2x  KM  	  Rx  Kn  	  R
x  Rx  \        V P                  4       F<  p
V
w  rxV P                  V
,           Uu. uF  q&V,          NK  	  ppRV
: RV: R2x  K>  	  Rx  R# u upi 5i)z@# Note: the order of the beta rules is used in the beta_triggerszbeta_rules = [r   z    # Rules implying r   r   z    ({z},r   z),z] # beta_ruleszbeta_triggers = {r   z: r   z} # beta_triggersN)
r   listr8   r<   r:   rs   r   r   rt   r   )r\   reverse_implicationsnprer   mindicesr   r   setstrquerytriggerss   &           r   _beta_rules_linesFactRules._beta_rules_lines  sW    *40!*4??!;A~ )00#: "< QP23G!KD)$s5'::.77
Q3sF3K#89xs++ 2.. 8 H 4 !!D../EKD,0,>,>u,EF,Eq

,EHF	H<q11 0 "! Gs   DD>D9 D>c                0   < V ^8  d   QhRS[ S[,          /# r   )r   rt   )r   r   s   "r   r   r   #  s     k kXc] kr   c              #  .  "   V P                  4        Rj  xL
  Rx  Rx  V P                  4        Rj  xL
  Rx  Rx  V P                  4        Rj  xL
  Rx  Rx  V P                  4        Rj  xL
  Rx  Rx  Rx  Rx  R#  Lv LX L: L5i)z@Returns a generator with lines to represent the facts and rules Nr   z`generated_assumptions = {'defined_facts': defined_facts, 'full_implications': full_implications,zZ               'prereq': prereq, 'beta_rules': beta_rules, 'beta_triggers': beta_triggers})r   r   r   r   r[   s   &r   r   FactRules.print_rules#  s     ,,...00222%%'''))+++ppjj 	/ 	3 	( 	,sC   BBBBBBB6B7BBBB)r<   r   r   r   rJ   N)rP   rQ   rR   rS   rT   r]   r   classmethodr   r   r   r   r   r   rU   r~   r   s   @r   r   r   |  sN     <9v- - 
 
")
":k kr   r   c                   &   a  ] tR tRt o R tRtV tR# )InconsistentAssumptionsi5  c                :    V P                   w  rpV: R V: RV: 2# )r   =)r4   )r\   kbr   r   s   &   r   __str__InconsistentAssumptions.__str__6  s    ))% $..r   rO   N)rP   rQ   rR   rS   r   rU   r~   r   s   @r   r   r   5  s     / /r   r   c                   <   a  ] tR tRt o RtR tR tR tR tRt	V t
R# )	FactKBi;  zL
A simple propositional knowledge base relying on compiled inference rules.
c                    R RP                  \        V P                  4       4       Uu. uF  pRV,          NK  	  up4      ,          # u upi )z{
%s}z,
z	%s: %s)r   rs   r!   )r\   r   s   & r   r   FactKB.__str__?  sB    %**%+DJJL%9:%9Z!^^%9:< < 	<:s   A
c                    Wn         R # r,   rI   )r\   rI   s   &&r   r]   FactKB.__init__C  s    
r   c                d    W9   d&   W,          e   W,          V8X  d   R# \        WV4      hW V&   R# )zhAdd fact k=v to the knowledge base.

Returns True if the KB has actually been updated, False otherwise.
FT)r   )r\   r   vs   &&&r   _tellFactKB._tellF  s3    
 9,w!|-dq99Gr   c                  a  S P                   P                  pS P                   P                  pS P                   P                  p\	        V\
        4      '       d   VP                  4       pV'       d   \        4       pV F_  w  rgS P                  Wg4      '       d   Vf   K"  W&V3,           F  w  rS P                  W4       K  	  VP                  W6V3,          4       Ka  	  . pV F`  p
WJ,          w  r\        ;QJ d    V 3R lV 4       F  '       d   K   RM	  RM! V 3R lV 4       4      '       g   KO  VP                  V4       Kb  	  K  R# )z
Update the KB with all the implications of a list of facts.

Facts can be specified as a dictionary or as a list of (key, value)
pairs.
Nc              3   N   <"   T F  w  rSP                  V4      VJ x  K  	  R # 5ir,   )r7   )r-   r   r   r\   s   &  r   r1   *FactKB.deduce_all_facts.<locals>.<genexpr>y  s      :EDAtxx{a'Es   "%FT)rI   r   r   r<   r
   r   r!   r   r   r   allr:   )r\   factsr   r   r<   beta_maytriggerr   r   rr   r   rF   r?   r0   s   f&           r   deduce_all_factsFactKB.deduce_all_factsW  s    !JJ88

00ZZ**
eT""KKME!eO zz!''19 #4qD"9"9JCJJs* #:  &&}T':;  E')/3:E:333:E:::LL' (! r   r   N)rP   rQ   rR   rS   rT   r   r]   r   r   rU   r~   r   s   @r   r   r   ;  s#     <"#( #(r   r   N)rT   collectionsr   typingr   logicr   r   r   r   r   r   r   r)   rG   rL   	ExceptionrN   rW   r   r#   r   r   r   rO   r   r   <module>r      s{   .` $  & &(%PL^L		 	
v7 v7vvk vkr/j /?(T ?(r   