| leonardo ( @ 2008-04-05 19:45:00 |
Self-recursive generators in D
I have (slightly) adapted the Python-like generators for D written by Witold Baryluk to my libs. They allow a simpler syntax that can be used for single iterations (not parallel scan allowed, you have to use some threads or light threads). So I have used them to translate to D some self-recursive generators from Python code by David Eppstein:
http://aspn.activestate.com/ASPN/Cookbo ok/Python/Recipe/221457
As an example this yields Fibbinary numbers (no consecutive ones in binary representation):
http://www.research.att.com/projects/OE IS?Anum=A003714
The syntax isn't as clean as Python one, but it's simple enough anyway. They are 2-3 times slower than handwritten opApply struct methods, so you may want to use them only where code size/readability matters more.
The whole output:
[1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, 5, 1, 2, 1, 3]
[1, 2, 4, 5, 8, 9, 10, 16, 17, 18, 20, 21, 32, 33, 34, 36, 37, 40, 41, 42]
[0, 1, 3, 2, 7, 6, 4, 5, 15, 14, 12, 13, 8, 9, 11, 10, 31, 30, 28, 29]
[0, 1, 3, 2, 7, 6, 4, 5, 15, 14, 12, 13, 8, 9, 11, 10, 31, 30, 28, 29]
[0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1]
[1, 2, 4, 7, 8, 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38]
["1", "10", "100", "101", "1000", "1001", "1010", "10000", "10001", "10010", "10100", "10101", "100000", "100001", "100010", "100100", "100101", "101000", "101001", "101010", "1000000", "1000001", "1000010", "1000100", "1000101", "1001000", "1001001", "1001010", "1010000", "1010001"]
I have (slightly) adapted the Python-like generators for D written by Witold Baryluk to my libs. They allow a simpler syntax that can be used for single iterations (not parallel scan allowed, you have to use some threads or light threads). So I have used them to translate to D some self-recursive generators from Python code by David Eppstein:
http://aspn.activestate.com/ASPN/Cookbo
As an example this yields Fibbinary numbers (no consecutive ones in binary representation):
http://www.research.att.com/projects/OE
struct A003714 {
void generator() {
yield(1);
foreach(x; A003714()) {
yield(2 * x);
if (!(x & 1))
yield(2 * x + 1);
}
}
mixin Generator!(int);
}
The original Python version:def A003714():
yield 1
for x in A003714():
yield 2 * x
if not (x & 1):
yield 2 * x + 1
The syntax isn't as clean as Python one, but it's simple enough anyway. They are 2-3 times slower than handwritten opApply struct methods, so you may want to use them only where code size/readability matters more.
import std.string: format;
import d.func: Tuple, putr, array, xslice, map;
import d.generators: Generator, IterBreak, IterLast;
/** Sequence of moves to solve Towers of Hanoi; has many other interpretations.
For more info see http://www.research.att.com/projects/OEIS?Anum=A001511 */
struct A001511 {
void generator() {
yield(1);
foreach(x; A001511()) {
yield(x + 1);
yield(1);
}
}
mixin Generator!(int);
}
/** Fibbinary numbers (no consecutive ones in binary representation).
For more info see http://www.research.att.com/projects/OEIS?Anum=A003714 */
struct A003714 {
void generator() {
yield(1);
foreach(x; A003714()) {
yield(2 * x);
if (!(x & 1))
yield(2 * x + 1);
}
}
mixin Generator!(int);
}
/** Inverse Gray code; each n occurs at position n^(n>>1) of the sequence.
For more info see http://www.research.att.com/projects/OEIS?Anum=A006068 */
struct A006068 {
void generator() {
yield(0);
foreach(x; A006068()) {
if (x & 1) {
yield(2 * x + 1);
yield(2 * x);
} else {
if (x)
yield(2 * x);
yield(2 * x + 1);
}
}
}
mixin Generator!(int);
}
/// Using usual D syntax. It's 2-3 times faster but the code is longer
struct A006068b {
int opApply(int delegate(ref int) dg) {
int result, aux;
aux = 0; result = dg(aux); if (result) return result;
foreach(x; A006068b()) {
if (x & 1) {
aux = 2 * x + 1; result = dg(aux); if (result) break;
aux = 2 * x; result = dg(aux); if (result) break;
} else {
if (x)
{ aux = 2 * x; result = dg(aux); if (result) break; }
aux = 2 * x + 1; result = dg(aux); if (result) break;
}
}
return result;
}
}
/** Thue-Morse sequence; binary sequence with no triply-repeated block.
For more info see http://www.research.att.com/projects/OEIS?Anum=A010060 */
struct A010060 {
void generator() {
yield(0);
int omit = 1;
foreach(x; A010060()) {
if (x) {
yield(1);
yield(0);
} else {
if (!omit)
yield(0);
yield(1);
}
omit = 0;
}
}
mixin Generator!(int);
}
/** Odious numbers: numbers with an odd number of ones in their binary representation.
For more info, see http://www.research.att.com/projects/OEIS?Anum=A000069 */
struct A000069 {
void generator() {
yield(1);
foreach (x; A000069()) {
if (x & 1 && x > 1)
yield(2 * x - 1);
yield(2 * x);
if (!(x & 1))
yield(2 * x + 3);
}
}
mixin Generator!(int);
}
void main() {
foreach(seq; Tuple!(A001511, A003714, A006068, A006068b, A010060, A000069))
putr(array(xslice(seq(), 20)));
putr();
putr( map((int n){ return format("%b", n); }, xslice(A003714(), 30)) );
}
The whole output:
[1, 2, 1, 3, 1, 2, 1, 4, 1, 2, 1, 3, 1, 2, 1, 5, 1, 2, 1, 3]
[1, 2, 4, 5, 8, 9, 10, 16, 17, 18, 20, 21, 32, 33, 34, 36, 37, 40, 41, 42]
[0, 1, 3, 2, 7, 6, 4, 5, 15, 14, 12, 13, 8, 9, 11, 10, 31, 30, 28, 29]
[0, 1, 3, 2, 7, 6, 4, 5, 15, 14, 12, 13, 8, 9, 11, 10, 31, 30, 28, 29]
[0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1]
[1, 2, 4, 7, 8, 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38]
["1", "10", "100", "101", "1000", "1001", "1010", "10000", "10001", "10010", "10100", "10101", "100000", "100001", "100010", "100100", "100101", "101000", "101001", "101010", "1000000", "1000001", "1000010", "1000100", "1000101", "1001000", "1001001", "1001010", "1010000", "1010001"]