
    rh4                        S r SSKJr  SSKJr  SSKJr  Sr " S S5      r  SS	 jr	S
 r
\S:X  a  SSKr\R                  " 5         gg)z
This module takes two XML files and displays the number of measures that
differ between the two before and after running the combined correction models
    )annotations)
correctors)	converterFc                      \ rS rSrSrSS jr\S 5       r\R                  S 5       rS r	S r
S	 rS
 rS rS rS rS rS rSrg)OmrGroundTruthPair   z
Object for making comparisons between an OMR score and the GroundTruth

Takes in a path to the OMR and a path to the groundTruth
(or a pair of music21.stream.Score objects).

See below for examples.

Nc                L   S U l         S U l        [        US5      (       a  UR                  U l        Xl        OXl        S U l        U R                  5       U l        [        US5      (       a  UR                  U l        X l	        OX l        S U l	        U R                  5       U l        g )NfilePath)_overriddenDebugnumberOfDifferenceshasattrr
   omrPathomrM21ScoregetOmrScoreomrScore
groundPathgroundM21ScoregetGroundScoregroundScore)selfomrgrounds      P/home/james-whalen/.local/lib/python3.13/site-packages/music21/omr/evaluators.py__init__OmrGroundTruthPair.__init__)   s     $#' 3
##<<DL"L#D((*6:&&$ooDO"($O"&D..0    c                @    U R                   c  [        $ U R                   $ )zG
Returns either the debug value set for this
evaluator, or globalDebug
)r   globalDebugr   s    r   debugOmrGroundTruthPair.debug>   s"       ((((r   c                    Xl         g )N)r   )r   newDebugs     r   r    r!   I   s     (r   c                X    U R                  5       U l        U R                  5       U l        g)z
Parse both scores.
N)r   r   r   r   r   s    r   parseAllOmrGroundTruthPair.parseAllM   s%     ((*..0r   c                l    U R                   R                  5         U R                  R                  5         g)z#
store the Hashes for both scores.
N)r   getAllHashesr   r   s    r   hashAllOmrGroundTruthPair.hashAllT   s&     	""$%%'r   c                    U R                   (       a  [        S5        U R                  (       d%  [        R                  " U R
                  5      U l        [        R                  " U R                  5      $ )af  
Returns a ScoreCorrector object of the OMR score. does not store it anywhere

 >>> omrPath = omr.correctors.K525omrShortPath
 >>> ground = omr.correctors.K525groundTruthShortPath
 >>> omrGTP = omr.evaluators.OmrGroundTruthPair(omr=omrPath, ground=ground)
 >>> ssOMR = omrGTP.getOmrScore()
 >>> ssOMR
 <music21.omr.correctors.ScoreCorrector object at 0x...>
zparsing OMR score)r    printr   r   parser   r   ScoreCorrectorr   s    r   r   OmrGroundTruthPair.getOmrScore[   sI     ::%&(t||<D(()9)9::r   c                    U R                   (       a  [        S5        U R                  (       d%  [        R                  " U R
                  5      U l        [        R                  " U R                  5      $ )aT  
Returns a ScoreCorrector object of the Ground truth score

 >>> omrPath = omr.correctors.K525omrShortPath
 >>> ground = omr.correctors.K525groundTruthShortPath
 >>> omrGTP = omr.evaluators.OmrGroundTruthPair(omr=omrPath, ground=ground)
 >>> ssGT = omrGTP.getGroundScore()
 >>> ssGT
 <music21.omr.correctors.ScoreCorrector object at 0x...>
zparsing Ground Truth score)r    r,   r   r   r-   r   r   r.   r   s    r   r   !OmrGroundTruthPair.getGroundScoren   sI     ::./"""+//$//"BD(()<)<==r   c                    X:X  a  gg)zL
define the substitution cost for x and y (2 if x and y are unequal else 0)
r       )r   xys      r   	substCostOmrGroundTruthPair.substCost   s     6r   c                    g)z+
define the insertion cost for x and y (1)
   r4   r   r5   s     r   
insertCostOmrGroundTruthPair.insertCost        r   c                    g)z*
define the deletion cost for x and y (1)
r:   r4   r;   s     r   
deleteCostOmrGroundTruthPair.deleteCost   r>   r   c                   [        U5      n[        U5      n[        US-   5       VVs/ s H"  n[        US-   5       Vs/ s H  nSPM     snPM$     nnn[        SUS-   5       H)  nXvS-
     S   U R                  XS-
     5      -   Xv   S'   M+     [        SUS-   5       H+  nUS   US-
     U R                  X%S-
     5      -   US   U'   M-     [        SUS-   5       Hi  n[        SUS-   5       HS  n[	        XvS-
     U   S-   Xv   US-
     S-   XvS-
     US-
     U R                  X%S-
     XS-
     5      -   5      Xv   U'   MU     Mk     Xs   U   $ s  snf s  snnf )zC
Computes the min edit distance from target to source. Figure 3.25
r:   r   )lenranger<   r@   minr7   )r   targetsourcenmjidistances           r   minEditDistOmrGroundTruthPair.minEditDist   st    KK7<QU|D|!a!e-1Q-|Dq!a%A%!e_Q/$//&Q-2PPHKN ! q!a%A%a[Q/$//&Q-2PPHQKN ! q!a%A1a!e_!$X!e_Q%7!%;%-[Q%7!%;%-!e_QU%;*...ASTu*V&W"XA % ! {1~ .Ds   EE
EEc                "   SU l         U R                  R                  5       nU R                  R                  5       n[	        [        U5      5       H1  nX   nX#   nU R                  XE5      nU =R                   U-  sl         M3     U R                   $ )ar  
Returns the total edit distance as an Int between
the two scores

This function is based on James H. Martin's minimum edit distance.

>>> omrPath = omr.correctors.K525omrShortPath
>>> ground = omr.correctors.K525groundTruthShortPath
>>> omrGTP = omr.evaluators.OmrGroundTruthPair(omr=omrPath, ground=ground)
>>> differences = omrGTP.getDifferences()
>>> differences
32
r   )r   r   r(   r   rD   rC   rM   )r   omrListgtListpartNumomrPartgtPartmeasureErrorss          r   getDifferences!OmrGroundTruthPair.getDifferences   s     $% --,,.!!..0S\*G&G_F ,,W=M$$5$	 +
 '''r   )r   r   r   r   r   r   r   r   )NN)__name__
__module____qualname____firstlineno____doc__r   propertyr    setterr%   r)   r   r   r7   r<   r@   rM   rV   __static_attributes__r4   r   r   r   r      sf    1* ) ) \\) )1(;&>J.(r   r   Nc                (   Uc  [         nSn[        XS9nU(       a  [        S5        Uc  UR                  5       nOUnU(       a  [        SU5        UR                  nUn	U(       a  [        S5        / n
SnSnUSL af  U	R
                  U   nUR                  5       nU(       a/  [        SU5        [        S	U	R
                  U   R                  5        UR                  5         O[        [        U	R
                  5      5       Hv  nU	R
                  U   nUR                  5       nU[        U5      -  nUR                  5       nU
R                  U5        U[        U	R
                  U   R                  5      -  nMx     U(       a8  [        S
5        [        S5        [        SU
5        [        S5        [        S5        U	R                  5       nU(       a8  [        S
5        [        S5        [        SU5        [        S5        [        S5        U	R                  U
U5      nU(       a  [        S5        [        U5        UR                  5       nU(       a>  [        SU5        [        SU5        [        SU5        U	R                  R                  5         UUUUS.nU$ )aK  
Get a dictionary showing the efficacy of the omr.correctors.ScoreCorrector on an OMR Score
by comparing it to the GroundTruth.

Set debug to True to see a lot of intermediary steps.

>>> omrFilePath = omr.correctors.K525omrShortPath
>>> groundTruthFilePath = omr.correctors.K525groundTruthShortPath
>>> returnDict = omr.evaluators.evaluateCorrectingModel(omrFilePath, groundTruthFilePath)
>>> for name in sorted(list(returnDict.keys())):
...     (name, returnDict[name])
('newEditDistance', 20)
('numberOfFlaggedMeasures', 13)
('originalEditDistance', 32)
('totalNumberOfMeasures', 84)
r:   )r   r   zgetting differenceszOriginal edit distancez2Running Horizontal Model (Prior-based-on-distance)r   TzIncorrect measure indices:zHashed notes:z+for each entry in the array below, we have zt[flagged measure part, flagged measure index, source measure part, source measure index, source measure probability]zHORIZONTAL CORRECTING ARRAYz"**********************************z-Running Vertical Model (Prior-based-on-Parts)zVERTICAL CORRECTING MEASURESz]Finding best from Horizontal and Vertical and replacing flagged measures with source measuresz4done replacing flagged measures with source measuresznew edit distancez%number of flagged measures originallyztotal number of measures)originalEditDistancenewEditDistancenumberOfFlaggedMeasurestotalNumberOfMeasures)r   r   r,   rV   r   singlePartsgetIncorrectMeasureIndiceshashedNotesrunHorizontalCorrectionModelrD   rC   appendrunVerticalCorrectionModelgenerateCorrectedScorescoreshow)r   groundTruthPathr    originalDifferences
runOnePartpnomrGTPr   
myOmrScorescorrectingArrayHorAllPartnumberOfIncorrectMeasuresnumberOfTotalMeasures	scorePartincorrectMeasureIndicestempPNcorrectingArrayHorOnePartcorrectingArrayVertAllPart
priorScorenewNumberOfDifferences
returnDicts                        r   evaluateCorrectingModelr      sk   & }	
B  GDF#$"$3351&(;<JABC " !TMM"%	"+"F"F"H.0GH/1==#4#@#@A..0C./Ff-I&/&J&J&L#%-D)EE%(1(N(N(P%%,,-FG!Sv)>)J)J%KK! 0 ;< D 	E+-FG23=>!"!=!=!?;< E 	F,.HI23 0 	1))*CE_`JDEj#224!#9:57PQ(*?@	*=%;-F+@BJ
 r   c                   [         R                  " U 5      nUR                  5       nSnSnUR                  n[	        U5       H  u  pgXV   R                  5       n[	        U5       Hz  u  pX;   a  M  US-  nSn[	        U5       H  u  pX:X  a  M  X:X  d  M  Sn  O   USL a2  [        [        U5      5       H  nX:X  a  M
  X.   U	   nX:X  d  M  Sn  O   USL d  Mu  US-  nM|     M     X44$ )aW  
Essentially it's the ratio of amount of rhythmic similarity within a piece, which
gives an upper bound on what the omr.corrector.prior measure should be able to
achieve for the flagged measures. If a piece has low rhythmic similarity in general, then
there's no way for a correct match to be found within the unflagged measures in the piece.

Returns a tuple of the total number of NON-flagged measures and the total number
of those measures that have a rhythmic match.

Takes in a stream.Score.

>>> c = converter.parse(omr.correctors.K525omrShortPath)  # first 21 measures
>>> totalUnflagged, totalUnflaggedWithMatches = omr.evaluators.autoCorrelationBestMeasure(c)
>>> (totalUnflagged, totalUnflaggedWithMatches)
(71, 64)
>>> print( float(totalUnflaggedWithMatches) / totalUnflagged )
0.901...


Schoenberg has low autoCorrelation.

>>> c = corpus.parse('schoenberg/opus19/movement6')
>>> totalUnflagged, totalUnflaggedWithMatches = omr.evaluators.autoCorrelationBestMeasure(c)
>>> (totalUnflagged, totalUnflaggedWithMatches)
(18, 6)
>>> print( float(totalUnflaggedWithMatches) / totalUnflagged )
0.333...

r   r:   FT)r   r.   r(   re   	enumeraterf   rD   rC   )
inputScoress	allHashestotalMeasurestotalMatchesre   pNum
pHashArrayincorrectIndicesrK   mHashmatchrJ   nHash	otherPNum	otherHashs                   r   autoCorrelationBestMeasurer   >  s   < 
	"	":	.B!IML..K%i0&,GGI!*-HA$QME &j16> E 2 ~!&s;'7!8I (  ) 4Q 7I ) $ "9 }!5 . 1: ((r   __main__)NNF)r\   
__future__r   music21.omrr   music21r   r   r   r   r   rX   mainTestr4   r   r   <module>r      s^    # "  w( w(t =AAFcLC)L z r   