# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
# Name:         chord.tables.py
# Purpose:      data and tables for chord and set class processing.
#
# Authors:      Christopher Ariza
#               Michael Scott Asato Cuthbert
#
# Copyright:    Copyright © 2001-11 Christopher Ariza
# Copyright:    Copyright © 2011-22 Michael Scott Asato Cuthbert
# License:      BSD, see license.txt
# ------------------------------------------------------------------------------
'''
This module stores numerous data lists used in deriving set-class values and other post-tonal
chord representations. All features of this module are made available through
:class:`~music21.chord.Chord` objects. Use of this module directly is thus not necessary.
'''

from __future__ import annotations

from collections import namedtuple
import unittest

from music21 import environment
from music21 import exceptions21

environLocal = environment.Environment('chord.tables')

ChordTableAddress = namedtuple('ChordTableAddress',
                               ['cardinality', 'forteClass', 'inversion', 'pcOriginal'])


# ------------------------------------------------------------------------------
class ChordTablesException(exceptions21.Music21Exception):
    pass


# ------------------------------------------------------------------------------
# TNI structures are defined as
# [0] = tuple of pitch classes (0-11)
# [1] = 6-tuple of interval class vector (ICV)
# [2] = 8-tuple of invariance vector (Robert Morris) -- see below
# [3] = index of Z-relation (0=none)
#
# The invariance vector can be used to determine symmetry.
#
# The first four entries in the invariance vector shows
# how many transpositions are invariant
# under Tn, TnI, TnM, TnMI respectively.
#
# Entries 5-8 (python 4-7) show how many map to their complements
# under Tn, TnI (inversion required), TnM, and TnMI respectively
# For index 2 (python [1]), a value of 1 or higher
# is symmetrical under inversion.

TNIStructure = tuple[
    tuple[int, ...],
    tuple[int, int, int, int, int, int],
    tuple[int, int, int, int, int, int, int, int],
    int,
]

# noinspection DuplicatedCode
t1: TNIStructure
t2: TNIStructure
t3: TNIStructure
t4: TNIStructure
t5: TNIStructure
t6: TNIStructure
t7: TNIStructure
t8: TNIStructure
t9: TNIStructure
t10: TNIStructure
t11: TNIStructure
t12: TNIStructure
t13: TNIStructure
t14: TNIStructure
t15: TNIStructure
t16: TNIStructure
t17: TNIStructure
t18: TNIStructure
t19: TNIStructure
t20: TNIStructure
t21: TNIStructure
t22: TNIStructure
t23: TNIStructure
t24: TNIStructure
t25: TNIStructure
# noinspection DuplicatedCode
t26: TNIStructure
t27: TNIStructure
t28: TNIStructure
t29: TNIStructure
t30: TNIStructure
t31: TNIStructure
t32: TNIStructure
t33: TNIStructure
t34: TNIStructure
t35: TNIStructure
t36: TNIStructure
t37: TNIStructure
t38: TNIStructure
t39: TNIStructure
t40: TNIStructure
t41: TNIStructure
t42: TNIStructure
t43: TNIStructure
t44: TNIStructure
t45: TNIStructure
t46: TNIStructure
t47: TNIStructure
t48: TNIStructure
t49: TNIStructure
t50: TNIStructure


t1   = ((0,), (0,0,0,0,0,0), (1,1,1,1,11,11,11,11), 0)  # 1-1
monad = (None, t1)

t1  = ((0,1), (1,0,0,0,0,0), (1,1,0,0,9,9,8,8),  0)  # 2-1
t2  = ((0,2), (0,1,0,0,0,0), (1,1,1,1,9,9,9,9),  0)  # 2-2
t3  = ((0,3), (0,0,1,0,0,0), (1,1,1,1,9,9,9,9),  0)  # 2-3
t4  = ((0,4), (0,0,0,1,0,0), (1,1,1,1,9,9,9,9),  0)  # 2-4
t5  = ((0,5), (0,0,0,0,1,0), (1,1,0,0,9,9,8,8),  0)  # 2-5
t6  = ((0,6), (0,0,0,0,0,1), (2,2,2,2,10,10,10,10), 0)  # 2-6
diad = (None, t1, t2, t3, t4, t5, t6)

t1  = ((0,1,2), (2,1,0,0,0,0), (1,1,0,0,7,7,4,4), 0)  # 3-1
t2  = ((0,1,3), (1,1,1,0,0,0), (1,0,0,0,5,6,5,5), 0)  # 3-2
t3  = ((0,1,4), (1,0,1,1,0,0), (1,0,0,0,5,6,5,5), 0)  # 3-3
t4  = ((0,1,5), (1,0,0,1,1,0), (1,0,1,0,5,6,5,6), 0)  # 3-4
t5  = ((0,1,6), (1,0,0,0,1,1), (1,0,0,1,6,7,7,6), 0)  # 3-5
t6  = ((0,2,4), (0,2,0,1,0,0), (1,1,1,1,7,7,7,7), 0)  # 3-6
t7  = ((0,2,5), (0,1,1,0,1,0), (1,0,0,0,5,6,5,5), 0)  # 3-7
t8  = ((0,2,6), (0,1,0,1,0,1), (1,0,0,1,6,7,7,6), 0)  # 3-8
t9  = ((0,2,7), (0,1,0,0,2,0), (1,1,0,0,7,7,4,4), 0)  # 3-9
t10 = ((0,3,6), (0,0,2,0,0,1), (1,1,1,1,8,8,8,8), 0)  # 3-10
t11 = ((0,3,7), (0,0,1,1,1,0), (1,0,0,0,5,6,5,5), 0)  # 3-11
t12 = ((0,4,8), (0,0,0,3,0,0), (3,3,3,3,9,9,9,9), 0)  # 3-12
trichord = (None, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)

t1  = ((0,1,2,3), (3,2,1,0,0,0), (1,1,0,0,5,5,1,1),  0)  # 4-1
t2  = ((0,1,2,4), (2,2,1,1,0,0), (1,0,0,0,3,4,1,1),  0)  # 4-2
t3  = ((0,1,3,4), (2,1,2,1,0,0), (1,1,0,0,3,3,2,2),  0)  # 4-3
t4  = ((0,1,2,5), (2,1,1,1,1,0), (1,0,0,0,1,3,2,3),  0)  # 4-4
t5  = ((0,1,2,6), (2,1,0,1,1,1), (1,0,0,0,2,4,3,2),  0)  # 4-5
t6  = ((0,1,2,7), (2,1,0,0,2,1), (1,1,1,1,4,4,4,4),  0)  # 4-6
t7  = ((0,1,4,5), (2,0,1,2,1,0), (1,1,0,0,3,3,3,3),  0)  # 4-7
t8  = ((0,1,5,6), (2,0,0,1,2,1), (1,1,1,1,4,4,4,4),  0)  # 4-8
t9  = ((0,1,6,7), (2,0,0,0,2,2), (2,2,2,2,6,6,6,6),  0)  # 4-9
t10 = ((0,2,3,5), (1,2,2,0,1,0), (1,1,1,1,3,3,3,3),  0)  # 4-10
t11 = ((0,1,3,5), (1,2,1,1,1,0), (1,0,1,0,1,3,1,3),  0)  # 4-11
t12 = ((0,2,3,6), (1,1,2,1,0,1), (1,0,0,0,2,4,3,2),  0)  # 4-12
t13 = ((0,1,3,6), (1,1,2,0,1,1), (1,0,0,1,2,4,4,2),  0)  # 4-13
t14 = ((0,2,3,7), (1,1,1,1,2,0), (1,0,0,0,1,3,2,3),  0)  # 4-14
t15 = ((0,1,4,6), (1,1,1,1,1,1), (1,0,0,0,0,3,3,1), 29)  # 4-15z
t16 = ((0,1,5,7), (1,1,0,1,2,1), (1,0,0,0,2,4,3,2),  0)  # 4-16
t17 = ((0,3,4,7), (1,0,2,2,1,0), (1,1,1,1,3,3,3,3),  0)  # 4-17
t18 = ((0,1,4,7), (1,0,2,1,1,1), (1,0,0,1,2,4,4,2),  0)  # 4-18
t19 = ((0,1,4,8), (1,0,1,3,1,0), (1,0,1,0,3,5,3,5),  0)  # 4-19
t20 = ((0,1,5,8), (1,0,1,2,2,0), (1,1,0,0,3,3,3,3),  0)  # 4-20
t21 = ((0,2,4,6), (0,3,0,2,0,1), (1,1,1,1,6,6,6,6),  0)  # 4-21
t22 = ((0,2,4,7), (0,2,1,1,2,0), (1,0,0,0,3,4,1,1),  0)  # 4-22
t23 = ((0,2,5,7), (0,2,1,0,3,0), (1,1,0,0,5,5,1,1),  0)  # 4-23
t24 = ((0,2,4,8), (0,2,0,3,0,1), (1,1,1,1,6,6,6,6),  0)  # 4-24
t25 = ((0,2,6,8), (0,2,0,2,0,2), (2,2,2,2,6,6,6,6),  0)  # 4-25
t26 = ((0,3,5,8), (0,1,2,1,2,0), (1,1,0,0,3,3,2,2),  0)  # 4-26
t27 = ((0,2,5,8), (0,1,2,1,1,1), (1,0,0,0,2,4,3,2),  0)  # 4-27
t28 = ((0,3,6,9), (0,0,4,0,0,2), (4,4,4,4,8,8,8,8),  0)  # 4-28
t29 = ((0,1,3,7), (1,1,1,1,1,1), (1,0,0,0,0,3,3,1), 15)  # 4-29z
tetrachord = (
    None, t1, t2, t3, t4, t5, t6, t7, t8, t9,
    t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
    t20, t21, t22, t23, t24, t25, t26, t27, t28, t29
)

t1  = ((0,1,2,3,4), (4,3,2,1,0,0), (1,1,0,0,3,3,0,0),  0)  # 5-1
t2  = ((0,1,2,3,5), (3,3,2,1,1,0), (1,0,0,0,1,2,1,1),  0)  # 5-2
t3  = ((0,1,2,4,5), (3,2,2,2,1,0), (1,0,0,0,1,1,1,0),  0)  # 5-3
t4  = ((0,1,2,3,6), (3,2,2,1,1,1), (1,0,0,0,0,2,0,0),  0)  # 5-4
t5  = ((0,1,2,3,7), (3,2,1,1,2,1), (1,0,0,0,0,1,1,1),  0)  # 5-5
t6  = ((0,1,2,5,6), (3,1,1,2,2,1), (1,0,0,0,0,1,1,1),  0)  # 5-6
t7  = ((0,1,2,6,7), (3,1,0,1,3,2), (1,0,0,1,2,3,3,2),  0)  # 5-7
t8  = ((0,2,3,4,6), (2,3,2,2,0,1), (1,1,0,0,2,2,0,0),  0)  # 5-8
t9  = ((0,1,2,4,6), (2,3,1,2,1,1), (1,0,0,0,0,2,0,1),  0)  # 5-9
t10 = ((0,1,3,4,6), (2,2,3,1,1,1), (1,0,0,0,0,1,1,0),  0)  # 5-10
t11 = ((0,2,3,4,7), (2,2,2,2,2,0), (1,0,1,0,1,1,1,1),  0)  # 5-11
t12 = ((0,1,3,5,6), (2,2,2,1,2,1), (1,1,1,1,0,0,0,0), 36)  # 5-12
t13 = ((0,1,2,4,8), (2,2,1,3,1,1), (1,0,0,0,0,2,0,1),  0)  # 5-13
t14 = ((0,1,2,5,7), (2,2,1,1,3,1), (1,0,0,0,0,1,1,1),  0)  # 5-14
t15 = ((0,1,2,6,8), (2,2,0,2,2,2), (1,1,1,1,2,2,2,2),  0)  # 5-15
t16 = ((0,1,3,4,7), (2,1,3,2,1,1), (1,0,0,0,0,1,1,0),  0)  # 5-16
t17 = ((0,1,3,4,8), (2,1,2,3,2,0), (1,1,0,0,1,1,2,2), 37)  # 5-17
t18 = ((0,1,4,5,7), (2,1,2,2,2,1), (1,0,0,0,0,1,1,0), 38)  # 5-18
t19 = ((0,1,3,6,7), (2,1,2,1,2,2), (1,0,0,1,0,2,2,0),  0)  # 5-19
t20 = ((0,1,3,7,8), (2,1,1,2,3,1), (1,0,0,0,0,1,1,1),  0)  # 5-20
t21 = ((0,1,4,5,8), (2,0,2,4,2,0), (1,0,1,0,3,3,3,3),  0)  # 5-21
t22 = ((0,1,4,7,8), (2,0,2,3,2,1), (1,1,1,1,2,2,2,2),  0)  # 5-22
t23 = ((0,2,3,5,7), (1,3,2,1,3,0), (1,0,0,0,1,2,1,1),  0)  # 5-23
t24 = ((0,1,3,5,7), (1,3,1,2,2,1), (1,0,0,0,0,2,0,1),  0)  # 5-24
t25 = ((0,2,3,5,8), (1,2,3,1,2,1), (1,0,0,0,0,1,1,0),  0)  # 5-25
t26 = ((0,2,4,5,8), (1,2,2,3,1,1), (1,0,1,0,0,2,0,2),  0)  # 5-26
t27 = ((0,1,3,5,8), (1,2,2,2,3,0), (1,0,0,0,1,1,1,0),  0)  # 5-27
t28 = ((0,2,3,6,8), (1,2,2,2,1,2), (1,0,0,1,0,2,2,0),  0)  # 5-28
t29 = ((0,1,3,6,8), (1,2,2,1,3,1), (1,0,0,0,0,2,0,0),  0)  # 5-29
t30 = ((0,1,4,6,8), (1,2,1,3,2,1), (1,0,0,0,0,2,0,1),  0)  # 5-30
t31 = ((0,1,3,6,9), (1,1,4,1,1,2), (1,0,0,1,0,3,3,0),  0)  # 5-31
t32 = ((0,1,4,6,9), (1,1,3,2,2,1), (1,0,0,0,0,1,1,0),  0)  # 5-32
t33 = ((0,2,4,6,8), (0,4,0,4,0,2), (1,1,1,1,6,6,6,6),  0)  # 5-33
t34 = ((0,2,4,6,9), (0,3,2,2,2,1), (1,1,0,0,2,2,0,0),  0)  # 5-34
t35 = ((0,2,4,7,9), (0,3,2,1,4,0), (1,1,0,0,3,3,0,0),  0)  # 5-35
t36 = ((0,1,2,4,7), (2,2,2,1,2,1), (1,0,0,1,0,1,1,0), 12)  # 5-36
t37 = ((0,3,4,5,8), (2,1,2,3,2,0), (1,1,0,0,1,1,2,2), 17)  # 5-37
t38 = ((0,1,2,5,8), (2,1,2,2,2,1), (1,0,0,0,0,1,1,0), 18)  # 5-38
pentachord = (
    None, t1, t2, t3, t4, t5, t6, t7, t8, t9,
    t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
    t20, t21, t22, t23, t24, t25, t26, t27, t28, t29,
    t30, t31, t32, t33, t34, t35, t36, t37, t38
)

t1  = ((0,1,2,3,4,5), (5,4,3,2,1,0), (1,1,0,0,1,1,0,0),  0)  # 6-1  A
t2  = ((0,1,2,3,4,6), (4,4,3,2,1,1), (1,0,0,0,0,1,0,0),  0)  # 6-2
t3  = ((0,1,2,3,5,6), (4,3,3,2,2,1), (1,0,0,0,0,0,0,0), 36)  # 6-3
t4  = ((0,1,2,4,5,6), (4,3,2,3,2,1), (1,1,0,0,0,0,0,0), 37)  # 6-4
t5  = ((0,1,2,3,6,7), (4,2,2,2,3,2), (1,0,0,0,0,1,0,0),  0)  # 6-5
t6  = ((0,1,2,5,6,7), (4,2,1,2,4,2), (1,1,0,0,0,0,1,1), 38)  # 6-6
t7  = ((0,1,2,6,7,8), (4,2,0,2,4,3), (2,2,2,2,2,2,2,2),  0)  # 6-7 B
t8  = ((0,2,3,4,5,7), (3,4,3,2,3,0), (1,1,1,1,1,1,1,1),  0)  # 6-8 D
t9  = ((0,1,2,3,5,7), (3,4,2,2,3,1), (1,0,1,0,0,1,0,1),  0)  # 6-9
t10 = ((0,1,3,4,5,7), (3,3,3,3,2,1), (1,0,0,0,0,0,0,0), 39)  # 6-10
t11 = ((0,1,2,4,5,7), (3,3,3,2,3,1), (1,0,0,0,0,0,1,0), 40)  # 6-11
t12 = ((0,1,2,4,6,7), (3,3,2,2,3,2), (1,0,0,1,0,0,0,0), 41)  # 6-12
t13 = ((0,1,3,4,6,7), (3,2,4,2,2,2), (1,1,0,0,0,0,0,0), 42)  # 6-13
t14 = ((0,1,3,4,5,8), (3,2,3,4,3,0), (1,0,1,0,1,0,1,0),  0)  # 6-14
t15 = ((0,1,2,4,5,8), (3,2,3,4,2,1), (1,0,0,0,0,1,0,0),  0)  # 6-15
t16 = ((0,1,4,5,6,8), (3,2,2,4,3,1), (1,0,1,0,0,1,0,1),  0)  # 6-16
t17 = ((0,1,2,4,7,8), (3,2,2,3,3,2), (1,0,0,1,0,0,0,0), 43)  # 6-17
t18 = ((0,1,2,5,7,8), (3,2,2,2,4,2), (1,0,0,0,0,1,0,0),  0)  # 6-18
t19 = ((0,1,3,4,7,8), (3,1,3,4,3,1), (1,0,0,0,0,0,1,0), 44)  # 6-19
t20 = ((0,1,4,5,8,9), (3,0,3,6,3,0), (3,3,3,3,3,3,3,3),  0)  # 6-20 E
t21 = ((0,2,3,4,6,8), (2,4,2,4,1,2), (1,0,0,0,0,1,0,0),  0)  # 6-21
t22 = ((0,1,2,4,6,8), (2,4,1,4,2,2), (1,0,1,0,0,1,0,1),  0)  # 6-22
t23 = ((0,2,3,5,6,8), (2,3,4,2,2,2), (1,1,1,1,0,0,0,0), 45)  # 6-23
t24 = ((0,1,3,4,6,8), (2,3,3,3,3,1), (1,0,0,0,0,0,0,0), 46)  # 6-24
t25 = ((0,1,3,5,6,8), (2,3,3,2,4,1), (1,0,0,0,0,0,0,0), 47)  # 6-25
t26 = ((0,1,3,5,7,8), (2,3,2,3,4,1), (1,1,0,0,0,0,0,0), 48)  # 6-26
t27 = ((0,1,3,4,6,9), (2,2,5,2,2,2), (1,0,0,1,0,1,1,0),  0)  # 6-27
t28 = ((0,1,3,5,6,9), (2,2,4,3,2,2), (1,1,1,1,0,0,0,0), 49)  # 6-28
t29 = ((0,1,3,6,8,9), (2,2,4,2,3,2), (1,1,0,0,0,0,0,0), 50)  # 6-29
t30 = ((0,1,3,6,7,9), (2,2,4,2,2,3), (2,0,0,2,0,2,2,0),  0)  # 6-30
t31 = ((0,1,3,5,8,9), (2,2,3,4,3,1), (1,0,0,0,0,1,0,0),  0)  # 6-31
t32 = ((0,2,4,5,7,9), (1,4,3,2,5,0), (1,1,0,0,1,1,0,0),  0)  # 6-32 C
t33 = ((0,2,3,5,7,9), (1,4,3,2,4,1), (1,0,0,0,0,1,0,0),  0)  # 6-33
t34 = ((0,1,3,5,7,9), (1,4,2,4,2,2), (1,0,0,0,0,1,0,0),  0)  # 6-34
t35 = ((0,2,4,6,8,10),(0,6,0,6,0,3), (6,6,6,6,6,6,6,6),  0)  # 6-35 F
t36 = ((0,1,2,3,4,7), (4,3,3,2,2,1), (1,0,0,0,0,0,0,0),  3)  # 6-36
t37 = ((0,1,2,3,4,8), (4,3,2,3,2,1), (1,1,0,0,0,0,0,0),  4)  # 6-37
t38 = ((0,1,2,3,7,8), (4,2,1,2,4,2), (1,1,0,0,0,0,1,1),  6)  # 6-38
t39 = ((0,2,3,4,5,8), (3,3,3,3,2,1), (1,0,0,0,0,0,0,0), 10)  # 6-39
t40 = ((0,1,2,3,5,8), (3,3,3,2,3,1), (1,0,0,0,0,0,1,0), 11)  # 6-40
t41 = ((0,1,2,3,6,8), (3,3,2,2,3,2), (1,0,0,1,0,0,0,0), 12)  # 6-41
t42 = ((0,1,2,3,6,9), (3,2,4,2,2,2), (1,1,0,0,0,0,0,0), 13)  # 6-42
t43 = ((0,1,2,5,6,8), (3,2,2,3,3,2), (1,0,0,1,0,0,0,0), 17)  # 6-43
t44 = ((0,1,2,5,6,9), (3,1,3,4,3,1), (1,0,0,0,0,0,1,0), 19)  # 6-44
t45 = ((0,2,3,4,6,9), (2,3,4,2,2,2), (1,1,1,1,0,0,0,0), 23)  # 6-45
t46 = ((0,1,2,4,6,9), (2,3,3,3,3,1), (1,0,0,0,0,0,0,0), 24)  # 6-46
t47 = ((0,1,2,4,7,9), (2,3,3,2,4,1), (1,0,0,0,0,0,0,0), 25)  # 6-47
t48 = ((0,1,2,5,7,9), (2,3,2,3,4,1), (1,1,0,0,0,0,0,0), 26)  # 6-48
t49 = ((0,1,3,4,7,9), (2,2,4,3,2,2), (1,1,1,1,0,0,0,0), 28)  # 6-49
t50 = ((0,1,4,6,7,9), (2,2,4,2,3,2), (1,1,0,0,0,0,0,0), 29)  # 6-50
hexachord = (
    None, t1, t2, t3, t4, t5, t6, t7, t8, t9,
    t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
    t20, t21, t22, t23, t24, t25, t26, t27, t28, t29,
    t30, t31, t32, t33, t34, t35, t36, t37, t38, t39,
    t40, t41, t42, t43, t44, t45, t46, t47, t48, t49,
    t50,
)
del t39, t40, t41, t42, t43, t44, t45, t46, t47, t48, t49, t50

t1  = ((0,1,2,3,4,5, 6), (6,5,4,3,2,1), (1,1,0,0,0,0,0,0),  0)  # 7-1
t2  = ((0,1,2,3,4,5, 7), (5,5,4,3,3,1), (1,0,0,0,0,0,0,0),  0)  # 7-2
t3  = ((0,1,2,3,4,5, 8), (5,4,4,4,3,1), (1,0,0,0,0,0,0,0),  0)  # 7-3
t4  = ((0,1,2,3,4,6, 7), (5,4,4,3,3,2), (1,0,0,0,0,0,0,0),  0)  # 7-4
t5  = ((0,1,2,3,5,6, 7), (5,4,3,3,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-5
t6  = ((0,1,2,3,4,7, 8), (5,3,3,4,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-6
t7  = ((0,1,2,3,6,7, 8), (5,3,2,3,5,3), (1,0,0,1,0,0,0,0),  0)  # 7-7
t8  = ((0,2,3,4,5,6, 8), (4,5,4,4,2,2), (1,1,0,0,0,0,0,0),  0)  # 7-8
t9  = ((0,1,2,3,4,6, 8), (4,5,3,4,3,2), (1,0,0,0,0,0,0,0),  0)  # 7-9
t10 = ((0,1,2,3,4,6, 9), (4,4,5,3,3,2), (1,0,0,0,0,0,0,0),  0)  # 7-10
t11 = ((0,1,3,4,5,6, 8), (4,4,4,4,4,1), (1,0,1,0,0,0,0,0),  0)  # 7-11
t12 = ((0,1,2,3,4,7, 9), (4,4,4,3,4,2), (1,1,1,1,0,0,0,0), 36)  # 7-12 z
t13 = ((0,1,2,4,5,6, 8), (4,4,3,5,3,2), (1,0,0,0,0,0,0,0),  0)  # 7-13
t14 = ((0,1,2,3,5,7, 8), (4,4,3,3,5,2), (1,0,0,0,0,0,0,0),  0)  # 7-14
t15 = ((0,1,2,4,6,7, 8), (4,4,2,4,4,3), (1,1,1,1,0,0,0,0),  0)  # 7-15
t16 = ((0,1,2,3,5,6, 9), (4,3,5,4,3,2), (1,0,0,0,0,0,0,0),  0)  # 7-16
t17 = ((0,1,2,4,5,6, 9), (4,3,4,5,4,1), (1,1,0,0,0,0,0,0), 37)  # 7-17 z
t18 = ((0,1,2,3,5,8, 9), (4,3,4,4,4,2), (1,0,0,0,0,0,0,0), 38)  # 7-18 z
t19 = ((0,1,2,3,6,7, 9), (4,3,4,3,4,3), (1,0,0,1,0,0,0,0),  0)  # 7-19
t20 = ((0,1,2,4,7,8, 9), (4,3,3,4,5,2), (1,0,0,0,0,0,0,0),  0)  # 7-20
t21 = ((0,1,2,4,5,8, 9), (4,2,4,6,4,1), (1,0,1,0,0,0,0,0),  0)  # 7-21
t22 = ((0,1,2,5,6,8, 9), (4,2,4,5,4,2), (1,1,1,1,0,0,0,0),  0)  # 7-22
t23 = ((0,2,3,4,5,7, 9), (3,5,4,3,5,1), (1,0,0,0,0,0,0,0),  0)  # 7-23
t24 = ((0,1,2,3,5,7, 9), (3,5,3,4,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-24
t25 = ((0,2,3,4,6,7, 9), (3,4,5,3,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-25
t26 = ((0,1,3,4,5,7, 9), (3,4,4,5,3,2), (1,0,1,0,0,0,0,0),  0)  # 7-26
t27 = ((0,1,2,4,5,7, 9), (3,4,4,4,5,1), (1,0,0,0,0,0,0,0),  0)  # 7-27
t28 = ((0,1,3,5,6,7, 9), (3,4,4,4,3,3), (1,0,0,1,0,0,0,0),  0)  # 7-28
t29 = ((0,1,2,4,6,7, 9), (3,4,4,3,5,2), (1,0,0,0,0,0,0,0),  0)  # 7-29
t30 = ((0,1,2,4,6,8, 9), (3,4,3,5,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-30
t31 = ((0,1,3,4,6,7, 9), (3,3,6,3,3,3), (1,0,0,1,0,0,0,0),  0)  # 7-31
t32 = ((0,1,3,4,6,8, 9), (3,3,5,4,4,2), (1,0,0,0,0,0,0,0),  0)  # 7-32
t33 = ((0,1,2,4,6,8,10), (2,6,2,6,2,3), (1,1,1,1,0,0,0,0),  0)  # 7-33
t34 = ((0,1,3,4,6,8,10), (2,5,4,4,4,2), (1,1,0,0,0,0,0,0),  0)  # 7-34
t35 = ((0,1,3,5,6,8,10), (2,5,4,3,6,1), (1,1,0,0,0,0,0,0),  0)  # 7-35
t36 = ((0,1,2,3,5,6, 8), (4,4,4,3,4,2), (1,0,0,1,0,0,0,0), 12)  # 7-36 z
t37 = ((0,1,3,4,5,7, 8), (4,3,4,5,4,1), (1,1,0,0,0,0,0,0), 17)  # 7-37 z
t38 = ((0,1,2,4,5,7, 8), (4,3,4,4,4,2), (1,0,0,0,0,0,0,0), 18)  # 7-38 z
septachord = (
    None, t1, t2, t3, t4, t5, t6, t7, t8, t9,
    t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
    t20, t21, t22, t23, t24, t25, t26, t27, t28, t29,
    t30, t31, t32, t33, t34, t35, t36, t37, t38
)
del t30, t31, t32, t33, t34, t35, t36, t37, t38

t1  = ((0,1,2,3,4,5,6, 7), (7,6,5,4,4,2), (1,1,0,0,0,0,0,0), 0 )  # 8-1
t2  = ((0,1,2,3,4,5,6, 8), (6,6,5,5,4,2), (1,0,0,0,0,0,0,0), 0 )  # 8-2
t3  = ((0,1,2,3,4,5,6, 9), (6,5,6,5,4,2), (1,1,0,0,0,0,0,0), 0 )  # 8-3
t4  = ((0,1,2,3,4,5,7, 8), (6,5,5,5,5,2), (1,0,0,0,0,0,0,0), 0 )  # 8-4
t5  = ((0,1,2,3,4,6,7, 8), (6,5,4,5,5,3), (1,0,0,0,0,0,0,0), 0 )  # 8-5
t6  = ((0,1,2,3,5,6,7, 8), (6,5,4,4,6,3), (1,1,1,1,0,0,0,0), 0 )  # 8-6
t7  = ((0,1,2,3,4,5,8, 9), (6,4,5,6,5,2), (1,1,0,0,0,0,0,0), 0 )  # 8-7
t8  = ((0,1,2,3,4,7,8, 9), (6,4,4,5,6,3), (1,1,1,1,0,0,0,0), 0 )  # 8-8
t9  = ((0,1,2,3,6,7,8, 9), (6,4,4,4,6,4), (2,2,2,2,0,0,0,0), 0 )  # 8-9
t10 = ((0,2,3,4,5,6,7, 9), (5,6,6,4,5,2), (1,1,1,1,0,0,0,0), 0 )  # 8-10
t11 = ((0,1,2,3,4,5,7, 9), (5,6,5,5,5,2), (1,0,1,0,0,0,0,0), 0 )  # 8-11
t12 = ((0,1,3,4,5,6,7, 9), (5,5,6,5,4,3), (1,0,0,0,0,0,0,0), 0 )  # 8-12
t13 = ((0,1,2,3,4,6,7, 9), (5,5,6,4,5,3), (1,0,0,1,0,0,0,0), 0 )  # 8-13
t14 = ((0,1,2,4,5,6,7, 9), (5,5,5,5,6,2), (1,0,0,0,0,0,0,0), 0 )  # 8-14
t15 = ((0,1,2,3,4,6,8, 9), (5,5,5,5,5,3), (1,0,0,0,0,0,0,0), 29)  # 8-15 z
t16 = ((0,1,2,3,5,7,8, 9), (5,5,4,5,6,3), (1,0,0,0,0,0,0,0), 0 )  # 8-16
t17 = ((0,1,3,4,5,6,8, 9), (5,4,6,6,5,2), (1,1,1,1,0,0,0,0), 0 )  # 8-17
t18 = ((0,1,2,3,5,6,8, 9), (5,4,6,5,5,3), (1,0,0,1,0,0,0,0), 0 )  # 8-18
t19 = ((0,1,2,4,5,6,8, 9), (5,4,5,7,5,2), (1,0,1,0,0,0,0,0), 0 )  # 8-19
t20 = ((0,1,2,4,5,7,8, 9), (5,4,5,6,6,2), (1,1,0,0,0,0,0,0), 0 )  # 8-20
t21 = ((0,1,2,3,4,6,8,10), (4,7,4,6,4,3), (1,1,1,1,0,0,0,0), 0 )  # 8-21
t22 = ((0,1,2,3,5,6,8,10), (4,6,5,5,6,2), (1,0,0,0,0,0,0,0), 0 )  # 8-22
t23 = ((0,1,2,3,5,7,8,10), (4,6,5,4,7,2), (1,1,0,0,0,0,0,0), 0 )  # 8-23
t24 = ((0,1,2,4,5,6,8,10), (4,6,4,7,4,3), (1,1,1,1,0,0,0,0), 0 )  # 8-24
t25 = ((0,1,2,4,6,7,8,10), (4,6,4,6,4,4), (2,2,2,2,0,0,0,0), 0 )  # 8-25
t26 = ((0,1,2,4,5,7,9,10), (4,5,6,5,6,2), (1,1,0,0,0,0,0,0), 0 )  # 8-26
t27 = ((0,1,2,4,5,7,8,10), (4,5,6,5,5,3), (1,0,0,0,0,0,0,0), 0 )  # 8-27
t28 = ((0,1,3,4,6,7,9,10), (4,4,8,4,4,4), (4,4,4,4,0,0,0,0), 0 )  # 8-28
t29 = ((0,1,2,3,5,6,7, 9), (5,5,5,5,5,3), (1,0,0,0,0,0,0,0), 15)  # 8-29 z
octachord = (
    None, t1, t2, t3, t4, t5, t6, t7, t8, t9,
    t10, t11, t12, t13, t14, t15, t16, t17, t18, t19,
    t20, t21, t22, t23, t24, t25, t26, t27, t28, t29
)
del t13, t14, t15, t16, t17, t18, t19
del t20, t21, t22, t23, t24, t25, t26, t27, t28, t29

t1  = ((0,1,2,3,4,5,6,7, 8), (8,7,6,6,6,3), (1,1,0,0,0,0,0,0), 0)  # 9-1
t2  = ((0,1,2,3,4,5,6,7, 9), (7,7,7,6,6,3), (1,0,0,0,0,0,0,0), 0)  # 9-2
t3  = ((0,1,2,3,4,5,6,8, 9), (7,6,7,7,6,3), (1,0,0,0,0,0,0,0), 0)  # 9-3
t4  = ((0,1,2,3,4,5,7,8, 9), (7,6,6,7,7,3), (1,0,1,0,0,0,0,0), 0)  # 9-4
t5  = ((0,1,2,3,4,6,7,8, 9), (7,6,6,6,7,4), (1,0,0,1,0,0,0,0), 0)  # 9-5
t6  = ((0,1,2,3,4,5,6,8,10), (6,8,6,7,6,3), (1,1,1,1,0,0,0,0), 0)  # 9-6
t7  = ((0,1,2,3,4,5,7,8,10), (6,7,7,6,7,3), (1,0,0,0,0,0,0,0), 0)  # 9-7
t8  = ((0,1,2,3,4,6,7,8,10), (6,7,6,7,6,4), (1,0,0,1,0,0,0,0), 0)  # 9-8
t9  = ((0,1,2,3,5,6,7,8,10), (6,7,6,6,8,3), (1,1,0,0,0,0,0,0), 0)  # 9-9
t10 = ((0,1,2,3,4,6,7,9,10), (6,6,8,6,6,4), (1,1,1,1,0,0,0,0), 0)  # 9-10
t11 = ((0,1,2,3,5,6,7,9,10), (6,6,7,7,7,3), (1,0,0,0,0,0,0,0), 0)  # 9-11
t12 = ((0,1,2,4,5,6,8,9,10), (6,6,6,9,6,3), (3,3,3,3,0,0,0,0), 0)  # 9-12
nonachord = (None, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)
del t7, t8, t9, t10, t11, t12

t1   = ((0,1,2,3,4,5,6,7,8, 9), (9,8,8,8,8,4), (1,1,0,0,0,0,0,0), 0)  # 10-1
t2   = ((0,1,2,3,4,5,6,7,8,10), (8,9,8,8,8,4), (1,1,1,1,0,0,0,0), 0)  # 10-2
t3   = ((0,1,2,3,4,5,6,7,9,10), (8,8,9,8,8,4), (1,1,1,1,0,0,0,0), 0)  # 10-3
t4   = ((0,1,2,3,4,5,6,8,9,10), (8,8,8,9,8,4), (1,1,1,1,0,0,0,0), 0)  # 10-4
t5   = ((0,1,2,3,4,5,7,8,9,10), (8,8,8,8,9,4), (1,1,0,0,0,0,0,0), 0)  # 10-5
t6   = ((0,1,2,3,4,6,7,8,9,10), (8,8,8,8,8,5), (2,2,2,2,0,0,0,0), 0)  # 10-6
decachord = (None, t1, t2, t3, t4, t5, t6)
del t2, t3, t4, t5, t6

t1 = ((0,1,2,3,4,5,6,7,8,9,10), (10,10,10,10,10,5), (1,1,1,1,0,0,0,0), 0)  # 11-1
undecachord = (None, t1)

t1   = ((0,1,2,3,4,5,6,7,8,9,10,11), (12,12,12,12,12,6), (12,12,12,12,0,0,0,0), 0)  # 12-1
dodecachord = (None, t1)
del t1

# ------------------------------------------------------------------------------
FORTE = (None, monad, diad, trichord, tetrachord, pentachord,
         hexachord, septachord, octachord,
         nonachord, decachord, undecachord, dodecachord)

# This dictionary defines the pitch classes to return for the inversion of a given
# forte number.  For instance (3, 11): (0, 4, 7) indicates that for the
# inverted form of Forte class 3-11 (minor/major triad) return 0, 4, 7
# (the zero could be assumed, but it makes my brain easier to have it there).
# It is faster to store this than to recompute it every time.
# Data cross-checked with
# https://web.archive.org/web/20130118035710/http://solomonsmusic.net/pcsets.htm
inversionDefaultPitchClasses = {
    (3, 2): (0, 2, 3),
    (3, 3): (0, 3, 4),
    (3, 4): (0, 4, 5),
    (3, 5): (0, 5, 6),
    (3, 7): (0, 3, 5),
    (3, 8): (0, 4, 6),
    (3,11): (0, 4, 7),
    (4, 2): (0, 2, 3, 4),
    (4, 4): (0, 3, 4, 5),
    (4, 5): (0, 4, 5, 6),
    (4,11): (0, 2, 4, 5),
    (4,12): (0, 3, 4, 6),
    (4,13): (0, 3, 5, 6),
    (4,14): (0, 4, 5, 7),
    (4,15): (0, 2, 5, 6),
    (4,16): (0, 2, 6, 7),
    (4,18): (0, 3, 6, 7),
    (4,19): (0, 3, 4, 8),
    (4,22): (0, 3, 5, 7),
    (4,27): (0, 3, 6, 8),
    (4,29): (0, 4, 6, 7),
    (5, 2): (0, 2, 3, 4, 5),
    (5, 3): (0, 1, 3, 4, 5),
    (5, 4): (0, 3, 4, 5, 6),
    (5, 5): (0, 4, 5, 6, 7),
    (5, 6): (0, 1, 4, 5, 6),
    (5, 7): (0, 1, 5, 6, 7),
    (5, 9): (0, 2, 4, 5, 6),
    (5,10): (0, 2, 3, 5, 6),
    (5,11): (0, 3, 4, 5, 7),
    (5,13): (0, 2, 3, 4, 8),
    (5,14): (0, 2, 5, 6, 7),
    (5,16): (0, 3, 4, 6, 7),
    (5,18): (0, 2, 3, 6, 7),
    (5,19): (0, 1, 4, 6, 7),
    (5,20): (0, 1, 5, 7, 8),
    (5,21): (0, 3, 4, 7, 8),
    (5,23): (0, 2, 4, 5, 7),
    (5,24): (0, 2, 4, 6, 7),
    (5,25): (0, 3, 5, 6, 8),
    (5,26): (0, 3, 4, 6, 8),
    (5,27): (0, 3, 5, 7, 8),
    (5,28): (0, 2, 5, 6, 8),
    (5,29): (0, 2, 5, 7, 8),
    (5,30): (0, 2, 4, 7, 8),
    (5,31): (0, 2, 3, 6, 9),
    (5,32): (0, 1, 4, 7, 9),
    (5,36): (0, 3, 5, 6, 7),
    (5,38): (0, 3, 6, 7, 8),
    (6, 2): (0, 2, 3, 4, 5, 6),
    (6, 3): (0, 1, 3, 4, 5, 6),
    (6, 5): (0, 1, 4, 5, 6, 7),
    (6, 9): (0, 2, 4, 5, 6, 7),
    (6,10): (0, 2, 3, 4, 6, 7),
    (6,11): (0, 2, 3, 5, 6, 7),
    (6,12): (0, 1, 3, 5, 6, 7),
    (6,14): (0, 3, 4, 5, 7, 8),
    (6,15): (0, 3, 4, 6, 7, 8),
    (6,16): (0, 2, 3, 4, 7, 8),
    (6,17): (0, 1, 4, 6, 7, 8),
    (6,18): (0, 1, 3, 6, 7, 8),
    (6,19): (0, 1, 4, 5, 7, 8),
    (6,21): (0, 2, 4, 5, 6, 8),
    (6,22): (0, 2, 4, 6, 7, 8),
    (6,24): (0, 2, 4, 5, 7, 8),
    (6,25): (0, 2, 3, 5, 7, 8),
    (6,27): (0, 2, 3, 5, 6, 9),
    (6,30): (0, 2, 3, 6, 8, 9),
    (6,31): (0, 1, 4, 6, 8, 9),
    (6,33): (0, 2, 4, 6, 7, 9),
    (6,34): (0, 2, 4, 6, 8, 9),
    (6,36): (0, 3, 4, 5, 6, 7),
    (6,39): (0, 3, 4, 5, 6, 8),
    (6,40): (0, 3, 5, 6, 7, 8),
    (6,41): (0, 2, 5, 6, 7, 8),
    (6,43): (0, 2, 3, 6, 7, 8),
    (6,44): (0, 1, 2, 5, 8, 9),
    (6,46): (0, 2, 4, 5, 6, 9),
    (6,47): (0, 2, 3, 4, 7, 9),
    (7, 2): (0, 2, 3, 4, 5, 6, 7),
    (7, 3): (0, 3, 4, 5, 6, 7, 8),
    (7, 4): (0, 1, 3, 4, 5, 6, 7),
    (7, 5): (0, 1, 2, 4, 5, 6, 7),
    (7, 6): (0, 1, 4, 5, 6, 7, 8),
    (7, 7): (0, 1, 2, 5, 6, 7, 8),
    (7, 9): (0, 2, 4, 5, 6, 7, 8),
    (7,10): (0, 2, 3, 4, 5, 6, 9),
    (7,11): (0, 2, 3, 4, 5, 7, 8),
    (7,13): (0, 2, 3, 4, 6, 7, 8),
    (7,14): (0, 1, 3, 5, 6, 7, 8),
    (7,16): (0, 1, 3, 4, 5, 6, 9),
    (7,18): (0, 1, 4, 6, 7, 8, 9),
    (7,19): (0, 1, 2, 3, 6, 8, 9),
    (7,20): (0, 1, 2, 5, 7, 8, 9),
    (7,21): (0, 1, 3, 4, 5, 8, 9),
    (7,23): (0, 2, 4, 5, 6, 7, 9),
    (7,24): (0, 2, 4, 6, 7, 8, 9),
    (7,25): (0, 2, 3, 5, 6, 7, 9),
    (7,26): (0, 2, 4, 5, 6, 8, 9),
    (7,27): (0, 2, 4, 5, 7, 8, 9),
    (7,28): (0, 2, 3, 4, 6, 8, 9),
    (7,29): (0, 2, 3, 5, 7, 8, 9),
    (7,30): (0, 1, 3, 5, 7, 8, 9),
    (7,31): (0, 2, 3, 5, 6, 8, 9),
    (7,32): (0, 1, 3, 5, 6, 8, 9),
    (7,36): (0, 2, 3, 5, 6, 7, 8),
    (7,38): (0, 1, 3, 4, 6, 7, 8),
    (8, 2): (0, 2, 3, 4, 5, 6, 7, 8),
    (8, 4): (0, 1, 3, 4, 5, 6, 7, 8),
    (8, 5): (0, 1, 2, 4, 5, 6, 7, 8),
    (8,11): (0, 2, 4, 5, 6, 7, 8, 9),
    (8,12): (0, 2, 3, 4, 5, 6, 8, 9),
    (8,13): (0, 2, 3, 5, 6, 7, 8, 9),
    (8,14): (0, 2, 3, 4, 5, 7, 8, 9),
    (8,15): (0, 1, 3, 5, 6, 7, 8, 9),
    (8,16): (0, 1, 2, 4, 6, 7, 8, 9),
    (8,18): (0, 1, 3, 4, 6, 7, 8, 9),
    (8,19): (0, 1, 3, 4, 5, 7, 8, 9),
    (8,22): (0, 1, 2, 3, 5, 7, 9,10),
    (8,27): (0, 1, 2, 4, 6, 7, 9,10),
    (8,29): (0, 2, 3, 4, 6, 7, 8, 9),
    (9, 2): (0, 2, 3, 4, 5, 6, 7, 8, 9),
    (9, 3): (0, 1, 3, 4, 5, 6, 7, 8, 9),
    (9, 4): (0, 1, 2, 4, 5, 6, 7, 8, 9),
    (9, 5): (0, 1, 2, 3, 5, 6, 7, 8, 9),
    (9, 7): (0, 1, 2, 3, 4, 5, 7, 9,10),
    (9, 8): (0, 1, 2, 3, 4, 6, 8, 9,10),
    (9,11): (0, 1, 2, 3, 5, 6, 8, 9,10),
}
# to access the data for a single form, use:
# forte   [size(tetra)] = 4
#         [number(forte)] = 3
#         [data(0=pitches, 1=ICV, 2=invariance vector (morris), 3 = Z-relation)]
#         [element in list]
# ------------------------------------------------------------------------------
def _makeCardinalityToChordMembers():
    _cardinalityToChordMembers = {}

    for cardinality in range(1, 13):
        forte_cardinality_lookup = FORTE[cardinality]
        this_cardinality_entries = {}
        for forte_after_dash in range(1, len(forte_cardinality_lookup)):
            forte_entry = forte_cardinality_lookup[forte_after_dash]
            has_distinct_inversion = (forte_entry[2][1] == 0)
            inversion_number = 1 if has_distinct_inversion else 0
            key = (forte_after_dash, inversion_number)
            pitches = forte_entry[0]
            morris_invariance = forte_entry[2]
            icv = forte_entry[1]
            value = (pitches, morris_invariance, icv)
            this_cardinality_entries[key] = value
            if not has_distinct_inversion:
                continue
            # now do the inversion of the pitch
            key = (forte_after_dash, -1)
            inversion_pitches = inversionDefaultPitchClasses[
                (cardinality, forte_after_dash)
            ]
            value = (inversion_pitches, morris_invariance, icv)
            this_cardinality_entries[key] = value

        _cardinalityToChordMembers[cardinality] = this_cardinality_entries
    return _cardinalityToChordMembers


cardinalityToChordMembers = _makeCardinalityToChordMembers()
del _makeCardinalityToChordMembers

# ------------------------------------------------------------------------------
# these dicts provide index max from cardinality key
maximumIndexNumberWithoutInversionEquivalence = {
    0:  1,
    1:  1,
    2:  6,
    3: 19,
    4: 43,
    5: 66,
    6: 80,
    7: 66,
    8: 43,
    9: 19,
    10: 6,
    11: 1,
    12: 1,
}

maximumIndexNumberWithInversionEquivalence = {
    0:  1,
    1:  1,
    2:  6,
    3: 12,
    4: 29,
    5: 38,
    6: 50,
    7: 38,
    8: 29,
    9: 12,
    10: 6,
    11: 1,
    12: 1,
}

# used to find TnI index numbers under Tn classification
forteNumberWithInversionToTnIndex = {
    (1,  1,  0):  1,
    (2,  1,  0):  1,
    (2,  2,  0):  2,
    (2,  3,  0):  3,
    (2,  4,  0):  4,
    (2,  5,  0):  5,
    (2,  6,  0):  6,
    (3,  1,  0):  1,
    (3,  2,  1):  2,
    (3,  2, -1):  3,
    (3,  3,  1):  4,
    (3,  3, -1):  5,
    (3,  4,  1):  6,
    (3,  4, -1):  7,
    (3,  5,  1):  8,
    (3,  5, -1):  9,
    (3,  6,  0): 10,
    (3,  7,  1): 11,
    (3,  7, -1): 12,
    (3,  8,  1): 13,
    (3,  8, -1): 14,
    (3,  9,  0): 15,
    (3, 10,  0): 16,
    (3, 11,  1): 17,
    (3, 11, -1): 18,
    (3, 12,  0): 19,
    (4,  1,  0):  1,
    (4,  2,  1):  2,
    (4,  2, -1):  3,
    (4,  3,  0):  4,
    (4,  4,  1):  5,
    (4,  4, -1):  6,
    (4,  5,  1):  7,
    (4,  5, -1):  8,
    (4,  6,  0):  9,
    (4,  7,  0): 10,
    (4,  8,  0): 11,
    (4,  9,  0): 12,
    (4, 10,  0): 13,
    (4, 11,  1): 14,
    (4, 11, -1): 15,
    (4, 12,  1): 16,
    (4, 12, -1): 17,
    (4, 13,  1): 18,
    (4, 13, -1): 19,
    (4, 14,  1): 20,
    (4, 14, -1): 21,
    (4, 15,  1): 22,
    (4, 15, -1): 23,
    (4, 16,  1): 24,
    (4, 16, -1): 25,
    (4, 17,  0): 26,
    (4, 18,  1): 27,
    (4, 18, -1): 28,
    (4, 19,  1): 29,
    (4, 19, -1): 30,
    (4, 20,  0): 31,
    (4, 21,  0): 32,
    (4, 22,  1): 33,
    (4, 22, -1): 34,
    (4, 23,  0): 35,
    (4, 24,  0): 36,
    (4, 25,  0): 37,
    (4, 26,  0): 38,
    (4, 27,  1): 39,
    (4, 27, -1): 40,
    (4, 28,  0): 41,
    (4, 29,  1): 42,
    (4, 29, -1): 43,
    (5,  1,  0):  1,
    (5,  2,  1):  2,
    (5,  2, -1):  3,
    (5,  3,  1):  4,
    (5,  3, -1):  5,
    (5,  4,  1):  6,
    (5,  4, -1):  7,
    (5,  5,  1):  8,
    (5,  5, -1):  9,
    (5,  6,  1): 10,
    (5,  6, -1): 11,
    (5,  7,  1): 12,
    (5,  7, -1): 13,
    (5,  8,  0): 14,
    (5,  9,  1): 15,
    (5,  9, -1): 16,
    (5, 10,  1): 17,
    (5, 10, -1): 18,
    (5, 11,  1): 19,
    (5, 11, -1): 20,
    (5, 12,  0): 21,
    (5, 13,  1): 22,
    (5, 13, -1): 23,
    (5, 14,  1): 24,
    (5, 14, -1): 25,
    (5, 15,  0): 26,
    (5, 16,  1): 27,
    (5, 16, -1): 28,
    (5, 17,  0): 29,
    (5, 18,  1): 30,
    (5, 18, -1): 31,
    (5, 19,  1): 32,
    (5, 19, -1): 33,
    (5, 20,  1): 34,
    (5, 20, -1): 35,
    (5, 21,  1): 36,
    (5, 21, -1): 37,
    (5, 22,  0): 38,
    (5, 23,  1): 39,
    (5, 23, -1): 40,
    (5, 24,  1): 41,
    (5, 24, -1): 42,
    (5, 25,  1): 43,
    (5, 25, -1): 44,
    (5, 26,  1): 45,
    (5, 26, -1): 46,
    (5, 27,  1): 47,
    (5, 27, -1): 48,
    (5, 28,  1): 49,
    (5, 28, -1): 50,
    (5, 29,  1): 51,
    (5, 29, -1): 52,
    (5, 30,  1): 53,
    (5, 30, -1): 54,
    (5, 31,  1): 55,
    (5, 31, -1): 56,
    (5, 32,  1): 57,
    (5, 32, -1): 58,
    (5, 33,  0): 59,
    (5, 34,  0): 60,
    (5, 35,  0): 61,
    (5, 36,  1): 62,
    (5, 36, -1): 63,
    (5, 37,  0): 64,
    (5, 38,  1): 65,
    (5, 38, -1): 66,
    (6,  1,  0):  1,
    (6,  2,  1):  2,
    (6,  2, -1):  3,
    (6,  3,  1):  4,
    (6,  3, -1):  5,
    (6,  4,  0):  6,
    (6,  5,  1):  7,
    (6,  5, -1):  8,
    (6,  6,  0):  9,
    (6,  7,  0): 10,
    (6,  8,  0): 11,
    (6,  9,  1): 12,
    (6,  9, -1): 13,
    (6, 10,  1): 14,
    (6, 10, -1): 15,
    (6, 11,  1): 16,
    (6, 11, -1): 17,
    (6, 12,  1): 18,
    (6, 12, -1): 19,
    (6, 13,  0): 20,
    (6, 14,  1): 21,
    (6, 14, -1): 22,
    (6, 15,  1): 23,
    (6, 15, -1): 24,
    (6, 16,  1): 25,
    (6, 16, -1): 26,
    (6, 17,  1): 27,
    (6, 17, -1): 28,
    (6, 18,  1): 29,
    (6, 18, -1): 30,
    (6, 19,  1): 31,
    (6, 19, -1): 32,
    (6, 20,  0): 33,
    (6, 21,  1): 34,
    (6, 21, -1): 35,
    (6, 22,  1): 36,
    (6, 22, -1): 37,
    (6, 23,  0): 38,
    (6, 24,  1): 39,
    (6, 24, -1): 40,
    (6, 25,  1): 41,
    (6, 25, -1): 42,
    (6, 26,  0): 43,
    (6, 27,  1): 44,
    (6, 27, -1): 45,
    (6, 28,  0): 46,
    (6, 29,  0): 47,
    (6, 30,  1): 48,
    (6, 30, -1): 49,
    (6, 31,  1): 50,
    (6, 31, -1): 51,
    (6, 32,  0): 52,
    (6, 33,  1): 53,
    (6, 33, -1): 54,
    (6, 34,  1): 55,
    (6, 34, -1): 56,
    (6, 35,  0): 57,
    (6, 36,  1): 58,
    (6, 36, -1): 59,
    (6, 37,  0): 60,
    (6, 38,  0): 61,
    (6, 39,  1): 62,
    (6, 39, -1): 63,
    (6, 40,  1): 64,
    (6, 40, -1): 65,
    (6, 41,  1): 66,
    (6, 41, -1): 67,
    (6, 42,  0): 68,
    (6, 43,  1): 69,
    (6, 43, -1): 70,
    (6, 44,  1): 71,
    (6, 44, -1): 72,
    (6, 45,  0): 73,
    (6, 46,  1): 74,
    (6, 46, -1): 75,
    (6, 47,  1): 76,
    (6, 47, -1): 77,
    (6, 48,  0): 78,
    (6, 49,  0): 79,
    (6, 50,  0): 80,
    (7,  1,  0):  1,
    (7,  2,  1):  2,
    (7,  2, -1):  3,
    (7,  3,  1):  4,
    (7,  3, -1):  5,
    (7,  4,  1):  6,
    (7,  4, -1):  7,
    (7,  5,  1):  8,
    (7,  5, -1):  9,
    (7,  6,  1): 10,
    (7,  6, -1): 11,
    (7,  7,  1): 12,
    (7,  7, -1): 13,
    (7,  8,  0): 14,
    (7,  9,  1): 15,
    (7,  9, -1): 16,
    (7, 10,  1): 17,
    (7, 10, -1): 18,
    (7, 11,  1): 19,
    (7, 11, -1): 20,
    (7, 12,  0): 21,
    (7, 13,  1): 22,
    (7, 13, -1): 23,
    (7, 14,  1): 24,
    (7, 14, -1): 25,
    (7, 15,  0): 26,
    (7, 16,  1): 27,
    (7, 16, -1): 28,
    (7, 17,  0): 29,
    (7, 18,  1): 30,
    (7, 18, -1): 31,
    (7, 19,  1): 32,
    (7, 19, -1): 33,
    (7, 20,  1): 34,
    (7, 20, -1): 35,
    (7, 21,  1): 36,
    (7, 21, -1): 37,
    (7, 22,  0): 38,
    (7, 23,  1): 39,
    (7, 23, -1): 40,
    (7, 24,  1): 41,
    (7, 24, -1): 42,
    (7, 25,  1): 43,
    (7, 25, -1): 44,
    (7, 26,  1): 45,
    (7, 26, -1): 46,
    (7, 27,  1): 47,
    (7, 27, -1): 48,
    (7, 28,  1): 49,
    (7, 28, -1): 50,
    (7, 29,  1): 51,
    (7, 29, -1): 52,
    (7, 30,  1): 53,
    (7, 30, -1): 54,
    (7, 31,  1): 55,
    (7, 31, -1): 56,
    (7, 32,  1): 57,
    (7, 32, -1): 58,
    (7, 33,  0): 59,
    (7, 34,  0): 60,
    (7, 35,  0): 61,
    (7, 36,  1): 62,
    (7, 36, -1): 63,
    (7, 37,  0): 64,
    (7, 38,  1): 65,
    (7, 38, -1): 66,
    (8,  1,  0):  1,
    (8,  2,  1):  2,
    (8,  2, -1):  3,
    (8,  3,  0):  4,
    (8,  4,  1):  5,
    (8,  4, -1):  6,
    (8,  5,  1):  7,
    (8,  5, -1):  8,
    (8,  6,  0):  9,
    (8,  7,  0): 10,
    (8,  8,  0): 11,
    (8,  9,  0): 12,
    (8, 10,  0): 13,
    (8, 11,  1): 14,
    (8, 11, -1): 15,
    (8, 12,  1): 16,
    (8, 12, -1): 17,
    (8, 13,  1): 18,
    (8, 13, -1): 19,
    (8, 14,  1): 20,
    (8, 14, -1): 21,
    (8, 15,  1): 22,
    (8, 15, -1): 23,
    (8, 16,  1): 24,
    (8, 16, -1): 25,
    (8, 17,  0): 26,
    (8, 18,  1): 27,
    (8, 18, -1): 28,
    (8, 19,  1): 29,
    (8, 19, -1): 30,
    (8, 20,  0): 31,
    (8, 21,  0): 32,
    (8, 22,  1): 33,
    (8, 22, -1): 34,
    (8, 23,  0): 35,
    (8, 24,  0): 36,
    (8, 25,  0): 37,
    (8, 26,  0): 38,
    (8, 27,  1): 39,
    (8, 27, -1): 40,
    (8, 28,  0): 41,
    (8, 29,  1): 42,
    (8, 29, -1): 43,
    (9,  1,  0):  1,
    (9,  2,  1):  2,
    (9,  2, -1):  3,
    (9,  3,  1):  4,
    (9,  3, -1):  5,
    (9,  4,  1):  6,
    (9,  4, -1):  7,
    (9,  5,  1):  8,
    (9,  5, -1):  9,
    (9,  6,  0): 10,
    (9,  7,  1): 11,
    (9,  7, -1): 12,
    (9,  8,  1): 13,
    (9,  8, -1): 14,
    (9,  9,  0): 15,
    (9, 10,  0): 16,
    (9, 11,  1): 17,
    (9, 11, -1): 18,
    (9, 12,  0): 19,
    (10, 1,  0): 1,
    (10, 2,  0): 2,
    (10, 3,  0): 3,
    (10, 4,  0): 4,
    (10, 5,  0): 5,
    (10, 6,  0): 6,
    (11, 1,  0): 1,
    (12, 1,  0): 1,
}


# ----------------------------------------------------------------||||||||||||--
# reference dict stores name and citation references

# names found from many sources, including:
# http://solo1.home.mindspring.com/pcsets.htm
# Larry Solomon, 1997, 2000
# Larry Solomon's 'The List of Chords, Their Properties and Use in Analysis,'
# in Interface, Journal of New Music Research , 1982, v11/2.
# http://www.sweb.cz/vladimir_ladma/english/music/structs/mus_rot.htm
# Vladimir Ladma, Czech Republic

# some changes:
# unison preferred to monad
# v7.3 -- Roma preferred.  Gypsy only in parentheses.
#      TODO: more removing and/or de-emphasizing of ethnic-stereotype names.

tnIndexToChordInfo = {
    # Cardinality 1
    (1,  1,  0): {'name': ('unison',
                           'monad',
                           'singleton')},
    # Cardinality 2
    (2,  1,  0): {'name': ('interval class 1',
                           'minor second',
                           'm2',
                           'half step',
                           'semitone')},
    (2,  2,  0): {'name': ('interval class 2',
                           'major second',
                           'M2',
                           'whole step',
                           'whole tone')},
    (2,  3,  0): {'name': ('interval class 3',
                           'minor third',
                           'm3',)},
    (2,  4,  0): {'name': ('interval class 4',
                           'major third',
                           'M3')},
    (2,  5,  0): {'name': ('interval class 5',
                           'perfect fourth',
                           'P4')},
    (2,  6,  0): {'name': ('tritone',
                           'diminished fifth',
                           'augmented fourth')},

    # Cardinality 3
    (3,  1,  0): {'name': ('chromatic trimirror',)},
    (3,  2,  1): {'name': ('phrygian trichord',)},
    (3,  2, -1): {'name': ('minor trichord',)},
    (3,  3,  1): {'name': ('major-minor trichord',)},
    (3,  3, -1): {'name': ('major-minor trichord',)},
    (3,  4,  1): {'name': ('incomplete major-seventh chord',)},
    (3,  4, -1): {'name': ('incomplete major-seventh chord',)},
    (3,  5,  1): {'name': ('tritone-fourth',)},
    (3,  5, -1): {'name': ('tritone-fourth',)},
    (3,  6,  0): {'name': ('whole-tone trichord',)},
    (3,  7,  1): {'name': ('incomplete minor-seventh chord',)},
    (3,  7, -1): {'name': ('incomplete dominant-seventh chord',)},
    (3,  8,  1): {'name': ('incomplete dominant-seventh chord',
                           'Italian augmented sixth chord')},
    (3,  8, -1): {'name': ('incomplete half-diminished seventh chord',)},
    (3,  9,  0): {'name': ('quartal trichord',)},
    (3, 10,  0): {'name': ('diminished triad',)},
    (3, 11,  1): {'name': ('minor triad',)},
    (3, 11, -1): {'name': ('major triad',)},
    (3, 12,  0): {'name': ('augmented triad',
                           'equal 3-part octave division')},

    # Cardinality 4
    (4,  1,  0): {'name': ('chromatic tetramirror',
                           'BACH')},
    (4,  2,  1): {'name': ('major-second tetracluster', )},
    (4,  2, -1): {'name': ('major-second tetracluster', )},
    (4,  3,  0): {'name': ('alternating tetramirror',)},
    (4,  4,  1): {'name': ('minor third tetracluster',)},
    (4,  4, -1): {'name': ('minor third tetracluster',)},
    (4,  5,  1): {'name': ('major third tetracluster',)},
    (4,  5, -1): {'name': ('major third tetracluster',)},
    (4,  6,  0): {'name': ('perfect fourth tetramirror',)},
    (4,  7,  0): {'name': ('Arabian tetramirror',)},
    (4,  8,  0): {'name': ('double-fourth tetramirror',)},
    (4,  9,  0): {'name': ('double tritone tetramirror',)},
    (4, 10,  0): {'name': ('minor tetramirror',)},
    (4, 11,  1): {'name': ('phrygian tetrachord',)},
    (4, 11, -1): {'name': ('lydian tetrachord', 'major tetrachord')},
    (4, 12,  1): {'name': ('harmonic minor tetrachord',)},
    (4, 12, -1): {'name': ('major-third diminished tetrachord',)},
    (4, 13,  1): {'name': ('minor-second diminished tetrachord',)},
    (4, 13, -1): {'name': ('perfect-fourth diminished tetrachord',)},
    (4, 14,  1): {'name': ('major-second minor tetrachord',)},
    (4, 14, -1): {'name': ('perfect-fourth major tetrachord',)},
    (4, 15,  1): {'name': ('all-interval tetrachord',)},
    (4, 15, -1): {'name': ('all-interval tetrachord',)},
    (4, 16,  1): {'name': ('minor-second quartal tetrachord',)},
    (4, 16, -1): {'name': ('tritone quartal tetrachord',)},
    (4, 17,  0): {'name': ('major-minor tetramirror',)},
    (4, 18,  1): {'name': ('major-diminished tetrachord',)},
    (4, 18, -1): {'name': ('minor-diminished tetrachord',)},
    (4, 19,  1): {'name': ('minor-augmented tetrachord',)},
    (4, 19, -1): {'name': ('augmented major tetrachord',)},
    (4, 20,  0): {'name': ('major seventh chord',)},
    (4, 21,  0): {'name': ('whole-tone tetramirror',)},
    (4, 22,  1): {'name': ('major-second major tetrachord',)},
    (4, 22, -1): {'name': ('perfect-fourth minor tetrachord',)},
    (4, 23,  0): {'name': ('quartal tetramirror',)},
    (4, 24,  0): {'name': ('augmented seventh chord',)},
    (4, 25,  0): {'name': ("Messiaen's truncated mode 6",
                           'French augmented sixth chord')},
    (4, 26,  0): {'name': ('minor seventh chord',)},
    (4, 27,  1): {'name': ('half-diminished seventh chord',)},
    (4, 27, -1): {'name': ('dominant seventh chord',
                           'major minor seventh chord',
                           'German augmented sixth chord',
                           'Swiss augmented sixth chord')},
    (4, 28,  0): {'name': ('diminished seventh chord',
                           'equal 4-part octave division')},
    (4, 29,  1): {'name': ('all-interval tetrachord',)},
    (4, 29, -1): {'name': ('all-interval tetrachord',)},

    # Cardinality 5
    (5,  1,  0): {'name': ('chromatic pentamirror',)},
    (5,  2,  1): {'name': ('major-second pentacluster',)},
    (5,  2, -1): {'name': ('major-second pentacluster',)},
    (5,  3,  1): {'name': ('minor-second major pentachord',)},
    (5,  3, -1): {'name': ('Spanish pentacluster',)},
    (5,  4,  1): {'name': ('blues pentacluster',)},
    (5,  4, -1): {'name': ('minor-third pentacluster',)},
    (5,  5,  1): {'name': ('major-third pentacluster',)},
    (5,  5, -1): {'name': ('major-third pentacluster',)},
    (5,  6,  1): {'name': ('Asian pentacluster',
                           'quasi raga Megharanji')},
    (5,  6, -1): {'name': ('Asian pentacluster',)},
    (5,  7,  1): {'name': ('double pentacluster',
                           'quasi raga Nabhomani')},
    (5,  7, -1): {'name': ('double pentacluster',)},
    (5,  8,  0): {'name': ('tritone-symmetric pentamirror',)},
    (5,  9,  1): {'name': ('tritone-expanding pentachord',)},
    (5,  9, -1): {'name': ('tritone-contracting pentachord',)},
    (5, 10,  1): {'name': ('alternating pentachord',)},
    (5, 10, -1): {'name': ('alternating pentachord',)},
    (5, 11,  1): {'name': ('center-cluster pentachord',)},
    (5, 11, -1): {'name': ('center-cluster pentachord',)},
    (5, 12,  0): {'name': ('locrian pentachord',)},
    (5, 13,  1): {'name': ('augmented pentacluster',)},
    (5, 13, -1): {'name': ('augmented pentacluster',)},
    (5, 14,  1): {'name': ('double-seconds triple-fourth pentachord',)},
    (5, 14, -1): {'name': ('double-seconds triple-fourth pentachord',)},
    (5, 15,  0): {'name': ('asymmetric pentamirror',)},
    (5, 16,  1): {'name': ('major-minor-diminished pentachord',)},
    (5, 16, -1): {'name': ('major-minor diminished pentachord',)},
    (5, 17,  0): {'name': ('minor-major ninth chord',)},
    (5, 18,  1): {'name': ('Roma (Gypsy) pentachord',)},
    (5, 18, -1): {'name': ('Roma (Gypsy) pentachord',)},
    (5, 19,  1): {'name': ('Javanese pentachord',)},
    (5, 19, -1): {'name': ('Balinese pentachord',)},
    (5, 20,  1): {'name': ('Balinese Pelog pentatonic',
                           'quasi raga Bhupala',
                           'quasi raga Bibhas')},
    (5, 20, -1): {'name': ('Hirajoshi pentatonic',
                           'Iwato',
                           'Sakura',
                           'quasi raga Saveri')},
    (5, 21,  1): {'name': ('major-augmented ninth chord',
                           'Syrian pentatonic',
                           'quasi raga Megharanji')},
    (5, 21, -1): {'name': ('Lebanese pentachord',
                           'augmented-minor chord')},
    (5, 22,  0): {'name': ('Persian pentamirror',
                           'quasi raga Ramkali')},
    (5, 23,  1): {'name': ('dorian pentachord',
                           'minor pentachord')},
    (5, 23, -1): {'name': ('major pentachord',)},
    (5, 24,  1): {'name': ('phrygian pentachord',)},
    (5, 24, -1): {'name': ('lydian pentachord',)},
    (5, 25,  1): {'name': ('diminished-major ninth chord',)},
    (5, 25, -1): {'name': ('minor-diminished ninth chord',)},
    (5, 26,  1): {'name': ('diminished-augmented ninth chord',)},
    (5, 26, -1): {'name': ('augmented-diminished ninth chord',)},
    (5, 27,  1): {'name': ('major-ninth chord',)},
    (5, 27, -1): {'name': ('minor-ninth chord',)},
    (5, 28,  1): {'name': ('augmented-sixth pentachord',)},
    (5, 28, -1): {'name': ('Javanese pentatonic',
                           'augmented-sixth pentachord')},
    (5, 29,  1): {'name': ('Kumoi pentachord',)},
    (5, 29, -1): {'name': ('Kumoi pentachord',)},
    (5, 30,  1): {'name': ('enigmatic pentachord',)},
    (5, 30, -1): {'name': ('enigmatic pentachord',
                           'altered pentatonic')},
    (5, 31,  1): {'name': ('diminished minor-ninth chord',)},
    (5, 31, -1): {'name': ('flat-ninth pentachord',
                           'quasi raga Ranjaniraga')},
    (5, 32,  1): {'name': ('Neapolitan pentachord',)},
    (5, 32, -1): {'name': ('Neapolitan pentachord',)},
    (5, 33,  0): {'name': ('whole-tone pentachord',)},
    (5, 34,  0): {'name': ('dominant-ninth',
                           'major-minor',
                           'Prometheus pentamirror',
                           'dominant pentatonic')},
    (5, 35,  0): {'name': ('major pentatonic',
                           'black-key scale',
                           'blues pentatonic',
                           'slendro',
                           'quartal pentamirror')},
    (5, 36,  1): {'name': ('major-seventh pentacluster',)},
    (5, 36, -1): {'name': ('minor-seventh pentacluster',)},
    (5, 37,  0): {'name': ('center-cluster pentamirror',)},
    (5, 38,  1): {'name': ('diminished pentacluster',)},
    (5, 38, -1): {'name': ('diminished pentacluster',)},

    # Cardinality 6
    (6,  1,  0): {'name': ('A all combinatorial (P6, I11, RI5, RI11)',
                           'chromatic hexamirror',
                           'first-order all-combinatorial')},
    (6,  2,  1): {'name': ('combinatorial I (I11)',)},
    (6,  2, -1): {'name': ('combinatorial I (I1)',)},
    (6,  3,  1): {},
    (6,  3, -1): {},
    (6,  4,  0): {'name': ('combinatorial RI (RI6)',)},
    (6,  5,  1): {'name': ('combinatorial I (I11)',)},
    (6,  5, -1): {'name': ('combinatorial I (I3)',)},
    (6,  6,  0): {'name': ('double cluster hexamirror',)},
    (6,  7,  0): {'name': ('B all combinatorial (P3, P9, I5, R6, R12, R8)',
                           "Messiaen's mode 5",
                           'second-order all combinatorial')},
    (6,  8,  0): {'name': ('D all combinatorial (P6, I1, RI7)',)},
    (6,  9,  1): {'name': ('combinatorial I (I11)',)},
    (6,  9, -1): {'name': ('combinatorial I (I3)',)},
    (6, 10,  1): {},
    (6, 10, -1): {},
    (6, 11,  1): {},
    (6, 11, -1): {},
    (6, 12,  1): {},
    (6, 12, -1): {},
    (6, 13,  0): {'name': ('alternating hexamirror',
                           'combinatorial I (I7)')},
    (6, 14,  1): {'name': ('combinatorial P (P6)',)},
    (6, 14, -1): {'name': ('combinatorial P (P6)',)},
    (6, 15,  1): {'name': ('combinatorial I (I11)',)},
    (6, 15, -1): {'name': ('combinatorial I (I5)',)},
    (6, 16,  1): {'name': ('combinatorial I (I3)',)},
    (6, 16, -1): {'name': ('combinatorial I (I1)',
                           'quasi raga Megha')},
    (6, 17,  1): {'name': ('all tri-chord hexachord',)},
    (6, 17, -1): {'name': ('all tri-chord hexachord (inverted form)',)},
    (6, 18,  1): {'name': ('combinatorial I (I11)',)},
    (6, 18, -1): {'name': ('combinatorial I (I5)',)},
    (6, 19,  1): {},
    (6, 19, -1): {},
    (6, 20,  0): {'name': ('E all combinatorial (P2, P6, P10, I3, I7, R4, R8, RI1, RI5, RI9)',
                           "Messiaen's truncated mode 3",
                           'Genus tertium',
                           'third-order all combinatorial')},
    (6, 21,  1): {'name': ('combinatorial I (I1)',)},
    (6, 21, -1): {'name': ('combinatorial I (I3)',)},
    (6, 22,  1): {'name': ('combinatorial I (I11)',)},
    (6, 22, -1): {'name': ('combinatorial I (I5)',)},
    (6, 23,  0): {'name': ('combinatorial RI (RI8)',
                           'super-locrian hexamirror')},
    (6, 24,  1): {},
    (6, 24, -1): {'name': ('melodic-minor hexachord',)},
    (6, 25,  1): {'name': ('locrian hexachord',)},
    (6, 25, -1): {'name': ('minor hexachord',)},
    (6, 26,  0): {'name': ('phrygian hexamirror',
                           'combinatorial RI (RI8)')},
    (6, 27,  1): {'name': ('combinatorial I (I11)',)},
    (6, 27, -1): {'name': ('combinatorial I (I1)',
                           'pyramid hexachord')},
    (6, 28,  0): {'name': ('double-phrygian hexachord',
                           'combinatorial RI (RI6)')},
    (6, 29,  0): {'name': ('combinatorial RI (RI9)',)},
    (6, 30,  1): {'name': ("Messiaen's truncated mode 2",
                           'minor-bitonal hexachord',
                           'combinatorial R (R6)',
                           'combinatorial I (I1, I7)')},
    (6, 30, -1): {'name': ("Stravinsky's Petrushka-chord",
                           "Messiaen's truncated mode 2",
                           'major-bitonal hexachord',
                           'combinatorial R (R6)',
                           'combinatorial I (I1, I7)')},
    (6, 31,  1): {'name': ('combinatorial I (I7)',)},
    (6, 31, -1): {'name': ('combinatorial I (I11)',)},
    (6, 32,  0): {'name': ('Guidonian hexachord',
                           'C all combinatorial (P6, I3, RI9)',
                           'major hexamirror',
                           'quartal hexamirror',
                           'first-order all combinatorial')},
    (6, 33,  1): {'name': ('dorian hexachord',
                           'combinatorial I (I6)')},
    (6, 33, -1): {'name': ('dominant-eleventh',
                           'lydian hexachord',
                           'combinatorial I (I1)')},
    (6, 34,  1): {'name': ("Scriabin's Mystic-chord",
                           'Prometheus hexachord',
                           'combinatorial I (I11)')},
    (6, 34, -1): {'name': ('augmented-eleventh',
                           'harmonic hexachord',
                           'combinatorial I (I7)')},
    (6, 35,  0): {'name': ('whole tone scale',
                           '6 equal part division',
                           'F all-combinatorial (P1, P3, P5, P7, P9, P11, I1, I3, I5, I7, '
                              + 'I9, I11, R2, R4, R6, R8, R10, RI2, RI4, RI6, RI8, RI10)',
                           "Messiaen's mode 1",
                           'sixth-order all combinatorial')},
    (6, 36,  1): {},
    (6, 36, -1): {},
    (6, 37,  0): {'name': ('combinatorial RI (RI4)',)},
    (6, 38,  0): {'name': ('combinatorial RI (RI3)',)},
    (6, 39,  1): {},
    (6, 39, -1): {},
    (6, 40,  1): {},
    (6, 40, -1): {},
    (6, 41,  1): {},
    (6, 41, -1): {},
    (6, 42,  0): {'name': ('combinatorial RI (RI3)',)},
    (6, 43,  1): {'name': ('complement of all tri-chord hexachord',)},
    (6, 43, -1): {'name': ('complement of all-tri-chord hexachord (inverted form)',)},
    (6, 44,  1): {'name': ('Schoenberg Anagram hexachord',)},
    (6, 44, -1): {'name': ('quasi raga Bauli',)},
    (6, 45,  0): {'name': ('combinatorial RI (RI6)',)},
    (6, 46,  1): {},
    (6, 46, -1): {},
    (6, 47,  1): {},
    (6, 47, -1): {'name': ('blues scale',)},
    (6, 48,  0): {'name': ('combinatorial RI (RI2)',)},
    (6, 49,  0): {'name': ('combinatorial RI (RI4)', 'Prometheus Neapolitan mode')},
    (6, 50,  0): {'name': ('combinatorial RI (RI1)',)},

    # Cardinality 7
    (7,  1,  0): {'name': ('chromatic heptamirror',)},
    (7,  2,  1): {},
    (7,  2, -1): {},
    (7,  3,  1): {},
    (7,  3, -1): {},
    (7,  4,  1): {},
    (7,  4, -1): {},
    (7,  5,  1): {},
    (7,  5, -1): {},
    (7,  6,  1): {},
    (7,  6, -1): {},
    (7,  7,  1): {},
    (7,  7, -1): {},
    (7,  8,  0): {},
    (7,  9,  1): {},
    (7,  9, -1): {},
    (7, 10,  1): {},
    (7, 10, -1): {},
    (7, 11,  1): {},
    (7, 11, -1): {},
    (7, 12,  0): {},
    (7, 13,  1): {},
    (7, 13, -1): {},
    (7, 14,  1): {},
    (7, 14, -1): {},
    (7, 15,  0): {},
    (7, 16,  1): {'name': ("Debussy's heptatonic",)},
    (7, 16, -1): {},
    (7, 17,  0): {},
    (7, 18,  1): {},
    (7, 18, -1): {},
    (7, 19,  1): {},
    (7, 19, -1): {},
    (7, 20,  1): {'name': ('chromatic phrygian inverse',)},
    (7, 20, -1): {'name': ('Greek chromatic',
                           'chromatic mixolydian',
                           'chromatic dorian',
                           'quasi raga Pantuvarali',
                           'mela Kanakangi')},
    (7, 21,  1): {},
    (7, 21, -1): {'name': ('Roma (Gypsy) hepatonic',)},
    (7, 22,  0): {'name': ('double harmonic scale',
                           'major Roma (Gypsy)',
                           'Hungarian minor',
                           'double harmonic scale',
                           'quasi raga Mayamdavagaula')},
    (7, 23,  1): {},
    (7, 23, -1): {'name': ('tritone major heptachord',)},
    (7, 24,  1): {},
    (7, 24, -1): {'name': ('mystic heptachord',
                           'Enigmatic heptatonic')},
    (7, 25,  1): {},
    (7, 25, -1): {},
    (7, 26,  1): {},
    (7, 26, -1): {},
    (7, 27,  1): {},
    (7, 27, -1): {'name': ('modified blues',)},
    (7, 28,  1): {},
    (7, 28, -1): {},
    (7, 29,  1): {},
    (7, 29, -1): {},
    (7, 30,  1): {'name': ('Neapolitan-minor mode',)},
    (7, 30, -1): {},
    (7, 31,  1): {'name': ('alternating heptachord',
                           'Hungarian major mode')},
    (7, 31, -1): {'name': ('diminished scale',
                           'alternating heptachord')},
    (7, 32,  1): {'name': ('harmonic minor scale',
                           'harmonic minor collection',
                           'Spanish Roma (Gypsy)',
                           'mela Kiravani')},
    (7, 32, -1): {'name': ('harmonic major scale (inverted)',
                           'harmonic minor collection (inverted)',
                           'mela Cakravana',
                           'quasi raga Ahir Bhairav')},
    (7, 33,  0): {'name': ('Neapolitan-major mode',
                           'leading-whole-tone mode')},
    (7, 34,  0): {'name': ('melodic minor ascending scale',
                           'jazz minor',
                           'augmented thirteenth heptamirror',
                           'harmonic/super-locrian')},
    (7, 35,  0): {'name': ('major scale',
                           'major diatonic heptachord',
                           'natural minor scale',
                           'dominant thirteenth',
                           'locrian',
                           'phrygian',
                           'major inverse')},
    (7, 36,  1): {},
    (7, 36, -1): {},
    (7, 37,  0): {},
    (7, 38,  1): {},
    (7, 38, -1): {},

    # Cardinality 8
    (8,  1,  0): {'name': ('chromatic octamirror',)},
    (8,  2,  1): {},
    (8,  2, -1): {},
    (8,  3,  0): {},
    (8,  4,  1): {},
    (8,  4, -1): {},
    (8,  5,  1): {},
    (8,  5, -1): {},
    (8,  6,  0): {},
    (8,  7,  0): {},
    (8,  8,  0): {},
    (8,  9,  0): {'name': ("Messiaen's mode 4",)},
    (8, 10,  0): {},
    (8, 11,  1): {},
    (8, 11, -1): {'name': ('blues octatonic',)},
    (8, 12,  1): {},
    (8, 12, -1): {},
    (8, 13,  1): {'name': ('blues octatonic',)},
    (8, 13, -1): {},
    (8, 14,  1): {},
    (8, 14, -1): {},
    (8, 15,  1): {},
    (8, 15, -1): {},
    (8, 16,  1): {},
    (8, 16, -1): {'name': ('enigmatic octachord',)},
    (8, 17,  0): {},
    (8, 18,  1): {},
    (8, 18, -1): {},
    (8, 19,  1): {},
    (8, 19, -1): {},
    (8, 20,  0): {},
    (8, 21,  0): {},
    (8, 22,  1): {},
    (8, 22, -1): {'name': ('Spanish octatonic scale',)},
    (8, 23,  0): {'name': ('Greek',
                           'quartal octachord',
                           'diatonic octad',)},
    (8, 24,  0): {},
    (8, 25,  0): {'name': ("Messiaen's mode 6",)},
    (8, 26,  0): {'name': ('Spanish phrygian',
                           'blues',)},
    (8, 27,  1): {},
    (8, 27, -1): {},
    (8, 28,  0): {'name': ('octatonic scale',
                           "Messiaen's mode 2",
                           'alternating octatonic scale',
                           'diminished scale')},
    (8, 29,  1): {},
    (8, 29, -1): {},

    # Cardinality 9
    (9,  1,  0): {'name': ('chromatic nonamirror',)},
    (9,  2,  1): {},
    (9,  2, -1): {},
    (9,  3,  1): {},
    (9,  3, -1): {},
    (9,  4,  1): {},
    (9,  4, -1): {},
    (9,  5,  1): {},
    (9,  5, -1): {},
    (9,  6,  0): {},
    (9,  7,  1): {'name': ('nonatonic blues',)},
    (9,  7, -1): {},
    (9,  8,  1): {},
    (9,  8, -1): {},
    (9,  9,  0): {},
    (9, 10,  0): {},
    (9, 11,  1): {},
    (9, 11, -1): {'name': ('diminishing nonachord',)},
    (9, 12,  0): {'name': ("Messiaen's mode 3",
                           'Tsjerepnin')},

    # Cardinality 10
    (10, 1,  0): {'name': ('chromatic decamirror',)},
    (10, 2,  0): {},
    (10, 3,  0): {},
    (10, 4,  0): {},
    (10, 5,  0): {'name': ('major-minor mixed',)},
    (10, 6,  0): {'name': ("Messiaen's mode 7",)},

    # Cardinality 11
    (11, 1,  0): {'name': ('chromatic undecamirror',)},

    # Cardinality 12
    (12, 1,  0): {'name': ('aggregate',
                           'dodecachord',
                           'twelve-tone chromatic',
                           'chromatic scale',
                           'dodecamirror')},}

# ------------------------------------------------------------------------------
# function to access data

def forteIndexToInversionsAvailable(card, index):
    '''
    Return possible inversion values for any cardinality and Forte index

    >>> chord.tables.forteIndexToInversionsAvailable(3, 1)
    [0]
    >>> chord.tables.forteIndexToInversionsAvailable(3, 2)
    [-1, 1]
    >>> chord.tables.forteIndexToInversionsAvailable(3, 3)
    [-1, 1]
    >>> chord.tables.forteIndexToInversionsAvailable(3, 6)
    [0]
    >>> chord.tables.forteIndexToInversionsAvailable(3, 12)
    [0]
    '''
    if card not in list(range(1,13)):
        raise ChordTablesException(f'cardinality {card} not valid')
    if index < 1 or index > maximumIndexNumberWithoutInversionEquivalence[card]:
        raise ChordTablesException(f'index {index} not valid')
    # get morris invariance vector
    morris = FORTE[card][index][2]
    if morris[1] > 0:  # second value stored inversion status
        return [0]
    else:
        return [-1, 1]

def _validateAddress(address):
    '''
    Check that an address is valid

    >>> chord.tables._validateAddress((3, 1, 0))
    (3, 1, 0)
    >>> chord.tables._validateAddress((2, 3))
    (2, 3, 0)
    >>> chord.tables._validateAddress((3, 12, None))
    (3, 12, 0)
    >>> chord.tables._validateAddress((3, 12))
    (3, 12, 0)

    >>> chord.tables._validateAddress((20, 1, 0))
    Traceback (most recent call last):
    music21.chord.tables.ChordTablesException: cardinality 20 not valid

    >>> chord.tables._validateAddress((8, 3000, 0))
    Traceback (most recent call last):
    music21.chord.tables.ChordTablesException: index 3000 not valid

    >>> chord.tables._validateAddress((8, 3, -30))
    Traceback (most recent call last):
    music21.chord.tables.ChordTablesException: inversion -30 not valid
    '''
    address = list(address)
    card = address[0]
    index = address[1]
    if len(address) >= 3:
        inversion = address[2]
    else:
        inversion = None

    if card not in list(range(1,13)):
        raise ChordTablesException(f'cardinality {card} not valid')

    # using TN mode for all comparisons
    if index < 1 or index > maximumIndexNumberWithoutInversionEquivalence[card]:
        raise ChordTablesException(f'index {index} not valid')

    inversionsAvailable = forteIndexToInversionsAvailable(card, index)
    if inversion is not None:
        if inversion not in inversionsAvailable:
            raise ChordTablesException(f'inversion {inversion} not valid')

    if inversion is None:  # get a default inversion
        # environLocal.printDebug(['getting inversion for:', card, index])
        if 0 in inversionsAvailable:
            inversion = 0
        else:
            inversion = 1

    # test access: will raise an exception on error
    # ultimately this can be removed
    # try:
    #     nfSet = cardinalityToChordMembers[card][(index, inversion)][0]
    # except KeyError:
    #     raise ChordTablesException('cannot validate address: %s' % address)

    return (card, index, inversion)


def addressToTransposedNormalForm(address):
    '''
    Given a TN address, return the normal form transposed to start on 0.

    >>> chord.tables.addressToTransposedNormalForm((3, 1, 0))
    (0, 1, 2)
    >>> chord.tables.addressToTransposedNormalForm((3, 11, -1))
    (0, 4, 7)
    >>> chord.tables.addressToTransposedNormalForm((3, 11, 1))
    (0, 3, 7)

    If the inversion in the address is omitted or None,
    then the default inversion is used:

    >>> chord.tables.addressToTransposedNormalForm((3, 11))
    (0, 3, 7)
    >>> chord.tables.addressToTransposedNormalForm((3, 11, None))
    (0, 3, 7)
    >>> chord.tables.addressToTransposedNormalForm((3, 1))
    (0, 1, 2)
    '''
    card, index, inversion = _validateAddress(address)
    return cardinalityToChordMembers[card][(index, inversion)][0]


def addressToPrimeForm(address):
    '''
    Given a TN address, return the prime form

    >>> chord.tables.addressToPrimeForm((3, 1, 0))
    (0, 1, 2)

    Since we are talking about primeForm, inversion does not matter.
    These both return the minor triad.

    >>> chord.tables.addressToPrimeForm((3, 11, -1))
    (0, 3, 7)
    >>> chord.tables.addressToPrimeForm((3, 11, 1))
    (0, 3, 7)

    If inversion is omitted or None the default value is used:

    >>> chord.tables.addressToPrimeForm((3, 11))
    (0, 3, 7)
    >>> chord.tables.addressToPrimeForm((3, 11, None))
    (0, 3, 7)
    '''
    # overriding inversion with None will always return prime form
    card, index, inversion = _validateAddress(address[0:2])
    return cardinalityToChordMembers[card][(index, inversion)][0]


def addressToIntervalVector(address):
    '''
    Given a TN address, return the interval class vector as a 6-tuple

    >>> chord.tables.addressToIntervalVector((3, 1, 0))
    (2, 1, 0, 0, 0, 0)
    >>> chord.tables.addressToIntervalVector((3, 11, -1))
    (0, 0, 1, 1, 1, 0)
    >>> chord.tables.addressToIntervalVector((3, 11, 1))
    (0, 0, 1, 1, 1, 0)

    Inversion can be omitted or None without causing an error (or, of course,
    changing the output)

    >>> chord.tables.addressToIntervalVector((4, 29))
    (1, 1, 1, 1, 1, 1)
    >>> chord.tables.addressToIntervalVector((3, 11, None))
    (0, 0, 1, 1, 1, 0)
    '''
    card, index, inversion = _validateAddress(address)
    return cardinalityToChordMembers[card][(index, inversion)][2]


def intervalVectorToAddress(vector):
    '''
    Given a vector as a 6-tuple, return a list of
    ChordTableAddress namedtuples for
    all addresses that match that vector.

    >>> chord.tables.intervalVectorToAddress((7, 6, 5, 4, 4, 2))
    [ChordTableAddress(cardinality=8, forteClass=1, inversion=None, pcOriginal=None)]
    >>> chord.tables.intervalVectorToAddress((12, 12, 12, 12, 12, 6))
    [ChordTableAddress(cardinality=12, forteClass=1, inversion=None, pcOriginal=None)]

    Vector can also be a list:

    >>> chord.tables.intervalVectorToAddress([2, 2, 3, 1, 1, 1])
    [ChordTableAddress(cardinality=5, forteClass=10, inversion=None, pcOriginal=None)]

    A value that matches nothing returns an empty set.

    >>> chord.tables.intervalVectorToAddress((2, 2, 3, 1, 1, 99))
    []

    In the case of Z-related pairs, such as the all-interval tetrachord,
    more than one address will be returned.

    >>> chord.tables.intervalVectorToAddress((1, 1, 1, 1, 1, 1))
    [ChordTableAddress(cardinality=4, forteClass=15, inversion=None, pcOriginal=None),
     ChordTableAddress(cardinality=4, forteClass=29, inversion=None, pcOriginal=None)]

    If the vector does not have six elements, raises a ValueError:

    >>> chord.tables.intervalVectorToAddress([0, 2, 4])
    Traceback (most recent call last):
    ValueError: Vector must have exactly six entries
    '''
    post = []
    vector = tuple(vector)
    if len(vector) != 6:
        raise ValueError('Vector must have exactly six entries')

    for card in range(1, 13):
        for num, sc in enumerate(FORTE[card]):
            if sc is None:
                continue  # first, used for spacing
            # index 1 is the vector
            if sc[1] == vector:
                post.append(ChordTableAddress(card, num, None, None))
    return post

def addressToZAddress(address):
    '''
    Given a TN address, return the ChordTableAddress of the Z-set if one exists.
    If none exists, returns None.

    >>> chord.tables.addressToZAddress((5, 12))
    ChordTableAddress(cardinality=5, forteClass=36, inversion=1, pcOriginal=None)
    >>> chord.tables.addressToZAddress((5, 36, None))
    ChordTableAddress(cardinality=5, forteClass=12, inversion=0, pcOriginal=None)

    >>> print(chord.tables.addressToZAddress([3, 11]))
    None

    >>> chord.tables.addressToZAddress((5, 37))
    ChordTableAddress(cardinality=5, forteClass=17, inversion=0, pcOriginal=None)
    >>> chord.tables.addressToZAddress((8, 29))
    ChordTableAddress(cardinality=8, forteClass=15, inversion=1, pcOriginal=None)
    '''
    card, index, unused_inversion = _validateAddress(address)
    z = FORTE[card][index][3]
    if z == 0:
        return None
    else:
        zAddress = _validateAddress((card, z, None))
        return ChordTableAddress(*zAddress, None)

def addressToCommonNames(address):
    '''
    Given a TN address, return one or more common names if available:

    >>> chord.tables.addressToCommonNames((3, 1, 0))
    ['chromatic trimirror']

    >>> major_address = chord.tables.ChordTableAddress(3, 11, -1, 2)
    >>> chord.tables.addressToCommonNames(major_address)
    ['major triad']

    More than one name might be returned:
    >>> chord.tables.addressToCommonNames([7, 33])
    ['Neapolitan-major mode', 'leading-whole-tone mode']

    This system does not take into account spelling or inversion, so
    that the minor triad would give the same name.  The `.commonName`
    property of the `chord.Chord` object itself takes into account
    non-post-tonal spellings.

    Note that names referring to ethnic stereotypes that are not in
    common usage will be removed in music21 v8 or at any time
    thereafter without a deprecation cycle.
    Those matching this description that are still in common use will be demoted
    to the end of the list of names and may still be removed in the future.
    '''
    address = _validateAddress(address)
    refDict = tnIndexToChordInfo[address]
    if 'name' in refDict:
        return list(refDict['name'])  # convert to a list
    else:
        return None

def addressToForteName(address, classification='tn'):
    '''
    Given an address, return the set-class name as a string.  By default,
    A and B are appended to chords without inversional equivalence:

    >>> octachord_address = chord.tables.ChordTableAddress(8, 15, -1, 10)
    >>> chord.tables.addressToForteName(octachord_address)
    '8-15B'
    >>> chord.tables.addressToForteName((8, 15))
    '8-15A'

    The augmented triad is invariant under inversion, so it gets no designation:

    >>> chord.tables.addressToForteName((3, 12))
    '3-12'

    If classification is the string 'tni' then the "A" and "B" for inversions
    will be omitted.

    >>> chord.tables.addressToForteName((8, 15), 'tni')
    '8-15'
    >>> chord.tables.addressToForteName((5, 37))
    '5-37'
    '''
    card, index, inversion = _validateAddress(address)
    iStr = ''
    if classification.lower() == 'tn':
        if inversion == -1:
            iStr = 'B'
        elif inversion == 1:
            iStr = 'A'
        elif inversion == 0:
            iStr = ''
    else:  # tni, ignore inversion
        iStr = ''
    return f'{card}-{index}{iStr}'


# noinspection GrazieInspection
def seekChordTablesAddress(c):
    '''
    Utility method to return the address to the chord table; used by
    many Chord operations, such as `.primeForm`, `.normalOrder`, etc.

    Table addresses are a ChordTableAddress named-tuple giving
    the cardinality, the Forte-index-number, the inversion, and the original
    pitch class that matched (it may be arbitrary for a symmetrical chord like
    the diminished seventh chord).

    Inversion is either 0 (for symmetrical under inversion) or -1, 1

    >>> c1 = chord.Chord(['c3'])
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=1, forteClass=1, inversion=0, pcOriginal=0)

    Here the only note that is missing is A-sharp/B-flat.

    >>> c1 = chord.Chord(
    ...     ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'b']
    ...     )
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=11, forteClass=1, inversion=0, pcOriginal=11)

    The major chord is considered the inversion of the minor:

    >>> c1 = chord.Chord(['g', 'b', 'd'])
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=3, forteClass=11, inversion=-1, pcOriginal=7)

    >>> c1 = chord.Chord(['c', 'e-', 'g'])
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=3, forteClass=11, inversion=1, pcOriginal=0)

    Chords invariant under inversion give an inversion of 0.

    >>> c1 = chord.Chord(['c', 'c#', 'd#', 'e', 'f#', 'g#', 'a#'])
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=7, forteClass=34, inversion=0, pcOriginal=0)

    >>> c1 = chord.Chord(['c', 'c#', 'b'])
    >>> chord.tables.seekChordTablesAddress(c1)
    ChordTableAddress(cardinality=3, forteClass=1, inversion=0, pcOriginal=11)

    Zero-length chords raise a pitch exception:

    >>> c2 = chord.Chord()
    >>> chord.tables.seekChordTablesAddress(c2)
    Traceback (most recent call last):
    music21.chord.tables.ChordTablesException: cannot access chord tables address
        for Chord with 0 pitches

    NOTE: this was once a time-consuming operation, though it is
    now quite a bit faster than before (order of 100 microseconds).  Nonetheless, it
    should only be run when necessary.  Methods that call this should
    try (as chord.Chord does) to cache the result.

    OMIT_FROM_DOCS

    Can the last entry be found?

    >>> c_aug = chord.Chord(['c', 'f-', 'g#'])
    >>> chord.tables.seekChordTablesAddress(c_aug)
    ChordTableAddress(cardinality=3, forteClass=12, inversion=0, pcOriginal=0)
    '''
    pcSet = c.orderedPitchClasses
    index = 0
    inversion = 0
    if not pcSet:
        raise ChordTablesException(
            f'cannot access chord tables address for Chord with {len(pcSet)} pitches')

    # environLocal.printDebug(['calling seekChordTablesAddress:', pcSet])

    card = len(pcSet)
    if card == 1:  # it is a singleton: return it
        return ChordTableAddress(1, 1, 0, pcSet[0])
    elif card == 12:  # it is the aggregate
        return ChordTableAddress(12, 1, 0, 0)

    # go through each rotation of pcSet
    candidates = []
    for rot in range(card):
        testSet = pcSet[rot:] + pcSet[0:rot]
        # transpose to lead with zero
        testSetOriginalPC = testSet[0]
        testSet = [(x - testSetOriginalPC) % 12 for x in testSet]
        # create inversion; first take difference from 12 mod 12
        testSetInvert = [(12 - x) % 12 for x in testSet]
        testSetInvert.reverse()  # reverse order (first steps now last)
        # transpose all steps (were last) to zero, mod 12
        testSetInvert = [(x + (12 - testSetInvert[0])) % 12
                         for x in testSetInvert]

        candidateTuple = (tuple(testSet), tuple(testSetInvert), testSetOriginalPC)
        candidates.append(candidateTuple)

    # compare sets to those in table
    match = False
    matchedPCOriginal = None

    for indexCandidate in range(1, len(FORTE[card])):  # first entry is None
        dataLine = FORTE[card][indexCandidate]
        dataLinePcs = dataLine[0]
        inversionsAvailable = forteIndexToInversionsAvailable(card, indexCandidate)

        for candidate, candidateInversion, candidateOriginalPC in candidates:
            # environLocal.printDebug([candidate])
            # need to only match form
            if dataLinePcs == candidate:
                index = indexCandidate
                if 0 in inversionsAvailable:
                    inversion = 0
                else:
                    inversion = 1
                matchedPCOriginal = candidateOriginalPC
                match = True
                break
            elif dataLinePcs == candidateInversion:
                index = indexCandidate
                if 0 in inversionsAvailable:
                    inversion = 0  # should never reach this line?
                else:
                    inversion = -1
                matchedPCOriginal = candidateOriginalPC
                match = True
                break
    if not match:
        raise ChordTablesException(f'cannot find a chord table address for {pcSet}')
    return ChordTableAddress(card, index, inversion, matchedPCOriginal)


# ------------------------------------------------------------------------------
class Test(unittest.TestCase):

    def testDummy(self):
        self.assertEqual(True, True)

    def testTnIndexToChordInfo(self):
        for key, value in tnIndexToChordInfo.items():
            self.assertEqual(len(key), 3)
            if value:
                # if we have keys, make sure that name is one of them
                self.assertTrue('name' in value)

    def testForteNumberWithInversionToTnIndex(self):
        partition = {}
        for key, value in forteNumberWithInversionToTnIndex.items():
            self.assertEqual(len(key), 3)
            # the third value of the key should be -1, 1, or 0
            self.assertTrue(key[2] in [-1, 0, 1])
            if key[0] not in partition:
                partition[key[0]] = []
                partition[key[0]].append(value)  # append unique ids
            else:
                partition[key[0]].append(value)  # append unique ids

        for key, value in partition.items():
            # the length of the list should be the max value stored
            self.assertEqual(max(value), len(value))

    def testCardinalityToChordMembers(self):
        for key, value in cardinalityToChordMembers.items():
            maxVal = maximumIndexNumberWithoutInversionEquivalence[key]
            # make sure the max value is the length of all keys for each size
            self.assertEqual(maxVal, len(value.keys()))

    def testForte(self):
        set_info = maximumIndexNumberWithInversionEquivalence.items()
        for setSize, setCount in set_info:  # look at TnI structures
            if setSize == 0:
                continue
            for i in range(1, setCount + 1):
                self.assertEqual(len(FORTE[setSize][1]), 4)
            # must subtract one b/c all groups contain a zero set to pad
            # index values
            self.assertEqual(len(FORTE[setSize]) - 1, setCount)


# ------------------------------------------------------------------------------
# define presented order in documentation
_DOC_ORDER = [addressToForteName, addressToPrimeForm, seekChordTablesAddress]


if __name__ == '__main__':
    import music21
    music21.mainTest()

