@ -1,4 +1,9 @@
				@@ -1,4 +1,9 @@
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					""" This module contains definitions and utilities for 2-, 4-, and 8-valued logic operations.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					""" This module contains definitions and tools for 2-, 4-, and 8-valued logic operations.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					Logic  values  are  stored  in  numpy  arrays  with  data  type  ` ` np . uint8 ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					There  are  no  explicit  data  structures  in  KyuPy  for  holding  patterns ,  pattern  sets  or  vectors .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					However ,  there  are  conventions  on  logic  value  encoding  and  on  the  order  of  axes .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					Utility  functions  defined  here  follow  these  conventions .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					8  logic  values  are  defined  as  integer  constants .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -21,10 +26,22 @@ Except when bit0 differs from bit1, but bit2 (activity) is 0:
				@@ -21,10 +26,22 @@ Except when bit0 differs from bit1, but bit2 (activity) is 0:
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					4 - valued  logic  only  considers  bit0  and  bit1 .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					8 - valued  logic  considers  all  3  bits .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					Logic  values  are  stored  in  numpy  arrays  of  data  type  ` ` np . uint8 ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					The  axis  convention  is  as  follows :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					*  The  * * last * *  axis  goes  along  patterns / vectors .  I . e .  ` ` values [ . . . , 0 ] ` `  is  pattern  0 ,  ` ` values [ . . . , 1 ] ` `  is  pattern  1 ,  etc .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					*  The  * * second - to - last * *  axis  goes  along  the  I / O  and  flip - flops  of  circuits .  For  a  circuit  ` ` c ` ` ,  this  axis  is  usually  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					` ` len ( c . s_nodes ) ` `  long .  The  values  of  all  inputs ,  outputs  and  flip - flops  are  stored  within  the  same  array  and  the  location  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					along  the  second - to - last  axis  is  determined  by  the  order  in  ` ` c . s_nodes ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					Two  storage  formats  are  used  in  KyuPy :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					*  ` ` mv . . . ` `  ( for  " multi-valued " ) :  Each  logic  value  is  stored  in  the  least  significant  3  bits  of  ` ` np . uint8 ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					*  ` ` bp . . . ` `  ( for  " bit-parallel " ) :  Groups  of  8  logic  values  are  stored  as  three  ` ` np . uint8 ` ` .  This  format  is  used  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					for  bit - parallel  logic  simulations .  It  is  also  more  memory - efficient .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					The  functions  in  this  module  use  the  ` ` mv . . . ` `  and  ` ` bp . . . ` `  prefixes  to  signify  the  storage  format  they  operate  on .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					"""  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					import  math  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					from  collections . abc  import  Iterable  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					import  numpy  as  np  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				 
				
					@ -80,41 +97,12 @@ def interpret(value):
				@@ -80,41 +97,12 @@ def interpret(value):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  UNKNOWN  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					_bit_in_lut  =  np . array ( [ 2  * *  x  for  x  in  range ( 7 ,  - 1 ,  - 1 ) ] ,  dtype = ' uint8 ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					@numba . njit  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bit_in ( a ,  pos ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  a [ pos  >>  3 ]  &  _bit_in_lut [ pos  &  7 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  unpackbits ( a  :  np . ndarray ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Unpacks the bits of given ndarray `a`.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Similar  to  ` np . unpackbits ` ,  but  accepts  any  dtype ,  preserves  the  shape  of  ` a `  and  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    adds  a  new  last  axis  with  the  bits  of  each  item .  Bits  are  in  ' little ' - order ,  i . e . ,  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    a [ . . . , 0 ]  is  the  least  significant  bit .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . unpackbits ( a . view ( np . uint8 ) ,  bitorder = ' little ' ) . reshape ( * a . shape ,  8 * a . itemsize )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  packbits ( a ,  dtype = np . uint8 ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Packs the values of a boolean-valued array `a` along its last axis into bits.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mvarray ( * a ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Converts (lists of) Boolean values or strings into a multi-valued array.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Similary  to  ` np . packbits ` ,  but  returns  an  array  of  given  dtype  and  the  shape  of  ` a `  with  the  last  axis  removed .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    The  last  axis  of  ` a `  is  truncated  or  padded  according  to  the  bit - width  of  the  given  dtype .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Signed  integer  datatypes  are  padded  with  the  most  significant  bit ,  all  others  are  padded  with  ` 0 ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    The  given  values  are  interpreted  and  the  axes  are  arranged  as  per  KyuPy ' s convention.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Use  this  function  to  convert  strings  into  multi - valued  arrays .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    dtype  =  np . dtype ( dtype )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    bits  =  8  *  dtype . itemsize  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    a  =  a [ . . . , : bits ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  a . shape [ - 1 ]  <  bits :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        p  =  [ ( 0 , 0 ) ] * ( len ( a . shape ) - 1 )  +  [ ( 0 ,  bits - a . shape [ - 1 ] ) ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        a  =  np . pad ( a ,  p ,  ' edge ' )  if  dtype . name [ 0 ]  ==  ' i '  else  np . pad ( a ,  p ,  ' constant ' ,  constant_values = 0 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . packbits ( a ,  bitorder = ' little ' ) . view ( dtype ) . reshape ( a . shape [ : - 1 ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mvarray ( * a ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    mva  =  np . array ( interpret ( a ) ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  mva . ndim  <  2 :  return  mva  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  mva . shape [ - 2 ]  >  1 :  return  mva . swapaxes ( - 1 ,  - 2 )  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -122,24 +110,13 @@ def mvarray(*a):
				@@ -122,24 +110,13 @@ def mvarray(*a):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_str ( mva ,  delim = ' \n ' ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Renders a given multi-valued array into a string.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    sa  =  np . choose ( mva ,  np . array ( [ * ' 0X-1PRFN ' ] ,  dtype = np . unicode_ ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  mva . ndim  ==  1 :  return  ' ' . join ( sa )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  delim . join ( [ ' ' . join ( c )  for  c  in  sa . swapaxes ( - 1 , - 2 ) ] )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_to_bp ( mva ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  mva . ndim  ==  1 :  mva  =  mva [ . . . ,  np . newaxis ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . packbits ( unpackbits ( mva ) [ . . . , : 3 ] ,  axis = - 2 ,  bitorder = ' little ' ) . swapaxes ( - 1 , - 2 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bparray ( * a ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  mv_to_bp ( mvarray ( * a ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bp_to_mv ( bpa ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  packbits ( np . unpackbits ( bpa ,  axis = - 1 ,  bitorder = ' little ' ) . swapaxes ( - 1 , - 2 ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  _mv_not ( out ,  inp ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    np . bitwise_xor ( inp ,  0b11 ,  out = out )   # this also exchanges UNASSIGNED <-> UNKNOWN  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    np . putmask ( out ,  ( inp  ==  UNKNOWN ) ,  UNKNOWN )   # restore UNKNOWN  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -148,13 +125,10 @@ def _mv_not(out, inp):
				@@ -148,13 +125,10 @@ def _mv_not(out, inp):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_not ( x1  :  np . ndarray ,  out = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A multi-valued NOT operator.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  Optionally  an  : py : class : ` MVArray `  as  storage  destination .  If  None ,  a  new  : py : class : ` MVArray `  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  An  : py : class : ` MVArray `  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(x1)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #x1 = mv_cast(x1, m=m)[0]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( x1 . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    _mv_not ( out ,  x1 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -176,14 +150,11 @@ def _mv_or(out, *ins):
				@@ -176,14 +150,11 @@ def _mv_or(out, *ins):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_or ( x1 ,  x2 ,  out = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A multi-valued OR operator.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  Optionally  an  : py : class : ` MVArray `  as  storage  destination .  If  None ,  a  new  : py : class : ` MVArray `  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  An  : py : class : ` MVArray `  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(x1, x2)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #x1, x2 = mv_cast(x1, x2, m=m)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( np . broadcast ( x1 ,  x2 ) . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    _mv_or ( out ,  x1 ,  x2 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -206,14 +177,11 @@ def _mv_and(out, *ins):
				@@ -206,14 +177,11 @@ def _mv_and(out, *ins):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_and ( x1 ,  x2 ,  out = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A multi-valued AND operator.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  Optionally  an  : py : class : ` MVArray `  as  storage  destination .  If  None ,  a  new  : py : class : ` MVArray `  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  An  : py : class : ` MVArray `  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(x1, x2)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #x1, x2 = mv_cast(x1, x2, m=m)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( np . broadcast ( x1 ,  x2 ) . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    _mv_and ( out ,  x1 ,  x2 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -233,24 +201,28 @@ def _mv_xor(out, *ins):
				@@ -233,24 +201,28 @@ def _mv_xor(out, *ins):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_xor ( x1 ,  x2 ,  out = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A multi-valued XOR operator.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  Optionally  an  : py : class : ` MVArray `  as  storage  destination .  If  None ,  a  new  : py : class : ` MVArray `  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  An  : py : class : ` MVArray `  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x1 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  x2 :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(x1, x2)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #x1, x2 = mv_cast(x1, x2, m=m)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( np . broadcast ( x1 ,  x2 ) . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    _mv_xor ( out ,  x1 ,  x2 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_latch ( d ,  t ,  q_prev ,  out = None ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A latch that is transparent if `t` is high. `q_prev` has to be the output value from the previous clock cycle.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ A multi-valued latch operator.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    A  latch  outputs  ` ` d ` `  when  transparent  ( ` ` t ` `  is  high ) .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    It  outputs  ` ` q_prev ` `  when  in  latched  state  ( ` ` t ` `  is  low ) .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  d :  A  multi - valued  array  for  the  data  input .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  t :  A  multi - valued  array  for  the  control  input .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  q_prev :  A  multi - valued  array  with  the  output  value  of  this  latch  from  the  previous  clock  cycle .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  for  the  latch  output  ` ` q ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(d, t, q_prev)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #d, t, q_prev = mv_cast(d, t, q_prev, m=m)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( np . broadcast ( d ,  t ,  q_prev ) . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ]  =  t  &  d  &  0b011  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ]  | =  ~ t  &  0b010  &  ( q_prev  <<  1 )  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -268,16 +240,11 @@ def mv_transition(init, final, out=None):
				@@ -268,16 +240,11 @@ def mv_transition(init, final, out=None):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Pulses  in  the  input  data  are  ignored .  If  any  of  the  inputs  are  ` ` UNKNOWN ` ` ,  the  result  is  ` ` UNKNOWN ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    If  both  inputs  are  ` ` UNASSIGNED ` ` ,  the  result  is  ` ` UNASSIGNED ` ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  init :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  final :  An  : py : class : ` MVArray `  or  data  the  : py : class : ` MVArray `  constructor  accepts .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  Optionally  an  : py : class : ` MVArray `  as  storage  destination .  If  None ,  a  new  : py : class : ` MVArray `  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  An  : py : class : ` MVArray `  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  init :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  final :  A  multi - valued  array .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : param  out :  An  optional  storage  destination .  If  None ,  a  new  multi - valued  array  is  returned .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    : return :  A  multi - valued  array  with  the  result .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #m = mv_getm(init, final)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #init, final = mv_cast(init, final, m=m)  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #init = init.data  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    #final = final.data  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out  =  out  or  np . empty ( np . broadcast ( init ,  final ) . shape ,  dtype = np . uint8 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ]  =  ( init  &  0b010 )  |  ( final  &  0b001 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ]  | =  ( ( out  <<  1 )  ^  ( out  <<  2 ) )  &  0b100  
				
			 
			
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
				 
				 
				
					@ -288,6 +255,28 @@ def mv_transition(init, final, out=None):
				@@ -288,6 +255,28 @@ def mv_transition(init, final, out=None):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  mv_to_bp ( mva ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Converts a multi-valued array into a bit-parallel array.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  mva . ndim  ==  1 :  mva  =  mva [ . . . ,  np . newaxis ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . packbits ( unpackbits ( mva ) [ . . . , : 3 ] ,  axis = - 2 ,  bitorder = ' little ' ) . swapaxes ( - 1 , - 2 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bparray ( * a ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Converts (lists of) Boolean values or strings into a bit-parallel array.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    The  given  values  are  interpreted  and  the  axes  are  arranged  as  per  KyuPy ' s convention.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Use  this  function  to  convert  strings  into  bit - parallel  arrays .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  mv_to_bp ( mvarray ( * a ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bp_to_mv ( bpa ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Converts a bit-parallel array into a multi-valued array.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  packbits ( np . unpackbits ( bpa ,  axis = - 1 ,  bitorder = ' little ' ) . swapaxes ( - 1 , - 2 ) )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bp_buf ( out ,  inp ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    unknown  =  ( inp [ . . . ,  0 ,  : ]  ^  inp [ . . . ,  1 ,  : ] )  &  ~ inp [ . . . ,  2 ,  : ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ,  0 ,  : ]  =  inp [ . . . ,  0 ,  : ]  |  unknown  
				
			 
			
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
				 
				 
				
					@ -356,3 +345,37 @@ def bp_latch(out, d, t, q_prev):
				@@ -356,3 +345,37 @@ def bp_latch(out, d, t, q_prev):
					 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ,  1 ,  : ]  & =  ~ any_unknown  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    out [ . . . ,  2 ,  : ]  & =  ~ any_unknown  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  out  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					_bit_in_lut  =  np . array ( [ 2  * *  x  for  x  in  range ( 7 ,  - 1 ,  - 1 ) ] ,  dtype = ' uint8 ' )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					@numba . njit  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  bit_in ( a ,  pos ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  a [ pos  >>  3 ]  &  _bit_in_lut [ pos  &  7 ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  unpackbits ( a  :  np . ndarray ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Unpacks the bits of given ndarray ``a``.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Similar  to  ` ` np . unpackbits ` ` ,  but  accepts  any  dtype ,  preserves  the  shape  of  ` ` a ` `  and  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    adds  a  new  last  axis  with  the  bits  of  each  item .  Bits  are  in  ' little ' - order ,  i . e . ,  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    a [ . . . , 0 ]  is  the  least  significant  bit  of  each  item .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . unpackbits ( a . view ( np . uint8 ) ,  bitorder = ' little ' ) . reshape ( * a . shape ,  8 * a . itemsize )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					def  packbits ( a ,  dtype = np . uint8 ) :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """ Packs the values of a boolean-valued array ``a`` along its last axis into bits.  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					
 
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Similar  to  ` ` np . packbits ` ` ,  but  returns  an  array  of  given  dtype  and  the  shape  of  ` ` a ` `  with  the  last  axis  removed .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    The  last  axis  of  ` a `  is  truncated  or  padded  according  to  the  bit - width  of  the  given  dtype .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    Signed  integer  datatypes  are  padded  with  the  most  significant  bit ,  all  others  are  padded  with  ` 0 ` .  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    """  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    dtype  =  np . dtype ( dtype )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    bits  =  8  *  dtype . itemsize  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    a  =  a [ . . . , : bits ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    if  a . shape [ - 1 ]  <  bits :  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        p  =  [ ( 0 , 0 ) ] * ( len ( a . shape ) - 1 )  +  [ ( 0 ,  bits - a . shape [ - 1 ] ) ]  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					        a  =  np . pad ( a ,  p ,  ' edge ' )  if  dtype . name [ 0 ]  ==  ' i '  else  np . pad ( a ,  p ,  ' constant ' ,  constant_values = 0 )  
				
			 
			
		
	
		
			
				
					 
					 
				
				 
				 
				
					    return  np . packbits ( a ,  bitorder = ' little ' ) . view ( dtype ) . reshape ( a . shape [ : - 1 ] )