Functions from Cope's 1992 article in the Computer Music Journal, "Modeling of Musical Intelligence in EMI" translated into Python. Actual code is here.

```
motive_size = 2
variance = 1
```

Used by `allow-variation`

. `motive1`

and `motive2`

are lists of integers
representing directed pitch intervals.

Compares `motive1`

with original, inversion, retrograde, and retrograde
inversion of `motive2`

. If the absolute pairwise differences for any of
these four comparisons are all less than or equal to the `variance`

,
returns `True`

; otherwise, returns `False`

.

`def allow_var(motive1, motive2):`

```
min_length = min(len(motive1), len(motive2))
comparisons = [motive2, inversion(motive2), retrograde(motive2),
inversion(retrograde(motive2))]
for comparison in comparisons:
for i in range(min_length):
if abs(motive1[i] - comparison[i]) > variance:
break
else:
return True
return False
```

Returns the inversion of `motive`

.

`def inversion(motive):`

` return [-el for el in motive]`

Returns the retrograde of `motive`

.

`def retrograde(motive):`

` return motive[::-1]`

`motive`

is a list of integers representing directed pitch intervals.
`motive_list`

is a list of such motives.

For each `comparison`

in `motive_list`

, calls `all_var`

to see if
`comparison`

matches `motive`

. For successful matches, both `motive`

and `comparison`

are added to `signatures`

.

Returns `signatures`

, a list of successful matches.

`def allow_variation(motive, motive_list):`

```
signatures = []
for comparison in motive_list:
if allow_var(motive, comparison):
signatures.extend([motive, comparison])
return signatures
```

`def produce_intervals(work):`

` return [work[i] - work[i-1] for i in range(1, len(work))]`

`intervals`

is a list of integers. Returns a list of ngrams of `intervals`

,
where n = `size`

.

`def break_into_patterns(intervals, size):`

` return [intervals[i:i+size] for i in range(len(intervals)-size+1)]`

Matches patterns for `pattern_match`

. Steps through the motives in
`interval_lists1`

for comparisons with `interval_lists2`

by calling
`allow_variation`

.

`def match(interval_lists1, interval_lists2):`

```
signatures = []
for intervals in interval_lists1:
signatures.extend(allow_variation(intervals, interval_lists2))
return signatures
```

`work1`

and `work2`

are lists of integers representing sequences of pitches.

Matches the works under analysis after they have been reduced to
intervals and broken into motives the length of `motive_size`

.
The process used by `break_into_patterns`

is thorough in that it finds
every contiguous pattern of the length prescribed by `motive_size`

so
that, for example, `[1, 2, 3, -4, -5]`

becomes
`[[1, 2, 3], [2, 3, -4], [3, -4, -5]]`

. Note that using intervals at
this stage means that a `motive_size`

of two equates to three actual notes.

`def pattern_match(work1, work2):`

```
intervals1 = break_into_patterns(produce_intervals(work1), motive_size)
intervals2 = break_into_patterns(produce_intervals(work2), motive_size)
signatures = match(intervals1, intervals2)
return signatures
```

Example `motive`

and `motivelist`

```
motive = [4, 3]
motivelist = [[0, 0], [0, 0], [0, -4], [-4, -3], [-3, 0]]
print('motive:', motive)
print('motive list:', motivelist)
```

Signatures discovered between `motive`

and `motivelist`

using
`allow_varation`

```
print('motive in motive list?', allow_variation(motive, motivelist))
print()
```

Example works

```
work1 = [72, 76, 79, 71, 72, 74, 72]
work2 = [76, 76, 76, 76, 72, 69, 69, 68, 68, 74, 71]
print('work 1 pitches:', work1)
print('work 2 pitches:', work2)
```

Signatures derived from comparison of the two works

```
print('patterns in common:', pattern_match(work1, work2))
```