# CopeEMIFunctions.py

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))
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```

`work` is a list of integers representing pitches.

Returns a list of intervals.

`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))

```