AlpsBoolImpl.mesa
Created by Bertrand Serlet, February 27, 1985 11:10:14 am PST
Last edited by serlet July 4, 1985 2:11:34 am PDT
This program contains all the data structures for mainupaling BoolOps.
DIRECTORY
AlpsBool, Convert, FS, IO, Process, Rope, RopeList, TerminalIO;
AlpsBoolImpl: CEDAR PROGRAM
IMPORTS Convert, FS, IO, Process, Rope, RopeList, TerminalIO
EXPORTS AlpsBool =
BEGIN
OPEN AlpsBool;
Constants
Variable # 0 is not a real variable
true: PUBLIC Expression = NEW [ExpressionRec ← [varNb: 0, case: case11]];
false: PUBLIC Expression = NEW [ExpressionRec ← [varNb: 0, case: case11, norm: FALSE]];
RopeFromCompClass: PUBLIC PROC [case: CompClass] RETURNS [rope: ROPE] = {
rope ← SELECT case FROM case11 => "case11", case10 => "case10", caseX1 => "caseX1", caseX0 => "caseX0", case1X => "case1X", case0X => "case0X", caseXNotX => "caseXNotX", caseXY => "caseXY", ENDCASE => ERROR;
};
Instanciation of expressions
Low level function for creating Expressions.
MakeComp: PUBLIC PROC [case: CompClass, varNb: VarNb, subexpr1, subexpr2: Expression, norm: BOOLTRUE] RETURNS [Expression] =
{RETURN [NEW [ExpressionRec ← [
varNb: varNb, case: case, subexpr1: subexpr1, subexpr2: subexpr2, norm: norm]]]};
Creates an expression, setting the case field to the appriopriate value depending on possible simplifications.
If comp=FALSE then both whenTrue and whenFalse have in fact opposite values
Comp: PUBLIC PROC [table: TableOfVariables, varNb: VarNb, whenTrue, whenFalse: Expression, norm: BOOLTRUE] RETURNS [Expression] =
BEGIN
SELECT TRUE FROM
whenTrue=true    => SELECT TRUE FROM
whenFalse=true          =>
RETURN [IF norm THEN true ELSE false];
whenFalse=false         =>
RETURN [MakeComp[case10, varNb, NIL, NIL, norm]];
ENDCASE           =>
RETURN [MakeComp[case1X, varNb, NIL, whenFalse, norm]];
whenTrue=false   => SELECT TRUE FROM
whenFalse=true          =>
RETURN [MakeComp[case10, varNb, NIL, NIL, ~norm]];
whenFalse=false         =>
RETURN [IF norm THEN false ELSE true];
ENDCASE           =>
RETURN [MakeComp[case0X, varNb, NIL, whenFalse, norm]];
ENDCASE     => SELECT TRUE FROM
whenFalse=true          =>
RETURN [MakeComp[caseX1, varNb, whenTrue, NIL, norm]];
whenFalse=false         =>
RETURN [MakeComp[caseX0, varNb, whenTrue, NIL, norm]];
Equal[table, whenTrue, whenFalse, TRUE] =>
RETURN [Norm[whenTrue, norm]];
Equal[table, whenTrue, whenFalse, FALSE] =>
RETURN [MakeComp[caseXNotX, varNb, whenTrue, NIL, norm]];
ENDCASE           =>
RETURN [MakeComp[caseXY, varNb, whenTrue, whenFalse, norm]];
END;
Does not take expr.norm into account
WhenTrue: PUBLIC PROC [expr: Expression] RETURNS [Expression] =
{RETURN [SELECT expr.case FROM
case11, case10, case1X       => true,
case0X          => false,
caseX1, caseX0, caseXNotX, caseXY  => expr.subexpr1,
ENDCASE          => ERROR]};
WhenFalse: PUBLIC PROC [expr: Expression] RETURNS [Expression] =
{RETURN [SELECT expr.case FROM
case11, caseX1         => true,
case10, caseX0        => false,
case0X, case1X, caseXY      => expr.subexpr2,
caseXNotX         => Not[expr.subexpr1],
ENDCASE          => ERROR]};
Var, ExprFromVarNb: PUBLIC PROC [varNb: VarNb, norm: BOOLTRUE] RETURNS [Expression] =
{RETURN [MakeComp[case10, varNb, true, false, norm]]};
Listify: PUBLIC PROC [expr1, expr2, expr3, expr4, expr5, expr6: Expression ← NIL]
RETURNS [list: LIST OF Expression ← NIL] =
{IF expr6#NIL THEN list ← LIST [expr6];
IF expr5#NIL THEN list ← CONS [expr5, list];
IF expr4#NIL THEN list ← CONS [expr4, list];
IF expr3#NIL THEN list ← CONS [expr3, list];
IF expr2#NIL THEN list ← CONS [expr2, list];
IF expr1#NIL THEN list ← CONS [expr1, list]};
Xor: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression] RETURNS [expr: Expression] = {
expr ← Or[
table,
AndTwo[table, expr1, expr2, TRUE, FALSE],
AndTwo[table, expr1, expr2, FALSE, TRUE]];
};
Returns (expr AND exprTrue) OR (~expr AND exprFalse)
Norm specifies whether or not If should negate both exprTrue and exprFalse
If: PUBLIC PROC [table: TableOfVariables, expr, exprTrue, exprFalse: Expression, norm: BOOLTRUE] RETURNS [Expression] =
{RETURN [OrTwo[table,
AndTwo[table, expr, exprTrue, TRUE, norm],
AndTwo[table, expr, exprFalse, FALSE, norm]]]};
Expanses once the expression expr, assuming that its first variable is an auxiliary
ExpandAux: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [Expression] = {
auxOutput: OutputRef ← table[expr.varNb].fromOutput;
IF auxOutput=NIL THEN ERROR;
IF auxOutput.type#aux THEN ERROR;
RETURN [If[table, auxOutput.expr, WhenTrue[expr], WhenFalse[expr], expr.norm]]};
ExpanseAux: PUBLIC PROC [table: TableOfVariables, expr, auxExpr: Expression, auxVarNb: VarNb] RETURNS [Expression] =
{RETURN [IF expr.varNb<auxVarNb THEN expr
ELSE IF expr.varNb>auxVarNb
THEN Comp[
table, expr.varNb,
ExpanseAux[table, WhenTrue[expr], auxExpr, auxVarNb],
ExpanseAux[table, WhenFalse[expr], auxExpr, auxVarNb],
expr.norm]
ELSE If[table, auxExpr, WhenTrue[expr], WhenFalse[expr], expr.norm]]};
And: PUBLIC PROC [table: TableOfVariables, expr1, expr2, expr3, expr4, expr5, expr6: Expression ← true] RETURNS [Expression] =
{RETURN [AndTwo[table, AndTwo[table, expr1, expr2], AndTwo[table, AndTwo[table, expr3, expr4], AndTwo[table, expr5, expr6]]]]};
AndList: PUBLIC PROC [table: TableOfVariables, exprs: LIST OF Expression] RETURNS [Expression] =
{RETURN [IF exprs=NIL THEN true ELSE IF exprs.rest=NIL THEN exprs.first
ELSE AndTwo[table, exprs.first, AndList[table, exprs.rest]]]};
AndTwo: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression, norm1, norm2: BOOLTRUE] RETURNS [Expression] =
{RETURN [NorTwo[table, expr1, expr2, ~norm1, ~norm2]]};
Or: PUBLIC PROC [table: TableOfVariables, expr1, expr2, expr3, expr4, expr5, expr6: Expression ← false] RETURNS [Expression] =
{RETURN [OrTwo[table, OrTwo[table, expr1, expr2], OrTwo[table, OrTwo[table, expr3, expr4], OrTwo[table, expr5, expr6]]]]};
OrList: PUBLIC PROC [table: TableOfVariables, exprs: LIST OF Expression] RETURNS [Expression] =
{RETURN [IF exprs=NIL THEN false ELSE IF exprs.rest=NIL THEN exprs.first
ELSE OrTwo[table, exprs.first, OrList[table, exprs.rest]]]};
Nor: PUBLIC PROC [table: TableOfVariables, expr1, expr2, expr3, expr4, expr5, expr6: Expression ← false] RETURNS [Expression] =
{RETURN [Not[Or[table, expr1, expr2, expr3, expr4, expr5, expr6]]]};
NorList: PUBLIC PROC [table: TableOfVariables, exprs: LIST OF Expression] RETURNS [Expression] =
{RETURN [Not[OrList[table, exprs]]]};
NorTwo: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression, norm1, norm2: BOOLTRUE] RETURNS [Expression] =
{RETURN [Not[OrTwo[table, expr1, expr2, norm1, norm2]]]};
This one is the primitive for the others
OrTwo: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression, norm1, norm2: BOOLTRUE] RETURNS [result: Expression] =
BEGIN
varNb: VarNb ← 0;
Output["OrTwo : ", RopeFromExpression[table, expr1, norm1], " & ", RopeFromExpression[table, expr2, norm2], "\n"];
IF expr1 = (IF norm1 THEN true ELSE false) OR expr2 = (IF norm2 THEN true ELSE false) THEN RETURN [true];
IF expr1 = (IF norm1 THEN false ELSE true) THEN RETURN [Norm[expr2, norm2]];
IF expr2 = (IF norm2 THEN false ELSE true) THEN RETURN [Norm[expr1, norm1]];
compute variable on which to switch
varNb ← MAX [expr1.varNb, expr2.varNb];
result ← Comp[table,
varNb,
OrTwo[table,
IF expr1.varNb=varNb THEN WhenTrue[expr1] ELSE expr1,
IF expr2.varNb=varNb THEN WhenTrue[expr2] ELSE expr2,
IF expr1.varNb=varNb THEN norm1=expr1.norm ELSE norm1,
IF expr2.varNb=varNb THEN norm2=expr2.norm ELSE norm2],
OrTwo[table,
IF expr1.varNb=varNb THEN WhenFalse[expr1] ELSE expr1,
IF expr2.varNb=varNb THEN WhenFalse[expr2] ELSE expr2,
IF expr1.varNb=varNb THEN norm1=expr1.norm ELSE norm1,
IF expr2.varNb=varNb THEN norm2=expr2.norm ELSE norm2]];
Output["-->", RopeFromExpression[table, result], "\n"];
END;
Norm: PUBLIC PROC [expr: Expression, norm: BOOL] RETURNS [Expression] =
{RETURN [IF norm THEN expr ELSE Not[expr]]};
Not: PUBLIC PROC [expr: Expression] RETURNS [Expression] =
{RETURN [IF expr = true THEN false ELSE IF expr = false THEN true ELSE MakeComp[varNb: expr.varNb, norm: ~expr.norm, case: expr.case, subexpr1: expr.subexpr1, subexpr2: expr.subexpr2]]};
Procs operating on expressions
NegCase: PROC [case: CompClass] RETURNS [CompClass] =
{RETURN [SELECT case FROM case0X => case1X, case1X => case0X, caseX0 => caseX1, caseX1 => caseX0, ENDCASE => case]};
This Equal follows auxVar for equality
FullEqual: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression, norm: BOOLTRUE] RETURNS [BOOL] =
BEGIN
IF expr1=expr2 THEN RETURN [norm];
norm ← IF expr1.norm=expr2.norm THEN norm ELSE ~norm;
IF table[expr1.varNb].fromOutput#NIL THEN
RETURN [FullEqual[table, ExpandAux[table, expr1], expr2,
IF expr1.norm=expr2.norm THEN norm ELSE ~norm]];
IF table[expr2.varNb].fromOutput#NIL THEN
RETURN [FullEqual[table, expr1, ExpandAux[table, expr2],
IF expr1.norm=expr2.norm THEN norm ELSE ~norm]];
IF expr1.varNb#expr2.varNb THEN RETURN [FALSE];
IF expr1.case#(IF norm THEN expr2.case ELSE NegCase[expr2.case])
THEN RETURN [FALSE];
RETURN [SELECT expr1.case FROM
case10, case11      => norm,
caseX0, caseX1, caseXNotX   => FullEqual[table, expr1.subexpr1, expr2.subexpr1, norm],
case0X, case1X      => FullEqual[table, expr1.subexpr2, expr2.subexpr2, norm],
ENDCASE        => FullEqual[table, expr1.subexpr1, expr2.subexpr1, norm] AND FullEqual[table, expr1.subexpr2, expr2.subexpr2, norm]];
END;
Equal: PUBLIC PROC [table: TableOfVariables, expr1, expr2: Expression, norm: BOOLTRUE] RETURNS [BOOL] =
BEGIN
IF expr1=expr2 THEN RETURN [norm];
norm ← IF expr1.norm=expr2.norm THEN norm ELSE ~norm;
IF expr1.varNb#expr2.varNb THEN RETURN [FALSE];
IF expr1.case#(IF norm THEN expr2.case ELSE NegCase[expr2.case])
THEN RETURN [FALSE];
RETURN [SELECT expr1.case FROM
case10, case11      => norm,
caseX0, caseX1, caseXNotX   => Equal[table, expr1.subexpr1, expr2.subexpr1, norm],
case0X, case1X      => Equal[table, expr1.subexpr2, expr2.subexpr2, norm],
ENDCASE        => Equal[table, expr1.subexpr1, expr2.subexpr1, norm] AND Equal[table, expr1.subexpr2, expr2.subexpr2, norm]];
END;
RopeFromExpression: PUBLIC PROC [table: TableOfVariables, expr: Expression, norm: BOOLTRUE, deep: INT ← 4] RETURNS [ROPE] =
{IF deep<=0 THEN RETURN[" ... "];
IF ~expr.norm THEN norm ← ~norm;
RETURN [IF norm
THEN SELECT expr.case FROM
case11   => "true",
case10   => Rope.Cat["Var[", RopeFromVarNb[table, expr.varNb], "]"],
caseX0  => Rope.Cat["And[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1, TRUE, deep-1], "]"],
caseX1   => Rope.Cat["Or[~", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1, TRUE, deep-1], "]"],
case0X   => Rope.Cat["And[~", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr2, TRUE, deep-1], "]"],
case1X   => Rope.Cat["Or[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr2, TRUE, deep-1], "]"],
caseXNotX  => Rope.Cat["Xor[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1 , FALSE, deep-1], "]"],
ENDCASE  => Rope.Cat["If[", RopeFromVarNb[table, expr.varNb], ", ", Rope.Cat[RopeFromExpression[table, expr.subexpr1, TRUE, deep-1], ", ", RopeFromExpression[table, expr.subexpr2, TRUE, deep-1], "]"]]
ELSE SELECT expr.case FROM
case11   => "false",
case10   => Rope.Cat["~", RopeFromVarNb[table, expr.varNb]],
caseX0  => Rope.Cat["Or[~", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1, FALSE, deep-1], "]"],
caseX1   => Rope.Cat["And[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1, FALSE, deep-1], "]"],
case0X   => Rope.Cat["Or[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr2, FALSE, deep-1], "]"],
case1X   => Rope.Cat["And[~", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr2, FALSE, deep-1], "]"],
caseXNotX  => Rope.Cat["Xor[", RopeFromVarNb[table, expr.varNb], ", ", RopeFromExpression[table, expr.subexpr1, TRUE, deep-1], "]"],
ENDCASE  => Rope.Cat["If[", RopeFromVarNb[table, expr.varNb], ", ", Rope.Cat[RopeFromExpression[table, expr.subexpr1, FALSE, deep-1], ", ", RopeFromExpression[table, expr.subexpr2, FALSE, deep-1], "]"]]]};
AlpsRopeFromExpr: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [rope: ROPE] = {
AlpsVarFromExpr: PROC [expr: Expression, norm: BOOLTRUE] RETURNS [rope: ROPE] = {
rope ← Rope.Cat["AlpsBool.Var[", RopeFromVarNb[table, expr.varNb], IF norm THEN "" ELSE ", FALSE", "]"];
};
IF expr=true THEN RETURN["AlpsBool.true"];
IF expr=false THEN RETURN["AlpsBool.false"];
IF ~expr.norm THEN RETURN[Rope.Cat["AlpsBool.Not[", AlpsRopeFromExpr[table, Not[expr]], "]"]];
rope ← SELECT expr.case FROM
case10   => AlpsVarFromExpr[expr],
caseX0  => Rope.Cat["table.And[", AlpsVarFromExpr[expr], ", ", AlpsRopeFromExpr[table, expr.subexpr1], "]"],
caseX1   => Rope.Cat["table.Or[", AlpsVarFromExpr[expr, FALSE], ", ", AlpsRopeFromExpr[table, expr.subexpr1], "]"],
case0X   => Rope.Cat["table.And[", AlpsVarFromExpr[expr, FALSE], ", ", AlpsRopeFromExpr[table, expr.subexpr2], "]"],
case1X   => Rope.Cat["table.Or[", AlpsVarFromExpr[expr], ", ", AlpsRopeFromExpr[table, expr.subexpr2], "]"],
caseXNotX  => Rope.Cat["table.Xor[", AlpsVarFromExpr[expr, FALSE], ", ", AlpsRopeFromExpr[table, expr.subexpr1], "]"],
caseXY   => Rope.Cat["table.If[", AlpsVarFromExpr[expr], ", ", Rope.Cat[AlpsRopeFromExpr[table, expr.subexpr1], ", ", AlpsRopeFromExpr[table, expr.subexpr2], "]"]],
ENDCASE  => ERROR;
};
RopeFromExpressions: PUBLIC PROC [exprs: LIST OF Expression] RETURNS [rope: ROPENIL] =
{IF exprs#NIL THEN {rope ← RopeFromExpression[table, exprs.first]; exprs ← exprs.rest};
WHILE exprs#NIL DO
rope ← Rope.Cat[rope, ", ", RopeFromExpression[table, exprs.first]]; exprs ← exprs.rest ENDLOOP};
Utilities
nameCounter: INT ← 0;
NewName: PUBLIC PROC [rope: ROPENIL] RETURNS [ROPE] =
{nameCounter ← nameCounter + 1; RETURN [Rope.Cat[rope, Convert.RopeFromInt[nameCounter]]]};
InitTableOfVariables: PUBLIC PROC [size: INT] RETURNS [table: TableOfVariables] =
BEGIN
Process.Yield[]; Process.SetPriority[Process.priorityBackground];
table ← NEW [TableOfVariablesRec[size]];
END;
AddOutput: PUBLIC PROC [table: TableOfVariables, output: OutputRef] = {
table.outputs ← CONS[output, table.outputs];
IF output.fedBackInput=0 THEN RETURN;
table[output.fedBackInput].fromOutput ← output;
};
VarNbFromRope: PUBLIC PROC [table: TableOfVariables, name: ROPE] RETURNS [varNb: VarNb] =
BEGIN
FOR i: VarNb IN [0..table.size) DO
IF Rope.Equal[table[i].name, name] THEN RETURN [i] ENDLOOP;
Output["Use of an illegal Variable\n"]; ERROR;
END;
RopeFromVarNb: PUBLIC PROC [table: TableOfVariables, varNb: VarNb] RETURNS [name: ROPENIL] = {
IF table[varNb].name=NIL THEN ERROR;
RETURN [table[varNb].name];
};
Append: PUBLIC PROC [list1, list2: LIST OF Expression] RETURNS [LIST OF Expression] =
{RETURN [IF list1=NIL THEN list2 ELSE CONS [list1.first, Append[list1.rest, list2]]]};
Reverse: PUBLIC PROC [list: LIST OF Expression] RETURNS [newList: LIST OF Expression ← NIL] =
{WHILE list#NIL DO newList ← CONS [list.first, newList]; list ← list.rest ENDLOOP};
Input: PUBLIC PROC [text: ROPE] RETURNS [ROPE] = {
RETURN[TerminalIO.RequestRope[text]];
};
Output: PUBLIC PROC [t1, t2, t3, t4, t5, t6: ROPENIL] = {
TerminalIO.WriteRope[Rope.Cat[t1, t2, t3, t4, t5, t6]];
};
Alps heart
ReadPLAFile: PUBLIC PROC [fileName: ROPE, inputs, outputs: LIST OF ROPENIL] RETURNS [table: TableOfVariables] =
BEGIN
SkipNext: PUBLIC PROC [rope: ROPE] RETURNS [ROPE] =
{RETURN [IF rope.IsEmpty THEN rope ELSE Rope.Substr[rope, 1]]};
SkipWhite: PUBLIC PROC [rope: ROPE] RETURNS [ROPE] =
{RETURN [IF rope.IsEmpty OR rope.Fetch[0]#' THEN rope ELSE SkipWhite[SkipNext[rope]]]};
Nth: PROC [list: LIST OF ROPE, n: INT] RETURNS [x: ROPE] = {
WHILE n>0 DO list ← list.rest; n ← n-1 ENDLOOP;
x ← list.first;
};
Skip: PROC [rope: ROPE] RETURNS [ROPE] = {RETURN[SkipWhite[SkipNext[rope]]]};
inStm: IO.STREAMFS.StreamOpen[fileName: fileName];
nbins, nbterms, nbouts: VarNb ← 0;
We make a first pass to count the number of inputs, terms and outputs
DO   -- for each line
ENABLE IO.EndOfStream => EXIT;
rope: ROPE ← SkipWhite[IO.GetLineRope[inStm]];
IF rope.IsEmpty OR (SELECT rope.Fetch[0] FROM '0, '1, '., '-, 'x, 'X => FALSE, ENDCASE => TRUE) THEN LOOP;
WHILE ~rope.IsEmpty AND rope.Fetch[0]#'| DO
IF nbterms=0 THEN nbins ← nbins+1;
rope ← Skip[rope];
ENDLOOP;
rope ← Skip[rope];
WHILE ~rope.IsEmpty DO
IF nbterms=0 THEN nbouts ← nbouts+1;
rope ← Skip[rope];
ENDLOOP;
Output["."];
nbterms ← nbterms+1;
ENDLOOP;
2nd Pass
IF inputs=NIL AND outputs=NIL THEN {
Output["First pass on ", fileName, " done: ", Convert.RopeFromInt[nbins], " inputs; ", Rope.Cat[Convert.RopeFromInt[nbterms], " terms; ", Convert.RopeFromInt[nbouts], " outputs.\n"]];
FOR i: INT DECREASING IN [0..nbins) DO
inputs ← CONS[Rope.Cat["Input", Convert.RopeFromInt[i]], inputs];
ENDLOOP;
FOR i: INT DECREASING IN [0..nbouts) DO
outputs ← CONS[Rope.Cat["Output", Convert.RopeFromInt[i]], outputs];
ENDLOOP;
} ELSE {
IF nbins#RopeList.Length[inputs] THEN {Output["Number of inputs of the TruthTable (", Convert.RopeFromInt[nbins], ") does NOT agree with the inputs given.\n"]; ERROR};
IF nbouts#RopeList.Length[outputs] THEN {Output["Number of outputs of the TruthTable (", Convert.RopeFromInt[nbouts], ") does NOT agree with the outputs given.\n"]; ERROR};
};
Initialize the table
table ← InitTableOfVariables[nbins+nbterms+1];
FOR i: VarNb IN [1..nbins] DO table[i].name ← Nth[inputs, i-1] ENDLOOP;
FOR i: VarNb DECREASING IN [0..nbouts) DO
AddOutput[table, NEW [OutputRec ← [name: Nth[outputs, i], expr: false]]];
ENDLOOP;
We now read for good the PLA
inStm ← FS.StreamOpen[fileName: fileName];
Output["\n"];
FOR term: VarNb IN [1..nbterms] DO   -- for each line
termName: ROPE ← Rope.Cat["Term", Convert.RopeFromInt[term]];
operands: LIST OF Expression ← NIL; -- operands making the AND plane
rope: ROPE ← "";
WHILE rope.IsEmpty OR (SELECT rope.Fetch[0] FROM '0, '1, '., '-, 'x, 'X => FALSE, ENDCASE => TRUE) DO rope ← SkipWhite[IO.GetLineRope[inStm]] ENDLOOP;
FOR input: VarNb IN [1..nbins] DO
IF rope.Fetch[0]='1 THEN operands ← CONS [ExprFromVarNb[nbins+1-input], operands];
IF rope.Fetch[0]='0 THEN operands ← CONS [ExprFromVarNb[nbins+1-input, FALSE], operands];
rope ← Skip[rope];
ENDLOOP;
IF rope.Fetch[0]#'| THEN ERROR;
rope ← Skip[rope];
table[nbins+term].name ← termName;
AddOutput[table, NEW [OutputRec ← [
name: termName, expr: AndList[table, operands],
type: aux, fedBackInput: nbins+term
]]];
Output["term: ", RopeFromExpression[table, expr], "\n"];
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
IF outs.first.type=output THEN {
IF rope.Fetch[0]='1 THEN outs.first.expr ← Or[table, Var[nbins+term], outs.first.expr];
rope ← Skip[rope];
};
ENDLOOP;
Output["."];
ENDLOOP;
Output["\n"];
END;
DumpTT: PUBLIC PROC [table: TableOfVariables, stream: IO.STREAM] = {
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
PrintTerm: PROC [previousRope: ROPE, previousInput: VarNb, expr: Expression, out: OutputRef, norm: BOOLTRUE] = {
norm ← norm=expr.norm;
IF expr.case=case11 THEN {
IF norm THEN {
THROUGH (0..previousInput) DO
previousRope ← Rope.Cat[previousRope, "-"] ENDLOOP;
IO.PutRope[stream, previousRope];
IO.PutRope[stream, " | "];
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
IO.PutRope[stream, IF outs.first=out THEN "1" ELSE "."];
ENDLOOP;
IO.PutRope[stream, "\n"];
};
RETURN;
};
THROUGH (expr.varNb .. previousInput) DO
previousRope ← Rope.Cat[previousRope, "-"];
ENDLOOP;
PrintTerm[Rope.Cat[previousRope, "1"], expr.varNb, WhenTrue[expr], out, norm];
PrintTerm[Rope.Cat[previousRope, "0"], expr.varNb, WhenFalse[expr], out, norm];
};
IF outs.first.type=aux THEN ERROR;
PrintTerm["", table.size, outs.first.expr, outs.first];
ENDLOOP;
};
DumpAlps: PUBLIC PROC [table: TableOfVariables, name: ROPE, stream: IO.STREAM] = {
QuoteRope: PROC [rope: ROPE] RETURNS [ROPE] = {RETURN[Rope.Cat["""", rope, """"]]};
stream.PutRope["DIRECTORY AlpsBool;\n"];
stream.PutRope[Rope.Cat[name, ": CEDAR PROGRAM IMPORTS AlpsBool = BEGIN\n"]];
stream.PutRope["AlpsTable: PUBLIC PROC RETURNS [table: AlpsBool.TableOfVariables] = {\n"];
FOR i: VarNb IN [1 .. table.size) DO
stream.PutRope[Rope.Cat[" ", table[i].name, ": AlpsBool.VarNb = ", Convert.RopeFromInt[i], ";\n"]];
ENDLOOP;
stream.PutRope[Rope.Cat["table ← AlpsBool.InitTableOfVariables[", Convert.RopeFromInt[table.size],"];\n"]];
FOR i: VarNb IN [1 .. table.size) DO
stream.PutRope[Rope.Cat[" table[", table[i].name, "].name ← ", QuoteRope[table[i].name], ";\n"]];
ENDLOOP;
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
stream.PutRope[Rope.Cat[" AlpsBool.AddOutput[table, NEW[AlpsBool.OutputRec ← [name: "]];
stream.PutRope[Rope.Cat[QuoteRope[outs.first.name], ", fedBackInput: ", Convert.RopeFromInt[outs.first.fedBackInput], ", type: ", SELECT outs.first.type FROM aux => "aux", output => "output", latch => "latch", ENDCASE => ERROR]];
stream.PutRope[Rope.Cat[", expr: ", AlpsRopeFromExpr[table, outs.first.expr], "]]];\n"]];
ENDLOOP;
stream.PutRope[" };\n"];
stream.PutRope["END.\n"];
};
Enumerate: PUBLIC PROC [expr: Expression, eachNodeProc: EachNodeProc] = {
IF eachNodeProc[expr] THEN RETURN;
SELECT expr.case FROM
case11, case10      => {};
caseX1, caseX0, caseXNotX   => Enumerate[expr.subexpr1, eachNodeProc];
case1X, case0X      => Enumerate[expr.subexpr2, eachNodeProc];
ENDCASE        => {Enumerate[expr.subexpr1, eachNodeProc]; Enumerate[expr.subexpr2, eachNodeProc]};
};
CopyTree: PUBLIC PROC [table: TableOfVariables, expr: Expression, eachBranchProc: EachBranchProc] RETURNS [newExpr: Expression] = {
subTrue: Expression ← eachBranchProc[WhenTrue[expr]];
subFalse: Expression ← eachBranchProc[WhenFalse[expr]];
newExpr ← Comp[table, expr.varNb, subTrue, subFalse, expr.norm];
};
Size: PUBLIC PROC [table: TableOfVariables, expr: Expression, varNb: VarNb] RETURNS [size: INT ← 0] = {
SizeProc: EachNodeProc = {size ← size + 1};
Enumerate[expr, SizeProc];
};
NbOfCaseXY: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [nbCaseXY: INT ← 0] = {
NbOfCaseXYProc: EachNodeProc = {IF expr.case=caseXY THEN nbCaseXY ← nbCaseXY+1};
Enumerate[expr, NbOfCaseXYProc];
};
NbOfCaseXNotX: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [nbCaseXNotX: INT ← 0] = {
NbOfCaseXNotXProc: EachNodeProc = {IF expr.case=caseXNotX THEN nbCaseXNotX ← nbCaseXNotX+1};
Enumerate[expr, NbOfCaseXNotXProc];
};
MaxWidth: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [INT] = {
RETURN [1+NbOfCaseXY[table, expr]+NbOfCaseXNotX[table, expr]];
};
MinWidth: PUBLIC PROC [table: TableOfVariables] RETURNS [minWidth: INT ← 0] = {
FOR input: VarNb IN [1..table.size) DO
width: INT ← 0;
ExprAddWidth: EachNodeProc = {IF expr.varNb<=input THEN {width ← width+1; quit ← TRUE}};
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
Enumerate[outs.first.expr, ExprAddWidth];
ENDLOOP;
minWidth ← MAX[width, minWidth];
ENDLOOP;
};
To create a fresh UsedVarsSequence with contents being ALL[FALSE]
NoUsedVarsSequence: PUBLIC PROC [table: TableOfVariables] RETURNS [allFalseUsedVarSequence: UsedVarsSequence] = {
allFalseUsedVarSequence ← NEW [UsedVarsSequenceRec[table.size]];
FOR i: VarNb IN [1 .. table.size) DO allFalseUsedVarSequence[i] ← FALSE ENDLOOP;
};
ExprAddUsedVars: PUBLIC PROC [expr: Expression, usedVars: UsedVarsSequence] = {
ExprAddUsedVarsProc: EachNodeProc = {usedVars[expr.varNb] ← TRUE};
Enumerate[expr, ExprAddUsedVarsProc];
};
NbVars: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [nb: INT ← 0] = {
usedVars: UsedVarsSequence ← NoUsedVarsSequence[table];
ExprAddUsedVars[expr, usedVars];
FOR i: VarNb IN [1 .. table.size) DO IF usedVars[i] THEN nb ← nb + 1 ENDLOOP;
};
NbUsedVar: PUBLIC PROC [expr: Expression, varNb: VarNb] RETURNS [nbUsedVar: INT ← 0] = {
NbUsedVarProc: EachNodeProc = {quit ← expr.varNb<=varNb; IF expr.varNb=varNb THEN nbUsedVar ← nbUsedVar+1};
Enumerate[expr, NbUsedVarProc];
};
Deep: PUBLIC PROC [table: TableOfVariables, expr: Expression] RETURNS [INT] = {
DeepVarNb: PUBLIC PROC [varNb: VarNb] RETURNS [INT] = {
RETURN [IF table[varNb].fromOutput#NIL AND table[varNb].fromOutput.type=aux THEN 3+Deep[table, table[varNb].fromOutput.expr] ELSE 0];
};
RETURN [SELECT expr.case FROM
case11       => 0,
case10       => DeepVarNb[expr.varNb],
caseX1, caseX0, caseXNotX => 1 + MAX [DeepVarNb[expr.varNb], Deep[table, expr.subexpr1]],
case1X, case0X    => 1 + MAX [DeepVarNb[expr.varNb], Deep[table, expr.subexpr2]],
ENDCASE      => 1 + MAX [DeepVarNb[expr.varNb], Deep[table, expr.subexpr1], Deep[table, expr.subexpr2]]];
};
NbOfVars: PUBLIC PROC [table: TableOfVariables] RETURNS [input, aux, output, latch: VarNb ← 0] = {
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
SELECT outs.first.type FROM aux => aux ← aux + 1; output => output ← output + 1; latch => latch ← latch+1; ENDCASE => ERROR;
ENDLOOP;
input ← table.size-1-aux;
};
printLevel=0 prints nothing and just returns statistics
PrintExpression: PUBLIC PROC [table: TableOfVariables, output: OutputRef, printLevel: INT ← 4] RETURNS [size, nbOfCaseXY, maxWidth, deep: INT] =
BEGIN
expr: Expression ← output.expr;
Process.Yield[];
size ← Size[table, expr, table.size-1];
nbOfCaseXY ← NbOfCaseXY[table, expr];
maxWidth ← MaxWidth[table, expr];
deep ← Deep[table, expr];
IF printLevel#0 THEN Output[
SELECT output.type FROM aux => "Aux ", latch => "Latch ", output => "Output ", ENDCASE => ERROR,
output.name,
IF output.fedBackInput#0 THEN Rope.Cat[" (fedBackInput: ", table[output.fedBackInput].name, ") : "] ELSE ": ",
RopeFromExpression[table, expr, TRUE, printLevel],
"\n"
];
IF printLevel#0 THEN {
Output["  size: ", Convert.RopeFromInt[size], "  NbOfCaseXY: ", Convert.RopeFromInt[nbOfCaseXY]];
Output["  MaxWidth: ", Convert.RopeFromInt[maxWidth], " Deep: ", Convert.RopeFromInt[deep], "\n"];
};
END;
TableStatistics: PUBLIC PROC [table: TableOfVariables, print: BOOLFALSE] RETURNS [area, sigmaSize, sigmaNbOfCaseXY, sigmaMaxWidth, maxDeep: INT ← 0] = {
nbOfCasesArray: NbOfCasesArray ← ALL[0];
addCase: EachNodeProc = {
case: CompClass ← IF expr.norm THEN expr.case ELSE NegCase[expr.case];
nbOfCasesArray[case] ← nbOfCasesArray[case] + 1;
};
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
size, nbOfCaseXY, maxWidth, deep: INT;
[size, nbOfCaseXY, maxWidth, deep] ←
PrintExpression[table, outs.first, 0];
sigmaSize ← sigmaSize + size;
sigmaNbOfCaseXY ← sigmaNbOfCaseXY + nbOfCaseXY;
sigmaMaxWidth ← sigmaMaxWidth + maxWidth;
maxDeep ← MAX [maxDeep, deep];
Enumerate[outs.first.expr, addCase];
ENDLOOP;
IF print THEN {
FOR case: CompClass IN CompClass DO
Output[RopeFromCompClass[case], ": ", Convert.RopeFromInt[nbOfCasesArray[case]], "; "];
ENDLOOP;
Output["\n"];
};
area ← EstimatedArea[table];
IF print THEN -- statistics about variables
FOR input: VarNb IN (0..table.size) DO
nbOfCasesArray: NbOfCasesArray ← ALL[0];
addCase: EachNodeProc = {IF expr.varNb=input THEN nbOfCasesArray[expr.case] ← nbOfCasesArray[expr.case] + 1};
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
Enumerate[outs.first.expr, addCase];
ENDLOOP;
Output[table[input].name, " => "];
FOR case: CompClass IN [case10..caseXY] DO
IF nbOfCasesArray[case]#0 THEN Output[RopeFromCompClass[case], ": ", Convert.RopeFromInt[nbOfCasesArray[case]], "; "];
ENDLOOP;
Output["\n"];
ENDLOOP;
IF print THEN {
Output["\n**** sigmaSize: ", Convert.RopeFromInt[sigmaSize]];
Output[" sigmaNbOfCaseXY: ", Convert.RopeFromInt[sigmaNbOfCaseXY]];
Output[" MinWidth: ", Convert.RopeFromInt[MinWidth[table]]];
Output[" sigmaMaxWidth: ", Convert.RopeFromInt[sigmaMaxWidth]];
Output[" maxDeep: ", Convert.RopeFromInt[maxDeep], "\n\n"];
};
};
With printLevel=0, just final statistics are printed
PrintTable: PUBLIC PROC [table: TableOfVariables, printLevel: INT ← 4] =
BEGIN
Output["\n"];
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
[] ← PrintExpression[table, outs.first, printLevel];
ENDLOOP;
[] ← TableStatistics[table, TRUE];
END;
IdentityRenum: PUBLIC RenumProc = {newVarNb ← oldVarNb};
ChangeVars: PUBLIC PROC [table: TableOfVariables, expr: Expression, renumProc: RenumProc] RETURNS [Expression] = {
NoChange: PROC [expr: Expression] RETURNS [BOOL] = {
RETURN [expr=true OR expr=false OR (renumProc[expr.varNb]=expr.varNb AND NoChange[WhenTrue[expr]] AND NoChange[WhenFalse[expr]])];
};
RETURN [IF NoChange[expr] THEN expr ELSE If[
table, ExprFromVarNb[renumProc[expr.varNb]],
ChangeVars[table, WhenTrue[expr], renumProc],
ChangeVars[table, WhenFalse[expr], renumProc],
expr.norm]];
};
Factorize: PUBLIC PROC [table: TableOfVariables, expr, aux: Expression, auxVar: VarNb] RETURNS [Expression] =
BEGIN
Returns an expression equalling expr when aux is equal to valAux (true/false depending on norm), but which does not depend on any variable used in aux, or NIL if it is not possible to find such an expression.
EvalExprWhenAuxIs: PUBLIC PROC [expr, aux: Expression, norm: BOOLEAN] RETURNS [res: Expression ← NIL] =
BEGIN
subTrue, subFalse: Expression;
SELECT TRUE FROM
expr=false OR expr=true       => RETURN [expr];
expr.varNb>aux.varNb        =>
BEGIN
subTrue ← EvalExprWhenAuxIs[WhenTrue[expr], aux, norm];
IF subTrue=NIL THEN RETURN;
subFalse ← EvalExprWhenAuxIs[WhenFalse[expr], aux, norm];
IF subFalse=NIL THEN RETURN;
RETURN [Comp[table, expr.varNb, subTrue, subFalse, expr.norm]];
END;
if meaninglesss when variable is true, just assume variable is false
FullEqual[table, WhenTrue[aux], true, ~norm]   =>
RETURN [EvalExprWhenAuxIs[IF expr.varNb=aux.varNb THEN WhenFalse[expr] ELSE expr, WhenFalse[aux], norm]];
if meaninglesss when variable is false, just assume variable is true
FullEqual[table, WhenTrue[aux], true, ~norm]   =>
RETURN [EvalExprWhenAuxIs[IF expr.varNb=aux.varNb THEN WhenTrue[expr] ELSE expr, WhenTrue[aux], norm]];
ENDCASE              =>
BEGIN
subTrue ← EvalExprWhenAuxIs[IF expr.varNb=aux.varNb THEN WhenTrue[expr] ELSE expr, WhenTrue[aux], norm];
IF subTrue=NIL THEN RETURN;
subFalse ← EvalExprWhenAuxIs[IF expr.varNb=aux.varNb THEN WhenFalse[expr] ELSE expr, WhenFalse[aux], norm];
IF subFalse=NIL THEN RETURN;
IF ~FullEqual[table, subTrue, subFalse, TRUE] THEN RETURN; -- no way to be independent of that variable
RETURN [subTrue];
END;
END;
IF expr=true OR expr=false THEN RETURN [expr];
IF expr.varNb > aux.varNb THEN RETURN [Comp[
table, expr.varNb,
Factorize[table, WhenTrue[expr], aux, auxVar],
Factorize[table, WhenFalse[expr], aux, auxVar],
expr.norm]];
IF expr.varNb<aux.varNb THEN RETURN [expr];
The two following are case that happen quite frequently, and which are easy to test
IF Equal[table, expr, aux] THEN
{Output["="]; RETURN [ExprFromVarNb[auxVar, TRUE]]};
IF Equal[table, expr, aux, FALSE] THEN
{Output["="]; RETURN [ExprFromVarNb[auxVar, FALSE]]};
Some factorization can be tried
Output["/"]; -- to show we are starting the real work
BEGIN
subTrue, subFalse, fact: Expression;
subTrue ← EvalExprWhenAuxIs[expr, aux, TRUE];
IF subTrue=NIL THEN RETURN [expr]; -- failed!
subFalse ← EvalExprWhenAuxIs[expr, aux, FALSE];
IF subFalse=NIL THEN RETURN [expr]; -- failed!
fact ← Comp[table, auxVar, subTrue, subFalse];
IF NbOfCaseXY[table, fact] < NbOfCaseXY[table, expr] THEN {Output["*"]; RETURN [fact]};
Output["?"]; -- probably a bug in the algorithm if this appear
RETURN [expr];
END;
END;
Permute2Vars: PUBLIC PROC [table: TableOfVariables, varNb1, varNb2: VarNb] RETURNS [newTable: TableOfVariables] = {
Renum: RenumProc =
{RETURN [IF oldVarNb=varNb1 THEN varNb2 ELSE IF oldVarNb=varNb2 THEN varNb1 ELSE oldVarNb]};
newTable ← InitTableOfVariables[table.size];
FOR i: VarNb IN [1 .. table.size) DO
newTable[Renum[i]].name ← table[i].name;
ENDLOOP;
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
output: OutputRef ← outs.first;
AddOutput[newTable, NEW[OutputRec ← [name: output.name, type: output.type, expr: ChangeVars[newTable, output.expr, Renum], fedBackInput: Renum[output.fedBackInput]]]];
ENDLOOP;
};
ExprWhenVarIs: PUBLIC PROC [table: TableOfVariables, expr: Expression, varNb: VarNb, varNbNorm: BOOLTRUE] RETURNS [newExpr: Expression] = {
IsUsed: EachNodeProc = {quit ← expr.varNb<=varNb; isUsed ← expr.varNb=varNb};
isUsed: BOOLFALSE;
Construct: EachBranchProc = {
IF expr.varNb<varNb THEN RETURN[expr];
IF expr.varNb=varNb THEN RETURN[Norm[(IF varNbNorm THEN WhenTrue ELSE WhenFalse)[expr], expr.norm]];
newExpr ← CopyTree[table, expr, Construct];
};
Enumerate[expr, IsUsed];
RETURN [IF ~isUsed THEN expr ELSE Construct[expr]];
};
Checksum: PUBLIC PROC [table: TableOfVariables] RETURNS [checksum: INT ← 0] = {
ExprWhenAll: PROC [expr: Expression, varValue: BOOL] RETURNS [BOOL] = {
aux: OutputRef ← table[expr.varNb].fromOutput;
IF expr=true OR expr=false THEN RETURN[expr=true];
RETURN[ExprWhenAll[
(IF (IF aux#NIL AND aux.type=aux THEN ExprWhenAll[aux.expr, varValue] ELSE varValue) THEN WhenTrue ELSE WhenFalse)[expr],
varValue] = expr.norm];
};
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
type: OutputType = outs.first.type;
IF type=output OR type=latch THEN {
IF ExprWhenAll[outs.first.expr, TRUE] THEN checksum ← checksum+100;
IF ExprWhenAll[outs.first.expr, FALSE] THEN checksum ← checksum+1;
};
ENDLOOP;
};
EstimatedArea: PUBLIC PROC [table: TableOfVariables] RETURNS [area: INT ← 0] = {
FOR outs: LIST OF OutputRef ← table.outputs, outs.rest WHILE outs#NIL DO
area ← area + MaxWidth[table, outs.first.expr] + (IF outs.first.type=output THEN 1 ELSE 2);
ENDLOOP;
area ← area * (table.size-1);
};
END.