Skip to content

Instantly share code, notes, and snippets.

@floer32
Last active August 29, 2015 13:56
Show Gist options
  • Save floer32/8892377 to your computer and use it in GitHub Desktop.
Save floer32/8892377 to your computer and use it in GitHub Desktop.
Method to multiply (?) two sequences in certain way, that may be useful in generating sets of harmonic frequencies.
""" Functions to "multiply" sequences in peculiar way. Intended for use in generating sets harmonic frequencies.
.. moduleauthor:: hangtwenty
A friend of mine was wondering how to do something like this so I just had fun coming up with a solution.
I may use it in Supercollider or something if I can figure out how to glue Python and SC together.
"""
def flat_product_of_sequences(seq1, seq2):
""" Given two flat lists of integers, return this program's particular kind of product of them.
I bet there's a math term for this... I don't think it's Cartesian product but it seems similar?
.. doctest::
>>> flat_product_of_sequences([1, 2, 3, 4], [1, 2, 3, 4])
[1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12, 4, 8, 12, 16]
>>> flat_product_of_sequences([2, 4, 6, 8], [1, 2, 3, 4])
[2, 4, 6, 8, 4, 8, 12, 16, 6, 12, 18, 24, 8, 16, 24, 32]
>>> flat_product_of_sequences([2, 4, 6, 8], [1, 2, 3, 4])
[2, 4, 6, 8, 4, 8, 12, 16, 6, 12, 18, 24, 8, 16, 24, 32]
"""
return [n * m for n in seq1 for m in seq2]
def nested_product_of_sequences(seq1, seq2):
""" Walks seq1 recursively until it gets down to a list of integers. Once it's down to that level it does
basically the same thing as fractalize_flat; except each integer is "replaced" with a list.
(Append vs. extend)
.. doctest ::
>>> nested_product_of_sequences([1, 2, 3, 4], [1, 2, 3, 4])
[[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12], [4, 8, 12, 16]]
>>> nested_product_of_sequences([2, 4, 6, 8], [1, 2, 3, 4])
[[2, 4, 6, 8], [4, 8, 12, 16], [6, 12, 18, 24], [8, 16, 24, 32]]
>>> x = nested_product_of_sequences([8, 16], [8, 16])
>>> x
[[64, 128], [128, 256]]
>>> nested_product_of_sequences(x, [1, 2])
[[[64, 128], [128, 256]], [[128, 256], [256, 512]]]
>>> nested_product_of_sequences(x, [10, 3])
[[[640, 1280], [192, 384]], [[1280, 2560], [384, 768]]]
"""
try:
return [nested_product_of_sequences(item, seq2) for item in seq1]
except TypeError:
return [[item * m for item in seq1] for m in seq2]
def compoundify(seq1, seq2, fn, n=5):
""" Apply fn to seq n times over, each time feeding back in the result from the last time...
It keeps seq2 constant through each operation.
If you just give the same sequence twice, it'll be kind of like the "square" of this algorithm...
but you could make seq1 be your frequencies, and seq2 be the multipliers, yeah?
.. doctest ::
>>> compoundify([1, 2, 3, 4], [1, 2, 3, 4], flat_product_of_sequences, n=1)
[1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12, 4, 8, 12, 16]
>>> compoundify([1, 2, 3, 4], [1, 2, 3, 4], nested_product_of_sequences, n=1)
[[1, 2, 3, 4], [2, 4, 6, 8], [3, 6, 9, 12], [4, 8, 12, 16]]
>>> compoundify([200, 300], [1, 2, 3, 4], nested_product_of_sequences, n=1)
[[200, 300], [400, 600], [600, 900], [800, 1200]]
>>> compoundify([440, 880], [1, 1.5], flat_product_of_sequences, n=2)
[440, 660.0, 660.0, 990.0, 880, 1320.0, 1320.0, 1980.0]
"""
for __ in range(0, n):
seq1 = fn(seq1, seq2)
return seq1
import pytest
from funcy import flatten
from harm import compoundify, nested_product_of_sequences, flat_product_of_sequences
@pytest.mark.parametrize(('seq1', 'seq2', 'depth'), (
([1, 2, 3, 4], [1, 2, 3, 4], 1),
([1, 2, 3, 4], [1, 2, 3, 4], 2),
([1, 2, 3, 4], [1, 2, 3, 4], 5),
([220, 440, 660, 880], [1, 2, 3, 4], 1),
([220, 440, 660, 880], [1, 2, 3, 4], 2),
([220, 440, 660, 880], [1, 2, 3, 4], 5),
# I would have thought these would pass, but they don't... Hmm...
# ([220, 440, 660, 880], [2, 1.5, 2, 3], 1),
# ([220, 440, 660, 880], [2, 1.5, 2, 3], 2),
# ([220, 440, 660, 880], [2, 1.5, 2, 3], 5),
))
def test_integrity_of_alternate_algorithms_given_sequences_of_same_length(seq1, seq2, depth):
nested_res = compoundify(seq1, seq2, nested_product_of_sequences, n=depth)
flat_res = compoundify(seq1, seq2, flat_product_of_sequences, n=depth)
assert list(flatten(nested_res)) == list(flat_res)
@pytest.mark.parametrize(('seq1', 'seq2', 'depth'), (
([1, 2, 3, 4], [1, 2, 3, 4], 1),
([1, 2, 3, 4], [1, 2, 3, 4], 2),
([1, 2, 3, 4], [1, 2, 3, 4], 5),
([440, 660, 880], [1, 2, 3, 4], 1),
([440, 660, 880], [1, 2, 3, 4], 2),
([440, 660, 880], [1, 2, 3, 4], 5),
([440, 660, 880], [1, 1.5], 1),
([440, 660, 880], [1, 1.5], 2),
([440, 660, 880], [1, 1.5], 5),
))
def test_integrity_of_alternate_algorithms_given_sequences_of_different_lengths(seq1, seq2, depth):
nested_res = compoundify(seq1, seq2, nested_product_of_sequences, n=depth)
flat_res = compoundify(seq1, seq2, flat_product_of_sequences, n=depth)
assert set(flatten(nested_res)) == set(flat_res)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment