
    rh%                      % S r SSKJr  SSKJr  SSKJr  SSKrSSKJ	r	J
r
  SSKrSSKrSSKrSSKrSSKJr  SSKJr  SS	KJr  SS
KJr  SSKJr  \R,                  " S5      r " S S\R0                  5      r " S S\R0                  5      r " S S\R0                  5      r " S S\R0                  5      r " S S\R0                  5      rSrSrSr Sr!Sr"\\\ \!\"/r#Sr$\%" \RL                  5      S/-   r'S4S jr(S r)S5S6S  jjr*S5S! jr+S" r,S7S# jr-S$ r. " S% S&5      r/ " S' S(5      r0 " S) S*5      r1 " S+ S,5      r2 " S- S.5      r3 " S/ S0\Rh                  5      r5/ r6S1\7S2'   \8S3:X  a  SSKr\Rr                  " \55        gg)8a  
A comprehensive, object model of the Xenakis Sieve. :class:`music21.sieve.Sieve`
objects can be created from high-level string notations, and used to generate line segments
in various representation. Additional functionality is available through associated objects.

The :class:`music21.sieve.Sieve` class permits generation segments in four formats.

>>> a = sieve.Sieve('3@2|7@1')
>>> a.segment()
[1, 2, 5, 8, 11, 14, 15, 17, 20, 22, 23, 26, 29, 32, 35, 36, 38, 41, 43, 44,
 47, 50, 53, 56, 57, 59, 62, 64, 65, 68, 71, 74, 77, 78, 80, 83, 85, 86, 89, 92, 95, 98, 99]

>>> a.segment(segmentFormat='binary')
[0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1,
 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1,
 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1]

>>> a.segment(segmentFormat='width')
[1, 3, 3, 3, 3, 1, 2, 3, 2, 1, 3, 3, 3, 3, 1, 2, 3, 2, 1, 3, 3, 3, 3, 1, 2, 3, 2,
 1, 3, 3, 3, 3, 1, 2, 3, 2, 1, 3, 3, 3, 3, 1]

>>> len(a.segment(segmentFormat='unit'))
43


A :class:`music21.sieve.CompressionSegment` can be used to derive a Sieve from a
ny sequence of integers.


>>> a = sieve.CompressionSegment([3, 4, 5, 6, 7, 8, 13, 19])
>>> str(a)
'6@1|7@6|8@5|9@4|10@3|11@8'


The :class:`music21.sieve.PitchSieve` class provides a quick generation of
:class:`music21.pitch.Pitch` lists from Sieves.

>>> a = sieve.PitchSieve('13@3|13@6|13@9', 'c1', 'c10', 'f#4')
>>> pitches = a()
>>> ', '.join([str(p) for p in pitches])
'F#1, A1, C2, G2, B-2, C#3, G#3, B3, D4, A4, C5, E-5, B-5, C#6, E6, B6, D7,
 F7, C8, E-8, F#8, C#9, E9, G9'
    )annotations)literal_eval)IterableN)gcdlcm)common)environment)exceptions21)interval)pitchsievec                      \ rS rSrSrg)UnitExceptionM    N__name__
__module____qualname____firstlineno____static_attributes__r       G/home/james-whalen/.local/lib/python3.13/site-packages/music21/sieve.pyr   r   M       r   r   c                      \ rS rSrSrg)ResidualExceptionQ   r   Nr   r   r   r   r   r   Q   r   r   r   c                      \ rS rSrSrg)SieveExceptionU   r   Nr   r   r   r   r   r   U   r   r   r   c                      \ rS rSrSrg)CompressionSegmentExceptionY   r   Nr   r   r   r   r"   r"   Y   r   r   r"   c                      \ rS rSrSrg)PitchSieveException]   r   Nr   r   r   r   r%   r%   ]   r   r   r%   {}&|^-@c              #     #    0 nSn UR                  US5      nUb  X2-   nXA;   a  XC-   nXA;   a  M  X1U'   OX"-  nX!U'   X :  a  Uv   US-   nMF  7f)ae  
Yields the sequence of prime numbers via the Sieve of Eratosthenes.
rather than creating a fixed list of a range (z) and crossing out
multiples of sequential candidates, this algorithm stores primes under
their next possible candidate, thus allowing the generation of primes
in sequence without storing a complete range (z).

Create a dictionary. Each entry in the dictionary is a key:item pair of
(key) the largest multiple of this prime so far found and (item)
the prime. The dictionary only has as many entries as found primes.

If a candidate is not a key in the dictionary, it is not a multiple of
any already-found prime; it is thus a prime. a new entry is added to the
dictionary, with the square of the prime as the key. The square of the prime
is the next possible multiple to be found.

To use this generator, create an instance and then call the .next() method
on the instance.


>>> a = sieve.eratosthenes()
>>> next(a)
2
>>> next(a)
3


We can also specify a starting value for the sequence, skipping over
initial primes smaller than this number:


>>> a = sieve.eratosthenes(95)
>>> next(a)
97
>>> next(a)
101
   N   )pop)firstCandidateDqpnextMults        r   eratosthenesr7   t   sy     L 	A	A
 EE!TN= uH-#< - hK uHhK"E) s
   -AAc                   [        U 5      n U S;   a  gU S-  nUS;  a  g/ SQnU S::  a  X;   a  ggU H  nX-  S:X  d  M    g   U S	-
  S	pTUS	-  (       d  US	-  nUS	-   nUS	-  (       d  M  [        S
5       HZ  n[        [        R                  " S	U S	-
  5      X@5      nUS	:X  a  M/  [        S	U5       H  nXpS	-
  :X  a    MI  [        USU 5      nM       g   g)a  
Returns True if an integer is likely prime or False if it is likely composite using the
Rabin Miller primality test.

See also here: http://www.4dsolutions.net/ocn/numeracy2.html


>>> sieve.rabinMiller(234)
False
>>> sieve.rabinMiller(5)
True
>>> sieve.rabinMiller(4)
False

>>> sieve.rabinMiller(97 * 2)
False

>>> sieve.rabinMiller(6 ** 4 + 1)  # prime
True

>>> sieve.rabinMiller(123986234193)  # divisible by 3, runs fast
False
)r/      T   )r0      F)r;                           %   )   +   /   5   ;   =   C   G   I   O   S   r#   a   d   r   r0   
   r/   )absrangepowrandomrandint)	nmprimesprimesriyjs	            r   rabinMillerra      s    0 	AAF{	AA;F 	Cx;9>  q5!q!e	aE !ee 2Yq!a%(!/6q!AEzAq!A 
   r   c                   U  H)  n[         R                  " U5      (       a  M   [        S5      e   / nUb  UR                  5         US   nUS   nO9[	        [
        R                  " U 5      5      nUR                  5         US   nUS   n[        XES-   5       H,  nX ;   a  UR                  S5        M  UR                  S5        M.     U$ )a  
Treat a sequence of integers as defining contiguous binary integers,
where provided values are 1's and excluded values are zero.

For instance, running [3, 10, 12] through this method gives a 1 for
the first entry (signifying 3), 0s for the next six entries (signifying
4-9), a 1 (for 10), a 0 (for 11), and a 1 (for 12).


>>> sieve.discreteBinaryPad([3, 10, 12])
[1, 0, 0, 0, 0, 0, 0, 1, 0, 1]

>>> sieve.discreteBinaryPad([3, 4, 5])
[1, 1, 1]

znon-integer value foundr   r0   )	r   isNumr   sortlistcopydeepcopyrT   append)seriesfixRangexdiscreteminValmaxVal	seriesAlts          r   discreteBinaryPadrq      s    $ ||A 9::  H!"v./	126A:&;OOAOOA	 '
 Or   c                |   Ub  UR                  5         US   nUS   nO[        U 5      n[        U 5      nX2-
  n/ n[        U 5      S:  aa  U  HY  nXb-
  n[        R
                  " U5      (       a  [        U5      nUS:w  a  UR                  Xt-  5        MH  UR                  S5        M[     U$ UR                  S5        U$ )a  
Given a list of numbers, create a proportional spacing across the unit interval.

The first entry will always be 0 and the last 1, other entries will be spaced
according to their distance between these two units.  For instance, for 0, 3, 4
the middle entry will be 0.75 since 3 is 3/4 of the distance between 0 and 4:


>>> sieve.unitNormRange([0, 3, 4])
[0.0, 0.75, 1.0]


but for [1, 3, 4], it will be 0.666... because 3 is 2/3 of the distance between
1 and 4


>>> sieve.unitNormRange([1, 3, 4])
[0.0, 0.666..., 1.0]


r   rc   r0   )re   minmaxlenr   rd   floatri   )rj   rk   minFoundmaxFoundspanunitvaldifs           r   unitNormRanger}   !  s    , A;B<v;v;DD
6{QC.C||C  CjqyCJ'A  K 	AKr   c                    U S::  a  S/$ U S:X  a  SS/$ / nSU S-
  -  n[        U S-
  5       H  nUR                  X2-  5        M     UR                  S5        U$ )a  
Given a certain number of parts, return a list unit-interval values
between 0 and 1, with as many divisions as parts; 0 and 1 are always inclusive.

>>> sieve.unitNormEqual(3)
[0.0, 0.5, 1]

If parts is 0 or 1, then a single entry of [0] is given:

>>> sieve.unitNormEqual(1)
[0]
r0   r   r/   )rT   ri   )partsrz   stepr_   s       r   unitNormEqualr   N  se     zs
	!1vEAIuqy!AKK! "Ar   c                    X:X  a  / $ X:  a  UnUnOUnUnSn/ nUnX::  a!  UR                  U5        X-  nUS-  nX::  a  M!  U(       a  [        U5      $ U$ )aN  
Given a step size and an a/b min/max range, calculate number of parts
to fill step through inclusive a,b, then return a unit interval list of values
necessary to cover region.

Note that returned values are, by default, normalized within the unit interval.


>>> sieve.unitNormStep(0.5, 0, 1)
[0.0, 0.5, 1]

>>> sieve.unitNormStep(0.5, -1, 1)
[0.0, 0.25, 0.5, 0.75, 1]

>>> sieve.unitNormStep(0.5, -1, 1, normalized=False)
[-1, -0.5, 0.0, 0.5, 1.0]

>>> post = sieve.unitNormStep(0.25, 0, 20)
>>> len(post)
81
>>> post = sieve.unitNormStep(0.25, 0, 20, normalized=False)
>>> len(post)
81

r   r0   )ri   r   )	r   ab
normalizedrn   ro   countvaluesrl   s	            r   unitNormStepr   h  su    4 	v	u EFA
+a		
 + U##r   c                v    SnUS:X  a  SnU$ X:X  a  SnU$ US:  a  X -  U-  nUS:X  a   U$ US-   nUS:  a  M  U$ )Nr   r0   '  r   )c1c2gr{   s       r   	_meziriacr     sm     	
A	Qw H 
 H %i6R-CaxH AA	 %i
 Hr   c                  4    \ rS rSrS rSS jrS rS	S jrSrg)
PrimeSegmenti  c                J    / U l         Xl        X l        U R                  5         g)z
A generator of prime number segments, given a start value
and desired length of primes.

>>> ps = sieve.PrimeSegment(3, 20)
>>> ps()
[3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73]
N)segstartlength
_fillRange)selfr   r   s      r   __init__PrimeSegment.__init__  s     
r   Nc                   / nSnUS-  S:X  a  X:  a  US:X  a  US-   nOUS-
  nOUn [        U5      (       a#  UR                  U5        [        U5      U:  a   U$ Xs:X  a   U$ Xv:  a  US:X  a  US-   nOUS-
  nOUS:X  a  US-   nOUS-
  nMe  )z
scan all number in range and return a list of primes
provide a max to force stoppage at  certain point before the
maximum length
direction determines which way things go.
   r/   r   upr0   )ra   ri   ru   )r   r   r   stop	directionr   _oddBoundaryrX   s           r   _fillRabinMillerPrimeSegment._fillRabinMiller  s     19>e2D AIAIA1~~

1s8v% 
 y 
 $AAAA$AAAA! r   c                   U R                   S:  a  U R                  [        U R                   5      U R                  SS5      nU Vs/ s H  o"* PM     nn[	        U5      U R                  :  a4  U R                  SU R                  [	        U5      -
  SS5      nX-   U l        gXl        gU R                  U R                   U R                  SS5      U l        gs  snf )z"
fill positive and negative range
r   downNr   )r   r   rS   r   ru   r   )r   segNegrl   segPoss       r   r   PrimeSegment._fillRange  s     ::>**3tzz?DKKFSF"()&Qb&F)6{T[[(..q$++F2K9=tE!?! ,,TZZdDQDH *s   Cc                   U R                   S   U R                   S   /nUS;   a  [        U R                   U5      $ US:X  a  [        U R                   U5      $ US;   a]  / n[        [	        U R                   5      S-
  5       H4  nUR                  U R                   US-      U R                   U   -
  5        M6     U$ U R                   $ )zn
assumes that min and max values are derived from found primes
means that primes will always be at boundaries
r   rc   binbinaryrz   widwidthr0   )r   rq   r}   rT   ru   ri   )r   segmentFormatzr   r^   s        r   __call__PrimeSegment.__call__   s    
 XXa[$((2,'--$TXXq11f$ 1--..C3txx=1,-

DHHQUOdhhqk9; .J88Or   )r   r   r   )Nr   N)	r   r   r   r   r   r   r   r   r   r   r   r   r   r     s    #JR$r   r   c                      \ rS rSrSrSS jrS rS rS rSS jr	SS	 jr
S
 rSS jrSS jrS rS rS rS rS rS rS rS rS rSrg)Residuali  z
object that represents a modulus and a start point
each object stores a range of integers (self._z) from which sections are drawn
this range of integers can be changed whenever the section os drawn

>>> residual = sieve.Residual(3, 2)
Nc                    Uc  [        [        S5      5      nX@l        Xl        US;  a  [	        S5      eX0l        U R                  S:X  a  X l        OX R                  -  U l        / SQU l        SU l        g )NrQ   )r   r0   z)negative value must be 0, 1, or a Booleanr   intr   rz   r   r   )	rf   rT   _z_mr   _neg_shift_segmentFormatOptions_segmentFormat)r   rY   shiftnegr   s        r   r   Residual.__init__  sg     9U3Z Af#$OPP	77a<K''/DK%B"#r   c                    Xl         g)z:
z is the range of integers to use when generating a list
Nr   r   r   s     r   setZResidual.setZ3  s	     r   c                <    [        [        XS-   5      5      U l        g)z^
z is the range of integers to use when generating a list
convenience function that fixes max
r0   Nrf   rT   r   r   minIntmaxInts      r   	setZRangeResidual.setZRange9      
 uVaZ01r   c                    UR                  5       R                  5       nXR                  ;   a  [        SU 35      eXl        g )Nzformat not in format options: )striplowerr   r   r   r   fmts     r   setSegmentFormatResidual.setSegmentFormat@  s;    iik!,,,#&DSE$JKK!r   c                <   Uc  U R                   nUc  U R                  n/ nU R                  S:X  a  U$ XR                  -   U R                  -  nU H(  nXU R                  -  :X  d  M  UR	                  U5        M*     U R
                  (       a3  [        R                  " U5      nU H  nUR                  U5        M     UnOUnUS;   a  [        Xr5      $ US:X  a  [        Xr5      $ US;   a  U R                  /[        U5      S-
  -  nU$ US;   a  U$ [        U S35      e)al  
get a residual subset of this modulus at this n
within the integer range provided by z
format can be 'int' or 'bin', for integer or binary

>>> a = sieve.Residual(3, 2)
>>> a.segment(3)
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47, 50, 53, 56, 59,
 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98]
>>> a.segment(3, range(3, 15))
[5, 8, 11, 14]
r   r   rz   r   r0   )r   integerz( not a valid sieve segmentFormat string.)r   r   r   r   ri   r   rg   rh   removerq   r}   ru   r   )	r   rX   r   r   subsetvaluecompSetr   r   s	            r   segmentResidual.segmentH  s    9A  //M77a<M_'EDGGO#e$  99mmA&Gu%  CC--$S,,f$ ((..77)s3x!|,CJ00J#}o5]$^__r   c                    U R                   $ )z`
period is M; obvious, but nice for completeness

>>> a = sieve.Residual(3, 2)
>>> a.period()
3
)r   r   s    r   periodResidual.periodw  s     wwr   c                    [         R                   " U R                  5      n[         R                   " U R                  5      n[         R                   " U R                  5      n[	        XX0R
                  5      $ r   )rg   r   r   r   r   r   )r   rY   r   r   s       r   rg   Residual.copy  sI    IIdgg		$++&ii		"#ww//r   c                &    U R                  XU5      $ )z
calls self.segment(); uses _segmentFormat

>>> a = sieve.Residual(3, 2)
>>> a()
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47,
 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98]
)r   r   rX   r   r   s       r   r   Residual.__call__  s     ||A-00r   c                   US:X  aT  U R                   S:w  a  U R                   SU R                    S3nOU R                   S3nU R                  (       a  SU 3nU$ U R                   SU R                    3nU R                  (       a  SU 3nU$ )z7
does not show any logical operator but unary negation
classicr   z(n+)z(n)r,   r-   )r   r   r   )r   stylerepStrs      r   	representResidual.represent  s     I{{a GG9C}A6 GG9CyyVH
  y$++/FyyVHr   c                "    U R                  5       $ )ze
str representation using M(n + shift) style notation

>>> a = sieve.Residual(3, 2)
>>> str(a)
'3@2'
r   r   s    r   __str__Residual.__str__  s     ~~r   c                    Uc  gU R                   UR                   :X  a5  U R                  UR                  :X  a  U R                  UR                  :X  a  gg)z6
==, compare residual classes in terms of m and shift
r   r0   r   r   r   r   others     r   __eq__Residual.__eq__  sB     =GGuxxKK5<</II+r   c                j   U R                   UR                   :  a  gU R                   UR                   :  a  gU R                   UR                   :X  ac  U R                  UR                  :  a  gU R                  UR                  :  a  gU R                  UR                  :w  a  U R                  S:X  a  gggg)z
allow comparison based on m and shift; if all equal look at neg

Still being used internally even though __cmp__ is not used in Python 3
rc   r0   r   Nr   r   s     r   __cmp__Residual.__cmp__  s     77UXXWWuxxWW {{U\\)u||+99

*yyA~!  !r   c                0    U R                  U5      S:X  a  gg)Nrc   TFr   r   s     r   __lt__Residual.__lt__  s    <<"$r   c                0    U R                  U5      S:X  a  gg)Nr0   TFr   r   s     r   __gt__Residual.__gt__  s    <<!#r   c                    U R                   (       a  SnOSn[        U R                  U R                  XR                  5      $ )z(
unary neg operators; return neg object
r   r0   )r   r   r   r   r   )r   r   s     r   __neg__Residual.__neg__  s0     99CCc77;;r   c                ^   UR                   (       d  U R                   (       a  [        S5      eU R                  U R                  UR                  U R                  UR                  5      u  p#[        U R                  5      [        UR                  5      -  n[        U5      n[        X#SU5      $ )z
&, produces an intersection of two Residual classes
returns a new Residual class
cannot be done if R under complementation

>>> a = sieve.Residual(3, 2)
>>> b = sieve.Residual(5, 1)
>>> c = a & b
>>> str(c)
'15@11'
z3complemented Residual objects cannot be intersectedr   )	r   r   _cmpIntersectionr   r   setr   rf   r   )r   r   rY   rX   zSetr   s         r   __and__Residual.__and__  sw     ::#$YZZ$$TWWehhU\\R477|c%((m+Ja##r   c                    g)z
|, not sure if this can be implemented
i.e., a union of two Residual classes can not be expressed as a single
Residual, that is intersections can always be reduced, whereas unions
cannot be reduced.
Nr   r   s     r   __or__Residual.__or__  s     	r   c                   [        X5      nX-  nX%-  nSnSn	US:w  a  US:w  a	  X1-  nXB-  nOX4$ US:w  a  X4-
  U-  S:w  a  X4$ US:w  a  X4-
  U-  S:X  a  X4:w  a  Xg:X  a  Un	UnX4$ Xg-  U-  n	[        Xg5      n
X:XC-
  -  U-  -   U	-  nX4$ )z
compression by intersection
find m,n such that the intersection of two Residuals can
be reduced to one Residual. Xenakis p 273.
r   r0   )r   r   )r   m1m2n1n2dr   r   n3m3r   s              r   r  Residual._cmpIntersection  s     KWW7rQwBB6M61})6M!V"'Q!+"(BB6M1B"!ARW*+r1B6Mr   )r   r   r   r   r   r   )r   r   Nr   NNreturnr   r   )r   r   r   r   __doc__r   r   r   r   r   r   rg   r   r   r   r   r   r   r   r  r  r
  r  r   r   r   r   r   r     sc    $*2"-`^0
1" 6<$*r   r   c                  J    \ rS rSrSrSS jrSS jrS rS rS r	S	 r
S
 rSrg)CompressionSegmenti-  a  
Utility to convert from a point sequence to sieve.

A z range can be supplied to explicitly provide the complete sieve segment,
both positive and negative values. all values in the z range not in the
segment are interpreted as negative values. thus, there is an essential
dependency on the z range and the realized sieve.

No matter the size of the z range, there is a modulus at which one point
in the segment can be found. As such, any segment can be reduced to, at a
minimum, a residual for each point in the segment, each, for the supplied z,
providing a segment with one point.

The same segment can then have multiplied logical string representations,
depending on the provided z.

>>> a = sieve.CompressionSegment([3, 4, 5, 6, 7, 8, 13, 19])
>>> str(a)
'6@1|7@6|8@5|9@4|10@3|11@8'

>>> b = sieve.CompressionSegment([0, 2, 4, 6, 8])
>>> str(b)
'2@0'

>>> c = sieve.CompressionSegment([0, 2, 4, 5, 7, 9, 11, 12])
>>> str(c)
'5@2|5@4|6@5|7@0'
Nc                   [        [        R                  " U5      5      nUR                  5         / U l        U H/  nX0R                  ;  d  M  U R                  R                  U5        M1     [        U R                  5      S::  a  [        S5      eU R                  U5        [        U R                  5      U l
         U R                  5         g ! [         a    [        S5      ef = f)Nr0   z'segment must have more than one elementz*no Residual classes found for this z range)rf   rg   rh   re   _matchri   ru   r"   _zUpdater   _maxMod_processAssertionError)r   srcr   nums       r   r   CompressionSegment.__init__K  s     4==%&
C++%""3'  t{{q -.WXXa 477|	\MMO 	\-.Z[[	\s   <C C#c                   UbP  U R                  U R                  U5      (       d  [        S5      eXl        U R                  S   U R                  S   p2g U R                  S   U R                  S   p2[	        [        X#S-   5      5      U l        g )Nz-z range must be a superset of desired segmentr   rc   r0   )_subsetr  r"   r   rf   rT   )r   r   zMinzMaxs       r   r  CompressionSegment._zUpdatec  sz    =<<Q//1CE E GTWWR[$ QR$5q23DGr   c                    U R                   $ )zW

>>> a = sieve.CompressionSegment([3, 4, 5, 6, 7, 8])
>>> b = a()
>>> str(b[0])
'1@0'
)
_residualsr   s    r   r   CompressionSegment.__call__r  s     r   c                    / n[        U R                  5      S:X  a  [        U R                  S   5      nU$ U R                   H  nUR                  [        U5      5        M     SR	                  U5      nU$ )Nr0   r   r*   )ru   r*  strri   join)r   resStrresObjs      r   r   CompressionSegment.__str__|  se    t1$+,F
  //c&k* *XXf%Fr   c                R    SnU H  nXB;   d  M
  US-   nM     U[        U5      :X  a  gg)z=
True if sub is part of set; assumes no redundancies in each
r   r0   )ru   )r   subthisSet	commonNumrl   s        r   r%  CompressionSegment._subset  s5     	A|%M	  C r   c                    SnX@R                   :  af  [        XASU R                  5      nU" 5       nU R                  Xb5      (       a  XV4$ U R                  Xc5      (       a  XV4$ US-   nX@R                   :  a  Mf  [	        SU R                    35      e)zG
given a point, and SieveSegment, find a modulus and shift that
match.
r0   r   za mod was not found less than )r  r   r   r%  r   )r   rX   partwholerY   objr   s          r   _findCompressionSegment._find  s    
 ,,1DGG,C%C||C&&xc))xAA ,, =dll^LMMr   c                   / U l         [        R                  " U R                  5      nSnU(       a  US-  nUS   nU R                  X1U R                  5      u  pEUc  [	        S5      eX@R                   ;  a<  U R                   R                  U5        U H  nXa;   d  M
  UR                  U5        M     U(       d  O	U(       a  M  U R                   R                  5         g)z
take a copy of match; move through each value of this list as if it
were n; for each n test each modulo (from 1 to len(z) + 1) to find a
residual. when found (one will be found), keep it; remove the found
segments from the match, and repeat.
r   r0   r   Nz_find() returned a None object)r*  rg   r  r;  r"   ri   r   re   )r   matchmaxToRunrX   r:  r   rl   s          r   r  CompressionSegment._process  s     		$++&MHaAzz!DKK8HC{12RSS//)&&s+AzQ   h 	r   )r  r  r*  r   r   )r   r   r   r   r  r   r  r   r   r%  r;  r  r   r   r   r   r  r  -  s,    :\04N&r   r  c                  N   \ rS rSrSrS)S*S jjrS rS rS rS r	S)S	 jr
S
 rS rS rS rS rS rS rS rS rS rS rS rS rS+S jrS rS rS,S jrS rS rS)S jrS rS)S jr S  r!S! r"    S-   S.S" jjr#S/S# jr$S0S$ jr% S1           S2S% jjr&S3S& jr'S' r(S(r)g)4Sievei  z
Create a sieve segment from a sieve logical string of any complexity.

>>> a = sieve.Sieve('3@11')
>>> b = sieve.Sieve('2&4&8|5')
>>> c = sieve.Sieve('(5|2)&4&8')
Nc                   Uc*  [        U[        5      (       a  [        [        S5      5      nOUc  [        R
                  " U5      (       a   X l        SU l        S U l        SU l	        / SQU l
        SU l        0 U l        SU l        SU l        SU l        SU l        SU l        Xl        U R$                  b  U R'                  5         g g )	NrQ   expr   r   Fr    rc   )
isinstancer-  rf   rT   r   
isListLiker   _state_expTyper   r   _nonCompressible_resLib_resId_expTree
_expPeriod_cmpTree
_cmpPeriod_usrStr_load)r   usrStrr   s      r   r   Sieve.__init__  s    9FC00U3Z AY6,,V44/4#%B" %,. <<#JJL $r   c                &   [         R                  " U R                  5      (       a<  U R                  5         U R	                  U R                  5        U R                  5         g U R                  5         U R                  5         U R                  5         g r   )r   rG  rQ  	_resClear_initLoadSegment_initCompression
_initParser   s    r   rR  Sieve._load  sa    T\\**NN!!$,,/!!# NNOO!!#r   c                "   SU l         [        U R                  ;   d<  [        U R                  ;   d(  [        U R                  ;   d  [
        U R                  ;   a   U R                  5         O U R                  5         SU l         SnU R                  (       a  SnU$ U R                   S:X  a  SnU$ U R                   S:X  a  SnU$ ! [         a
    SU l         NRf = f! [         a,     U R                  5          Ns! [         a    SU l          Nf = ff = f)Ncomplexr0   simplerE  zno compression possibler   intersection)rI  NEGrM  LGROUPRGROUPXOR_cmpSegment
IndexErrorrJ  r  	TypeError)r   methods     r   rX  Sieve._initCompression  s    "4== T]]*T]]*$--'*  ".%%' (   .F
 	 ]]i'F  ]]h&#F'  *()%*  ..$$&! .,-D)..s<   C +C CC
D#C55D
D	D

Dc                    U R                  S5      nU R                  S5      n[        U6 nX:X  a  X0l        X0l        gX0l        [        U6 U l        g)zR
Lazy period initialization, called only when needed from public period() method.
rD  cmpN)_resPeriodListr   rN  rP  )r   mListExpmListCmplcmExps       r   _initPeriodSieve._initPeriod;  sM     &&u-&&u-h$O$O$O!8nDOr   c                    SU l         g)z'
Set this Sieve to its expanded state.
rD  N)rH  r   s    r   expandSieve.expandK  s     r   c                    Ub6  XR                   :w  a'  Xl         U R                  S5        U R                  5         U R                  (       a  gSU l        g)z)
Set this sieve to its compressed state.
Nri  )r   rV  rX  rJ  rH  r   s     r   compressSieve.compressQ  sA     =Q''\GNN5!!!#  DKr   c                    SU R                  S5      0nU R                  c-  U R                  U R                  S5         R                  US'   U$ U R                  US'   U$ )z8
Provides a dictionary data representation for exchange
logStrrD  r   r   )r   r   rK  
_resKeyStrr   )r   datas     r   _getParameterDataSieve._getParameterDataa  s`    
 dnnU+
 77?T__Q%78::DI  DIr   c                    Xl         g)z]
Set the z as a list. The z is the range of integers to use when
generating a sieve segment.
Nr   r   s     r   r   
Sieve.setZp  s	    
 r   c                <    [        [        XS-   5      5      U l        g)zj
Set the z as a min and max value. The z is the range of
integers to use when generating a sieve segment.
r0   Nr   r   s      r   r   Sieve.setZRangew  r   r   c                    UR                  5       R                  5       nXR                  ;  a  [        SU 35      eXl        g )Nzcannot set to format: )r   r   r   r   r   r   s     r   r   Sieve.setSegmentFormat~  s;    iik!000 #9#!?@@!r   c                    U R                  5       nSR                  [        [        US   [        /5      nUS   n[        X#5      $ )z)
unary neg operators; return neg object.
rE  rw  r   )rz  r.  r_  r`  ra  rB  )r   dataSelfrS  r   s       r   r  Sieve.__neg__  sL     ))+X	
  SMVr   c           	        U R                  5       nUR                  5       nSR                  [        US   [        [        [        US   [        /5      n[        US   5      [        US   5      -  n[        U5      n[        XF5      $ )z
&, produces an intersection of two

>>> a = sieve.Sieve('3@11')
>>> b = sieve.Sieve('2&4&8|5')
>>> c = sieve.Sieve('(5|2)&4&8')
>>> d = a & b
>>> str(d)
'{2@0&4@0&8@0|5@0}&{3@2}'
rE  rw  r   )rz  r.  r`  ra  ANDr  rf   rB  r   r   r  	dataOtherrS  r  r   s          r   r  Sieve.__and__  s     ))+++-	hX
  8C=!C	#$77JVr   c           	        U R                  5       nUR                  5       nSR                  [        US   [        [        [        US   [        /5      n[        US   5      [        US   5      -  n[        U5      n[        XF5      $ )z
|, produces a union

>>> a = sieve.Sieve('3@11')
>>> b = sieve.Sieve('2&4&8|5')
>>> d = a | b
>>> str(d)
'{2@0&4@0&8@0|5@0}|{3@2}'
rE  rw  r   )rz  r.  r`  ra  ORr  rf   rB  r  s          r   r
  Sieve.__or__  s     ))+++-	hX
  8C=!C	#$77JVr   c           	        U R                  5       nUR                  5       nSR                  [        US   [        [        [        US   [        /5      n[        US   5      [        US   5      -  n[        U5      n[        XF5      $ )z$
^, produces exclusive disjunction.
rE  rw  r   )rz  r.  r`  ra  rb  r  rf   rB  r  s          r   __xor__Sieve.__xor__  s     ))+++-	hX
  8C=!C	#$77JVr   c                   Sn[         R                  " U5      (       a  [        U5      SSS.$ UR                  5       nU(       d  gUR	                  S5      (       a  UR                  SS5      nUR	                  S5      (       a  UR                  SS5      nUR                  [        S5      nUR                  [        S5      nUS   S:X  a  S	nUS	S R                  5       nOSnU(       d  g [        U5      nSn[         R                  " U5      (       a  [        U5      nSnO7[         R                  " U5      (       a  US   n[        U5      S	:  a  US	   nOSnUUUS
.$ ! [        [        [        4 a     gf = f)a1  
process an arg string for proper Residual creation
valid syntax for Mod, shift pairs:
all valid: MsubN, M@N, M,N, M
if M is given alone, shift is assumed to be 0
this method assumes that all brackets have been replaced with parentheses
returns a dictionary of args suitable for creating a Residual class
r   )rY   rX   r   Nr3  ,r-   rE  r,   r0   )rY   r   r   )r   rd   r   r   findreplacer`  ra  r   	NameErrorSyntaxErrorre  rG  ru   )r   rS  rY   r   argsr   s         r   _parseResidualSieve._parseResidual  sb    <<V1Q77;;u^^E3/F;;s^^C-F ++ !9CABZ%%'FC	  'D <<D	AEt$$QA4y1}Q 	 ;	2 		s   +E E65E6c                   [         R                  " U5      (       a  [        U5      nU S3nUR                  S5      S:  a  UR	                  S[
        5      nUR                  S5      S:  a  UR	                  S[
        5      nUR                  S5      S:  a  UR	                  S[        5      nUR                  S5      S:  a  UR	                  S[        5      nUR                  S5      S:  a  UR	                  S[        5      nUR                  S	5      S:  a  UR	                  S	[        5      nUR                  S
5      S:  a  UR	                  S
[        5      nUR                  S5      S:  a  UR	                  S[        5      nUR                  S5      S:  a  UR	                  S[        5      nUR                  S5      S:  a  UR	                  S[        5      nUR	                  SS5      nU$ )a  
provide synonyms for logical symbols
intersection == and, &, *
union        == or, |, +
not          == not, -
the native format for str representation uses only &, |, -
this method converts all other string representations

all brackets and braces are replaced with parenthesis
parentheses are only used for the internal representation
on string representation, braces are restored
z@0andr   *or+xorr+   not[](r    rE  )
r   rd   r   r  r  r  r  r_  r`  ra  )r   rS  s     r   _parseLogicSieve._parseLogic!  s    <<[Fxr]F;;u"^^E3/F;;sq ^^C-F;;t!^^D"-F;;sq ^^C,F;;u"^^C,F;;u"^^E3/F;;sq ^^C0F;;sq ^^C0F;;sq ^^C0F;;sq ^^C0FR(r   c                Z    [        U5      n[        U5      R                  SS5      nSU S3$ )z6
return string necessary to instantiate a set object.
r  rE  zset(r   )rf   reprr  )r   valLists     r   _setInstantiateStrSieve._setInstantiateStrM  s2     w-w-''R0gYa  r   c                    SU S3$ )Nz<R>r   )r   resIds     r   rx  Sieve._resKeyStrU  s    E7!}r   c                "   US;  a  [        S5      eUS:X  a9  / nU R                   H%  nX0R                  ;   d  M  UR                  U5        M'     U$ US:X  a9  / nU R                   H%  nX0R                  ;   d  M  UR                  U5        M'     U$ g)z%
get residual keys based on library.
)ri  rD  zstate must be 'cmp' or 'exp'ri  rD  N)r   rK  rO  ri   rM  )r   statelibKeyskeys       r   _resKeysSieve._resKeysX  s     & !?@@E>G||--'NN3' $ Ne^G||--'NN3' $ N r   c                    / nU R                  U5       H8  nU R                  U   R                  5       nXB;  d  M'  UR                  U5        M:     UR	                  5         U$ )z
For all residual classes, get the period, or the value of M,
and return these in a list. Remove any redundant values and sort.
)r  rK  r   ri   re   )r   r  mListr  r5   s        r   rj  Sieve._resPeriodListk  sS    
 =='CS!((*A~Q ( 	

r   c                2   U R                  SR                  U5      5      nUc&  SR                  U5      nSU 3n[        SU< S35      e[        US   US   US   U R                  5      nX`R
                  U R                  U5      '   U R                  U5      $ )zz
create a residual object, store in expResidualLib
return a string id representation
this uses self._z at initialization.
rE  zcannot parse zbad residual class notation: (r   rY   r   r   )r  r.  r   r   r   rK  rx  )r   r  r/  resDictjoinedmsgr0  s          r   
_resCreateSieve._resCreatex  s     %%bggfo6?WWV_F!&*C #A#!JKK'#,(8!%.$''3 06T__U+,u%%r   c                ^    X R                   U R                  U5      '   U R                  U5      $ r   )rK  rx  )r   r  r0  s      r   
_resAssignSieve._resAssign  s&    /5T__U+,u%%r   c                    Uc  U R                   n[        R                  " U5      (       d  Ub  [        SU< 35      eU R                  U   " X#5      nU R                  U5      $ )zu
this is where residuals are converted to set evaluating strings
z should not be stored; should be a temporary value
z"z must be a list of integers, not )r   r   rG  r   rK  r  )r   r  rX   r   r  s        r   _resToSetStrSieve._resToSetStr  s^    
 9A  ## #EaU!KLL,,u%a+&&w//r   c                ,    U R                   S-   U l         g)z
increment the _resId.
r0   N)rL  r   s    r   _resIdIncrementSieve._resIdIncrement  s     kkAor   c                6   [        [        U R                  R                  5       5      5      nU H?  nU R	                  U5      nX0R
                  ;  d  M%  X0R                  ;  d  M6  [        S5      e   [        U R                  R                  5       5      U l        g)z
reset self._resId to the next available number
may need to re-label some residual classes if gaps develop
ids should be contiguous integer sequence
zgap in residual keysN)	rT   ru   rK  keysrx  rO  rM  r   rL  )r   iValsr^   testKeys       r   _resResetIdSieve._resResetId  sr     c$,,++-./Aooa(Gmm+}}0L$%;<< 
 $,,++-.r   c                    Uc  0 U l         SU l        g US:X  a8  U R                  U5      nU H  nU R                   U	 M     U R                  5         g US:X  a  [	        S5      eg )Nr   ri  rD  z1Expanded residual classes should never be cleared)rK  rL  r  r  r   )r   r  cmpKeysr  s       r   rV  Sieve._resClear  sf    =DLDKe^mmE*GLL%  e^ !TUU r   c                j   / U l         [        XR                  5      nU R                  c  UR                  U l        U" 5       nU HH  nU R                   R                  U R	                  U R
                  U5      5        U R                  5         MJ     [        R                  U R                   5      U l         g)z%
load from a segments
reload _resId.
N)	rM  r  r   ri   r  rL  r  r  r.  )r   usrDatasegObjunionr0  s        r   rW  Sieve._initLoadSegment  s     #GWW577?iiDGFMM  f!EF  "  .r   c                P   0 U l         SU l        / U l        U R                  [        R
                  " U R                  5      5      nSn U[        U5      :X  a  GOX#   nUS:X  a  SnOX#S-
     nU[        U5      S-
  :X  a  SnOX#S-      nU[        ;   a"  U R                  R                  U5        US-   nGOU[        :X  a  Uc  Sn[        SU S35      eU[        :X  a  Ub  U[        ;   a  Sn[        SU S35      eU[        :X  a]  UbZ  U[        :X  aP  Ub+  U[        [        [        [         4;  a  S	n[        S
U S35      eU R                  R                  U5        US-  nGOU["        R$                  ;   d
  U[        :X  a  / n[        R                  " U5      n	Sn
X)U
-      [        :X  a  UR                  [        5        U
S-   n
 X-   [        U5      :X  a  O4X)U
-      nU[        ;   d
  U[        :X  a  OUR                  U5        U
S-   n
MF  U R                  R                  U R'                  U R                  SR)                  U5      5      5        U R+                  5         X:-   nOUS-   nGM#  U R                   (       d  [        S5      eSR)                  U R                  5      U l        g)zF
process usrStr string into proper argument dictionaries for Residual
r   r0   Nz(negation cannot be used without operandsz"badly formed logical string (a): (r   z,negation cannot be used as a binary operatorz"badly formed logical string (b): (z6negation must be of a group and isolated by delimitersz"badly formed logical string (c): (rE  zno residual classes defined)rK  rL  rM  r  rg   rh   rQ  ru   BOUNDSri   r_  r   RESIDUALr`  r  r  rb  stringdigitsr  r.  r  )r   r   rw  r^   charcharPreviouscharNextr  r/  subStartsubLensubChars               r   rY  Sieve._initParse  s   
 !!$--"=>CK9DAv#%!e}CK!O#!a%= v~$$T*E !1@$'I#a%PQQ#+"."h.D$'I#a%PQQ #+*&( !,(b#0FFRC(+McURS)TUU$$T*Q
 &$#+99Q<V+,3MM#&#aZF )c&k9$%67G&(GsNg.!'!  $$T__T[["''&/%RS$$&JEO R || !>??.r   c                   / U l         [        R                  " U R                  5      nUR                  [        5      nSnU H  nUS:X  a  M  UR                  [
        5      n[        U5      S:X  a  U R                  US      nOP[        [        U5      S-
  5       H5  nUS:X  a  U R                  XV      nOUnU R                  XVS-         nXx-  nM7     U R                   R                  U R                  U R                  U5      5        U R                  5         M     [        R                  U R                   5      U l         g)z)
an unbound sieve, intersection Residual
r   rE  r0   N)rO  rg   rM  splitr  r  ru   rK  rT   ri   r  rL  r  r.  )	r   rw  orListr^  orGroupandListr^   r   r   s	            r   r  Sieve._cmpIntersection+  s    4==)b!G"}mmC(G7|q #||GAJ7s7|a/0AAv LL4(WU^4A#$5L 1 MM  l!KL  ") * .r   c                p   / U l         U R                  S5      nU(       d  [        S5      e[        XR                  5      nU" 5        HH  nU R                   R                  U R                  U R                  U5      5        U R                  5         MJ     [        R                  U R                   5      U l         g)z,
a bound sieve, uss a newly created segment
rD  z/empty segment; segment compression not possibleN)rO  r   rd  r  r   ri   r  rL  r  r  r.  )r   r   r  r0  s       r   rc  Sieve._cmpSegmentK  s    
 ll5!NOO#C1hFMM  f!EF  "  .r   c           	        Uc  U R                   nUc  U R                  nUc  U R                  nUS:X  a!  [        R                  " U R                  5      nO)US:X  a!  [        R                  " U R
                  5      nOSnU R                  U5      n[        SSSU5      nU R                  U" 5       5      nUR                  SUS-   5      nU H$  n	UR                  XR                  XU5      5      nM&     UR                  [        S5      nUR                  [        S	5      n [        US
S[        000 5      n
[#        U
5      n
U
R%                  5         US;   a  ['        X5      $ US:X  a  [)        X5      $ US;   a=  / n[+        [-        U
5      S-
  5       H  nUR/                  XS-      X   -
  5        M      U$ U
$ ! [         a  n[!        SU S	35      UeSnAff = f)aR  
Return a sieve segment in various formats.

>>> a = sieve.Sieve('3@11')
>>> a.segment('exp')
[2, 5, 8, 11, 14, 17, 20, 23, 26, 29, 32, 35, 38, 41, 44, 47,
 50, 53, 56, 59, 62, 65, 68, 71, 74, 77, 80, 83, 86, 89, 92, 95, 98]

>>> c = sieve.Sieve('(5|2)&4&8')
>>> c.segment('cmp', segmentFormat='wid')
[8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8]
NrD  ri  rE  r0   r   r,   r  r   __builtins__r  zbadly formed logical string (r   rz   r   )rH  r   r   rg   rM  rO  r  r   r  r  r  r`  ra  evalr  r  r   rf   re   rq   r}   rT   ru   ri   )r   r  rX   r   r   evalStrr  r0  setStrr  r   ser   r^   s                 r   r   Sieve.segment^  s   & =KKE9A  //ME>ii.Ge^ii.GG}}U# !Q1%((2//#v|4Cooc+<+<SQ+GHG  //&#.//&#.		 w% >CC 3i
--$S,,f$ ((..C3s8a<(

CAJ/1 )JJ#  	 /y:	s   F6 6
G GGc                    U R                   nU R                  S:X  a  U R                  5         US:X  a  U R                  $ US:X  a  U R                  $ [	        S5      e)z
Return the period of the sieve.

>>> a = sieve.Sieve('3@11')
>>> a.period()
3
>>> b = sieve.Sieve('2&4&8|5')
>>> b.period()
40
>>> c = sieve.Sieve('(5|2)&4&8')
>>> c.period()
40

* Changed in v9: state is taken from the object.
rc   rD  ri  zState must be exp or cmp)rH  rN  rn  rP  
ValueError)r   r  s     r   r   Sieve.period  sS    ( ??b E>??"e^??"788r   c                <    U R                  U R                  XU5      $ r   )r   rH  r   s       r   r   Sieve.__call__  s    ||DKK}==r   c           
        / nUnSnUS:  a  Un	Xu-   n
US;   a1  U R                  U R                  U[        [        X5      5      U5      nO0U R                  U R                  U[        [        X5      5      S5      nXkSS -   nXu-   nUS-   n[	        U5      U:  a  OUS:  a  M  USU n[	        U5      U:w  a  [        S5      eUS:X  a  [        U[        US   US	   S-   5      5      $ US
;   a  [        U[        US   US	   S-   5      5      $ U$ )z
Collect sieve segment points for the provided length and format.

>>> a = sieve.Sieve('3@11')
>>> a.collect(10, 100, 10, 'int')
[102, 105, 108, 111, 114, 117, 120, 123, 126, 129]
r   r   r   r   Nr0   z/desired length of sieve segment cannot be foundrz   rc   r   )r   rH  rf   rT   ru   r   r}   rq   )r   rX   zMinimumr   r   zStepfoundr5   zExtendCountr&  r'  segmentPartialr   s                r   collectSieve.collect  s6   * U"D9D  00!%dkk1.253D.E}"V "&dkk1.253D.Eu"N 1--E	A'!+L5zV## U"( GVns8v !RSS F" eCFCGaK&@AA//$S%AB!*DEEJr   c                R   Uc  U R                   nUS:X  a!  [        R                  " U R                  5      nO)US:X  a!  [        R                  " U R                  5      nOSnU R	                  U5      nU H0  nUR                  XPR                  U   R                  U5      5      nM2     U$ )zz
style of None is use for users; adds | to single residuals
style abs (absolute) does not add | tos single residual class
rD  ri  rE  )rH  rg   rM  rO  r  r  rK  r   )r   r  r   r  r  r  s         r   r   Sieve.represent  s    
 =KKEE>))DMM*Ce^))DMM*CC }}U#C++c<<#4#>#>u#EFC 
r   c                "    U R                  5       $ r   r   r   s    r   r   Sieve.__str__  s    ~~r   )rP  rO  rN  rM  rI  rJ  rL  rK  r   r   rH  rQ  r   r   )rS  zstr | list[str]r   zlist[int] | None)r  	list[int])r   N)Nr   NN)r  z*t.Literal['cmp'] | t.Literal['exp'] | Noner  r  r  r  )rQ   )rX   r   r  r   r   r   r   r-  r  r   r  r  )NN)*r   r   r   r   r  r   rR  rX  rn  rq  rt  rz  r   r   r   r  r  r
  r  r  r  r  rx  r  rj  r  r  r  r  r  rV  rW  rY  r  rc  r   r   r   r  r   r   r   r   r   r   rB  rB    s%   8	$>-   2"  6 6 .;z)X!&&"&0&/V /$V/v/@/* 9=

K5K 
KZ9>> 99 9 	9
 9 9 
9v* r   rB  c                  L    \ rS rSrSr    S       S	S jjrS rS
S jrSrg)
PitchSievei$  aP  
Quick utility generator of :class:`music21.pitch.Pitch` lists
from :class:`music21.sieve.Sieve` objects.

>>> ps = sieve.PitchSieve('6@0', 'c4', 'c8')
>>> [str(p) for p in ps()]
['C4', 'F#4', 'C5', 'F#5', 'C6', 'F#6', 'C7', 'F#7', 'C8']

>>> a = sieve.PitchSieve('4@7')
>>> [str(p) for p in a()]
['E-3', 'G3', 'B3', 'E-4', 'G4', 'B4']
Nc                   Xl         [        U R                   5      U l        Ub  [        R                  " U5      U l        O[        R                  " S5      U l        Ub  [        R                  " U5      U l        O[        R                  " S5      U l        Ub  [        R                  " U5      U l        O%[        R                  " U R
                  5      U l        Ub  [        U5      U l        g XPl        g )Nc3c5)sieveStringrB  sieveObjectr   Pitch
pitchLower
pitchUpperpitchOriginrg   rh   rv   eld)r   r  r
  r  r  r  s         r   r   PitchSieve.__init__2  s     ' #((8(8"9!#kk*5DO#kk$/DO!#kk*5DO#kk$/DO"${{;7D#}}T__=D?SzDHHr   c           	        U R                   R                  nU R                  R                  n[        [	        [        U5      [        US-   5      5      5      nU R                  R                  nU R                  S:X  aJ  U R                  XC5      n/ nU H/  n[        R                  " 5       nXxl        UR                  U5        M1     U$ [        U R                  XSS9n	[        [	        [        U	5      5      5      nU R                  XCS5      n
/ n[	        [        U
5      5       H<  nX   S:X  d  M  [        R                  " 5       nX   Ul        UR                  U5        M>     U$ )a  
Return a sieve segment as a list of :class:`music21.pitch.Pitch` objects,
mapped to the range between pitchLower and pitchUpper.

>>> a = sieve.PitchSieve('4@7&5@4')
>>> a()
[<music21.pitch.Pitch G4>]

>>> a = sieve.PitchSieve('13@3|13@6|13@9', 'c1', 'c10')
>>> ', '.join([str(p) for p in a()])
'E-1, F#1, A1, E2, G2, B-2, F3, G#3, B3, F#4, A4, C5, G5, B-5, C#6, G#6, B6,
 D7, A7, C8, E-8, B-8, C#9, E9, B9'

>>> a = sieve.PitchSieve('3@0', 'c4', 'c5', 'c4', 0.5)
>>> a.eld
0.5

The following is a microtonal pitch sieve; presently these are not
displayed; true values are
[0, 1.5, 3.0, 4.5, 6.0, 7.5, 9.0, 10.5, 12.0]

>>> pitches = a()
>>> ', '.join([str(p) for p in pitches])
'C4, C#~4, E-4, E~4, F#4, G~4, A4, B`4, C5'

True values: [0.5, 2.0, 3.5, 5.0, 6.5, 8.0, 9.5, 11.0]

>>> a = sieve.PitchSieve('3@0', 'c4', 'c5', 'c#4', 0.5)
>>> pitches = a()
>>> ', '.join([str(p) for p in pitches])
'C~4, D4, E`4, F4, F#~4, G#4, A~4, B4'
r0   F)r   r   )r
  psr  rf   rT   r   r  r  r  r   r	  ri   r   ru   )r   minPSmaxPSr   rX   sieveSegIntegerssieveSegpsNumr5   r  binSegr^   s               r   r   PitchSieve.__call__R  s$   D """"s5z3uqy>23 88q=#//5H)KKM" *&  #488UeLG U3w<()A%%aE2FH3v;'9>A":ADOOA&	 (
 r   c                R   U R                   R                  5       nUS:  a  [        [        US-   5      5      nOSnU R                  SUSS9n/ n[	        U5       H8  u  pV[
        R                  " X`R                  -  5      nUR                  U5        M:     U(       d  [        S5      eU$ )a  
Return a list of Interval objects that defines the complete structure
of this :class:`music21.sieve.Sieve`.

>>> a = sieve.PitchSieve('3@0')
>>> a.getIntervalSequence()
[<music21.interval.Interval m3>]

>>> a = sieve.PitchSieve('3@0|7@0')
>>> a.sieveObject.segment()
[0, 3, 6, 7, 9, 12, 14, 15, 18, 21, 24, 27, 28, 30, 33, 35, 36, 39, 42, 45, 48, 49,
 51, 54, 56, 57, 60, 63, 66, 69, 70, 72, 75, 77, 78, 81, 84, 87, 90, 91, 93, 96, 98, 99]
>>> a.sieveObject.period()
21
>>> a.getIntervalSequence()
[<music21.interval.Interval m3>, <music21.interval.Interval m3>,
 <music21.interval.Interval m2>, <music21.interval.Interval M2>,
 <music21.interval.Interval m3>, <music21.interval.Interval M2>,
 <music21.interval.Interval m2>, <music21.interval.Interval m3>,
 <music21.interval.Interval m3>]

This is the PitchSieve for a major scale:

>>> b = sieve.PitchSieve('(-3@2 & 4) | (-3@1 & 4@1) | (3@2 & 4@2) | (-3 & 4@3)')
>>> b.getIntervalSequence()
[<music21.interval.Interval M2>,
 <music21.interval.Interval M2>,
 <music21.interval.Interval m2>,
 <music21.interval.Interval M2>,
 <music21.interval.Interval M2>,
 <music21.interval.Interval M2>,
 <music21.interval.Interval m2>]
iɚ;r0   Nr   r   )r   zinterval segment has no values)
r  r   rf   rT   	enumerater   Intervalr  ri   r%   )r   r5   r   widthSegmentspostr^   r   intervalObjs           r   getIntervalSequencePitchSieve.getIntervalSequence  s    P ##% y=U1q5\"AA ((AU(C(*!-0HA"++EHH,<=KKK$ 1
 %&FGGr   )r  r
  r  r  r  r  )NNNr0   )r
  
str | Noner  r   r  r   r  zint | float)r  zlist[interval.Interval])	r   r   r   r   r  r   r   r  r   r   r   r   r  r  $  sL     )-(,)-"#% & '	
  @>@=r   r  c                  J    \ rS rSrS rS rS rS rS rS r	S r
S	 rS
 rSrg)Testi  c                (    U R                  SS5        g )NT)assertEqualr   s    r   	testDummyTest.testDummy  s    t$r   c                j    SnU H  nU[        U5      S-   -  nM     US[        U5      S-
   nUS-  nU$ )Nr  z, r   r/   r  )r-  ru   )r   listInoutr5   s       r   pitchOutTest.pitchOut  sE    A3q6D= C !CHqL!s

r   c                n    [        S5      n/ SQnU H   u  p4pV[        X55      n[        XF5      nX-  nM"     g )Nr9   ))r9   r:   r/   r;   )r   r:   r0   r9   )r;   r   r9   r/   )r   )	r   r   testArgsr  r  r  r  r   r^   s	            r   testIntersectionTest.testIntersection  s9    QK?&NBB A AA 'r   c           	     j    / SQnU H)  n[        U5      nU" S[        [        S5      5      5      nM+     g )N)z-5 | 4 & 4sub3 & 6 | 4 & 4z2 or 4 and 4 & 6 or 4 & 4r9   )r/   r   r:      )r0   r:   r=      r?   r      )rB  rf   rT   )r   r-  argtestObjdummys        r   testSieveParseTest.testSieveParse  s2     CCjGAtE"I/E r   c                r    [        SSS5      n[        S5      nUR                  UR                  4nU" 5       ng )Nz-5 | 4 & 4sub3 & 6b3zf#4)r  r
  r  )r   unused_testObjr5  r6  s       r   testSievePitchTest.testSievePitch  s9    #$8$F12""G$6$66	r   c                j    / SQnU H)  n[        U5      n[        [        U5      5      nU" 5       nM+     g )N))r9   r:      )	r   r:   r?           r3  $   *   )r   r:   r>   )r/   r9   r   r;   r1  	   rR   r=      r?   r@      rA   rB     rB   rC   )r   r/   r   r;   r<   rE  r=   r?  rF  r2  r?   r@      rA   rB  )
r0   r/   r9   r   r;   r:   r<   r1  rE  rR   )iir   r/   r0   )r  rB  r-  )r   r  r!  r:  sObjr6  s         r   testTimePointTest.testTimePoint  s3     C$S)CS?DFE r   c                   [        [        S5      5      nSn[        X!5      nU R                  [	        U5      S5        Sn[        X!5      nU R                  [	        U5      S5        Sn[        X!5      nU R                  [	        U5      S5        Sn[        X!5      nU R                  [	        U5      S	5        S
n[        X!5      nU R                  [	        U5      S5        g )NrQ   z"3@2 & 4@1 | 2@0 & 3@1 | 3@3 | -4@2z3@2&4@1|2@0&3@1|3@0|-4@2z5-(3@2 & -4@1 & -(12@3 | 12@8) | (-2@0 & 3@1 | (3@3)))z)-{3@2&-4@1&-{12@3|12@8}|{-2@0&3@1|{3@0}}}z[(8@0 | 8@1 | 8@7) & (5@1 | 5@3)] |   [(8@0 | 8@1 | 8@2) & 5@0] | [8@3 & (5@0 | 5@1 | 5@2 | 5@3 | 5@4)] | [8@4 & (5@0 | 5@1 | 5@2 | 5@3 | 5@4)] | [(8@5 | 8@6) & (5@2 | 5@3 | 5@4)] | (8@1 & 5@2) | (8@6 & 5@1)z{{8@0|8@1|8@7}&{5@1|5@3}}|{{8@0|8@1|8@2}&5@0}|{8@3&{5@0|5@1|5@2|5@3|5@4}}|{8@4&{5@0|5@1|5@2|5@3|5@4}}|{{8@5|8@6}&{5@2|5@3|5@4}}|{8@1&5@2}|{8@6&5@1}z4(-3@2 & 4) | (-3@1 & 4@1) | (3@2 & 4@2) | (-3 & 4@3)z*{-3@2&4@0}|{-3@1&4@1}|{3@2&4@2}|{-3@0&4@3}zV(-(13@3 | 13@5 | 13@7 | 13@9) & 11@2) | (-(11@4 | 11@8) & 13@9) | (13@0 | 13@1 | 13@6)zB{-{13@3|13@5|13@7|13@9}&11@2}|{-{11@4|11@8}&13@9}|{13@0|13@1|13@6})rf   rT   rB  r$  r-  )r   r   rS  r   s       r   	testSieveTest.testSieve  s    s5&Q!;<H&Q!LMR &QI	J H&Q!MN)&Q]	_r   c                    SSK Jn  UR                  SSS5      nU R                  U R	                  U" 5       5      S5        UR                  SSSSS9nU R                  U R	                  U" 5       5      S	5        g )
Nr   r   z3@0|7@0r   c6z\[C2, E-2, F#2, G2, A2, C3, D3, E-3, F#3, A3, C4, E-4, E4, F#4, A4, B4, C5, E-5, F#5, A5, C6]r/   r  z5[C2, D2, F#2, C3, E3, F#3, C4, F#4, C5, F#5, G#5, C6]music21r   r  r$  r*  r   r   s1s      r   testPitchSieveATest.testPitchSieveA=  su    !it4rt,B	C it;rt,P	Rr   c                    SSK Jn  UR                  SSSSS9nU R                  U R	                  U" 5       5      S5        UR                  S	SSSS9nU R                  U R	                  U" 5       5      S
5        g )Nr   rS  z1@0r   rT  g      ?rU  a  [C2, C~2, C#2, C#~2, D2, D~2, E-2, E`2, E2, E~2, F2, F~2, F#2, F#~2, G2, G~2, G#2, G#~2, A2, A~2, B-2, B`2, B2, B~2, C3, C~3, C#3, C#~3, D3, D~3, E-3, E`3, E3, E~3, F3, F~3, F#3, F#~3, G3, G~3, G#3, G#~3, A3, A~3, B-3, B`3, B3, B~3, C4, C~4, C#4, C#~4, D4, D~4, E-4, E`4, E4, E~4, F4, F~4, F#4, F#~4, G4, G~4, G#4, G#~4, A4, A~4, B-4, B`4, B4, B~4, C5, C~5, C#5, C#~5, D5, D~5, E-5, E`5, E5, E~5, F5, F~5, F#5, F#~5, G5, G~5, G#5, G#~5, A5, A~5, B-5, B`5, B5, B~5, C6]z3@0z[C2, C#~2, E-2, E~2, F#2, G~2, A2, B`2, C3, C#~3, E-3, E~3, F#3, G~3, A3, B`3, C4, C#~4, E-4, E~4, F#4, G~4, A4, B`4, C5, C#~5, E-5, E~5, F#5, G~5, A5, B`5, C6]rV  rX  s      r   testPitchSieveBTest.testPitchSieveBI  s}    ! eT4S9rt,Z	[ eT4S9rt,-	.r   r   N)r   r   r   r   r%  r*  r.  r7  r<  rM  rP  rZ  r]  r   r   r   r   r"  r"    s2    %0_B
R.r   r"  z
list[type]
_DOC_ORDER__main__)r/   r   )rj   zIterable[int]r  r  )r   r0   T):r  
__future__r   astr   collections.abcr   rg   mathr   r   rV   r  typingtunittestrW  r   r	   r
   r   r   EnvironmentenvironLocalMusic21Exceptionr   r   r   r"   r%   r`  ra  r  r  rb  r  r_  rf   r  r  r7   ra   rq   r}   r   r   r   r   r   r  rB  r  TestCaser"  r_  __annotations__r   mainTestr   r   r   <module>rn     s  +X #  $            &&w/	L11 		55 		\22 		,"?"? 		,77 	 
			
&#r3	'	#&=@?L$N*Z4/n4X XxT TpS S~r  r pk kBv.8 v.| 
J zT r   