leonardo ([info]leonardo_m) wrote,
@ 2008-04-05 19:45:00
Previous Entry  Add to memories!  Tell a Friend  Next Entry
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/Cookbook/Python/Recipe/221457

As an example this yields Fibbinary numbers (no consecutive ones in binary representation):
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);
}

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"]


Advertisement


(No comments)

Post a comment in response:

From:
Help
Identity URL: 
Username:
Password:
Don't have an account? Create one now.
Subject:
No HTML allowed in subject
   Help
Message:

 
Create an Account
Forgot your login or password?
Login w/ OpenID
English • Español • Deutsch • Русский…