adding script dump of jupyter notebook
parent
91f68f3066
commit
1be96953b8
@ -0,0 +1,577 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[2]:
|
||||
|
||||
|
||||
import itertools as it
|
||||
import networkx as nx
|
||||
from collections import Counter
|
||||
import copy
|
||||
import matplotlib.pyplot as plt
|
||||
import random
|
||||
from fractions import Fraction
|
||||
import math
|
||||
|
||||
def collapse(fraction):
|
||||
if fraction < 1:
|
||||
while fraction < 1:
|
||||
fraction *= Fraction(2, 1)
|
||||
elif fraction >= 2:
|
||||
while fraction >= 2:
|
||||
fraction *= Fraction(1, 2)
|
||||
return fraction
|
||||
|
||||
def hsPointToFR(point):
|
||||
fraction = Fraction(1, 1)
|
||||
for dim in point:
|
||||
if dim > 0:
|
||||
fraction = fraction * dim
|
||||
else:
|
||||
fraction = fraction * 1/abs(dim)
|
||||
return fraction
|
||||
|
||||
def pitches(iterable, r):
|
||||
for base in it.combinations_with_replacement(iterable, r - 1):
|
||||
split = tuple(list(g) for k, g in it.groupby(tuple(b for b in base if b != 1)))
|
||||
mults = list(it.product([-1, 1], repeat = len(split)))
|
||||
for mult in mults:
|
||||
yield tuple(it.chain(*[[val * mult[idx] for val in g] for idx, g in enumerate(split)]))
|
||||
|
||||
def expandPitch(pitch):
|
||||
num = 1;
|
||||
den = 1;
|
||||
expandedPitch = list(pitch)
|
||||
for dim in pitch:
|
||||
if dim > 0:
|
||||
num *= dim
|
||||
else:
|
||||
den *= abs(dim)
|
||||
fraction = num/den
|
||||
if fraction < 1:
|
||||
while fraction < 1:
|
||||
fraction *= 2
|
||||
expandedPitch = [2] + expandedPitch
|
||||
elif fraction >= 2:
|
||||
while fraction >= 2:
|
||||
fraction *= 1/2
|
||||
expandedPitch = [-2] + expandedPitch
|
||||
return tuple(expandedPitch)
|
||||
|
||||
def expandChord(chord):
|
||||
return tuple([expandPitch(p) for p in chord])
|
||||
|
||||
|
||||
def transposePitch(pitch, trans):
|
||||
transposedPitch = list(pitch)
|
||||
for t in trans:
|
||||
if (t * -1) in transposedPitch:
|
||||
transposedPitch.remove(t * -1)
|
||||
else:
|
||||
transposedPitch.append(t)
|
||||
transposedPitch.sort(key=lambda val: abs(val))
|
||||
return transposedPitch
|
||||
|
||||
def transposeChord(chord, trans):
|
||||
transposedChord = list(chord)
|
||||
for pdx, pitch in enumerate(chord):
|
||||
transposedPitch = transposePitch(pitch, trans)
|
||||
transposedChord[pdx] = tuple(transposedPitch)
|
||||
return tuple(transposedChord)
|
||||
|
||||
def chords(pitches, r):
|
||||
def is_connected(iterable):
|
||||
points = comparitors = list(iterable)
|
||||
connectedPoints = []
|
||||
base = points[0]
|
||||
bIdxScroll = 0
|
||||
while True:
|
||||
for comp in comparitors:
|
||||
comps = sorted([base, comp], key=len, reverse=True)
|
||||
if ((Counter(comps[0]) - Counter(comps[1])).total() == 1) and (len(comps[0]) - len(comps[1]) == 1):
|
||||
comparitors = connectedPoints = connectedPoints + comps
|
||||
points.remove(base)
|
||||
if comp in points:
|
||||
points.remove(comp)
|
||||
if(len(points) == 0):
|
||||
return True
|
||||
else:
|
||||
base = points[0]
|
||||
bIdxScroll = 0
|
||||
break
|
||||
else:
|
||||
if bIdxScroll < (len(points) - 1):
|
||||
bIdxScroll += 1
|
||||
base = points[bIdxScroll]
|
||||
else:
|
||||
return False
|
||||
def is_centered(iterable):
|
||||
return len(list(iterable)[0]) == 0
|
||||
#return filter(is_connected, it.takewhile(is_centered, it.combinations(pitches, r)))
|
||||
return {c for c in it.takewhile(is_centered, it.combinations(pitches, r)) if is_connected(c)}
|
||||
|
||||
def pitchDifference(frs):
|
||||
cents1 = (1200 * math.log(hsPointToFR(frs[0]), 2))
|
||||
cents2 = (1200 * math.log(hsPointToFR(frs[1]), 2))
|
||||
return abs(cents2 - cents1)
|
||||
|
||||
def difference(p1, p2):
|
||||
return transposePitch(p1, [p * -1 for p in p2])
|
||||
|
||||
def edges(chords):
|
||||
def edgeDict(transposition, symDiff):
|
||||
dict = {}
|
||||
dict['melodic_movement'] = pitchDifference(symDiff)
|
||||
dict['transposition'] = transposition
|
||||
return dict
|
||||
def reverseDict(dict):
|
||||
revDict = copy.deepcopy(dict)
|
||||
if revDict['transposition'] != ():
|
||||
revDict['transposition'] = tuple(t * -1 for t in revDict['transposition'])
|
||||
return revDict
|
||||
def edgeData(iterable):
|
||||
[base, comp] = list(iterable)
|
||||
expandedBase = expandChord(base)
|
||||
expandedComp = expandChord(comp)
|
||||
transpositions = set([tuple(difference(pair[0], pair[1])) for pair in set(it.product(expandedBase, expandedComp))])
|
||||
edges = [(expandedBase, expandedComp, edgeDict(t, symDiff)) for t in transpositions if len(symDiff := list(set(expandedBase) ^ set(tChord := transposeChord(expandedComp, t)))) == 2]
|
||||
edges = edges + [(e[1], e[0], reverseDict(e[2])) for e in edges]
|
||||
if edges != []:
|
||||
return edges
|
||||
else:
|
||||
return None
|
||||
return list(it.chain(*[e for c in it.combinations(chords, 2) if (e := edgeData(c)) is not None]))
|
||||
|
||||
def graph(edges):
|
||||
G = nx.MultiDiGraph()
|
||||
G.add_edges_from(edges)
|
||||
return G
|
||||
|
||||
def hamiltonian(G):
|
||||
F = [(G,[list(G.nodes())[0]])]
|
||||
n = G.number_of_nodes()
|
||||
while F:
|
||||
graph,path = F.pop()
|
||||
confs = []
|
||||
neighbors = (node for node in graph.neighbors(path[-1])
|
||||
if node != path[-1]) #exclude self loops
|
||||
for neighbor in neighbors:
|
||||
conf_p = path[:]
|
||||
conf_p.append(neighbor)
|
||||
conf_g = nx.Graph(graph)
|
||||
conf_g.remove_node(path[-1])
|
||||
confs.append((conf_g,conf_p))
|
||||
for g,p in confs:
|
||||
if len(p)==n:
|
||||
return p
|
||||
else:
|
||||
F.append((g,p))
|
||||
return None
|
||||
|
||||
def stochastic_hamiltonian(graph):
|
||||
check_graph = graph.copy()
|
||||
#next_node = random.choice(list(graph.nodes()))
|
||||
next_node = list(graph.nodes())[0]
|
||||
check_graph.remove_node(next_node)
|
||||
path = [next_node]
|
||||
while (nx.number_of_nodes(check_graph) > 0) and (len(path) < 5000):
|
||||
neighbors = graph[next_node]
|
||||
nd_list = list(graph.degree(list(neighbors)))
|
||||
neighbors, weights = zip(*[[n, 1/pow(d, 2) if n not in path else 0.0000001] for n, d in nd_list])
|
||||
next_node = random.choices(neighbors, weights=weights)[0]
|
||||
path.append(next_node)
|
||||
if next_node in check_graph.nodes:
|
||||
check_graph.remove_node(next_node)
|
||||
return [path, check_graph]
|
||||
|
||||
def stochastic_hamiltonian(graph):
|
||||
check_graph = graph.copy()
|
||||
#next_node = random.choice(list(graph.nodes()))
|
||||
next_node = list(graph.nodes())[0]
|
||||
check_graph.remove_node(next_node)
|
||||
path = []
|
||||
while (nx.number_of_nodes(check_graph) > 0) and (len(path) < 5000):
|
||||
outEdges = list(graph.out_edges(next_node, data=True))
|
||||
weights = [(1 if e[2]['melodic_movement'] < 200 else 0.001) * (1 if e[1] not in [pE[0] for pE in path] else 0.0000001) for e in outEdges]
|
||||
edge = random.choices(outEdges, weights=weights)[0]
|
||||
next_node = edge[1]
|
||||
path.append(edge)
|
||||
if next_node in check_graph.nodes:
|
||||
check_graph.remove_node(next_node)
|
||||
return path
|
||||
|
||||
|
||||
# In[3]:
|
||||
|
||||
|
||||
pSet = pitches([1, 3, 5], 4)
|
||||
#print(len(list(pSet)))
|
||||
cSet = chords(pSet, 4)
|
||||
#print(cSet)
|
||||
eSet = edges(cSet)
|
||||
#for e in eSet:
|
||||
# print(e)
|
||||
testGraph = graph(eSet)
|
||||
|
||||
|
||||
# In[4]:
|
||||
|
||||
|
||||
len(testGraph.nodes)
|
||||
|
||||
|
||||
# In[5]:
|
||||
|
||||
|
||||
len(testGraph.edges)
|
||||
|
||||
|
||||
# In[6]:
|
||||
|
||||
|
||||
sGraph = nx.Graph(testGraph)
|
||||
pos = nx.draw_spring(sGraph, node_size=5, width=0.1)
|
||||
|
||||
# larger figure size
|
||||
plt.figure(1, figsize=(12,12))
|
||||
nx.draw(sGraph, pos, node_size=5, width=0.1)
|
||||
#plt.show()
|
||||
plt.savefig('compact_sets.png', dpi=150)
|
||||
|
||||
|
||||
# In[7]:
|
||||
|
||||
|
||||
def reconcilePath(ham):
|
||||
def sortByOther(c1, c2, trans):
|
||||
indices = list(range(len(c1)))
|
||||
sortedChord = copy.deepcopy(c2)
|
||||
for pitch in c2:
|
||||
transposedPitch = tuple(transposePitch(pitch, trans))
|
||||
if transposedPitch in c1:
|
||||
index = c1.index(transposedPitch)
|
||||
sortedChord[index] = pitch
|
||||
indices.remove(index)
|
||||
else:
|
||||
diff = pitch
|
||||
sortedChord[indices[0]] = diff
|
||||
return sortedChord
|
||||
rPath = [[[], [list(p) for p in ham[0][0]]]]
|
||||
for cdx in range(len(ham)-1):
|
||||
c1 = list(ham[cdx][0])
|
||||
c2 = list(ham[cdx][1])
|
||||
trans = list(ham[cdx][2]['transposition'])
|
||||
c2 = sortByOther(c1, c2, trans)
|
||||
ham[cdx+1][0] = c2
|
||||
rPath.append([trans, [list(p) for p in c2]])
|
||||
return rPath
|
||||
|
||||
ham = stochastic_hamiltonian(testGraph)
|
||||
ham = [list(e) for e in ham]
|
||||
print(len(ham))
|
||||
for e in ham:
|
||||
print(e)
|
||||
rPath = reconcilePath(ham)
|
||||
rPath
|
||||
|
||||
|
||||
# In[8]:
|
||||
|
||||
|
||||
def pathToChords(path):
|
||||
curRoot = Fraction(1, 1)
|
||||
chords = []
|
||||
for trans, points in path:
|
||||
curRoot = curRoot * hsPointToFR(trans)
|
||||
chord = [float(curRoot * hsPointToFR(p)) for p in points]
|
||||
chords.append(chord)
|
||||
return chords
|
||||
|
||||
fPath = pathToChords(rPath)
|
||||
len(set([tuple(p) for p in fPath]))
|
||||
fPath
|
||||
|
||||
|
||||
# In[284]:
|
||||
|
||||
|
||||
# Opening a file in write mode{
|
||||
file = open("seq.txt", "w+")
|
||||
|
||||
# Converting the array to a string and writing to the file
|
||||
content = str(fPath)
|
||||
file.write(content)
|
||||
|
||||
# Closing the file
|
||||
file.close()
|
||||
|
||||
|
||||
# In[279]:
|
||||
|
||||
|
||||
for edge in list(testGraph.edges(data=True))[:1000]:
|
||||
print(edge)
|
||||
|
||||
|
||||
# In[161]:
|
||||
|
||||
|
||||
import networkx as nx
|
||||
from matplotlib import pyplot as plt
|
||||
import math
|
||||
|
||||
G = nx.grid_graph(dim=(range(-3, 4), range(-3, 4)))
|
||||
|
||||
def getLabel(x, y):
|
||||
num = 1
|
||||
den = 1
|
||||
if x >= 0:
|
||||
num *= math.pow(3, x)
|
||||
else:
|
||||
den *= math.pow(3, abs(x))
|
||||
if y >= 0:
|
||||
num *= math.pow(2, y)
|
||||
else:
|
||||
den *= math.pow(2, abs(y))
|
||||
return str(int(num)) + "/" + str(int(den))
|
||||
|
||||
|
||||
|
||||
plt.figure(figsize=(10 * math.log2(3), 10 * math.log2(2)))
|
||||
#plt.figure(figsize=(10, 10))
|
||||
pos = {(x, y):(x * math.log2(3), y * math.log2(2)) for x,y in G.nodes()}
|
||||
labels = {(x, y):getLabel(x, y) for x,y in G.nodes()}
|
||||
nx.draw_networkx_labels(G, pos, labels=labels)
|
||||
nx.draw(G, pos=pos,
|
||||
node_color='white',
|
||||
with_labels=False,
|
||||
node_size=1000)
|
||||
|
||||
|
||||
# In[160]:
|
||||
|
||||
|
||||
import networkx as nx
|
||||
from matplotlib import pyplot as plt
|
||||
import math
|
||||
|
||||
G = nx.grid_graph(dim=(range(-2, 3), range(-2, 3)))
|
||||
|
||||
def collapseLabel(fraction):
|
||||
if fraction < 1:
|
||||
while fraction < 1:
|
||||
fraction *= Fraction(2, 1)
|
||||
elif fraction >= 2:
|
||||
while fraction >= 2:
|
||||
fraction *= Fraction(1, 2)
|
||||
return fraction
|
||||
|
||||
def getLabel(x, y):
|
||||
num = 1
|
||||
den = 1
|
||||
if x >= 0:
|
||||
num *= math.pow(5, x)
|
||||
else:
|
||||
den *= math.pow(5, abs(x))
|
||||
if y >= 0:
|
||||
num *= math.pow(3, y)
|
||||
else:
|
||||
den *= math.pow(3, abs(y))
|
||||
fraction = collapse(Fraction(int(num), int(den)))
|
||||
num = fraction.numerator
|
||||
den = fraction.denominator
|
||||
return str(int(num)) + "/" + str(int(den))
|
||||
|
||||
plt.figure(figsize=(5 * math.log2(5), 5 * math.log2(3)))
|
||||
#plt.figure(figsize=(10, 10))
|
||||
pos = {(x, y):(x, y) for x,y in G.nodes()}
|
||||
labels = {(x, y):getLabel(x, y) for x,y in G.nodes()}
|
||||
nx.draw_networkx_labels(G, pos, labels=labels)
|
||||
nx.draw(G, pos=pos,
|
||||
node_color='white',
|
||||
with_labels=False,
|
||||
node_size=2000)
|
||||
|
||||
|
||||
# In[44]:
|
||||
|
||||
|
||||
for node in list(testGraph.nodes)[2:3]:
|
||||
edges = list(testGraph.out_edges(node, data=True))
|
||||
for edge in edges:
|
||||
if list(edge)[2]['transposition'] != ():
|
||||
print(edge)
|
||||
|
||||
|
||||
# In[251]:
|
||||
|
||||
|
||||
import networkx as nx
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
|
||||
# The graph to visualize
|
||||
G = nx.grid_graph(dim=(range(-1, 2), range(-1, 2), range(-1, 2)))
|
||||
|
||||
# 3d spring layout
|
||||
#pos = nx.spring_layout(G, dim=3, seed=779)
|
||||
pos = {(x, y, z):(math.log2(2) * x, math.log2(3) * y, math.log2(5) * z) for x,y,z in G.nodes()}
|
||||
# Extract node and edge positions from the layout
|
||||
node_xyz = np.array([pos[v] for v in sorted(G)])
|
||||
edge_xyz = np.array([(pos[u], pos[v]) for u, v in G.edges()])
|
||||
|
||||
# Create the 3D figure
|
||||
fig = plt.figure(figsize=(10, 10))
|
||||
ax = fig.add_subplot(111, projection="3d")
|
||||
|
||||
# Plot the nodes - alpha is scaled by "depth" automatically
|
||||
ax.scatter(*node_xyz.T, s=100, ec="w")
|
||||
|
||||
ax.view_init(elev=30, azim=45, roll=15)
|
||||
|
||||
ax.axis('equal')
|
||||
|
||||
# Plot the edges
|
||||
for vizedge in edge_xyz:
|
||||
ax.plot(*vizedge.T, color="tab:gray")
|
||||
|
||||
|
||||
def _format_axes(ax):
|
||||
"""Visualization options for the 3D axes."""
|
||||
# Turn gridlines off
|
||||
ax.grid(False)
|
||||
# Suppress tick labels
|
||||
for dim in (ax.xaxis, ax.yaxis, ax.zaxis):
|
||||
dim.set_ticks([])
|
||||
# Set axes labels
|
||||
ax.set_xlabel("x")
|
||||
ax.set_ylabel("y")
|
||||
ax.set_zlabel("z")
|
||||
|
||||
|
||||
_format_axes(ax)
|
||||
fig.tight_layout()
|
||||
plt.show()
|
||||
|
||||
|
||||
# In[31]:
|
||||
|
||||
|
||||
from tikzpy import TikzPicture
|
||||
|
||||
def collapseLabel(fraction):
|
||||
if fraction < 1:
|
||||
while fraction < 1:
|
||||
fraction *= Fraction(2, 1)
|
||||
elif fraction >= 2:
|
||||
while fraction >= 2:
|
||||
fraction *= Fraction(1, 2)
|
||||
return fraction
|
||||
|
||||
def getLabel(x, y, z, collapse = False):
|
||||
num = 1
|
||||
den = 1
|
||||
if x >= 0:
|
||||
num *= math.pow(3, x)
|
||||
else:
|
||||
den *= math.pow(3, abs(x))
|
||||
|
||||
if y >= 0:
|
||||
num *= math.pow(5, y)
|
||||
else:
|
||||
den *= math.pow(5, abs(y))
|
||||
|
||||
if z >= 0:
|
||||
num *= math.pow(2, z)
|
||||
else:
|
||||
den *= math.pow(2, abs(z))
|
||||
if collapse:
|
||||
fraction = collapseLabel(Fraction(int(num), int(den)))
|
||||
else:
|
||||
fraction = Fraction(int(num), int(den))
|
||||
num = fraction.numerator
|
||||
den = fraction.denominator
|
||||
return str(int(num)) + "/" + str(int(den))
|
||||
|
||||
def chord2Points(chord):
|
||||
points = []
|
||||
for n in chord:
|
||||
counter = Counter(n)
|
||||
points.append(tuple([counter[d] - counter[-d] for d in [2, 3, 5]]))
|
||||
return tuple(points)
|
||||
|
||||
def genLattice(chord = None, ranges = None, filename = "tikz", collapse = False, scale = 1):
|
||||
|
||||
dx = math.log2(3) * scale
|
||||
dy = math.log2(5) * scale
|
||||
dz = math.log2(2) * scale
|
||||
|
||||
if chord:
|
||||
set = chord2Points(chord)
|
||||
|
||||
if ranges:
|
||||
rz,rx,ry = ranges
|
||||
else:
|
||||
rz,rx,ry = [[min(t), max(t) + 1] for t in list(zip(*set))]
|
||||
|
||||
if collapse:
|
||||
rz = [0, 1]
|
||||
|
||||
tikz = TikzPicture(center=True)
|
||||
tikz.set_tdplotsetmaincoords(30, -30)
|
||||
tikz.options = "tdplot_main_coords"
|
||||
|
||||
for x in range(*rx):
|
||||
for y in range(*ry):
|
||||
for z in range(*rz):
|
||||
line = tikz.line((x * dx - dx / 2, y * dy, z * dz), (x * dx + dx / 2, y * dy, z * dz), options="thick, black, -")
|
||||
line = tikz.line((x * dx, y * dy - dy / 2, z * dz), (x * dx, y * dy + dy / 2, z * dz), options="thick, black, -")
|
||||
if not collapse:
|
||||
line = tikz.line((x * dx, y * dy, z * dz - dz / 2), (x * dx, y * dy, z * dz + dz / 2), options="thick, black, -")
|
||||
node = tikz.node((x * dx, y * dy, z * dz), options="draw, fill=white, scale=0.5", text=getLabel(x,y,z, collapse))
|
||||
|
||||
if chord:
|
||||
for e in set:
|
||||
z,x,y = e
|
||||
if collapse:
|
||||
z = 0
|
||||
line = tikz.line((x * dx - dx / 2, y * dy, z * dz), (x * dx + dx / 2, y * dy, z * dz), options="thick, black, -")
|
||||
line = tikz.line((x * dx, y * dy - dy / 2, z * dz), (x * dx, y * dy + dy / 2, z * dz), options="thick, black, -")
|
||||
if not collapse:
|
||||
line = tikz.line((x * dx, y * dy, z * dz - dz / 2), (x * dx, y * dy, z * dz + dz / 2), options="thick, black, -")
|
||||
node = tikz.node((x * dx, y * dy, z * dz), options="draw, fill=yellow, scale=0.5", text=getLabel(x,y,z, collapse))
|
||||
|
||||
tikz.compile(filename + ".pdf", True)
|
||||
|
||||
texFile = open(filename + ".tex", "w+")
|
||||
texFile.write(tikz.code())
|
||||
texFile.close()
|
||||
|
||||
|
||||
# In[72]:
|
||||
|
||||
|
||||
edge = (((), (-2, 3), (2, 3, -5), (3, 3, -5)), ((), (2, 2, -3), (-2, 3), (-2, -2, 5)), {'melodic_movement': 813.6862861351653, 'transposition': (2, 3, -5)})
|
||||
chord = transposeChord(edge[0], (-2, -3, 5))
|
||||
#genLattice(chord, path="figure.pdf", collapse=False)
|
||||
genLattice(chord, ranges=[[-2, 2], [-2, 2], [-2, 2]], filename="compact_set_1_transposed_expanded_padded", collapse=False, scale=2)
|
||||
|
||||
|
||||
# In[79]:
|
||||
|
||||
|
||||
edge = (((), (-2, 3), (2, 3, -5), (3, 3, -5)), ((), (2, 2, -3), (-2, 3), (-2, -2, 5)), {'melodic_movement': 813.6862861351653, 'transposition': (2, 3, -5)})
|
||||
chord = transposeChord(edge[0], (-2, -3, 5))
|
||||
#genLattice(chord, path="figure.pdf", collapse=False)
|
||||
genLattice(chord, ranges=[[-2, 2], [-1, 3], [-1, 2]], filename="compact_set_1_transposed_expanded_padded", collapse=False, scale=2)
|
||||
|
||||
|
||||
# In[80]:
|
||||
|
||||
|
||||
edge = (((), (-2, 3), (2, 3, -5), (3, 3, -5)), ((), (2, 2, -3), (-2, 3), (-2, -2, 5)), {'melodic_movement': 813.6862861351653, 'transposition': (2, 3, -5)})
|
||||
chord = edge[0]
|
||||
#genLattice(chord, path="figure.pdf", collapse=False)
|
||||
genLattice(chord, ranges=[[-2, 2], [-1, 3], [-1, 2]], filename="compact_set_1_expanded_padded", collapse=False, scale=2)
|
||||
|
Loading…
Reference in New Issue