-
Notifications
You must be signed in to change notification settings - Fork 0
Xenakis Sieves
Xenakis sieves are a method for creating symmetrical and complex integer sequences created by Iannis Xenakis. Sieves consist of a step size i
and a modulo value m
, and are defined in shorthand using the `@`
notation. A sieve defined as 3`@`0
will result in the following residue:
0, 3, 6, 9, ..., 3n
And the sieve defined as 3`@`1
should result in the following residue:
1, 4, 7, 10, ..., 3n + 1
To actually get numbers out of a sieve, you can provide it a range of values for which you are "sieving" through. For example, the following REPL output demonstrates how you would use a sieve in practice:
scala> import rc.dsl.gen.sieve._
import rc.dsl.gen.sieve._
scala> 4`@`0
res0: rc.dsl.gen.sieve.Residual = Residual(4,0)
scala> res0(0 to 10)
res1: IndexedSeq[Int] = Vector(0, 4, 8)
scala> (3`@`2)(0 to 10)
res2: IndexedSeq[Int] = Vector(2, 5, 8)
A single sieve is purely symmetrical and not complex, but sieves can be joined together using logical operators: unions, intersections, and differences. These work in the same way you would expect if you are familiar with set theory: unions result in a set of all numbers from both sieves, intersections result in a set of all numbers both sieves share, and differences result in a set of all numbers not shared between the sieves. There is also a fourth operation called a complement, which applies to a single sieve rather than combining two, and represents all of the numbers not in the set defined by the sieve.
Unions can be created using the binary |
operator, so the union defined by two sieves could look like (4`@`0) | (4`@`1)
. When run in the REPL it will result in the following sequence:
scala> (4`@`0) | (4`@`1)
res2: rc.dsl.gen.sieve.package.Sieve = Union(Residual(4,0),Residual(4,1))
scala> res2(0 to 10)
res3: IndexedSeq[Int] = Vector(0, 1, 4, 5, 8, 9)
Intersections can be created using the binary &
operator, so an intersection can be defined as (2`@`0) & (4`@`0)
. When run in the REPL it will result in the following sequence:
scala> (2`@`0) & (4`@`0)
res4: rc.dsl.gen.sieve.package.Sieve = Intersection(Residual(2,0),Residual(4,0))
scala> res4(0 to 10)
res5: IndexedSeq[Int] = Vector(0, 4, 8)
Differences can be created using the binary ^
operator, so a difference can be defined as (3`@`2) ^ (4`@`1)
. When run in the REPL it will result in the following sequence:
scala> (3`@`2) ^ (4`@`1)
res10: rc.dsl.gen.sieve.package.Sieve = Difference(Residual(3,2),Residual(4,1))
scala> res10(0 to 10)
res11: IndexedSeq[Int] = Vector(2, 8)
Complements can be create using the unary operator -
, so a complement of a sieve can be defined as -(2`@`0)
. When run in the REPL it will result in the following sequence:
scala> -(2`@`0)
res12: rc.dsl.gen.sieve.Sieve = Complement(Residual(2,0))
scala> res12(0 to 10)
res13: IndexedSeq[Int] = Vector(1, 3, 5, 7, 9)
Sieves have multiple uses due to their symmetrical and complex nature, such as defining a set of pitches in a serialistic piece, creating a melodic line, or a sequence of beats.
TODO: Provide examples...