Update solution 12 to avoid overflow.

Update solution 12 to avoid overflow.

Previously, it had a loop that went up to max(int). This overflows on the very
final check, since the index will be max(int) and then it will add 1 to it. To
avoid the overflow, iterate to max(int)-1.

/*
 * Highly divisible triangular number
 */

config const minDivisors = 500,
  printNumbers = false;

proc main() {
  for t in triangleNumbers() {

    if printNumbers then
      writef("%n: ", t);

    var count = 0;
    for f in factors(t) {
      count += 1;

      if printNumbers then
        writef("%n, ", f);
    }
    if printNumbers then
      writeln();

    if count > minDivisors {
      writeln(t);
      break;
    }
  }
}

// Yield all the factors of n.
iter factors(n) {
  // Yield 1 and n first, then all intermediate factors.
  yield 1;
  yield n;

  var i = 2;
  while (i < sqrt(n)) {
    if n % i == 0 {
      yield i;
      yield n / i;
    }
    i += 1;
  }

  if i ** 2 == n {
    yield i;
  }
}

// Yield triangle numbers for all integer values. Up to caller to break
// iteration.
iter triangleNumbers() {
  var triangleNum = 1;
  for num in 2..max(int)-1 {
    yield triangleNum;
    triangleNum += num;
  }
}

/*
 * Highly divisible triangular number
 */

config const minDivisors = 500,
  printNumbers = false;

proc main() {
  for t in triangleNumbers() {

    if printNumbers then
      writef("%di: ", t);

    var count = 0;
    for f in factors(t) {
      count += 1;

      if printNumbers then
        writef("%di, ", f);
    }
    if printNumbers then
      writeln();

    if count > minDivisors {
      writeln(t);
      break;
    }
  }
}

// Yield all the factors of n.
iter factors(n) {
  // Yield 1 and n first, then all intermediate factors.
  yield 1;
  yield n;

  var i = 2;
  while (i < sqrt(n)) {
    if n % i == 0 {
      yield i;
      yield n / i;
    }
    i += 1;
  }

  if i ** 2 == n {
    yield i;
  }
}

// Yield triangle numbers infinitely. Up to caller to break iteration.
iter triangleNumbers() {
  var num = 1,
    triangleNum = num;
  for i in 1..max(int) {
    yield triangleNum;
    num += 1;
    triangleNum += num;
  }
}


update 37 - use int arithmetic instead of string manipulation for left-to-right check

/*
 * Truncatable primes
 */

use MathFunctions;

/* When true, print the truncatable primes. */
config const printPrimes = false;

proc main() {
  var count = 0,
    sum: uint = 0;
  for p in primesUpTo(max(uint)) {
    if isTruncatable(p) {
      if printPrimes then
        writeln(p, " is truncatable.");
      sum += p;
      count += 1;
    }
    if count == 11 then
      break;
  }
  writeln(sum);
}

// Assumes `p` is prime.
proc isTruncatable(p: uint) {
  // 2, 3, 5, and 7 are not considered to be truncatable primes.
  if p < 10 then
    return false;
  return isTruncRtoL(p) && isTruncLtoR(p);
}

// Removes first digit from `k`. Returns 2..n digits for for number `k` with
// 1..n digits.
proc removeFirst(k: uint) {
  if k < 10 then
    return 0: uint;

  var d: uint = k / 10,
    r: uint = k % 10,
    multiplier: uint = 1;

  while d >= 10 {
    multiplier *= 10;
    r = multiplier * (d % 10) + r;
    d /= 10;
  }

  return r;
}

// Check if p is truncatable, working from left to right.
proc isTruncLtoR(p: uint) {
  var d = removeFirst(p);
  while d > 0 {
    if !isPrime(d) then
      return false;
    d = removeFirst(d);
  }
  return true;
}

// Check if p is truncatable, working from right to left.
proc isTruncRtoL(p: uint) {
  var d = p / 10;
  while d > 0 {
    if !isPrime(d) then
      return false;
    d /= 10;
  }
  return true;
}

/*
 * Truncatable primes
 */

use MathFunctions;

/* When true, print the truncatable primes. */
config const printPrimes = false;

proc main() {
  var count = 0,
    sum: uint = 0;
  for p in primesUpTo(max(uint)) {
    if isTruncatable(p) {
      if printPrimes then
        writeln(p, " is truncatable.");
      sum += p;
      count += 1;
    }
    if count == 11 then
      break;
  }
  writeln(sum);
}

// Assumes `p` is prime.
proc isTruncatable(p: uint) {
  // 2, 3, 5, and 7 are not considered to be truncatable primes.
  if p < 10 then
    return false;

  /* var ltor, rtol: bool; */
  /* cobegin { */
  /*   ltor = isTruncLtoR(p); */
  /*   rtol = isTruncRtoL(p); */
  /* } */
  /* return rtol && ltor; */

  return isTruncRtoL(p) && isTruncLtoR(p);
}

// Removes first digit from `k`. Returns 2..n digits for for number `k` with
// 1..n digits.
proc removeFirst(k: uint) {
  const s = k: string,
    d = s.substring(2..s.length);
  if d.length == 0 then
    return 0: uint;
  return d: uint;
}

// Check if p is truncatable, working from left to right.
proc isTruncLtoR(p: uint) {
  var d = removeFirst(p);
  while d > 0 {
    if !isPrime(d) then
      return false;
    d = removeFirst(d);
  }
  return true;
}

// Check if p is truncatable, working from right to left.
proc isTruncRtoL(p: uint) {
  var d = p / 10;
  while d > 0 {
    if !isPrime(d) then
      return false;
    d /= 10;
  }
  return true;
}


use indexer

use indexer

use Logging, Memory, LibEv, IO, Indexer, Search, Partitions;

// TODO: port to pure chapel
extern proc initialize_socket(port: c_int): c_int;

// trampolines
extern var c_accept_cb: opaque;

extern proc send(sockfd:c_int, buffer: c_string, len: size_t, flags: c_int);

config var port: c_int = 3033;

// TODO: we need to know which client context this is so that we can maintain parsing context
//       is the fd enough?
export proc handle_received_data(fd: c_int, buffer: c_string, read: size_t, buffer_size: size_t) {
  // writeln("from chpl: " + buffer);
  // accumulate string buffer
  var word = buffer;
  var trimmedWord: string = "";
  writeln("word: ", word);
  for i in 1..word.length {
  	var ch = word.substring(i);
  	if (ch != "\r" && ch != "\n") {
	  	writeln("ch: ", word.substring(i));
	  	trimmedWord += word.substring(i);
  	}
  }
//  writeln("trimmedWord: ", trimmedWord);
	if (trimmedWord == "dump") {
		dumpPartition(partitionForWord("dog"));
	} else {
		writeln("<adding>");
	  indexWord(trimmedWord, 1);
		dumpPostingTableForWord(trimmedWord);
		writeln("</adding>");
	}
  send(fd, buffer, read, 0);
}

proc initIndex() {
	writeln("This program is running on ", numLocales, " locales");
	writeln("It began running on locale #", here.id);
	writeln();

  initPartitions();
  initIndices();

  initIndexer();

 //  writeln("adding 3 entries");
	// indexWord("dog", 1);
	// indexWord("cat", 2);
	// indexWord("cat", 3);

 //  writeln("dumping partition holding word: dog");
	// dumpPartition(partitionForWord("dog"));

 //  writeln("dumping posting table for word: cat");
	// dumpPostingTableForWord("cat");

  var infile = open("words.txt", iomode.r);
  var reader = infile.reader();
  var word: string;
  var docId: DocId = 1;
  while (reader.readln(word)) {
    enqueueIndexRequest(word, docId);
    docId = (docId + 1) % 1000 + 1; // fake different docs
  }

  waitForIndexer();

  dumpPostingTableForWord("the");

  // TODO: build execution Tree w/ conj / disj. (operator) nodes
  // test basic boolean operators
  writeln("conjunction");
  var conj = conjunction(["the", "dog"]);
  writeln(conj);

  writeln("disjunction");
  var disj = disjunction(["the", "dog"]);
  writeln(disj);
}

proc conjunction(words: [] string): domain(DocId) {
  writeln("finding conjunction of: ", words);
  var doms: [1..words.size] domain(DocId);

  for j in 1..words.size {
    var word = words[j];
    var entry = entryForWord(word);
    if (entry != nil) {
      on entry {
        for docId in documentIdsForEntry(entry) {
          doms[j] += docId;
        }
      }
    }
  }

  writeln("applying intersection");

  for j in 2..words.size {
    doms[1] = doms[1] & doms[j];
  }

  return doms[1];
}

proc disjunction(words: [] string): domain(DocId) {
  writeln("finding disjunction of: ", words);
  var doms: [1..words.size] domain(DocId);

  for j in 1..words.size {
    var word = words[j];
    var entry = entryForWord(word);
    if (entry != nil) {
      on entry {
        for docId in documentIdsForEntry(entry) {
          doms[j] += docId;
        }
      }
    }
  }

  writeln("applying disjunction");

  for j in 2..words.size {
    doms[1] = doms[1] | doms[j];
  }

  return doms[1];
}

proc writeLocInfo(loc: locale) {
  on loc {
    writeln("locale #", here.id, "...");
    writeln("  ...is named: ", here.name);
    writeln("  ...has ", here.numCores, " processor cores");
    writeln("  ...has ", here.physicalMemory(unit=MemUnits.GB, retType=real), " GB of memory");
    writeln("  ...has ", here.maxTaskPar, " maximum parallelism");
  }
}

proc main() {

	// writeln("creating socket...");
	// var sd: ev_fd = initialize_socket(port);
	// writeln("socket id = ", sd);
	// if (sd == -1) {
	// 	writeln("socket error");
	// 	return -1;
	// }

  writeln("initializing index");
  initIndex();

	// writeln("initializing event loop...");

 //  // port c_accept_cb, c_read_cb
	// var w_accept: ev_io = new ev_io();
	// ev_io_init(w_accept, c_accept_cb, sd, EV_READ);
	// ev_io_start(EV_DEFAULT, w_accept);

	// while (1) {
	// 	ev_loop_fn(EV_DEFAULT, 0);
	// }
}

use Logging, Memory, LibEv, IO, Indexer, Search, Partitions;

// TODO: port to pure chapel
extern proc initialize_socket(port: c_int): c_int;

// trampolines
extern var c_accept_cb: opaque;

extern proc send(sockfd:c_int, buffer: c_string, len: size_t, flags: c_int);

config var port: c_int = 3033;

// TODO: we need to know which client context this is so that we can maintain parsing context
//       is the fd enough?
export proc handle_received_data(fd: c_int, buffer: c_string, read: size_t, buffer_size: size_t) {
  // writeln("from chpl: " + buffer);
  // accumulate string buffer
  var word = buffer;
  var trimmedWord: string = "";
  writeln("word: ", word);
  for i in 1..word.length {
  	var ch = word.substring(i);
  	if (ch != "\r" && ch != "\n") {
	  	writeln("ch: ", word.substring(i));
	  	trimmedWord += word.substring(i);
  	}
  }
//  writeln("trimmedWord: ", trimmedWord);
	if (trimmedWord == "dump") {
		dumpPartition(partitionForWord("dog"));
	} else {
		writeln("<adding>");
	  indexWord(trimmedWord, 1);
		dumpPostingTableForWord(trimmedWord);
		writeln("</adding>");
	}
  send(fd, buffer, read, 0);
}

proc initIndex() {
	writeln("This program is running on ", numLocales, " locales");
	writeln("It began running on locale #", here.id);
	writeln();

  initPartitions();
  initIndices();

// temporarily disable indexer
//  initIndexer();

 //  writeln("adding 3 entries");
	// indexWord("dog", 1);
	// indexWord("cat", 2);
	// indexWord("cat", 3);

 //  writeln("dumping partition holding word: dog");
	// dumpPartition(partitionForWord("dog"));

 //  writeln("dumping posting table for word: cat");
	// dumpPostingTableForWord("cat");

  var infile = open("words.txt", iomode.r);
  var reader = infile.reader();
  var word: string;
  var docId: DocId = 1;
  while (reader.readln(word)) {
    //enqueueIndexRequest(word, docId);
    indexWord(word, docId);
    docId = (docId + 1) % 1000 + 1; // fake different docs
  }

  //waitForIndexer();

  dumpPostingTableForWord("the");

  // TODO: build execution Tree w/ conj / disj. (operator) nodes
  // test basic boolean operators
  writeln("conjunction");
  var conj = conjunction(["the", "dog"]);
  writeln(conj);

  writeln("disjunction");
  var disj = disjunction(["the", "dog"]);
  writeln(disj);
}

proc conjunction(words: [] string): domain(DocId) {
  writeln("finding conjunction of: ", words);
  var doms: [1..words.size] domain(DocId);

  for j in 1..words.size {
    var word = words[j];
    var entry = entryForWord(word);
    if (entry != nil) {
      on entry {
        for docId in documentIdsForEntry(entry) {
          doms[j] += docId;
        }
      }
    }
  }

  writeln("applying intersection");

  for j in 2..words.size {
    doms[1] = doms[1] & doms[j];
  }

  return doms[1];
}

proc disjunction(words: [] string): domain(DocId) {
  writeln("finding disjunction of: ", words);
  var doms: [1..words.size] domain(DocId);

  for j in 1..words.size {
    var word = words[j];
    var entry = entryForWord(word);
    if (entry != nil) {
      on entry {
        for docId in documentIdsForEntry(entry) {
          doms[j] += docId;
        }
      }
    }
  }

  writeln("applying disjunction");

  for j in 2..words.size {
    doms[1] = doms[1] | doms[j];
  }

  return doms[1];
}

proc writeLocInfo(loc: locale) {
  on loc {
    writeln("locale #", here.id, "...");
    writeln("  ...is named: ", here.name);
    writeln("  ...has ", here.numCores, " processor cores");
    writeln("  ...has ", here.physicalMemory(unit=MemUnits.GB, retType=real), " GB of memory");
    writeln("  ...has ", here.maxTaskPar, " maximum parallelism");
  }
}

proc main() {

	// writeln("creating socket...");
	// var sd: ev_fd = initialize_socket(port);
	// writeln("socket id = ", sd);
	// if (sd == -1) {
	// 	writeln("socket error");
	// 	return -1;
	// }

  writeln("initializing index");
  initIndex();

	// writeln("initializing event loop...");

 //  // port c_accept_cb, c_read_cb
	// var w_accept: ev_io = new ev_io();
	// ev_io_init(w_accept, c_accept_cb, sd, EV_READ);
	// ev_io_start(EV_DEFAULT, w_accept);

	// while (1) {
	// 	ev_loop_fn(EV_DEFAULT, 0);
	// }
}