2

I have a black box with eight inputs and three outputs and I would like to write minimized boolean functions for them. I know how to simplify the boolean expressions given a truth table, but I don't have a truth table to start with. I only know how many times every output combination should appear out of the $2^8$ input combinations.

For example (combination $\times$ number of times out of $256$): \begin{align}&000 \times 51, \\ &001 \times 62, \\ &010 \times 61, \\ &011 \times 56, \\ &100 \times 14, \\ &101 \times 10,\\ &110 \times 2,\\ &111 \times 0.\end{align}

I want to fill the truth table with these combinations so that the output functions are minimized and performing an exhaustive study is unfeasible so i'm looking for other approaches. Is this a known optimization problem?

The output functions should be minimized meanining that the total number of boolean gates (it's possible to use also gates with more than two inputs) used to express the three functions is minimum

In my first attempt I used groups of powers of $2$ in order to have larger cubes so that the SOP would be minimized a little but this method depends on how I approach the problem and another person could obtain a different function. Therefore I tried to automatize the method in some heuristic algorithm but I couldn't make it. Do you have suggestions on alternatives approaches or how to develop an heuristic method?

  • Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on [meta], or in [chat]. Comments continuing discussion may be removed. – Xander Henderson Jul 04 '24 at 12:58

3 Answers3

2

Warning: What is below is not a rigorous mathematical theorem, but merely an idea of how to handle the problem in practice corroborated with some experimental observations. It gives a fairly decently performing algorithm, but the purely mathematical minimization question still remains wide open.

The key idea is to split the problem into 2 independent parts. The first part is to construct Boolean variables $a_j$ of your input variables $x_i$ such that the sets $S_j=\{x:a_j(x)=1\}$ satisfy $S_1\subset S_2\subset\dots\subset S_7$ and have prescribed cardinalities. The second part is then easy: we just interpret them as the increasing unions of cells in the Wenn diagram for $y_1,y_2,y_3$ and build the $y's$. Of course, we get the auxiliary problem of designing the building procedute that can be realized using just few gates. For the full Wenn diagram of 3 variables, I'm using the following picture:

enter image description here

That allows me to use just 6 gates after $a$'s are build to get $y$'s. Namely,

Y[1]=A[4] (no gates)
Y[2]=(A[7] AND (NOT A[5])) OR A[2] (3 gates)
Y[3]=(A[6] AND (NOT A[3])) OR A[1] (3 gates)

and if I assign appropriate cardinalities to 7 nested sets $S_j$ (represented by intervals from the left end to the $j$-th vertical line), I can get any counts I wish for the Wenn cells for three $y$'s. This is the most efficient building diagram for the full Wenn diagram, but if you know in advance that some cells are empty, you can improve it. We'll discuss the efficient building diagrams later, but now I want just to say that I'm currently trying to optimize the number of gates needed to construct $a$'s and that I can do staying in low 20's (so the final count will be in high twenties or low thirties). To give you some flavor of the resulting Boolean circuits, I'll just copy some output from the current version of the program. There is some small inconsistency in the notation here: the program lists my $a_i$ in the reverse order, so my $a_i$ is $A[8-i]$ in the code output.

For the cardinalities 20,36,51,85,133,145,174 of $S_j$ (random sample; if you want some particular one, I'll be happy to oblige), you get the Boolean circuit with 19 gates (count $19+6=25$ for $y$'s)

1 : U[1] = AND(X[8],X[7])
2 : U[2] = OR(X[8],X[7])
3 : U[3] = OR(X[6],X[7])
4 : U[4] = OR(X[5],U[3])
5 : U[5] = AND(X[4],U[4])
6 : U[6] = OR(X[3],U[5])
7 : U[7] = AND(X[2],U[6])
8 : A[1] = OR(X[1],U[7])
9 : U[8] = AND(U[2],U[6])
10 : U[9] = OR(X[2],U[8])
11 : A[2] = AND(A[1],U[9])
12 : U[10] = OR(X[2],X[4])
13 : A[3] = AND(A[2],U[10])
14 : A[4] = AND(A[3],X[4])
15 : U[11] = AND(X[3],U[3])
16 : U[12] = NOT(U[11])
17 : A[5] = AND(A[4],U[12])
18 : A[6] = AND(A[5],U[7])
19 : A[7] = AND(A[6],X[5])

I apologize for the delays, but setting the program right and making its output humanly readable takes time.

Now about building of $a_i$, or, equivalently, $S_i$. In the program above, I went from the top, building $S_7$ first. You can go from the beginning or the middle as well, and that gives you an opportunity to choose several starting points and then use the result of the best attempt (which I'm shamelessly doing now), but to illustrate the idea, it suffices to consider the descending case.

The first observation is that you can always explicitly build an interval $I(a)=[a,255]$ using only 7 AND and OR in succession. Indeed, treating $x_1$ as the top binary digit, we can either restrict the range to $[0,128)$ by putting $X[1] AND$ as the beginning of the Boolean formula, or restrict it to $[128,255)$ using $X[1] OR$. On both intervals the remaining variables will build everything, so you can continue this way. If you start with saving the odd combinations of the last two digits (two gates; one AND for 1 and one OR for 3), you reduce the maximal number of gates per interval from 7 to 6. So, if you need $m$ intervals total, you can always do it with $2+6m$ gates, which, for $m=7$, yields $44$ (that is where the theoretical bound of 50 came from). But that is too expensive. However, the very first $S_7$ needs to be built this way and the gate bound is sharp: no odd cardinality can be obtained without using all variables and that requires 7 gates, period.

However, beyond the first interval, we have some already built junk at our disposal. The idea is just to search this junk heap first at depth 4. That merely requires maintaining the heap $W$ itself and the heap $H$ of sets that can be built out of sets in $W$ in one AND, OR, or NOT. That is not too expensive: the size of $W$ for your 8/3 case is about 20 and the size of H is a few hundreds, if you weed it properly. Notice that after $S_7$ is built, we care only about the intersections of the junk heap elements with $S_7$. Then, when $S_6$ is built, we care only about the intersections with $S_6$, etc., so we can do one step a time. And all we care about at each step is just one integer parameter from 1 to 255 that also goes down, while the set of sets that can be built in 1-4 gates from the junk we have accumulated goes up. So, quite soon we will be able to add sets at the cost of about 3 intersections per set (often 2 and sometimes 1 or 4). It turns out that usually we need the interval construction only for the original seed. But in the rare case when the heap search produces no results, we can always resort to $S_7\cap I(a)$ with appropriately chosen $a$ to get any desired cardinality. That will cost us one more gate now, so the rather pessimistic count for 8/3 is $2+6+7+5\cdot 3=30$, yielding 36 gates for $y$'s. Usually, we can get away with one interval, for which the rather pessimistic scenario is $2+6+6\cdot 3=26$ and 32 gates for $y's$, which is exactly what I'm getting occasionally, though 90% of the time I stay in upper 20's. If these counts are acceptable to you, I'll go into details. If you want me to try to get even lower counts, then I'll need some time for both thinking and experimenting. I should say that it is quite an addictive problem. The main advantages of my technique are that you separate two stories (the number of output variables and the number of input ones) almost entirely and that at each step you perform just a 1-dimensional search instead of trying to adjust two or more Wenn cells simultaneously, which I have no idea how to do efficiently. So, should I go into details, or you prefer me to think more first?

fedja
  • 19,348
  • Comments have been moved to chat; please do not continue the discussion here. Before posting a comment below this one, please review the purposes of comments. Comments that do not request clarification or suggest improvements usually belong as an answer, on [meta], or in [chat]. Comments continuing discussion may be removed. – Xander Henderson Jul 04 '24 at 12:58
  • @XanderHenderson I should admit that the chat works for us so far, so you were right to move the discussion there. My sincere apologies here. As to "attacking other users", I'm not entering other people's parties with automatic rifles and tell them that since I find their existence objectionable, or just meaningless for my purposes, I'll just shoot them now. What was done, was an exact analogue of this, so my tone was extremely restrained in that case. You may delete this message after reading. – fedja Jul 06 '24 at 23:12
0

Here is a current Asymptote code. It is pretty long, so I decided to post it as a separate answer. If you want to try it on the university of Alberta website, you have to comment out the bottom pause(); command first. Also reduce MM to one iteration and chainlength to at most 8 Otherwise it times out there. I still do not guarantee that it is completely bug-free, but disp() has been fixed and one more very subtle bug has been removed :-)

I have also made it more user friendly: to play with it in various modes, just change the head settings in the top box.

 ////////// FEEL FREE TO INSERT THE DESIRED VALUES HERE  ////////////////////////////////

int inputs=9, chainlength=15; // The number of x-variables and the number of non-empty cells in the Wenn diagram

bool verbose=true; //Whether you want to see the building process step by step

bool randommode=true; //Random generation of the decreasing sequences in the range [1,2^inputs-1]

bool statistics=true; //To see the distribution of results over the runs

bool circuit=true; //To output the final circuit

int MM=10; //The number of random runs

int[] sample={}; //Insert the sequence you want to see realized here

if(randommode==false) chainlength=sample.length; sample=reverse(sort(sample)); if(sample[0]>2^inputs) {write("Unfeasible; not enough space!"); exit();} if(sample[0]==2^inputs) {write("You don't need that long chain: A[1]=TRUE"); exit();} //just to prevent a crash for an idiotic reason

////////////////////////////////////////////////////////////////////////////////////////

/* Asymptote also defnes bitwise functions int AND(int,int), int OR(int,int), int XOR(int,int), int NOT(int), int CLZ(int) (count leading zeros), int CTZ(int) (count trailing zeros), int popcount(int) (count bits populated by ones) */

int BUILD(int length) { return chainlength-1+ceil(4*max(chainlength-7,0)/7); //The cost for the final assembly. //We'll figure the correct values here later. This is just a crude approximation //that may be a couple of gates off in your range.

} //The count for the final assembly stage (not programmed yet) //In the rest I just replaced 7 by chainlength and 8 by inputs (but be careful: some 7 were actually 8-1 :lol:)

int N=0,NN=0, COUNT=0; int Q=2^(inputs-5); int ONES=2^32-1; int NOTTT(int q) { return AND(ONES,NOT(q)); }

int[] ss; for(int k=0;k<90;++k) ss[k]=0;

int ref=Q+1, op=Q+2, arg1=Q+3, arg2=Q+4, name=Q+5, anmbr=Q+6; string[] oper={"AND","OR","NOT","INPUT"}; string[] named={"X","U","A"}; int andd=0, orr=1, nott=2, inputt=3, varr=0, auxx=1,outt=2; int REF=1;

srand(seconds());

int[][] comb(int[][] W) { int[][] WW=copy(W); int N=W.length; int F(int q) { for(int k=0;k<N;++k) if(W[k][ref]==q) return k+1; return 0; }

for(int k=0;k<N;++k) { WW[k][ref]=k+1; WW[k][arg1]=F(W[k][arg1]); WW[k][arg2]=F(W[k][arg2]); } return WW; }

void print(int[][] W) { for(int k=0;k<W.length;++k) write(string(k+1)+" : "+string(W[k][ref])+ "=" +oper[W[k][op]]+"("+string(W[k][arg1])+","+string(W[k][arg2])+")"+" used as "+ named[W[k][name]] +(W[k][name]==outt? string(W[k][anmbr]):"") ); //pause(); }

void disp(int[][] W) { int[][] WW=copy(W); int[] cnt={1,1,1}; for(int k=0;k<W.length;++k) { int u=W[k][name]; if(W[k][name]==outt) WW[k][ref]=W[k][anmbr]; else {WW[k][ref]=cnt[u]; ++cnt[u];} } string s="";

for(int k=inputs;k<W.length;++k) { s+=string(k-inputs+1)+ " : "; int u=W[k][name]; s+=named[u]+"["+string((u==outt? W[k][anmbr]:WW[k][ref]))+"] = "+oper[W[k][op]]+"("; u=W[k][arg1]; if(u>0) s+=named[W[u-1][name]]+"["+string(WW[u-1][ref])+"]"; u=W[k][arg2]; if(u>0) s+=","+named[W[u-1][name]]+"["+string(WW[u-1][ref])+"]"; s+=')\n'; } write(s); write(""); //pause(); }

int[] AA(int[][] W) { int[] gg; for(int k=0;k<chainlength;++k) gg[k]=0; for(int q=0;q<2^inputs;++q) { bool[] u; int qq=q; for(int k=0;k<inputs;++k) {u[k]=(qq%2==1); qq=quotient(qq,2);} for(int k=inputs; k<W.length; ++k) { if(W[k][op]==andd) u[k]= u[W[k][arg1]-1]&& u[W[k][arg2]-1]; if(W[k][op]==orr) u[k]=u[W[k][arg1]-1] || u[W[k][arg2]-1]; if(W[k][op]==nott) u[k]=!u[W[k][arg1]-1]; if(W[k][op]==inputt) u[k]=u[W[k][arg1]-1]; if(W[k][name]==outt){if(u[k]) ++gg[W[k][anmbr]-1];} } } return(gg); }

int summ(int[] A) { int s=0; for(int q=0;q<Q;++q) s+=popcount(A[q]); return s; }

int[] COPY(int[] A) { int[] C; for(int q=0;q<Q;++q) C[q]=A[q]; C[ref]=REF; C[op]=inputt; C[arg1]=A[ref]; C[arg2]=0; C[name]=inputt; ++REF; return C; }

int[] ANDD(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) {C[q]=AND(A[q],B[q]);} C[ref]=REF; C[op]=andd; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; ++REF;

return C; }

int[] ORR(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) C[q]=OR(A[q],B[q]); C[ref]=REF; C[op]=orr; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; ++REF; return C; }

int[] Sstrt, Sup, Sdown,Sa;

bool EQ(int[] A, int[] B) { bool flag=true; for(int q=0;q<Q && flag;++q) { if(AND(A[q],Sdown[q])!=AND(B[q],Sdown[q])) flag=false; if(AND(A[q],NOTTT(Sup[q]))!=AND(B[q],NOTTT(Sup[q]))) flag=false; } return flag; }

bool NEW(int[] A, int[][] W) { bool flag=true; for(int k=0; k<W.length && flag; ++k) if(EQ(A,W[k])) flag=false; return flag; }

int IND(int[] A, int[][] W) { int ind=-1; bool flag=true; for(int k=0; k<W.length && flag; ++k) { //write(A,W[k]); pause(); if(EQ(A,W[k])) {ind=k; flag=false;} } return ind; }

int[][] purge(int[][] H, int[][] W) { int[][] S; for(int k=0;k<H.length;++k) if(NEW(H[k],S) && IND(H[k],W)<0) S[S.length]=copy(H[k]); //if(verbose) write(string(H.length-S.length)+" entries removed from H as essential duplicates"); return S; }

int[] NOTT(int[] A) { int[] C; for(int q=0;q<Q;++q) C[q]=NOTTT(A[q]); C[ref]=REF; C[op]=nott; C[arg1]=A[ref]; C[arg2]=0; C[name]=auxx; ++REF; return C; }

int[][] DIG; for(int k=0; k<inputs; ++k) { DIG[k]=new int[]; int[] dig; for(int q=0;q<Q2^inputs;++q) dig[q]=quotient(q,2^(inputs-1-k))%2; for(int q=0;q<Q;++q) { int r=0, u=1; for(int s=0;s<32;++s) {r+=dig[32q+s]u; u=2;} DIG[k][q]=r; } DIG[k][ref]=REF; DIG[k][op]=inputt; DIG[k][arg1]=0; DIG[k][arg2]=0; DIG[k][name]=varr; ++REF; } //DIG[inputs]=ANDD(DIG[inputs-1],DIG[inputs-2]); //DIG[inputs+1]=ORR(DIG[inputs-1],DIG[inputs-2]);

int[][] LSTORD;

LSTORD[0]=new int[]; LSTORD[1]=new int[]; for(int k=0; k<inputs; ++k) {LSTORD[0][k]=k; LSTORD[1][k]=inputs-1-k;} /* { {0,1,2,3,4,5,6,7}, {7,6,5,4,3,2,1,0}, {0,1,2,3,5,4,6,7}, {1,0,5,4,3,2,6,7}, {4,5,6,7,0,1,2,3} }; */

int[][] LST(int a, int ord, int[][] W, int[][] H) { int[][] LST; int b=Q*32-a, k=inputs-1; while(b%2==0) {b=quotient(b,2);--k;} LST[k]=copy(DIG[LSTORD[ord][k]]); b=quotient(b,2); //write(LST[k]); write("DIG?"); pause(); while(k>0) { --k; //write(LST[k+1],DIG[LSTORD[ord][k]]); pause(); LST[k]=(b%2==0?ORR(DIG[LSTORD[ord][k]],LST[k+1]):ANDD(DIG[LSTORD[ord][k]],LST[k+1])); //write(LST[k]); write("DIG?"); pause(); int ind=IND(LST[k],W); if(ind>=0) {LST[k]=copy(W[ind]); LST=LST[0:k+1];} ind=IND(LST[k],H); if(ind>=0 && k<LST.length-1) {LST[k]=copy(H[ind]); LST=LST[0:k+2];} b=quotient(b,2);

} if(LST.length==1) {LST[1]=copy(LST[0]); LST[0]=COPY(LST[1]);} return LST; }

struct T{int cost; int ord; string dirr;}

T CHECKINTCOST(int qup, int qdown, int[] a, int[][] W, int[][]H) { int bestord=0, bestcost=1000; string dirr; for(int ord=0; ord<LSTORD.length;++ord) { int cost=1000; if(qdown<chainlength) { int aa=1; while(summ(ANDD(Sdown,LST(aa,ord,W,H)[0]))<a[qdown]) {aa+=a[qdown]-summ(ANDD(Sdown,LST(aa,ord,W,H)[0]));} cost=LST(aa,ord,W,H).length; if(cost<bestcost) {bestcost=cost; bestord=ord; dirr="down";} } if(qup>=0) { int aa=1; while(summ(ORR(Sup,LST(aa,ord,W,H)[0]))<a[qup]) {aa+=a[qup]-summ(ORR(Sup,LST(aa,ord,W,H)[0]));} cost=LST(aa,ord,W,H).length; if(cost<bestcost) {bestcost=cost; bestord=ord; dirr="up";} } //write("For order "+string(ord)+" upcost="+string(upcost)+" downcost="+string(downcost)); } T S=new T; S.cost=bestcost; S.ord=bestord; S.dirr=dirr; return S; }

for(int mm=0; mm<(randommode? MM:1); ++mm) { int[] a; int[] str; for(int k=0;k<Q32;++k) str[k]=0; int kk=0; while(kk<chainlength) {int r=rand()%(Q32-1)+1; if(str[r]==0) {str[r]=1;++kk;}} kk=0; for(int k=Q*32-1;k>=0;--k) if(str[k]==1) {a[kk]=k;++kk;}

int ccount=100000; int[][] Wopt;

for(int qstrt=0; qstrt<chainlength; ++qstrt) { int qqq=0; write("attempt starting with A"+string(qstrt+1));

int m=0, count=BUILD(chainlength); int[][] W,H; for(int k=0;k<DIG.length;++k) W[k]=copy(DIG[k]);

if(! randommode) a=copy(sample);

string s=""; for(int k=0;k<chainlength;++k) s+=string(a[k])+" "; if(verbose || qstrt==0) write(s);

for(int q=0;q<Q;++q) {Sup[q]=0; Sdown[q]=ONES;}

int[][] WA=copy(LST(a[qstrt],0,W,H));

for(int k=WA.length-2;k>=0;--k) { W[W.length]=copy(WA[k]); if(WA[k][op]!=inputt) ++count; } Sstrt=copy(WA[0]); Sup=copy(WA[0]); Sdown=copy(WA[0]); W[W.length-1][name]=outt; W[W.length-1][anmbr]=qstrt+1; int qdown=qstrt+1, qup=qstrt-1;

if(verbose) write("done with choice "+string(1)+" with count="+string(count)+" W="+string(W.length)+" H="+string(H.length) +" we have "+string(summ(Sstrt))+"="+string(a[qstrt]));

int WLENOLD=0;

for(int qq=chainlength-2; qq>=0; --qq) { bool flag=true; int qupold=qup, qdownold=qdown;

int S=W.length; for(int k=0;k<S && flag;++k) { if(qdown<chainlength) { int[] A=W[k]; int[] T=ANDD(Sdown,A); if(flag && summ(T)==a[qdown]) {++count; W[W.length]=copy(T); Sdown=copy(T); flag=false; ++qdown;}
} if(qup>=0) { int[] A=W[k]; int[] T=ORR(Sup,A); if(flag && summ(T)==a[qup]) {++count; W[W.length]=copy(T); Sup=copy(T); flag=false; --qup;}
} }

for(int k=WLENOLD;k<S;++k) for(int m=0;m<S;++m) { int[] A=ANDD(W[k],W[m]), B=ORR(W[k],W[m]); if(NEW(A,H)) H[H.length]=copy(A); if(NEW(B,H)) H[H.length]=copy(B); }

for(int k=WLENOLD;k<S;++k) { int[] A=NOTT(W[k]); if(NEW(A,H)) H[H.length]=copy(A); }

H=purge(H,W);

WLENOLD=W.length;

if(qq==chainlength-2 && verbose) write("H grew to length "+string(H.length));

int SS=H.length;

for(int k=0;k<SS && flag;++k) { int[] A=copy(H[k]); if(qdown<chainlength) {int[] T=ANDD(Sdown,A); if(flag && summ(T)==a[qdown]) {count+=2; W[W.length]=copy(A); W[W.length]=copy(T); Sdown=copy(T); flag=false;++qdown;}} if(qup>=0) {int[] T=ORR(Sup,A); if(flag && summ(T)==a[qup]) {count+=2; W[W.length]=copy(A); W[W.length]=copy(T); Sup=copy(T); flag=false;--qup;}}
}

/* for(int k=0;k<S && flag;++k) for(int m=k;m<S && flag;++m) { int[] AA=ANDD(W[k],W[m]), A=NOTT(AA), BB=ORR(W[k],W[m]), B=NOTT(BB); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown]) {count+=3; W[W.length]=copy(AA); W[W.length]=copy(A); W[W.length]=ANDD(Sdown,A); Sdown=copy(W[W.length-1]);flag=false;++qdown;} if(flag && summ(ANDD(Sdown,B))==a[qdown]) {count+=3; W[W.length]=copy(BB); W[W.length]=copy(B); W[W.length]=ANDD(Sdown,B); Sdown=copy(W[W.length-1]); flag=false;++qdown;} } if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup]) {count+=3; W[W.length]=copy(AA); W[W.length]=copy(A); W[W.length]=ORR(Sup,A); Sup=copy(W[W.length-1]);flag=false;--qup;} if(flag && summ(ORR(Sup,B))==a[qup]) {count+=3; W[W.length]=copy(BB); W[W.length]=copy(B); W[W.length]=ORR(Sup,B); Sup=copy(W[W.length-1]); flag=false;--qup;} } } */

for(int m=0;m<SS && flag;++m) { int[] A=copy(H[m]); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown]) {count+=2; W[W.length]=copy(A); Sdown=copy(W[W.length-1]); flag=false;++qdown;} } if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup]) {count+=2; W[W.length]=copy(A); W[W.length]=ORR(Sup,A); Sup=copy(W[W.length-1]); flag=false;--qup;} } }

for(int m=0;m<SS && flag;++m) { int[] A=NOTT(H[m]); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ANDD(Sdown,A); Sdown=copy(W[W.length-1]); flag=false;++qdown;} } if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ORR(Sup,A); Sup=copy(W[W.length-1]); flag=false;--qup;} } }

for(int k=0;k<S && flag;++k) for(int m=0;m<SS && flag;++m) { int[] A=ANDD(W[k],H[m]), B=ORR(W[k],H[m]); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ANDD(Sdown,A); Sdown=copy(W[W.length-1]); flag=false;++qdown;} if(flag && summ(ANDD(Sdown,B))==a[qdown]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(B); W[W.length]=ANDD(Sdown,B); Sdown=copy(W[W.length-1]);flag=false;++qdown;} } if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ORR(Sup,A); Sup=copy(W[W.length-1]); flag=false;--qup;} if(flag && summ(ORR(Sup,B))==a[qup]) {count+=3; W[W.length]=copy(H[m]); W[W.length]=copy(B); W[W.length]=ORR(Sup,B); Sup=copy(W[W.length-1]);flag=false;--qup;;} }

}

T INTCOST;

if(flag) {INTCOST=CHECKINTCOST(qup,qdown,a,W,H); if(verbose) write("Cost of interval build = "+string(INTCOST.cost));}

bool fflag=false; if(flag && verbose) {write("working slowly SS="+string(SS)); fflag=true;}

if(flag && INTCOST.cost>4) for(int k=0;k<SS && flag;++k) { if(k%20==0 && verbose) write(k); for(int m=k+1;m<SS && flag;++m) { int[] A=ANDD(H[k],H[m]), B=ORR(H[k],H[m]); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown]) {count+=4;
W[W.length]=copy(H[k]); W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ANDD(Sdown,A); Sdown=copy(W[W.length-1]); flag=false;++qdown;} if(flag && summ(ANDD(Sdown,B))==a[qdown]) {count+=4; W[W.length]=copy(H[k]); W[W.length]=copy(H[m]); W[W.length]=copy(B); W[W.length]=ANDD(Sdown,B); Sdown=copy(W[W.length-1]);flag=false;++qdown;} }

if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup]) {count+=4;
W[W.length]=copy(H[k]); W[W.length]=copy(H[m]); W[W.length]=copy(A); W[W.length]=ORR(Sup,A); Sup=copy(W[W.length-1]); flag=false;--qup;} if(flag && summ(ORR(Sup,B))==a[qup]) {count+=4; W[W.length]=copy(H[k]); W[W.length]=copy(H[m]); W[W.length]=copy(B); W[W.length]=ORR(Sup,B); Sup=copy(W[W.length-1]);flag=false;--qup;} } } }

if(fflag) write("done this step");

if(flag) { int ord=INTCOST.ord; write("INTERVAL AT CHOICE "+string(chainlength-qq)+" WITH ord="+string(ord)+" W="+string(W.length)+" H="+string(H.length) ); int beg=count; int aa; int qq; int[][] WA; if(INTCOST.dirr=="down") qq=qdown; else qq=qup; if(qq==qdown) { aa=1; while(summ(ANDD(Sdown,LST(aa,ord,W,H)[0]))<a[qdown]) {aa+=a[qdown]-summ(ANDD(Sdown,LST(aa,ord,W,H)[0]));} //write(summ(ANDD(Sdown,LST(aa,ord,W,H)[0])),a[qdown]); pause(); WA=copy(LST(aa,ord,W,H)); for(int k=WA.length-2;k>0 && flag;--k) { W[W.length]=copy(WA[k]); ++count; } } if(qq==qup) { aa=1; while(summ(ORR(Sup,LST(aa,ord,W,H)[0]))<a[qup]) {aa+=a[qup]-summ(ORR(Sup,LST(aa,ord,W,H)[0]));} WA=copy(LST(aa,ord,W,H)); for(int k=WA.length-2;k>0 && flag;--k) { W[W.length]=copy(WA[k]); ++count; } } if(flag) { W[W.length]=copy(WA[0]); ++count; if(qq==qdown) { if(qq!=qstrt+1 || ord!=0) {W[W.length]=ANDD(Sdown,WA[0]); Sdown=copy(W[W.length-1]); ++count;} else Sdown=copy(WA[0]); ++qdown; } if(qq==qup) { if(qq!=qstrt-1 || ord!=0) {W[W.length]=ORR(Sup,WA[0]); Sup=copy(W[W.length-1]); ++count;} else Sup=copy(WA[0]); --qup;} } write("added "+string(count-beg)); }

//

W[W.length-1][name]=outt; if(qup<qupold) W[W.length-1][anmbr]=qupold+1; if(qdown>qdownold) W[W.length-1][anmbr]=qdownold+1;

if(verbose) { write("done with choice "+string(chainlength-qq)+" with count="+string(count)+" W="+string(W.length)+" H="+string(H.length) +" we have "+(qupold>=0?string(summ(Sup))+"="+string(a[qupold]):"")+" or " +(qdownold<chainlength?string(summ(Sdown))+"="+string(a[qdownold]):"")); //pause(); }

if(count+qq>=ccount) {qq=-1; count=100;} } if(count<ccount){ccount=count; Wopt=copy(W);} write(ccount,count, H.length);

}

++NN; ++ss[ccount]; write("summary"); write(ccount, NN); COUNT=max(COUNT,ccount);

//print(Wopt); //print(comb(Wopt)[inputs:Wopt.length]); if(circuit) {write("Circuit"); write(""); disp(comb(Wopt)); write("");} //pause(); int[] aact=AA(comb(Wopt)); for(int k=0;k<chainlength;++k) if(aact[k]!=a[k]) {write("Failure!"); write(AA(comb(Wopt))); pause();} //write(AA(comb(Wopt)));

if(statistics) { write(""); write("Statistics for "+string(NN)+" runs:"); write(""); int[] NUM; for(int k=0; k<200;++k) NUM[k]=k; int u=0; while(ss[u]==0) ++u; write( NUM[u:COUNT+1], ss[u:COUNT+1]); write(""); }

write(""); write("*************************"); write(""); } pause();

This one is to accomodate for what (as I was kindly notified by Andrea) are the common logical gates in microelectronics: NOT and NAND/NOR with 2 or 3 inputs (the cost of each element in terms of the area on the motherboard is just the number of inputs, so it is still weighted summation if you ignore the geometric layout subtleties). Again, the pause(); in the end has to be removed before you try it on the U of Alberta site. The rest works exactly as before except the initial count is set to 0 and the cost is output in the total number of inputs of the standard gates. To compare meaningfully, the median cost of the AND/OR circuit the previous version built on the 8/3 case (inputs=8, chainlength=7) would be (26-6)*3=60. If you are curious what it is now, just run the code :lol:

fedja
  • 19,348
  • @AndreaMarenco (and everyone else who cared) I just posted the attempt at the solution for the more precise formalization of the real engineering problem in question in a separate answer. The code in this one can be kept or eventually deleted at moderators discretion. I'm letting it stay for now. – fedja Jul 06 '24 at 22:11
0

Alas, the new code doesn't fit together with the previous one. New answer then :-)

////////// FEEL FREE TO INSERT THE DESIRED VALUES HERE  ////////////////////////////////

int inputs=9, chainlength=15; // The number of x-variables and the number of non-empty cells in the Wenn diagram

int MAXGATEINPUT=3; //the maximal number of allowed inputs for AND, OR, NAND, NOR

int MAXHEAPSIZE=700;

bool verbose=true; //Whether you want to see the building process step by step

bool randommode=false; //Random generation of the decreasing sequences in the range [1,2^inputs-1]

bool statistics=true; //To see the distribution of results over the runs

bool circuit=true, rawcircuit=false; //To output the final circuit

int MM=1000; //The number of random runs

int[] sample={471,448,438,384,326,282,264,248,204,144,102,46,24,16,8}; //124 118 68 53 22 4 //Insert the sequence you want to see it realized here

if(randommode==false) chainlength=sample.length; sample=reverse(sort(sample)); if(!randommode && sample[0]>2^inputs) {write("Unfeasible; not enough space!"); pause(); exit();} if(!randommode && sample[0]==2^inputs) {write("You don't need that long chain: A[1]=TRUE"); pause(); exit();} //just to prevent a crash for an idiotic reason

////////////////////////////////////////////////////////////////////////////////////////

/* Asymptote also defnes bitwise functions int AND(int,int), int OR(int,int), int XOR(int,int), int NOT(int), int CLZ(int) (count leading zeros), int CTZ(int) (count trailing zeros), int popcount(int) (count bits populated by ones) */

int[][] assembly= { {}, {1}, {1,2}, {1,3,2}, {1,3,2,4}, {2,3,1,5,4}, {5,1,3,2,6,4}, {7,5,1,3,2,6,4}, {7,5,1,3,2,6,4,8}, {7,5,4,6,2,3,1,9,8} }; //Can you see the pattern? I'm too stupid to discern it yet, so I'll play a bit more with small values...

int FAILCOUNT=0;

int BUILD(int length) { return 0; if(length<10) { int t=length-1; if(popcount(length)==1) ++t; return 2t; }
else return 2
(chainlength-1+ceil(4*max(chainlength-7,0)/7)); //The cost for the final assembly. //We'll figure the correct values for length>9 later. This is just a crude approximation //that may be a couple of gates off in your range.

} //The count for the final assembly stage (not programmed yet) //In the rest I just replaced 7 by chainlength and 8 by inputs (but be careful: some 7 were actually 8-1 :lol:)

int N=0,NN=0, COUNT=0, GATE3COUNT=0; int red=min(inputs,5), RED=2^red; int Q=2^(inputs-red); int ONES=2^RED-1; int NOTTT(int q) { return AND(ONES,NOT(q)); }

int[] ss; for(int k=0;k<400;++k) ss[k]=0;

int cost=Q, ref=Q+1, op=Q+2, name=Q+3, anmbr=Q+4, args=Q+5, arg1=args, arg2=args+1; string[] oper={"AND","OR","NAND", "NOR", "NOT","INPUT","BRED","BRED"}; string[] named={"X","U","A","B","FALSE","TRUE","BRED"}; int andd=0, orr=1, nandd=2, norr=3, nott=4, inputt=5, varr=0, auxx=1,outt=2,outnott=3, falst=4, truee=5, upp=0, downn=1;

int REF=1;

int[] opcost={3,3,2,2,1,0};

srand(seconds());

int[][] comb(int[][] W) { int[][] WW=copy(W); int N=W.length; int F(int q) { for(int k=0;k<N;++k) if(W[k][ref]==q) return k+1; return 0; }

for(int k=0;k<N;++k) { WW[k][ref]=k+1; for(int arg=args; arg<WW[k].length; ++arg) WW[k][arg]=F(W[k][arg]); } //write("comb finished"); return WW; }

void print(int[][] W) { for(int k=0;k<W.length;++k) { string s=""; s+=string(k+1)+" : "+string(W[k][ref])+ "=" +oper[W[k][op]]; s+="("; for(int arg=args; arg<W[k].length;++arg) { if(arg==args) s+"("; s+=string(W[k][arg]); if(arg<W[k].length-1) s+=","; if(arg==W[k].length-1) s+=")"; }

s+=" used as "+ named[W[k][name]] +(W[k][name]==outt || W[k][name]==outnott? string(W[k][anmbr]):""); write(s); } //pause(); }

void disp(int[][] W) { int[][] WW=copy(W); int[] cnt={1,1,1}; for(int k=0;k<W.length;++k) { int u=W[k][name]; if (u==falst || u==truee) u=varr; if(W[k][name]==outt|| W[k][name]==outnott) WW[k][ref]=W[k][anmbr]; else {WW[k][ref]=cnt[u]; ++cnt[u];} } string s=""; int inputts=inputs+2; for(int k=inputts;k<W.length;++k) { s+=string(k-inputts+1)+ " : "; int u=W[k][name]; s+=named[u]+"["+string((u==outt || u==outnott? W[k][anmbr]:WW[k][ref]))+"] = "+oper[W[k][op]]+"("; for(int arg=args; arg<W[k].length; ++arg) { u=W[k][arg]; if(u>0) s+=named[W[u-1][name]]+(W[u-1][name]==falst || W[u-1][name]==truee? "" : "["+string(WW[u-1][ref])+"]"); if(arg<W[k].length-1) s+=","; } s+=')\n'; } write(s); write(""); //pause(); }

int[] AA(int[][] W, int ccount) { int costcount=BUILD(chainlength);

int[] gg, ggnott; for(int k=0;k<chainlength;++k) {gg[k]=0; ggnott[k]=0;} for(int q=0;q<2^inputs;++q) { bool[] u; int qq=q; for(int k=0;k<inputs;++k) {u[k]=(qq%2==1); qq=quotient(qq,2);} u[inputs]=false; u[inputs+1]=true; //if(q==137) for(int k=0;k<inputs;++k) write(string(k)+" "+(u[k]?"true":"false")); int inputts=inputs+2; for(int k=inputts; k<W.length; ++k) {

if(W[k][op]==nott) {u[k]=!u[W[k][args]-1]; if(q==0) costcount+=opcost[nott];} if(W[k][op]==inputt) {u[k]=u[W[k][args]-1]; if(q==0) costcount+=opcost[inputt];} bool currand=true, curror=false; for(int arg=args; arg<W[k].length; ++arg) { currand=currand && u[W[k][arg]-1]; curror=curror || u[W[k][arg]-1]; } if(W[k][op]==andd) {u[k]= currand; if(q==0) costcount+=opcost[andd]+W[k].length-args-2;} if(W[k][op]==orr) {u[k]= curror; if(q==0) costcount+=opcost[orr]+W[k].length-args-2;} if(W[k][op]==nandd) {u[k]= !currand; if(q==0) costcount+=opcost[nandd]+W[k].length-args-2;} if(W[k][op]==norr) {u[k]= !curror; if(q==0) costcount+=opcost[norr]+W[k].length-args-2;}

//if(q==137) write(string(k)+" "+(u[k]?"true":"false"));

if(W[k][name]==outt){if(u[k]) ++gg[W[k][anmbr]-1];} if(W[k][name]==outnott){if(u[k]) ++ggnott[W[k][anmbr]-1];} } //if(q==137) pause();

}

for(int k=0;k<gg.length;++k) if(gg[k]+ggnott[k]!=Q*RED) {write("Misnegation!"); write(gg,ggnott); pause();}

if(costcount!=ccount) {write("Cost miscalculation!"); write(costcount, ccount); pause();}

return(gg); }

int summ(int[] A) { int s=0; for(int q=0;q<Q;++q) s+=popcount(A[q]); return s; }

bool LESS(int[] A, int[] B) { return A[cost]<B[cost]; }

int[] COPY(int[] A) { int[] C; for(int q=0;q<Q;++q) C[q]=A[q]; C[ref]=REF; C[op]=inputt; C[arg1]=A[ref]; C[name]=auxx; C[cost]=opcost[inputt]; ++REF; return C; }

int[] ANDD(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) {C[q]=AND(A[q],B[q]);} C[ref]=REF; C[op]=andd; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; C[cost]=opcost[andd]; ++REF;

return C; }

int[] ORR(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) C[q]=OR(A[q],B[q]); C[ref]=REF; C[op]=orr; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; C[cost]=opcost[orr]; ++REF; return C; }

int[] NORR(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) C[q]=NOTTT(OR(A[q],B[q])); C[ref]=REF; C[op]=norr; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; C[cost]=opcost[norr]; ++REF; return C; }

int[] NANDD(int[] A, int[] B) { int[] C; for(int q=0;q<Q;++q) {C[q]=NOTTT(AND(A[q],B[q]));} C[ref]=REF; C[op]=nandd; C[arg1]=A[ref]; C[arg2]=B[ref]; C[name]=auxx; C[cost]=opcost[nandd]; ++REF;

return C; }

int[] Sstrt, Sup, Sdown,Sa;

bool EQ(int[] A, int[] B) { bool flag=true; for(int q=0;q<Q && flag;++q) { if(AND(A[q],Sdown[q])!=AND(B[q],Sdown[q])) flag=false; if(AND(A[q],NOTTT(Sup[q]))!=AND(B[q],NOTTT(Sup[q]))) flag=false; } return flag; }

int IND(int[] A, int[][] W) { int ind=-1, ccost=10000; bool flag=true; for(int k=0; k<W.length; ++k) { if(EQ(A,W[k]) && W[k][cost]<ccost) {ind=k; ccost=W[k][cost];} } return ind; }

bool NEW(int[] A, int[][] W) { bool flag=true; int ind=IND(A,W); if(ind>=0 && W[ind][cost]<=A[cost]) flag=false; return flag; }

int[] REPORT(int[][] H) { int[] R={0,0,0,0}; for(int k=0;k<H.length;++k) ++R[H[k][cost]]; return R; }

int[][] purge(int[][] H, int[][] W, int START) { int[][] S=copy(H[0:START]); for(int k=START;k<H.length;++k) { if(NEW(H[k],S) && IND(H[k],W)<0) S[S.length]=copy(H[k]); } if(verbose) write(string(H.length-S.length)+" entries removed from H as costlier duplicates"); return S; }

int[] NOTT(int[] A) { int[] C; for(int q=0;q<Q;++q) C[q]=NOTTT(A[q]); C[ref]=REF; C[op]=nott; C[arg1]=A[ref]; C[name]=auxx; C[cost]=opcost[nott]; ++REF; return C; }

int EXTRAARGNUM(int[] A){return max(0,A.length-args-2);}

int[] NCONVERT(int[] A) { if(A[op]!=andd && A[op]!=orr) return copy(A);

int[] C; for(int q=0;q<Q;++q) C[q]=NOTTT(A[q]); C[ref]=REF; if(A[op]==orr) C[op]=norr; if(A[op]==andd) C[op]=nandd; for(int arg=args; arg<A.length; ++arg) C[arg]=A[arg]; C[cost]=opcost[C[op]]+EXTRAARGNUM(C); C[name]=auxx; ++REF;

return C; }

int[] ADJ(int[] A, int[] B) //Adding B to the list of arguments of A { if(A[op]!=andd && A[op]!=orr) return copy(A); if(EXTRAARGNUM(A)==MAXGATEINPUT-2) return copy(A); int[] C; for(int q=0;q<Q;++q) C[q]=(A[op]==andd ? AND(A[q],B[q]) : OR(A[q],B[q])); C[ref]=REF; C[op]=A[op]; for(int arg=args; arg<A.length; ++arg) C[arg]=A[arg]; C[C.length]=B[ref]; C[cost]=opcost[C[op]]+EXTRAARGNUM(C); C[name]=auxx; ++REF; return C; }

int[] NADJ(int[] A, int[] B) //Adding B to the list of arguments of A { if(A[op]!=nandd && A[op]!=norr) return copy(A); if(EXTRAARGNUM(A)==MAXGATEINPUT-2) return copy(A); int[] C; for(int q=0;q<Q;++q) C[q]=(A[op]==nandd ? NOTTT(AND(NOTTT(A[q]),B[q])) : NOTTT(OR(NOTTT(A[q]),B[q])) ); C[ref]=REF; C[op]=A[op]; for(int arg=args; arg<A.length; ++arg) C[arg]=A[arg]; C[C.length]=B[ref]; C[cost]=opcost[C[op]]+EXTRAARGNUM(C); C[name]=auxx; ++REF; return C; }

int[] FALSE; for(int k=0;k<Q;++k) FALSE[k]=0; FALSE[op]=inputt; FALSE[ref]=REF; FALSE[name]=falst; FALSE[args]=0; FALSE[cost]=opcost[inputt]; ++REF;

int[] TRUE; for(int k=0;k<Q;++k) TRUE[k]=ONES; TRUE[op]=inputt; TRUE[ref]=REF; TRUE[name]=truee; TRUE[args]=0; TRUE[cost]=opcost[inputt]; ++REF;

int[][] DIG; for(int k=0; k<inputs; ++k) { DIG[k]=new int[]; int[] dig; for(int q=0;q<Q2^inputs;++q) dig[q]=quotient(q,2^(inputs-1-k))%2; for(int q=0;q<Q;++q) { int r=0, u=1; for(int s=0;s<RED;++s) {r+=dig[REDq+s]u; u=2;} DIG[k][q]=r; } DIG[k][ref]=REF; DIG[k][op]=inputt; DIG[k][args]=0; DIG[k][name]=varr; DIG[k][cost]=opcost[inputt]; ++REF; } DIG[inputs]=FALSE; DIG[inputs+1]=TRUE;

int[][] LSTORD; LSTORD[0]=new int[]; for(int k=0; k<inputs; ++k) LSTORD[0][k]=k; for(int m=0;m<=inputs;++m) { LSTORD[m]=copy(LSTORD[0]); for(int vv=0; vv<inputs^2; ++vv) { int i=rand()%inputs, j=rand()%inputs; int t=LSTORD[m][i]; LSTORD[m][i]=LSTORD[m][j]; LSTORD[m][j]=t; } }

int[][] NLST(int a, int ord, int[][] W, int[][] H, bool thorough=false, int maxlength=inputs) { int[][] LST; if(a==0) { LST[0]=copy(FALSE); } else { int[] eps; int b=a%(QRED); int kk=inputs-1; if(a<QRED) while(b%2==0) {b=quotient(b,2); --kk;}

if(a<Q*RED) { while(kk>0) { if(b>=2^kk){eps[eps.length]=0; b=2^(kk+1)-b;} else{eps[eps.length]=1; b=2^kk-b;} --kk; } } else { while(kk>0) { eps[eps.length]=(eps.length+inputs+b)%2; b=quotient(b,2); --kk; } }

int k=min(eps.length,maxlength); int kk=k; if(a<2QRED) LST[k]=copy(DIG[LSTORD[ord][kk]]); else if(a<3QRED) { LST[k]=copy(FALSE); } else LST[k]=copy(TRUE);

while(k>0) { --k; --kk; LST[k]=(eps[k]==0?NANDD(DIG[LSTORD[ord][kk]],LST[k+1]):NORR(DIG[LSTORD[ord][kk]],LST[k+1])); //write(LST[k]); write("DIG?"); pause(); if(thorough) { int ind=IND(LST[k],W); if(ind>=0 && k<LST.length-1) {LST[k]=copy(W[ind]); LST=LST[0:k+1];} ind=IND(LST[k],H); if(ind>=0 && k<LST.length-2) {LST[k]=copy(H[ind]); LST=LST[0:k+2];} } } } if(LST.length==1) {LST[1]=copy(LST[0]); LST[0]=COPY(LST[1]);} return LST; }

int SHOOT(int aa, int dirr, int ord, int[][] W={}, int[][] H={},int maxlength=inputs) { if(dirr==upp) return summ(ORR(Sup,NLST(aa,ord,W,H,maxlength)[0])); if(dirr==downn) return summ(ANDD(Sdown,NLST(aa,ord,W,H,maxlength)[0])); write("Invalid request!"); return -1; }

int QQ=QRED; int[] CHAIN={2QQ, QQ, 3*QQ};

for(int k=1;k<inputs;++k) { int N=CHAIN.length; for(int q=0; q<N;++q) { int quot=quotient(CHAIN[q],QQ); if(quot>1) quot=5-quot; CHAIN[2*N-1-q]=quot*QQ+2^(inputs-k-1)+2^(inputs)-2^(inputs-k)-CHAIN[q]%QQ; } } if(inputs%2==0) CHAIN=reverse(CHAIN);

int NEXT(int k, int m) { if(m%2==1) {int kk=k; if(kk%(32^(m-1))==2) {kk-=2; kk+=32^(m-1);} else ++kk; return kk;} else {int kk=k; if(kk%(32^(m-1))==0) {kk+=2; kk+=32^(m-1);} else --kk; return kk;} }

int LSTARG(int goal, int dirr, int ord, int maxlength=inputs-1) { int m=1; inputs-maxlength; int[] CHN; for(int k=2*((m+1)%2); k<CHAIN.length; k=NEXT(k,m)) CHN[CHN.length]=CHAIN[k]; int a=0, b=CHN.length-1, try=-1; while(a<b) { int c=quotient(a+b,2), try=SHOOT(CHN[c], dirr, ord); if(try>=goal) b=c; else a=min(b,c+1); } if(SHOOT(CHN[a],dirr,ord,maxlength)==goal) return CHN[a]; else return -1; }

struct T{int cost; int ord; string dirr; int start; int length;}

T CHECKINTCOST(int qup, int qdown, int[] a, int[][] W, int[][]H, bool thorough=false) { int bestord=0, bestcost=100000, beststart, bestlength; string dirr; if(verbose) write("started check with qup="+string(qup)+" qdown="+string(qdown)); for(int ord=0; ord<(thorough?LSTORD.length:LSTORD.length);++ord) for(int maxlength=1; maxlength<inputs;++maxlength) { //if(verbose) write(ord); int ccost=10000; if(qdown<chainlength) { int aa=LSTARG(a[qdown],downn,ord,maxlength); if(aa>=0) { int[][] WA=NLST(aa,ord,W,H,true,maxlength); ccost=0; for(int k=0;k<WA.length-1;++k) ccost+=WA[k][cost]; if(ccost<bestcost) {bestcost=ccost; bestord=ord; dirr="down"; beststart=aa; bestlength=maxlength;} } } if(qup>=0) { int aa=LSTARG(a[qup],upp,ord,maxlength); if(aa>=0) { int[][] WA=NLST(aa,ord,W,H,true,maxlength); ccost=0; for(int k=0;k<WA.length-1;++k) ccost+=WA[k][cost]; if(ccost<bestcost) {bestcost=ccost; bestord=ord; dirr="up"; beststart=aa; bestlength=maxlength;} } } //write(maxlength,ccost,bestcost); }

if(verbose) write("ended check with beststart="+string(beststart)); if(bestcost>100) pause(); T S=new T; S.cost=bestcost+opcost[andd]; S.ord=bestord; S.dirr=dirr; S.start=beststart; S.length=bestlength; return S; }

for(int mm=0; mm<(randommode? MM:1); ++mm) { int[] a; int[] str; for(int k=0;k<QRED;++k) str[k]=0; int kk=0; while(kk<chainlength) {int r=rand()%(QRED-1)+1; if(str[r]==0) {str[r]=1;++kk;}} kk=0; for(int k=Q*RED-1;k>=0;--k) if(str[k]==1) {a[kk]=k;++kk;}

int ccount=100000; int[][] Wopt;

for(int qstrt=0; qstrt<chainlength; ++qstrt) { int qqq=0; write("attempt starting with A"+string(qstrt+1));

int m=0, count=BUILD(chainlength); int[][] W,H; for(int k=0;k<DIG.length;++k) W[k]=copy(DIG[k]);

if(! randommode) a=copy(sample);

string s=""; for(int k=0;k<chainlength;++k) s+=string(a[k])+" "; if(verbose || qstrt==0) write(s);

for(int q=0;q<Q;++q) {Sup[q]=0; Sdown[q]=ONES;}

void APPENDNOTT(int[] X, int qqq) { W[W.length]=copy(X); count+=X[cost]; W[W.length-1][name]=outnott; W[W.length-1][anmbr]=qqq+1; }

int[][] WA=copy(NLST(a[qstrt],0,W,H));

for(int k=WA.length-2;k>=0;--k) { W[W.length]=copy(WA[k]); count+=WA[k][cost]; }

Sstrt=copy(WA[0]); Sup=copy(WA[0]); Sdown=copy(WA[0]); W[W.length-1][name]=outt; W[W.length-1][anmbr]=qstrt+1; APPENDNOTT(NOTT(W[W.length-1]),qstrt);

int qdown=qstrt+1, qup=qstrt-1;

if(verbose) write("done with choice 1 with count="+string(count)+" W="+string(W.length)+" H="+string(H.length) +" we have "+string(summ(Sstrt))+"="+string(a[qstrt]));

int WLENOLD=0;

for(int qq=chainlength-2; qq>=0; --qq) {

bool flag=true; int qupold=qup, qdownold=qdown;

void APPEND(int[] X, int dir, bool flagg=true) {

if(flag && dir==upp) { int[] Y=NORR(Sup,X), Z=NOTT(Y); if(flagg) {W[W.length]=copy(X); count+=X[cost];} W[W.length]=copy(Y); W[W.length-1][name]=outnott; W[W.length-1][anmbr]=qup+1; W[W.length]=copy(Z); Sup=copy(Z); W[W.length-1][name]=outt; W[W.length-1][anmbr]=qup+1; --qup; count+=opcost[norr]+opcost[nott]; flag=false; } if(flag && dir==downn) { int[] Y=NANDD(Sdown,X), Z=NOTT(Y); if(flagg) {W[W.length]=copy(X); count+=X[cost];} W[W.length]=copy(Y); W[W.length-1][name]=outnott; W[W.length-1][anmbr]=qdown+1; W[W.length]=copy(Z); Sdown=copy(Z); W[W.length-1][name]=outt; W[W.length-1][anmbr]=qdown+1; ++qdown; count+=opcost[nandd]+opcost[nott]; flag=false; }

}

int S=W.length;

for(int k=0;k<S && flag;++k) { if(qdown<chainlength) { int[] A=W[k]; int[] T=ANDD(Sdown,A); if(flag && summ(T)==a[qdown]) {APPEND(A,downn,false);}
} if(qup>=0) { int[] A=W[k]; int[] T=ORR(Sup,A); if(flag && summ(T)==a[qup]) {APPEND(A,upp,false);} } }

int HLENOLD=H.length;

for(int k=WLENOLD;k<S;++k) { int[] A=NOTT(W[k]); for(int[] X : new int[][]{A}) if(NEW(X,H)) H[H.length]=copy(X); }

for(int k=WLENOLD;k<S;++k) for(int m=0;m<S;++m) { int[] A=ANDD(W[k],W[m]), B=ORR(W[k],W[m]), C=NANDD(W[k],W[m]), D=NORR(W[k],W[m]), E=NADJ(W[k],W[m]), F=NADJ(W[m],W[k]); for(int[] X: new int[][]{C,D,E,F})//,A,B}) if(NEW(X,H)) H[H.length]=copy(X); }

int SS=H.length;

for(int m=0;m<SS && H.length<MAXHEAPSIZE;++m) for(int k=WLENOLD;k<S;++k) { int[] A=NADJ(H[m],W[k]); for(int[] X: new int[][]{A})//,A,B}) if(NEW(X,H)) H[H.length]=copy(X); }

H=purge(H,W, HLENOLD); H=sort(H,LESS); if(verbose) write(REPORT(H));

SS=H.length;

WLENOLD=W.length;

if(qq==chainlength-2 && verbose) write("H grew to length "+string(H.length));

T INTCOST;

if(flag) INTCOST=CHECKINTCOST(qup,qdown,a,W,H); if(flag && verbose) { string s=""; for(int k=0;k<inputs;++k) s+=string(LSTORD[INTCOST.ord][k])+" "; write("Cost of interval build = "+string(INTCOST.cost) + " with order "+s+ " length "+string(INTCOST.length)); }

for(int k=0;k<SS && flag;++k) {

int[] A=copy(H[k]); if(qdown<chainlength) { int[] T=ANDD(Sdown,A); if(flag && summ(T)==a[qdown] && A[cost]+opcost[andd]<=INTCOST.cost) { APPEND(A,downn); } } if(qup>=0)
{ int[] T=ORR(Sup,A); if(flag && summ(T)==a[qup] && A[cost]+opcost[andd]<=INTCOST.cost) { APPEND(A,upp); } }

}

for(int m=0;m<SS && flag;++m) { int[] A=NOTT(H[m]); if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,A))==a[qdown] && H[m][cost]+A[cost]+opcost[andd]<=INTCOST.cost) { count+=H[m][cost]; W[W.length]=copy(H[m]); APPEND(A,downn);} } if(qup>=0) { if(flag && summ(ORR(Sup,A))==a[qup] && H[m][cost]+A[cost]+opcost[andd]<=INTCOST.cost) { count+=H[m][cost]; W[W.length]=copy(H[m]); APPEND(A,upp);} } }

for(int m=0;m<SS && flag;++m) for(int k=0;k<S && flag;++k) { int[] E=NADJ(H[m],W[k]), F=NOTT(E);

int[][] XX= new int[][]{E,F};//A,B}; int[] wm={1,1}; for(int k=0;k<XX.length;++k) { int[] X=XX[k]; if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,X))==a[qdown] && X[cost]+wm[k]H[m][cost]+opcost[andd]<INTCOST.cost) { if(k!=0) {count+=E[cost]; W[W.length]=copy(E);} APPEND(X,downn); if(k==0) ++GATE3COUNT; } } if(qup>=0) { if(flag && summ(ORR(Sup,X))==a[qup] && X[cost]+wm[k]H[m][cost]+opcost[andd]<INTCOST.cost) { if(k!=0) {count+=E[cost]; W[W.length]=copy(E);} APPEND(X,upp); if(k==0) ++GATE3COUNT; } } } }

for(int m=0;m<SS && flag;++m) for(int k=0;k<S && flag;++k) { int[] A=ANDD(W[k],H[m]), B=ORR(W[k],H[m]), C=NANDD(W[k],H[m]), D=NORR(W[k],H[m]), E=NADJ(H[m],W[k]);

int[][] XX= new int[][]{E,C,D};//A,B}; int[] wm={0,1,1}; for(int k=0;k<XX.length;++k) { int[] X=XX[k]; if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,X))==a[qdown] && X[cost]+wm[k]H[m][cost]+opcost[andd]<=INTCOST.cost) { if(k!=0) {count+=H[m][cost]; W[W.length]=copy(H[m]);} APPEND(X,downn); if(k==0) ++GATE3COUNT; } } if(qup>=0) { if(flag && summ(ORR(Sup,X))==a[qup] && X[cost]+wm[k]H[m][cost]+opcost[andd]<=INTCOST.cost) { if(k!=0) {count+=H[m][cost]; W[W.length]=copy(H[m]);} APPEND(X,upp); if(k==0) ++GATE3COUNT; } } } }

if(verbose && flag) {write("working slowly SS="+string(SS));}

if(flag) {

for(int k=0;k<SS && flag;++k) { if(k%20==0 && verbose) write(k); for(int m=0;m<k && flag;++m) { int[] A=NANDD(H[k],H[m]), B=NORR(H[k],H[m]), C=ANDD(H[k],H[m]), D=ORR(H[k],H[m]), E=NADJ(H[m],H[k]), F=NADJ(H[k],H[m]); int[] wm=new int[]{0,1,1,1}, wk=new int[]{1,0,1,1}; int[][] XX=new int[][]{E,F,A,B}; for(int kk=0;kk<XX.length;++kk) { int[] X=XX[kk]; if(qdown<chainlength) { if(flag && summ(ANDD(Sdown,X))==a[qdown] && opcost[andd]+X[cost]+H[m][cost]wm[kk]+H[k][cost]wk[kk]<=INTCOST.cost) { count+=H[m][cost]wm[kk]+H[k][cost]wk[kk];
if(wk[kk]>0) W[W.length]=copy(H[k]); if(wm[kk]>0) W[W.length]=copy(H[m]); APPEND(X,downn);} }

if(qup>=0) { if(flag && summ(ORR(Sup,X))==a[qup] && opcost[andd]+X[cost]+H[m][cost]wm[kk]+H[k][cost]wk[kk]<=INTCOST.cost) { count+=H[m][cost]wm[kk]+H[k][cost]wk[kk];
if(wk[kk]>0) W[W.length]=copy(H[k]); if(wm[kk]>0) W[W.length]=copy(H[m]); APPEND(X,upp);} }

} } } }

if(flag) { INTCOST=CHECKINTCOST(qup,qdown,a,W,H,true); if(flag && verbose) write("Cost of interval build revised to "+string(INTCOST.cost));

int ord=INTCOST.ord; if(verbose) write("INTERVAL AT CHOICE "+string(chainlength-qq)+" WITH ord="+string(ord)+" W="+string(W.length)+" H="+string(H.length) ); int beg=count; int aa=INTCOST.start, maxlength=INTCOST.length; int qq1; int[][] WA; if(INTCOST.dirr=="down") qq1=qdown; else qq1=qup;

if(qq1==qdown) { WA=copy(NLST(aa,ord,W,H,true,maxlength));

for(int k=WA.length-2;k>0 && flag;--k) { W[W.length]=copy(WA[k]); count+=WA[k][cost]; } }

if(qq1==qup) {

WA=copy(NLST(aa,ord,W,H,true,maxlength)); for(int k=WA.length-2;k>0;--k) { W[W.length]=copy(WA[k]); count+=WA[k][cost]; } }

{ if(qq1==qdown) { APPEND(WA[0],downn); } if(qq1==qup) { APPEND(WA[0],upp); }

}

if(verbose) write("added "+string(count-beg)+" to get "+string(count)); }

if(verbose) { write("done with choice "+string(chainlength-qq)+" with count="+string(count)+" W="+string(W.length)+" H="+string(H.length) +" we have "+(qupold>=0?string(summ(Sup))+"="+string(a[qupold]):"")+" or " +(qdownold<chainlength?string(summ(Sdown))+"="+string(a[qdownold]):"")); //pause(); }

if(count+qq>=ccount) {qq=-1; count=10000;} }

if(count<ccount){ccount=count; Wopt=copy(W);}

if(verbose) {disp(comb(W));} write(ccount,count,H.length);

bool flag3=false; for(int k=0;k<W.length;++k) if(EXTRAARGNUM(W[k])>0) flag3=true; //if(flag3) {disp(comb(W));} }

++NN; ++ss[ccount]; write("summary"); write(ccount, NN); COUNT=max(COUNT,ccount);

if(rawcircuit) {write("Raw circuit"); write(""); print(comb(Wopt)[0*inputs:Wopt.length]); write("");} if(circuit) {write("Circuit"); write(""); disp(comb(Wopt)); write("");} //pause(); int[] aact=AA(comb(Wopt),ccount); for(int k=0;k<chainlength;++k) if(aact[k]!=a[k]) {write("Failure!"); write(aact); pause();}

if(statistics) { write(""); write("Statistics for "+string(NN)+" runs:"); write(""); write("3 input gates were used "+string(GATE3COUNT)+" times; CHECKINCOST failed "+string(FAILCOUNT)+" times"); write(""); int[] NUM; for(int k=0; k<200;++k) NUM[k]=k; int u=0; while(ss[u]==0) ++u; write( NUM[u:COUNT+1], ss[u:COUNT+1]); write(""); }

write(""); write("*************************"); write(""); }

pause();

fedja
  • 19,348
  • @AndreaMarenco (and others). The code for the first stage updated to the final build. The new MAXHEAPSIZE parameter allows to trade speed for search depth. – fedja Jul 08 '24 at 17:57