#include "collapsing.h"
#include <time.h>


TVnejsi* Collapsing::minim(TVnejsi* nove) {  // minimalizuje SOP
	if (atoi(arg[2]) ==-1 || atoi(arg[2]) >= nove->clenu) return nove;  // arg[2]: -1 -zadna, 1 -vsechny, 2..x -vic nez 2..x clenu
//	if (nove->vnejsi[0] == NULL) return nove;
#ifdef DEBUG
	clock_t s = clock();
#endif
	TVnejsi* nove2;
	int clenu,i;
	char c;
	FILE *soubor;
	soubor = fopen("pom.pla","w");
	fprintf(soubor,".i %d\n",INPUT);
	fprintf(soubor,".o 1\n");
//	fprintf(soubor,".p %d\n",nove->clenu);
	i=0;
	while (nove->vnejsi[i] != NULL) {
		for (int j=0; j<INPUT; j++)
			switch (nove->vnejsi[i]->vnitrni2[j]) {
				case 0: fprintf(soubor,"-"); break;
				case 1: fprintf(soubor,"1"); break;
				case -1: fprintf(soubor,"0"); break;
			}
		fprintf(soubor," 1\n");
		i++;
	}
	fprintf(soubor,".e\n");
	fclose(soubor);
//	char   psBuffer[128];
//	FILE   *pPipe;
//	if( (pPipe = _popen( "espresso pom.pla","rt" )) == NULL ) exit(1);
//	fstream f("pom2.pla",ios::out);
//	while(fgets(psBuffer, 128, pPipe)) f << psBuffer; /* Read pipe until end of file, or an error occurs. */
	system("espresso < pom.pla > pom2.pla");
//	f.close();
	soubor = fopen("pom2.pla","r");
	fscanf(soubor,"%c%c%d\n%c%c%d\n%c%c%d\n",&c,&c,&i,&c,&c,&i,&c,&c,&clenu);
	nove2 = new TVnejsi(clenu+1);
	for (int i=0; i<clenu; i++) {
		nove2->vnejsi[i] = new TVnitrni(INPUT);
		for (int j=0; j<INPUT; j++)
			switch (getc(soubor)) {
				case '-': nove2->vnejsi[i]->vnitrni2[j]=0; break;
				case '1': nove2->vnejsi[i]->vnitrni2[j]=1; nove2->vnejsi[i]->pocet_norm++; break;
				case '0': nove2->vnejsi[i]->vnitrni2[j]=-1; nove2->vnejsi[i]->pocet_neg++;  break;
			}
		fscanf(soubor,"%c%c\n",&c,&c);
	}
	fclose(soubor);
	delete nove;
#ifdef DEBUG
		casEsp += clock() - s;
		pocEsp++;
#endif

	return nove2;
}


void Collapsing::absorpce(TVnejsi* nove, int* novy_soucin) {  // pouzije se absorpcni pravidlo A + A*B = A
  if (strcmp(arg[4],"true") == 0) {
#ifdef DEBUG
	clock_t s = clock();
#endif
#ifndef OLD_ABS
#ifdef ALL_ABS
	TVnejsi* to_abs;
	int index=0;
#endif
	int starsi_souciny;
	int iterator;
	char *inp,*novy,*starsi,*pom;
	bool nalezen, konec;
	int i;  // 0 - stejne, 1 - novy ma prvky navic, 2 - stary ma prvky navic, 3 - ruzne, 4 - absorpce negace
	int novy_pocet, novy_pocet_neg, novy_pocet_norm, starsi_pocet, starsi_pocet_neg, starsi_pocet_norm;  // pocet promennych v novem a starsim soucinu;
	nalezen=false;
	novy_pocet_neg = nove->vnejsi[*novy_soucin]->pocet_neg; novy_pocet_norm = nove->vnejsi[*novy_soucin]->pocet_norm;
	novy_pocet = novy_pocet_neg + novy_pocet_norm;
	starsi_souciny = *novy_soucin-1;
	while (!nalezen && starsi_souciny>=0) {
		iterator = 0; konec = false;
		starsi = &(nove->vnejsi[starsi_souciny]->vnitrni2[0]);
		novy = &(nove->vnejsi[*novy_soucin]->vnitrni2[0]);
		inp = novy + INPUT;
		starsi_pocet_neg = nove->vnejsi[starsi_souciny]->pocet_neg; starsi_pocet_norm = nove->vnejsi[starsi_souciny]->pocet_norm;
		starsi_pocet = starsi_pocet_neg + starsi_pocet_norm;
		if (novy_pocet > starsi_pocet && novy_pocet_neg+1>=starsi_pocet_neg && novy_pocet_norm+1>=starsi_pocet_norm) {
			while ((*novy == *starsi || *starsi == 0) && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
			if (novy == inp) {  // absorpce, tj. ab + abcd = ab
				delete nove->vnejsi[*novy_soucin];
				nove->vnejsi[*novy_soucin]=NULL;
				(*novy_soucin)--;
				nalezen = true;
			}
			else  // absorpce negace, tj. abe + !abcde = abe + bcde
				if (*novy == -*starsi) {
					pom = novy; novy++; starsi++;
					while ((*novy == *starsi || *starsi == 0) && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
					if (novy == inp) {
						if (*pom < 0) {nove->vnejsi[*novy_soucin]->pocet_neg--; novy_pocet_neg--;}
						else {nove->vnejsi[*novy_soucin]->pocet_norm--; novy_pocet_norm--;}
						novy_pocet = novy_pocet_neg + novy_pocet_norm;
						*pom = 0;  // mazu promennou
						starsi_souciny = *novy_soucin;
					}
				}
		}
		else if (novy_pocet < starsi_pocet && novy_pocet_neg<=starsi_pocet_neg+1 && novy_pocet_norm<=starsi_pocet_norm+1) {
			while ((*novy == *starsi || *novy == 0) && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
			if (novy == inp) {  // absorpce, tj. abcd + ab = ab
				delete nove->vnejsi[starsi_souciny];  // rusim abcd
				nove->vnejsi[starsi_souciny]=nove->vnejsi[*novy_soucin-1];
				nove->vnejsi[*novy_soucin-1]=nove->vnejsi[*novy_soucin];
				nove->vnejsi[*novy_soucin]=NULL;
				(*novy_soucin)--;
			}
			else  // absorpce negace, tj. !abcde + abe = bcde + abe
				if (*novy == -*starsi) {
					pom = starsi; novy++; starsi++;
					while ((*novy == *starsi || *novy == 0) && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
					if (novy == inp) {
						if (*pom < 0) nove->vnejsi[starsi_souciny]->pocet_neg--;
						else nove->vnejsi[starsi_souciny]->pocet_norm--;
						*pom = 0;  // mazu promennou
#ifdef ALL_ABS
						if (index==0) to_abs = new TVnejsi();
						if (index==to_abs->clenu-1) to_abs->Zvetsi();
						to_abs->vnejsi[index] = new TVnitrni();
						to_abs->vnejsi[index]->vnitrni2 = new char[INPUT];
						for (int i=0; i<INPUT; i++) to_abs->vnejsi[index]->vnitrni2[i]=nove->vnejsi[starsi_souciny]->vnitrni2[i];
						to_abs->vnejsi[index]->pocet_neg = nove->vnejsi[starsi_souciny]->pocet_neg;
						to_abs->vnejsi[index]->pocet_norm = nove->vnejsi[starsi_souciny]->pocet_norm;
						index++;
#endif
					}
				}
		}
		else if (novy_pocet == starsi_pocet && novy_pocet_neg+1>=starsi_pocet_neg && novy_pocet_norm+1>=starsi_pocet_norm) {
			while (*novy == *starsi && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
			if (novy == inp) {  // stejne, tj. abcd + abcd = abcd
				delete nove->vnejsi[*novy_soucin];
				nove->vnejsi[*novy_soucin]=NULL;
				(*novy_soucin)--;
				nalezen = true;
			}
			else  // jedna ruzna promenna, tj. abcd + !abcd = bcd
				if (*novy == -*starsi) {
					pom = novy; novy++; starsi++;
					while ((*novy == *starsi) && novy!=inp) {novy++; starsi++;}  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
					if (novy == inp) {
						if (*pom < 0) {nove->vnejsi[*novy_soucin]->pocet_neg--; novy_pocet_neg--;}
						else {nove->vnejsi[*novy_soucin]->pocet_norm--; novy_pocet_norm--;}
						novy_pocet = novy_pocet_neg + novy_pocet_norm;
						*pom = 0;  // mazu promennou
						delete nove->vnejsi[starsi_souciny];  // rusim abcd
						nove->vnejsi[starsi_souciny]=nove->vnejsi[*novy_soucin-1];
						nove->vnejsi[*novy_soucin-1]=nove->vnejsi[*novy_soucin];
						nove->vnejsi[*novy_soucin]=NULL;
						(*novy_soucin)--;
						starsi_souciny = *novy_soucin;
					}
				}
		}
		starsi_souciny--;
	}
#ifdef ALL_ABS
	if (index != 0) {
		for (i=0; i<index; i++) {
			if (++(*novy_soucin) == nove->clenu-1) nove->Zvetsi();  // pokud nedostacuje pole pro nove souciny, tak se zvetsi
			nove->vnejsi[*novy_soucin]=to_abs->vnejsi[i];
			absorpce(nove,novy_soucin);
		}
	}
#endif
#else
	int starsi_souciny,k;
	int iterator;
	bool nalezen=false, AB=true;  // AB znaci A-B
	starsi_souciny = *novy_soucin-1;
	while (!nalezen && starsi_souciny>=0)
		if (AB) {
			iterator = 0;
			while (iterator!=INPUT && (nove->vnejsi[starsi_souciny]->vnitrni2[iterator] == nove->vnejsi[*novy_soucin]->vnitrni2[iterator] || nove->vnejsi[starsi_souciny]->vnitrni2[iterator] == 0)) iterator++;  // pokud jsou stejne prvky nebo v starsi_souciny neni promenna, tak muzeme novy_soucin rusit
			if (iterator == INPUT) {  // A-B == 0, tj. B ma nektere prvky navic oproti A, a B muzem zrusit
				delete nove->vnejsi[*novy_soucin];
				nove->vnejsi[*novy_soucin]=NULL;
				(*novy_soucin)--;
				nalezen = true;
			}
			else {
				if (starsi_souciny>0) starsi_souciny--;
				else {AB = false; starsi_souciny = *novy_soucin -1;}
			}
		}
		else {  // B-A
			iterator = 0;
			while (iterator!=INPUT && (nove->vnejsi[starsi_souciny]->vnitrni2[iterator] == nove->vnejsi[*novy_soucin]->vnitrni2[iterator] || nove->vnejsi[*novy_soucin]->vnitrni2[iterator] == 0)) iterator++;  // pokud jsou stejne prvky nebo v novy_soucin neni promenna, tak muzeme stary_soucin rusit
			if (iterator == INPUT) {  // A-B == 0, tj. B ma nektere prvky navic oproti A, a B muzem zrusit
				delete nove->vnejsi[starsi_souciny];
				for ( k=starsi_souciny; k<*novy_soucin; k++) nove->vnejsi[k]=nove->vnejsi[k+1];
				nove->vnejsi[*novy_soucin]=NULL;
				(*novy_soucin)--; starsi_souciny--;
			}
			else {
				starsi_souciny--;
			}
		}
#endif
#ifdef DEBUG
		casAbs += clock() - s;
		pocAbs++;
#endif
}
}



TVnejsi* Collapsing::minim_hradlo(std::string hradlo, bool negace) {
	int i,j,k,novy_soucin;
	bool zrus;
#ifdef DEBUG
	clock_t s;
#endif
#ifdef STATE
	pocVnor++;
#endif
	TVnejsi *nove;  // zde bude nove vysledne minimalizovane hradlo
	std::string nazev_hradla, vstup;

	map <std::string,Hradlo> :: iterator uk_hradlo = data->hradla.find(hradlo);
	nazev_hradla = uk_hradlo->second.typ;
	if (nazev_hradla[0] == 'n') negace = !negace;  // pokud je hradlo negovane
	bool vytvor = false;
#ifndef NOPAK_HR
	if (data->vystup_hradla.count(hradlo) > 1)  // pokud se hradlo opakuje vickrat
		if (uk_hradlo->second.hotove_hradlo[negace] != NULL)  // pokud tam uz je vytvorene hotove hradlo
			#ifdef STATE
					{ pocVnor--;
			#endif
			return uk_hradlo->second.hotove_hradlo[negace];
			#ifdef STATE
					}
			#endif
		else vytvor = true;
#endif
	int poc_vst_int = uk_hradlo->second.inputs.size();
	THradlo *hr = new THradlo(poc_vst_int);  // struktura pro ulozeni 2 urovnove minimalizovaneho obvodu

	int pocet_hradel=0;  // pocet hradel na ktere jde vystup

	list<std::string> :: iterator uk_vstupy = uk_hradlo->second.inputs.begin();
	for (i=0,k=0; i<poc_vst_int; i++) {
		if (data->hradla.count(uk_vstupy->data())) {
			vstup = (data->hradla.find(*uk_vstupy))->first.data();
			hr->hradlo[i] = minim_hradlo(vstup,negace);
		}
		else {
			hr->hradlo[i]=new TVnejsi;
			hr->hradlo[i]->vnejsi[0]=new TVnitrni(INPUT);
			j=0;
			vstup = *uk_vstupy;//(data->hradla.find(uk_vstupy->data()))->first.data();
			while (vstup != vstupy[j]) j++;
			if (negace) hr->hradlo[i]->vnejsi[0]->vnitrni2[j] = -1; 
			else hr->hradlo[i]->vnejsi[0]->vnitrni2[j] = 1; 
		}
		uk_vstupy++;
	}

	if (nazev_hradla == "and") { if (negace) nazev_hradla = "or"; }
	else if (nazev_hradla == "or") { if (negace) nazev_hradla = "and"; }
	else if (nazev_hradla == "nand") if (negace) nazev_hradla = "or";
										else nazev_hradla = "and";
	else if (nazev_hradla == "nor") if (negace) nazev_hradla = "and";
								else nazev_hradla = "or";
	else if (nazev_hradla == "not") nazev_hradla = "buf";

//printf("%s )",hradlo.data());

#ifdef STATE
	printf("%5d\b\b\b\b\b",pocVnor);
#endif
	if (nazev_hradla == "buf") {
		if (vytvor) {
			uk_hradlo->second.hotove_hradlo[negace] = new TVnejsi(hr->hradlo[0]->clenu);
			TVnejsi *po = uk_hradlo->second.hotove_hradlo[negace];
			i = 0;
			while (hr->hradlo[0]->vnejsi[i]!=NULL) {
				po->vnejsi[i] = new TVnitrni(INPUT);
				for (j=0; j<INPUT; j++) po->vnejsi[i]->vnitrni2[j] = hr->hradlo[0]->vnejsi[i]->vnitrni2[j];
				i++;
			}
		}
#ifdef STATE
		pocVnor--;
#endif
		return hr->hradlo[0];
	}
	else if (nazev_hradla == "and") {  // (ab+cd) AND (ef+gh) = abef + abgh + cdef + cdgh
#ifdef DEBUG
		s=clock();
#endif
#ifndef OLD_AND
		int pom_poc_vst;
		pom_poc_vst = poc_vst_int;
		if (pom_poc_vst > 2) {
			poc_vst_int = 2;
		}
	  while (pom_poc_vst > 1) {

//printf("\n%d ",pom_poc_vst);
		nove = new TVnejsi;
		for (i=0; i<poc_vst_int; i++)
			if ( hr->hradlo[i]->vnejsi[0] == NULL) 
				#ifdef STATE
						{ pocVnor--;
				#endif
				return nove;  // pokud by nektery ze vstupu byl nulovy, je tez cely and nulovy
				#ifdef STATE
						}
				#endif
		int *vynasobeno = new int[poc_vst_int];  // pole prave nasobenych clenu
		for (i=0; i<poc_vst_int; i++) vynasobeno[i]=0;
		int promenna;  // iterator prochazejici promenne v mnozine
#ifndef NSTEJNA
		bool *stejny_clen = new bool[poc_vst_int];  // pole urcujici zda promenna tam uz je, pokud true, tak se nepude na dalsi promennou v clenu ale na konec
		for (j=0; j<poc_vst_int; j++) stejny_clen[j]=false;
#endif
		novy_soucin=0;
		while (hr->hradlo[0]->vnejsi[vynasobeno[0]] != NULL) {  // dokud je v prvnim nasobenem clenu este co nasobit
			nove->vnejsi[novy_soucin] = new TVnitrni(INPUT);
			zrus = false;
			for (i=0; i<poc_vst_int && !zrus; i++) {  // tolik clenu se vzdy vynasobi
				promenna = 0;
				while (hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna] == 0) promenna++;  // iterator na prvni promennou v mnozine
#ifndef NSTEJNA
				stejny_clen[i] = true; // nastavim, a pokud alespon jedna promenna v clenu nebude stejna s uz vlozenou promennou,tak se da pak false a dalsi cleny nelze absorbovat
#endif
				while (promenna != INPUT && !zrus) {  // prepisu promenne
					if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] == -hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]) {  // mam dat promennou, ale pokud uz tam je ta znegovana, tak je vysledek logicka 0
						delete nove->vnejsi[novy_soucin];
						nove->vnejsi[novy_soucin]=NULL;
						//novy_soucin--;
						zrus = true;
#ifndef NSTEJNA
						stejny_clen[i] = false;
#endif
					}
					else
						if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] == hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]) {
							promenna++;
							while (promenna!=INPUT && hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]==0) promenna++;
						}
						else {
							nove->vnejsi[novy_soucin]->vnitrni2[promenna] = hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna];  // vlozim
							if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] < 0) nove->vnejsi[novy_soucin]->pocet_neg++;
							else nove->vnejsi[novy_soucin]->pocet_norm++;
#ifndef NSTEJNA
							stejny_clen[i] = false;
#endif
							promenna++;
							while (promenna!=INPUT && hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]==0) promenna++;
						}
				}
			}

			if (!zrus) {
				absorpce(nove,&novy_soucin);
				novy_soucin++;  // bude novy nasobeny clen
				if (novy_soucin == nove->clenu-1) nove->Zvetsi();  // pokud nedostacuje pole pro nove souciny, tak se zvetsi
				i=poc_vst_int-1;
			}
			else i--;
			while (hr->hradlo[0]->vnejsi[vynasobeno[0]] != NULL) {  // v poli vynasobeno[] si pamatuju ktere cleny sem spolu uz vynasobil (ve stylu binarniho cisla s vic moznostmi nez 0/1) a postupne ho zvetsuju
#ifndef NSTEJNA
				if (stejny_clen[i]) {  // pokud davam stejny clen
					j=vynasobeno[i];
					while (hr->hradlo[i]->vnejsi[j] != NULL) j++;
					vynasobeno[i] = j;  // posunu se na konec
					stejny_clen[i] = false;
				}
				else 
#endif
					vynasobeno[i]++;
				if (i>0 && hr->hradlo[i]->vnejsi[vynasobeno[i]] == NULL) vynasobeno[i--]=0;
				else break;
			}
		}
		if (pom_poc_vst > 2) {
//			delete hr->hradlo[0];
//			delete hr->hradlo[1];
			hr->hradlo[0] = nove;//minim(nove);
			for (i=2; i<pom_poc_vst; i++) hr->hradlo[i-1] = hr->hradlo[i];
			hr->hradlo[i-1] = NULL;
		}
//printf("%d",clock()-s);
		pom_poc_vst--;
	  }
#else
		nove = new TVnejsi;
		int *vynasobeno = new int[poc_vst_int];  // pole prave nasobenych clenu
		for (i=0; i<poc_vst_int; i++) vynasobeno[i]=0;
		int promenna;  // iterator prochazejici promenne v mnozine
#ifndef NSTEJNA
		bool *stejny_clen = new bool[poc_vst_int];  // pole urcujici zda promenna tam uz je, pokud true, tak se nepude na dalsi promennou v clenu ale na konec
		for (j=0; j<poc_vst_int; j++) stejny_clen[j]=false;
#endif
		int novy_soucin=0;
		while (hr->hradlo[0]->vnejsi[vynasobeno[0]] != NULL) {  // dokud je v prvnim nasobenem clenu este co nasobit
			nove->vnejsi[novy_soucin] = new TVnitrni(INPUT);
			zrus = false;
			for (i=0; i<poc_vst_int && !zrus; i++) {  // tolik clenu se vzdy vynasobi
				promenna = 0;
				while (hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna] == 0) promenna++;  // iterator na prvni promennou v mnozine
#ifndef NSTEJNA
				stejny_clen[i] = true; // nastavim, a pokud alespon jedna promenna v clenu nebude stejna s uz vlozenou promennou,tak se da pak false a dalsi cleny nelze absorbovat
#endif
				while (promenna != INPUT && !zrus) {  // prepisu promenne
					if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] == -hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]) {  // mam dat promennou, ale pokud uz tam je ta znegovana, tak je vysledek logicka 0
						delete nove->vnejsi[novy_soucin];
						nove->vnejsi[novy_soucin]=NULL;
						zrus = true;
#ifndef NSTEJNA
						stejny_clen[i] = false;
#endif
					}
					else
						if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] == hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]) {
							promenna++;
							while (promenna!=INPUT && hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]==0) promenna++;
						}
						else {
							nove->vnejsi[novy_soucin]->vnitrni2[promenna] = hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna];  // vlozim
							if (nove->vnejsi[novy_soucin]->vnitrni2[promenna] < 0) nove->vnejsi[novy_soucin]->pocet_neg++;
							else nove->vnejsi[novy_soucin]->pocet_norm++;
#ifndef NSTEJNA
							stejny_clen[i] = false;
#endif
							promenna++;
							while (promenna!=INPUT && hr->hradlo[i]->vnejsi[vynasobeno[i]]->vnitrni2[promenna]==0) promenna++;
						}
				}
			}

			if (!zrus) {
				absorpce(nove,&novy_soucin);
				novy_soucin++;  // bude novy nasobeny clen
				if (novy_soucin == nove->clenu-1) nove->Zvetsi();  // pokud nedostacuje pole pro nove souciny, tak se zvetsi
				i=poc_vst_int-1;
			}
			else i--;
			while (hr->hradlo[0]->vnejsi[vynasobeno[0]] != NULL) {  // v poli vynasobeno[] si pamatuju ktere cleny sem spolu uz vynasobil (ve stylu binarniho cisla s vic moznostmi nez 0/1) a postupne ho zvetsuju
#ifndef NSTEJNA
				if (stejny_clen[i]) {  // pokud davam stejny clen
					j=vynasobeno[i];
					while (hr->hradlo[i]->vnejsi[j] != NULL) j++;
					vynasobeno[i] = j;  // posunu se na konec
					stejny_clen[i] = false;
				}
				else 
#endif
					vynasobeno[i]++;
				if (i>0 && hr->hradlo[i]->vnejsi[vynasobeno[i]] == NULL) vynasobeno[i--]=0;
				else break;
			}
		}
#endif
#ifdef DEBUG
		casAnd += clock() - s;
		pocAnd++;
#endif
//	nove = minim(nove);
	}

	else if (nazev_hradla == "or") {  // (ab+cd) OR (ef+gh) = ab + cd + ef +gh
#ifdef DEBUG
		s=clock();
#endif
		nove = new TVnejsi;
		novy_soucin = 0;
		for (i=0; i<poc_vst_int; i++) {
				j=0;
				while (hr->hradlo[i]->vnejsi[j] != NULL) { 
					nove->vnejsi[novy_soucin] = new TVnitrni(INPUT);
					for (k=0; k<INPUT; k++) {
						nove->vnejsi[novy_soucin]->vnitrni2[k] = hr->hradlo[i]->vnejsi[j]->vnitrni2[k];
						if (nove->vnejsi[novy_soucin]->vnitrni2[k] != 0) 
							if (nove->vnejsi[novy_soucin]->vnitrni2[k] < 0) nove->vnejsi[novy_soucin]->pocet_neg++;
							else nove->vnejsi[novy_soucin]->pocet_norm++;
					}
					absorpce(nove,&novy_soucin);
					novy_soucin++; j++;
					if (novy_soucin == nove->clenu-1) nove->Zvetsi();  // pokud nedostacuje pole pro nove souciny, tak se zvetsi
				}
		}
#ifdef DEBUG
		casOr += clock() - s;
		pocOr++;
#endif
	}

	nove = minim(nove);
#ifndef NOPAK_HR
	if (vytvor) {
		uk_hradlo->second.hotove_hradlo[negace] = new TVnejsi(nove->clenu);
		TVnejsi *po = uk_hradlo->second.hotove_hradlo[negace];
		i = 0;
		while (nove->vnejsi[i]!=NULL) {
			po->vnejsi[i] = new TVnitrni(INPUT);
			for (j=0; j<INPUT; j++) po->vnejsi[i]->vnitrni2[j] = nove->vnejsi[i]->vnitrni2[j];
			i++;
		}
	}
#endif
#ifdef STATE
	pocVnor--;
#endif
	return nove;
}

void Collapsing::minimalize() {	
	int i,j,k,l;
#if defined DEBUG || defined CAS
	clock_t s = clock(),e;
#endif

	INPUT = data->input->index;
	vstupy = new string[INPUT];
	j=0;
	for (i=0; i<INPUT; i++) {				// prohledam porty
		vstupy[i] = data->input->p[i];
	}

#ifdef DEBUG
	casAnd=0,casOr=0,casEsp=0,casAbs=0;
	pocAnd=0,pocOr=0,pocEsp=0,pocAbs=0;
#endif

	THradlo *hr = new THradlo(data->output.size());
	list<std::string> :: iterator out_it;

	char *pomc = arg[2];
	for (out_it = data->output.begin(),i=0; out_it!=data->output.end(); out_it++,i++) {				// prohledam porty
		hr->hradlo[i]=new TVnejsi;
#ifdef STATE
		printf("\r%d/%d",i,hr->poc_vst);
		pocVnor = 0;
		printf(" Vnoreno: ");
#endif
		hr->hradlo[i] = minim_hradlo(*out_it);  // zde budou minimalizovane vystupni porty
		if (strcmp(arg[3],"true") == 0 && atoi(pomc) != 1) {  // kdyz mam pouzit espresso na vysledek && pokud to uz neni zbytecne
			arg[2] = "1";
			hr->hradlo[i] = minim(hr->hradlo[i]);
			arg[2] = pomc;
		}
	}
#ifdef STATE
		printf("\r%d/%d\n",hr->poc_vst,hr->poc_vst);
#endif
#if defined DEBUG || defined CAS
	e = clock();
#endif
	k=0;
	for (l=0; l<i; l++) {
		j=0;
		while (hr->hradlo[l]->vnejsi[j] != NULL) j++;
		k+=j;
	}
#ifdef DEBUG
	printf("AND: %d/%d, OR: %d/%d\n",casAnd,pocAnd,casOr,pocOr);
	printf("Espresso: %d/%d, Absorpce: %d/%d, Ostatni: %d\n",casEsp,pocEsp,casAbs,pocAbs,e-s-casEsp-casAnd-casOr);
	printf("Termu: %d\n",k);
#endif
#if defined DEBUG || defined CAS
	printf("Cas: %d\n",e-s);
#endif


	FILE *soubor = fopen(arg[1],"w");
	fprintf(soubor,".i %d\n",INPUT);
	fprintf(soubor,".o %d\n",data->output.size());
	fprintf(soubor,".ilb");
	for (i = 0; i < INPUT; i++)  // prohledam porty
		fprintf(soubor," %s",vstupy[i].data());//vstupy[i]);
	fprintf(soubor,"\n.ob");
	for (out_it = data->output.begin(); out_it!=data->output.end(); out_it++)  // prohledam porty
		fprintf(soubor," %s",out_it->data());
	fprintf(soubor,"\n.p %d\n",k);
	for (i=0; i<data->output.size(); i++) {
		j=0;
		while (hr->hradlo[i]->vnejsi[j] != NULL) {
			for (k=0; k<INPUT; k++)
				switch (hr->hradlo[i]->vnejsi[j]->vnitrni2[k]) {
					case 0: fprintf(soubor,"-"); break;
					case 1: fprintf(soubor,"1"); break;
					case -1: fprintf(soubor,"0"); break;
				}
			fprintf(soubor," ");
			for (k=0; k<data->output.size(); k++)
				if (k!=i) fprintf(soubor,"0");
				else fprintf(soubor,"1");
			fprintf(soubor,"\n");
			j++;
		}
	}
	fprintf(soubor,".e\n");
	fclose(soubor);


}