/*
*
* allint.m,  2 Apr 12
*
* Calculate the list of all values that can be generated
* by expressions containing +, -, * and / and any single
* digit number other than zero.
*/

one_nine : [1,2,3,4,5,6,7,8,9];
PLUS : 1;
MINUS : 2;
TIMES : 3;
DIVIDE : 4;
EXPON : 5;

operators : [PLUS, MINUS, TIMES, DIVIDE];

do_op(op1, op2, operator) := block (
if (operator = PLUS) then
   return(op1 + op2),

if (operator = MINUS) then
   return(op1 - op2),

if (operator = TIMES) then
   return(op1 * op2),

if (operator = DIVIDE) then
   return(op1 / op2)
);

eval_op(op1, op2, operator) := (

result : [],

l_op1 : length(op1),
l_op2 : length(op2),

/*
 * Call unique of every iteration to cut down on memory usage.
 * Loop over shorter list (because it is probably faster???)
 */
if (l_op1 < l_op2) then
   for i in op1 do
      result : unique(append(result, do_op(i, op2, operator)))
else
   for i in op2 do
      result : unique(append(result, do_op(op1, i, operator))),
delete(0, result)
);

apply_all_ops(op1, op2) := (
result : [],

for i_op in operators do
   result : unique(append(result, eval_op(op1, op2, i_op))),

result
);

non_neg(n) := ( n >= 0);

list_info(l) := block (
l_i : sublist(l, integerp),
/* Add 1 to include 0 in count */
print("Elements ", length(l)+1,
      ", integer elements ", length(l_i)+1,
      ", non-negative integer elements ", length(sublist(l_i, non_neg))+1),
last_l: last(l_i),
for i:1 thru last_l do
   if (member(i, l_i) = false) then
      (
      print("First missing value ", i),
      return(1)
      ) 
);

all_1 : sort(unique(flatten(append(
                  eval_op(one_nine, one_nine, TIMES),
                  eval_op(one_nine, one_nine, DIVIDE),
                  eval_op(one_nine, one_nine, MINUS),
                  eval_op(one_nine, one_nine, PLUS)))));
list_info(all_1);

all_2 : sort(unique(append(
                    apply_all_ops(one_nine, all_1),
                    apply_all_ops(all_1, one_nine))));
list_info(all_2);
all_3 : sort(unique(append(
                    apply_all_ops(all_1, all_1),
                    apply_all_ops(one_nine, all_2),
                    apply_all_ops(all_2, one_nine))));
all_4 : sort(unique(append(
                     apply_all_ops(all_1, all_2),
                     apply_all_ops(all_2, all_1),
                     apply_all_ops(one_nine, all_3),
                     apply_all_ops(all_3, one_nine))));
all_5 : sort(unique(append(
                     apply_all_ops(all_2, all_2),
                     apply_all_ops(all_1, all_3),
                     apply_all_ops(all_3, all_1),
                     apply_all_ops(one_nine, all_4),
                     apply_all_ops(all_4, one_nine))));

/* Need more than 4G of memory for the following to execute */
all_6 : sort(unique(append(
                     apply_all_ops(all_3, all_3),
                     apply_all_ops(all_2, all_4),
                     apply_all_ops(all_4, all_2),
                     apply_all_ops(all_1, all_5),
                     apply_all_ops(all_5, all_1))));

