20-CS-122-001 Computer Science II Spring 2012
Hamming's sequence

Virtual functions, classes, inheritance, lists, queues, stacks, applications

Prev     Next     Lectures     hamming.cc     ham_stream.cc

#include <iomanip>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include "bigint.h"
using namespace std;

// Stream declaration
class Stream {
public:
   bool isNull;
   BigInt *first;
   virtual Stream *rest () { return NULL; }
   Stream () { isNull = true; }
};

// successor declaration
class Successor : public Stream {
public:
   Successor (BigInt *num) { 
      first = num;
      isNull = false; 
   }

   Successor *rest () {  
      return new Successor (first->add(new BigInt("1")));
   }
};

// Inputs: two streams of integers in increasing order
// Output: a stream in increasing order consisting of exactly those
// numbers in the input streams (assume only infinite streams).
class Merge : public Stream {
   Stream *s1, *s2;

public:
   Merge (Stream *a, Stream *b) {
      isNull = false;
      if (!a->isNull && (b->isNull || a->first->lessThan(b->first))) {
         s1 = a;
         s2 = b;
      } else if (!b->isNull && (a->isNull || b->first->lessThan(a->first))) {
         s1 = b;
         s2 = a;
      } 
      else {
         isNull = true;
      }
      if (!isNull) first = s1->first;
   }

   Stream *rest () { return new Merge(s1->rest(), s2);  }
};
        
// Inputs: an integer n and a Stream s of numbers
// Output: the Stream of all tokens of s multiplied by n
class Times : public Stream {
   Stream *s1;  BigInt *multiplier;

public:
   Times (BigInt *n, Stream *s) {
      isNull = s->isNull;
      s1 = s;
      multiplier = n;
      if (!isNull) first = s->first->multiply(n);
   }

   Times *rest() { return new Times (multiplier, s1->rest()); }
};

// Finite size array of objects as a stream
class Array : public Stream {
   BigInt **array;
   int n;

public:
   Array (BigInt **a, int m) {
      if (m < 1 || a == NULL) isNull = true; 
      else { isNull = false; first = a[0]; }
      n = m;
      array = a;
   }

   Array *rest () { return new Array(&array[1], n-1); }
};

// p is a list of prime numbers in increasing order
// + is concatenate, * is streams times
// hamming(p) = 
//    if (p == null) return null;
//    return first(p) + merge(first(p)*hamming(p), hamming(rest(p));
//
/* Note: "this" replaces "new Hamming(primes)" in "Stream *rest()" */
class Hamming : public Stream {
   Array *primes;

public:
   Hamming (Array *primes) {
      isNull = primes->isNull;
      first = primes->first;
      this->primes = primes;
   }

   Merge *rest () {
      return new Merge(new Hamming(primes->rest()),
                       new Times(primes->first, this));
   }
};

// Hamming
int main(int argc, char **argv) {
   if (argc == 1) {
      cout << "Usage: " << argv[0] << " <1|2|3> <number> ...\n";
      cout << "  where 1 for successor demo,\n"; 
      cout << "        2 for successor and times demo,\n";
      cout << "        3 for hamming sequence demo\n";
      exit(0);
   }
   if (atoi(argv[1]) == 1) {  // Successor
      if (argc < 3) {
         cout << "Usage: " << argv[0] << " 1 <start-number>\n";
         exit(0);
      }
      cout << "Successor:\n";
      cout << "----------\n";
      Stream *s = new Successor(new BigInt(argv[2]));
      for (int i=0 ; i < 10 ; i++) {
         cout << s->first << " ";
         s = s->rest();
      }
      cout << "\n";
   } else if (atoi(argv[1]) == 2) {  // Successor and Times
      if (argc < 4) {
         cout << "Usage: " << argv[0] << " 2 <start-number> <multiplier>\n";
         exit(0);
      }
      cout << "Successor and Times:\n";
      cout << "--------------------\n";
      Stream *s = new Times(new BigInt(argv[3]),
                            new Successor(new BigInt(argv[2])));
      for (int i=0 ; i < 10 ; i++) {
         cout << s->first << " ";
         s = s->rest();
      }
      cout << "\n";
   } else if (atoi(argv[1]) == 3) {  // Hamming sequence
      if (argc < 3) {
         cout << "Usage: " << argv[0] << " 3 <prime-number> ...\n";
         exit(0);
      }
      cout << "Hamming sequence given primes 3,5,11:\n";
      cout << "-------------------------------------\n";
      BigInt **primes = new BigInt*[argc-2];
      for (int i=2 ; i < argc ; i++) primes[i-2] = new BigInt(argv[i]);

      Stream *s = new Hamming(new Array(primes, argc-2));
      for (int i=0 ; i < 10000 ; i++, s = s->rest()) 
         cout << i+1 << ": " << s->first << "\n";
      cout << "\n\n";
   } else {
      cout << "Usage: " << argv[0] << " <1|2|3> <number> ...\n";
      exit(0);
   }      
}