//---------------------------------------------------------------------------
#include <stdio.h>  // printf
#include <stdlib.h> // atoi, random
#include <string.h>
#include <time.h>
#include <sys\timeb.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <math.h>


#define DELKA_NAZVU_HRADLA 20
#define DELKA_NAZVU_SPOJE 20
#define DELKA_NAZVU_SOUBORU 255
// maximalni urovne jsou zde jen pro definici uroven vystupu - melo by bejt nastaveno na vic nez pocet hradel*2 - nema jinej vliv
#define MAX_UROVNI_HRADEL 10000
#define MAX_UROVNI_SPOJU ((MAX_UROVNI_HRADEL+1)*2)
#define VELIKOST_POPULACE 80
// definuje defaultni hodnotu poctu generaci da se prepsat prepinacem
#define POCET_GENERACI 50
#define POCET_ELITISMU 1
// definuje pocet novych ciste nahodnych jedincu v populaci
#define PRAVDEPODOBNOST_MUTACE 5
#define GEN_POCET_TURNAJU 2
//	definuje pocet pokusu kolikrat zkousime vyber z nahodna nez to vzdame a jdeme jinou cestou (napr smazem a jdem od zacatku)
#define POCET_POKUSU 20
#define DEFAULT_MAX_VSTUPY_HRADEL 2
#define DEFAULT_P_HRADEL 5

// definovani ruznych ladicich hlasek v programu
//#define VYPIS_CASU
//#define LH_GEN
//#define LADICI_HLASENI
//#define LH_INFO_HLASENI
//#define LH_VYPIS_SPOJU
//#define LH_VYPIS_HRADEL
//#define ZAPNUTE_KONTROLY

// definujeme pomocne inline fce
#define random(n)	(rand()%(n))
#define drandom()  (double) (((double)rand())/RAND_MAX)
#define abs(a)		((a) <  0  ? -(a) : (a))
#define min(a,b)	((a) < (b) ?  (a) : (b))
#define max(a,b)	((a) > (b) ?  (a) : (b))
#define signum(a)	((a) <  0  ?  -1  :  ((a) >  0  ?  1  :  0 )   ) 


// co se tyce typu hradel...
#define POCET_TYPU_HRADEL 7				// nepocitame branch
enum Typy_hradel { BRANCH=0,AND=1,NAND=2,OR=4,NOR=8,XOR=16,XNOR=32,NOT=64 };
char *poradi_na_nazev[POCET_TYPU_HRADEL] = { "AND","NAND","OR","NOR","XOR","XNOR","NOT" };
enum Typy_ukladani { BENCH=1,BLIF=2,SLIF=4 };
#define POCET_TYPU_VAH 5
enum Typy_vah { LEV=1,GAT=2,CON=4,OBS=8,TES=16};

//---------------------------------------------------------------------------



class Thlavni;
class Thradlo;
class Tspoj;
class Tobvod;
class Tuzel;
class Tinfo;


Thlavni *hlavni;

//	TODO:
//
//	nacitani parametru z konfiguracniho souboru, vcetne pomeru generovani vsech hradel, a jejich maximalni fanin, maximalni stupen
//		vetveni - s tim souvisejici jinak generovani init obvodu - po vstupech ne po hradlech... + kontrola aby se nezapojovala 2x stejna hrana do hradla
//	
//	algoritums na smrsknuti obvodu na co nejmin urovni ?? - neni treba pocitame realne urovne a koliduje s genetikou 
//
//	testovatelnost !! - zatim implementovana SCOAD, ta neni implementovana do fitness.
//		metoda CAMELOT (TMEAS) je implementovana a zohlednena ve fitness. 
//		chtelo by tgo pridat nejakou sofistikovanejsi metodu
//
//	vysledna "mohutnost" obovdu. Nejak se zkusit poresit aby se pri vetsim obvode neredukovali vystupy a vnitrni vetve na tautologie nebo velmi jednoduche fce.
//		zkoumani problemu reseni a jeho implementace by stala na dalsi minimalne BP.

// BUGS:
//		metody s operator= nejsou updatovane takze nekopiruji veci dodelane pozdeji. napr Tobvod::stat apod...
//		nejsou v programu pouzity.

int porovnej_obvod_fitness (const void* a,const void* b);		// fce na porovnavani pro serazeni quicksortem podle fitnessfce
int typ_na_poradi(int n);	// zmeni typ hradla na poradi v poli 1->0,2->1,4->2...64->6
int poradi_na_typ(int n);	// prevede poradi typu hradel na jejich typ 0->1...6->64

class Thlavni {		// hlavni trida ktera resi genetiku, genrace, cislovani obvodu atd..
public:
	char *output_file;			// nazev vystupniho souboru bez koncovky
	int cislovani_obvodu;		// globalni pocitadlo pro cislovani novych obvodu
	int typy_ukladani;			// nese informaci v ajkejch formatech se bude ukladat viz enum Typy_ukladani
	int zadanej_pocet_generaci;	// kolik generaci musi prezit nejlepsi jedinec aby skoncila genetika
	int zadanej_total_generaci; // kolik generaci celkem budem prochazet
	int zadana_velikost_populace;		// zadana velikost populace.
	int vypocitany_pocet_jedincu;		// pocet nove generovanych jedincu v nove populaci.
	Tobvod * obvod1;			// ukazatel na obvod do kteryho se nactpu vsechny potrebne vlastnosti z argument listu
	Tobvod ** generace;			// pole ukazatelu na obvody.
	void zaloz_generaci();		// metoda ktera zaplni generaci nahodnymi obvody vytvorene pomoci fce Tobvod::vygeneruj_obvod()
	int nova_generace();		// provede pomoci genetiky vyber, krizeni a mutaci a zaplni noveymi obvody pole generace.
	void help();				// vypise help do stderr.
	void init();
	Thlavni();					// konstruktor kterej vse pripravy
	~Thlavni();					// destruktor
};

class Tobvod {					// trida pro jeden obvod - metody pro pocitani con,obs,tes, vypis, fitness, vygenerovani nahodneho obvodu.
public:
	int id;							// id obvodu
	int pocet_vstupu;				// zadanej pocet vstupu
	int pocet_vystupu;				// zadanej pocet vystupu
	int maximalni_vetveni;			// zadane maximalni vetveni branche
	int pocet_hradel;				// zadanej pocet hradel
	int zadane_urovne;				// zadanej pocet urovni
	double zadana_controlabilita;	// zadana con. z prikazove radky
	double zadana_observabilita;	// zadana obs. z prikazove radky
	double zadana_testabilita;		// zadana tes. z prikazove radky
	int zadane_cg;
	int zadane_info;				// zadanej prepinac info z pr. r.

	int akt_vstup;				// aktualni pocet vstupu
	int akt_vystup;				// aktualni pocete vystupu
	int max_uroven;				// uvadi dalsi neobsazenou uroven pro nove generovane hradlo
	Tspoj *Spoje;				// seznam vsech spoju v obvodu.
	Thradlo *Hradla;			// seznam vsech hradel v obvodu
	Tspoj **Vstupy;				// pole ukazatelu na glob. vstupy
	Tspoj **Vystupy;			// pole ukazatelu na glob. vystupy
	int celkem_spoju;			// celkem vsech spoju;
	int realne_urovne;			// pocet realnych urovni - pocita se az pozdeji pomoci metody. aktualni uroven je definovana v max_uroven.
	int celkem_op_spoju;		// celkem spoju ktere vedou z funkcnich hradel + glob. vstupy: pri vetveni jsou dupl hrany.
	int celkem_hradel;			// celkem pocet vsech hradel vcetne branchu.
	int celkem_op_hradel;		// celkem pocet hradel mimo vetveni spoju (typ==0)
	int celkem_fc_spoju;		// celkem spoju funkcnich (ty co nevedou do branche) resp. ty co vedou do nejakeho vstupu funkcnich hradel+glob vystupy = celkem_spoju-celkem_hradel+celkem_op_hradel;
	int nezap_vstupy_hradel;	// nezapojene vstupy hradel vcetne branchu
	int nezap_vystupy_hradel;	// nezapojene vystupy hradel vcetne branchu
	int nezap_zac_spoju;		// nezapojene zacatky spoju
	int nezap_kon_spoju;		// nezapojene konce spoju
	double * vahy;				// pole vah pro fitness fci.
	double celkova_controlabilita;	// controlabilita pocitana jako prumer z kazdeho vystupu, ze SCOAP prevedena lin transformaci na interval <0,1>.
	double celkova_observabilita;	// podobne jako controlabilita
	double celkova_testabilita;		// prumer testability ze vsech spoju
	double vfitness;				// zde je ulozenej vysledek fitness funkce.

	int cislovani_spoju;		// id dalsiho spoje
	int cislovani_hradel;		// id dalsiho hradla
	
	// razenej obousmernej spoj. seznam ukazatelu na vsechny hradla (i branche) podle urovne - kvuli prochazeni obvodem
	int seznam_pocet;			// pocet prvku v seznamu
	Tuzel *seznam_zac;			// zacatek seznamu
	Tuzel *seznam_kon;			// konec seznamu

	int *typy_gen_max;			// pole maximalnich urovni kazdeho typu hradla
	double *typy_gen_max_k;		// pole konstant na vypocet pravdepodobnosti. suma vsech podilu od 1 do n viz pocitani pravdepodobnosti vicevstupovych hradel. pocitano v Tobvod::vytvor_nove_hradlo();
	int *typy_gen_p;			// pole pravdepodobnosti vsech typu hradel
	int typy_gen_pk;			// vypocitana konstanta - suma vsech pravdepodobnosti generovanych hradel
	Tinfo *stat;				// trida se statistikama o obvodu;

	void vypis_vse(FILE *fil=stderr);		// vypise obvod, spoje i hradla
	void vypis_obvod(FILE *fil=stderr);		// vypise info o obvodu
	void vypis_spoje(FILE *fil=stderr);		// vypise seznam vsech spoju
	void vypis_hradla(FILE *fil=stderr);	// vypise seznam vsech hradel
	void vypis_info(FILE *fil=stderr);		// vypise informace o obvode
	void seznam_vloz_hradlo(Thradlo *hr);	// vlozi hradlo hr do seznamu *seznam_zac
	void seznam_vyndej_hradlo(Thradlo *hr);	// vynda hradlo hr ze seznamu *seznam_zac
	void UlozINFO(FILE * f);
	void UlozSLIF(char * fname);				// ulozi this ve formatu SLIF do souboru fname. fname nijak neupravuje.
	void UlozBLIF(char * fname);				// -----
	void UlozBENCH(char * fname);			// -----
	void UlozVSE(Thlavni * hl=hlavni);		// ulozi this podle hlavni::typy_ukladani do souboru hlavni::output_file a prida odpovidajici koncovky. 
	void pojmenuj_vse();					// pojmenuje vsechny spoje a hradla spravne pred ukladanim.
	void vypocitej_testabilitu_CAMELOT();	// vypocte v celem obvode con,obs a testabilitu podle metody CAMELOT.
	void vypocitej_testabilitu_SCOAP(int typ=3);	// pocita testabilitu: 1-controlablity, 2-observability, 3- oboje. Metoda SCOAP momentalne se nepouziva.
	Thradlo * vytvor_nove_hradlo(int pnot=0);		// funkce na vyber vytvareneho hradla podle zadanych parametru. pnot 0 not generujem podle parametru, 1 not negenerujem.
	void preber_vstupni_hodnoty(Tobvod * obv);		// obvod this prebere inicializacni parametry od obvodu obv.
	void proved_mutaci(int typ=0);					// provede nahodnou mutaci 1-zmeni typ hradla,2-prekrizi 2 hrany,3-rozdeli hranu/y z vetveni nekam jinam. 0 provede nahodne jeden ze tri typu
	void spocti_urovne();							// spocte realne urovne obvodu a vypni Tobvod::realne_urovne
	void spocti_fitness();							// vypocte fitness fci obvodu, podle vah.
	void proved_kontrolu(int aaa=0);				// provede kontrolu inegrity nastaveni vsech spoju a hradel. aaa!=0 provede i kontrolu celku obvodu jestli je vsechno zapojeny a jestli nejsou nejake vstupy vystupy volne. Vypisuje do stderr chyby a jsou naastaveny breakpointy.
	void init();									// vytvori dat struktury , predvyplni typy_gen_pole atd. musi byt volano az po nacteni zadanych parametru - resp po Tobvod::preber_vstupni_hodnoty()
	int vygeneruj_obvod();							// vygeneruje nahodnej obvod podle parametru. if ret==1 tak se nepodarilo vytvorit. 
	Tobvod & operator= (const Tobvod & src);		// kopirovaci konstruktor - nejspis neni aktualni chybi kopirovani pozdeji pridanych veci. V programu nepouzivano
	Tobvod();										// konstruktor predvyplni prvky
	~Tobvod();										// smaze celej obvod vcetne vsech spoju a hradel co obsahuje.
};

class Tspoj {			// trida ktera urcuje jeden spoj, obsahuje metody na vypis, pripojeni a odpojeni od hradel, prevod na gvystup, gvstup, pocitani testabilit.
public:
	char *nazev;				// nazev spoje
	int named;					// pouzivano pri obvod::pojmenuj_vse() pro urceni jestli uz je obvod pojmenovanej nebo ne.
	int uid;					// id spoje
	int enabled;				// enabled - nepouzivano
	int valid;					// valid - nepouzivano
	int vetveni;				// pocet dalsich vetvy tohoto spoje. Pouze pokud spoj vede do BRANCHe. Takze pocet_vetvi=vetveni+1; (kdyz se hrana deli na 2=jde do branche s fanoutem 2 tak ma nastaveny vetveni 1).
	int vstup;					// jeslti je glob. vstup.
	int vystup;					// jestli je glob. vystup
	int op;						// jestli je to op spoj. = je pripoojenej na vystup op hradla nebo gvstup. op hradlo= hradlo mimo BRANCHe
	int fc;						// jestli je to fc spoj. = je pripojenej na vstup op hradla nebo gvystup.
	int zac_uroven;				// pocatecni uroven spoje.
	int realna_uroven;			// realna uroven pocatku spoje.
	int kon_uroven;				// konecna uroven spoje.
	int pres_pocet_urovni;		// pres kolik vede urovni.
	int cc1;					// SCOAP con1.
	int cc0;					// SCOAP con0.
	int co;						// SCOAP obs.
	double cy,oy,ty;			// CAMELOT con,obs,tes.
	Thradlo *zac;				// ukazatel na hradlo ktere je pripojene na zacatek spoje
	Thradlo *kon;				// ukazatel na hradlo ktere je pripojeno na konec spoje.
	Tspoj *next;				// ukazatel na dalsi spoj. - tohle je primarni spoj seznam vsech spoju v obvode
	Tobvod *obvod;				// ukazatel na obvod ve kterem se spoj nachazi.
	void vypis(FILE *fil=stderr);	// vypise info o spoji
	Thradlo * preved_na_vystup();			// udela ze spoje gvystup - pripadne odpojene hradlo vrati
	Thradlo * preved_na_vstup();			// udela ze spoje gvstup - pripadne odpojene hradlo vrati
	int pripoj_na_vstup(Thradlo *hr);		// pripoji na vstup hradla hr. ret==0 ok jinak chyba.
	int pripoj_na_vystup(Thradlo *hr);		// pripoji na vystup hradla hr. ret==0 ok jinak chyba.
	Thradlo * odpoj_od_vstupu();			// odpoji spoj od vystupu hradla kam je pripojene. vrati odpojene hr, jinak NULL
	Thradlo * odpoj_od_vystupu();			// odpoji spoj od vstupu hradla kam je pripojene. vrati odpojene hr, jinak NULL
	int spocti_controlabilitu_SCOAP();		// 0-ok jinak chyba	
	int spocti_observabilitu_SCOAP();		// 0-ok jinak chyba	
	Tspoj * Rozvetvi();						// rozvetvi spoj vice info v deklaraci. vraci nove vytvorenej spoj rovnou zapojenej do branche.
	Tspoj & operator= ( const Tspoj & src );	// kopirovaci konstruktor, pravdepodobne neni aktualni - mozna nekopiruje nove veci napr CAMELOT - nepouzivano
	void Tinit();						// spolecnej kod pro oba konstruktory.
	Tspoj();									
	Tspoj(Tobvod *obv,int urv,int vst=0,int vyst=0);	// konstruktor vytvori novej spoj v obvodu obv, sed zac_urovni urv, vst je nastaveni pro glob vstup, vyst pro glob. vystup.
	~Tspoj();					// odpoji hradlo, smaze ho ze spoj seznamu, smaze ho ze seznamu glob vstupu/vystupu, upravi odpovidajici parametry obvodu, 
};

class Thradlo {
public:
	char *nazev;				// nazev hradla
	int uid;					// uid hradla
	int enabled;				// enabled - nepouzivano
	int valid;					// valid - nepouzivano
	int pocet_vstupu;			// pocet vstupu 
	int zapojene_vstupy;		// zapojene vstupy
	int pocet_vystupu;			// pocet vystupu
	int zapojene_vystupy;		// zapojene vystupy
	int typ;					// typ hradla podle Enmu Typy_hradel.
	double ctf,otf;				// CAMELOT konstanty pro pocitgani con, obs, tes
	Tspoj **vstupy;				// pole ukazatelu na zapojene spoje na vstupu.
	Tspoj **vystupy;			// pole ukazatelu na zapojene spoje na vystupu.
	int uroven;					// uroven hradla v ramci obvodu
	int realna_uroven;			// realna uroven hradla.
	Thradlo *next;				//
	Tobvod *obvod;
	int zvys_uroven_inasl(int n=2);		// OBSOLETE - zvysi uroven hradel a jeho nasledovniku o n - melo by bejt deliotelny 2ma, def=2. vraci pocet ovlivnenych hradel (i branchu). nebere zretel na valid vsude nastavi 0 a pak 1.
	int zvaliduj_inasl();				// OBSOLETE - pouziva se na zvalidneni vsech nasledujicich hradel.
	int prirad_volnej_vstup(Tspoj *spoj); // zapoji spoj do volneho vstupu. 0 OK, 1 - vsechny vstupy uz zapojeny
	int prirad_volnej_vystup(Tspoj *spoj); // zapoji spoj do volneho vystupu. 0 OK, 1 - vsechny vystupy uz zapojeny
	int odeber_vstup(Tspoj *spoj);
	int odeber_vystup(Tspoj *spoj);		// odpoji spoj z vystupu
	Tspoj * odeber_vstup(int n);		// odpoji spoj z vystupu na pozici n, kdyz neni tak NULL
	Tspoj * odeber_vstup();				// odpoji nahodnej spoj na vystupu
	Tspoj * odeber_vystup(int n);		// odpoji spoj z vystupu na pozici n, kdyz neni tak NULL
	Tspoj * odeber_vystup();			// odpoji nahodnej spoj na vystupu
	Tspoj * odeber_vystup_mimoglob();	//odpoji nahodnej spoj na vystupu kterej neni gobalni.
	int zvetsi_hradlo();
	int spocti_controlabilitu_SCOAP();
	int spocti_observabilitu_SCOAP();
	int spocti_controlabilitu_CAMELOT();
	int spocti_observabilitu_CAMELOT();
	void vypocti_koeficienty();
	int test_pripojeni_vstupu(Thradlo *hr);		// testuje jestli neni nejakej vstup uz pripojenej na hradlo hr. 0-neni, 1-je.
	int test_pripojeni_vstupu(Tspoj *sp);		// testuje jestli spoj nebo jeho vetev neni pripojena na hradlo 0-neni 1-je.

	int predsad_hradlo();	// posune hradlo co nejvice do nizsi urovne vrati do jake se posunulo. NENI implement
	int zmensi_hradlo();	// zmensi hradlo o jeden vstup (BRANCHE o vystup) 0-ok >0 - neprovedeno podrobneji viz popis v deklaraci.
	void vypln_nazev(int gen_id=0);		// vyplni nazev tohoto hradla pokud gen_id=0 tak vyplnuje pracovni nazvy, gen_id=1 vyplni nazvy vhodne pro ukladani do vystupu.
	void vypis(FILE *fil=stderr);		// vypise drobne info o ovbodu.
	Thradlo();
	Thradlo(Tobvod *obv,int typ, int count=2);
	~Thradlo();
	Thradlo & operator=(const Thradlo & src); // kopirovaci kostruktor - nepouzivan - nedoplnen o novy veci -> neplne funkcni !
};
class Tuzel {
public:		// uzel spojoveho seznamu kterej muze vest bud hradla nebo spoje. pouzivan pro Tobvod::seznam_zac
	Tspoj * spoj;
	Thradlo * hradlo;
	Tuzel * next;
	Tuzel * prev;
	Tuzel();
};

class Tinfo {
public:		// trida na uchovani a vypocet statistickejch informaci o prirazenem obvodu. Mezi hradle nepocita BRANCHE
	int spoj_min;			// minimalni vetveni spoje v obvode
	double spoj_avg;		// prumerne ---
	int spoj_max;			// maximalni ---
	int spoj_cnt;			// pocet spoju
	int h_max,h_min,h_cnt;	// max, min, pocet fan-in vsech hradel dohromady (NE BRANCHE)
	double h_avg;			// prumer ----
	int *hr_min;			// pole min fan-in hradel podle typu
	double *hr_avg;			// pole prumer --
	int *hr_max;			// pole max ---
	int *hr_cnt;			// pole poctu --
	Tobvod *obvod;			// obvod ze ktereho pocitame
	double *zhr_avg;		// pole prumeru fan-in hradel vypocitanych z max fan-in 
	double *zhr_cnt;		// pole poctu jednotlivych typu hradel vypocitane podle pravdepodobnosti generovani - pouzivano pri prepinaci -cg na pocitani fitness.
	void vypocti_hodnoty(); // vypocita vsechny hodnoty z obvodu.
	void vypis(FILE *fil=stderr);	// vypise droben info.
	Tinfo();
	Tinfo(Tobvod *obv);
	~Tinfo();

};
int typ_na_poradi(int n) {
	int j=1;
	for(int i=0;i<POCET_TYPU_HRADEL;++i) {
		if (j&n) return i;
		j = j << 1;
	}
	fprintf_s(stderr,"WRN: typ_na_poradi(): typ mimo hranice hradel nebo BRANCH - neprovedeno\n");
	return -1;
}
int poradi_na_typ(int n) {
	int i;
	if ((n<0) && (n>POCET_TYPU_HRADEL)) {
		fprintf_s(stderr,"WRN: poradi_na_typ(): poradi mimo hranice - neprovedeno\n");
		return -1;
	}
	i=1<<n;
	return i;
}

int porovnej_obvod_fitness (const void* a,const void* b) {
    Tobvod** arg1 = (Tobvod**) a;
    Tobvod** arg2 = (Tobvod**) b;
    if ( (*arg1)->vfitness < (*arg2)->vfitness ) return 1;
    else if ( (*arg1)->vfitness == (*arg2)->vfitness ) return 0;
    else return -1;
}

Tinfo::Tinfo() {
	spoj_min=0;
	spoj_avg=0;
	spoj_max=0;
	spoj_cnt=0;
	h_min=0;
	h_max=0;
	h_avg=0;
	h_cnt=0;
	hr_min=NULL;
	hr_avg=NULL;
	hr_max=NULL;
	hr_cnt=NULL;
	obvod=NULL;;
	zhr_avg=NULL;
	zhr_cnt=NULL;
}
Tinfo::Tinfo(Tobvod *obv) {
	int i;
	spoj_min=0;
	spoj_avg=0;
	spoj_max=0;
	spoj_cnt=0;
	h_min=0;
	h_max=0;
	h_avg=0;
	h_cnt=0;
	obvod=obv;
	hr_min = new int [POCET_TYPU_HRADEL];
	hr_avg = new double [POCET_TYPU_HRADEL];
	hr_max = new int [POCET_TYPU_HRADEL];
	hr_cnt = new int [POCET_TYPU_HRADEL];
	zhr_avg = new double [POCET_TYPU_HRADEL];
	zhr_cnt = new double [POCET_TYPU_HRADEL];
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		hr_min[i]=0;
		hr_avg[i]=0;
		hr_max[i]=0;
		hr_cnt[i]=0;
		zhr_cnt[i]=0;
		zhr_avg[i]=0;
	}
}
Tinfo::~Tinfo() {
	if (hr_min!=NULL) delete [] hr_min;
	if (hr_avg!=NULL) delete [] hr_avg;
	if (hr_max!=NULL) delete [] hr_max;
	if (hr_cnt!=NULL) delete [] hr_cnt;
	if (zhr_avg!=NULL) delete [] zhr_avg;
	if (zhr_cnt!=NULL) delete [] zhr_cnt;
}
void Tinfo::vypocti_hodnoty() {
	// princip jednoduchej projde vsehcny hradla ze seznamu a pocita...
	Tuzel *uz;
	int i,j,k,l;
	double d1,d2;
	Thradlo *hr;
	uz=obvod->seznam_zac;
	spoj_min=obvod->Vstupy[0]->vetveni+1;
	spoj_cnt=0;
	spoj_max=0;
	spoj_avg=0;
	h_min=0;
	h_cnt=0;
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		if (obvod->typy_gen_max[i]!=0) hr_min[i]=obvod->typy_gen_max[i];
		h_min=max(h_min,hr_min[i]); 
		hr_avg[i]=0;
		hr_max[i]=0;
		hr_cnt[i]=0;
		zhr_cnt[i]=((double)obvod->typy_gen_p[i]/obvod->typy_gen_pk)*obvod->pocet_hradel;
		d1=0;
		l=obvod->typy_gen_max[i]-1;
		d2=obvod->typy_gen_max_k[i];
		for (k=1;k<obvod->typy_gen_max[i];k++) {
			d1+=(((double)l/k)/d2)*(k+1);
		}
		if (d1==0) d1=1;
		zhr_avg[i]=d1;
	}
	for (i=0;i<obvod->pocet_vstupu;++i) {
		spoj_min=min(spoj_min,obvod->Vstupy[i]->vetveni+1);
		spoj_avg+=obvod->Vstupy[i]->vetveni+1;
		spoj_max=max(spoj_max,obvod->Vstupy[i]->vetveni+1);
		spoj_cnt++;
	}
	while (uz) {
		if (uz->hradlo->typ!=BRANCH) {
			hr=uz->hradlo;
			j=typ_na_poradi(hr->typ);
			k=hr->pocet_vstupu;
			spoj_min=min(spoj_min,hr->vystupy[0]->vetveni+1);
			spoj_avg+=hr->vystupy[0]->vetveni+1;
			spoj_max=max(spoj_max,hr->vystupy[0]->vetveni+1);
			spoj_cnt++;
			hr_min[j]=min(hr_min[j],k);
			hr_avg[j]+=k;
			hr_max[j]=max(hr_max[j],k);
			hr_cnt[j]++;
			h_min=min(h_min,k);
			h_avg+=k;
			h_max=max(h_max,k);
			h_cnt++;

		}
		uz=uz->next;
	}
	spoj_avg=spoj_avg/spoj_cnt;
	h_avg=h_avg/h_cnt;
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		if (hr_cnt[i]==0) {
			hr_min[i]=0;
			hr_avg[i]=0;
		}
		else hr_avg[i]=hr_avg[i]/hr_cnt[i];
	}
#ifdef LH_INFO_HLASENI
	this->vypis_info(stderr);
#endif
}
void Tinfo::vypis(FILE *fil) {
	int i;
	fprintf_s(fil, "\nSPOJE: CNT:%3d MIN:%1d MAX:%1d AVG:%4.2f\n",spoj_cnt,spoj_min,spoj_max,spoj_avg);
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		fprintf_s(fil, "%5s: CNT:%3d MIN:%1d MAX:%1d AVG:%4.2f - ZADANE CNT:%6.2f AVG:%4.2f\n",poradi_na_nazev[i],hr_cnt[i],hr_min[i],hr_max[i],hr_avg[i],zhr_cnt[i],zhr_avg[i]);
	}
}
void Tobvod::proved_kontrolu(int aaa) {
// nesmyslne prirazovani hodnot, je jen proto aby program spadnul pri cteni z neplatne adresy. Jinak neni co vysvetlovat.
	Tuzel *uz;
	Thradlo *hr;
	Tspoj *sp;
	int nzs=0;
	int nks=0;
	int nih=0;
	int noh=0;
	int i,j,k;
	int poh=0;
	int pvh=0;
	int pvhs=0;
	int pvs=0;
	int pos=0;
	int pfs=0;
	int pi=0;
	int po=0;
	for(i=0;i<akt_vstup;++i) {
		j=Vstupy[i]->fc;
		if (Vstupy[i]->vstup!=1) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj je v poli Vstupy ale nema vstup==1.\n");
		}

	}
	for(i=0;i<akt_vystup;++i) {
		j=Vystupy[i]->fc;
		if (Vystupy[i]->vystup!=1) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj je v poli Vystupy ale nema vystup==1.\n");
		}
	}
	hr=Hradla;
	while (hr) {
		j=hr->typ;				
		for(i=0;i<hr->zapojene_vstupy;++i) {
			k=hr->vstupy[i]->vetveni;
		}
		for(i=0;i<hr->zapojene_vystupy;++i) {
			k=hr->vystupy[i]->vetveni;
		}
		if (j!=0) {
			poh++;
		}
		pvh++;
		nih+=hr->pocet_vstupu-hr->zapojene_vstupy;
		noh+=hr->pocet_vystupu-hr->zapojene_vystupy;
		hr=hr->next;
	}
	sp = Spoje;
	while (sp!=NULL) {
		pvs++;
		if (sp->zac!=NULL) {
			if (sp->vstup==1) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj ma nastaven vstup a ma zac!=NULL.\n");
			}
			j=sp->zac->pocet_vystupu;
			if ((sp->zac->typ!=BRANCH) || (sp->vstup==1)) {
				pos++;
				if (sp->op!=1) {
					fprintf_s(stderr,"WRN: proved_kontrolu(): spoj je op ale nema op nastaven.\n");
				}
			}
			if ((sp->zac->typ==BRANCH) && (sp->op==1)) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj vede z BRANCHe ale ma op nastaven.\n");
			}
		}
		else if (sp->vstup==0) nzs++;
		else {
			pi++;
			pos++;
		}
		if (sp->kon!=NULL) {
			if (sp->vystup==1) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj ma nastaven vystup a ma kon!=NULL.\n");
			}
			j=sp->kon->pocet_vystupu;
			if ((sp->kon->typ!=BRANCH) || (sp->vystup==1)) {
				pfs++;
				if  (sp->fc!=1) {
					fprintf_s(stderr,"WRN: proved_kontrolu(): spoj je fc ale nema fc nastaven.\n");
				}
			}
			if ((sp->kon->typ==BRANCH) && (sp->fc==1)) {
				fprintf_s(stderr,"WRN: proved_kontrolu(): spoj vede do BRANCHe ale ma fc nastaven.\n");
			}

		}
		else if (sp->vystup==0) nks++;
		else {
			po++;
			pfs++;
		}
		sp=sp->next;
	}
	uz=seznam_zac;
	while (uz!=NULL) {
		hr=uz->hradlo;
		j=hr->typ;
		pvhs++;
		uz=uz->next;
	}
	if (pvhs!=seznam_pocet) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet hradel v seznam != seznam_poc.\n");
	}
	if (pvhs!=pvh) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet hradel v seznam != poctu hradel v Hradla.\n");
	}
	if (nih!=nezap_vstupy_hradel) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene vstupy hradel neodpovidaji.\n");
	}
	if (noh!=nezap_vystupy_hradel) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene vystupy hradel neodpovidaji.\n");
	}
	if (nzs!=nezap_zac_spoju) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene zacatky spoju neodpovidaji.\n");
	}
	if (nks!=nezap_kon_spoju) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene konce spoju neodpovidaji.\n");
	}
	if (poh!=celkem_op_hradel) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet op hradel neodpovida.\n");
	}
	if (pvh!=celkem_hradel) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet vsech hradel neodpovida.\n");
	}
	if (pvs!=celkem_spoju) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet vsech spoju neodpovida.\n");
	}
	if (pos!=celkem_op_spoju) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet op spoju neodpovida.\n");
	}
	if (pfs!=celkem_fc_spoju) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet fc spoju neodpovida.\n");
	}
	if (pi!=akt_vstup) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet spoju se vstup==1 neodpovida akt_vstup.\n");
	}
	if (po!=akt_vystup) {
		fprintf_s(stderr,"WRN: proved_kontrolu(): pocet spoju se vystup==1 neodpovida akt_vystup.\n");
	}
	if (aaa!=0) {
		if (0!=nezap_vstupy_hradel) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene vstupy hradel != 0.\n");
		}
		if (0!=nezap_vystupy_hradel) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene vystupy hradel != 0.\n");
		}
		if (0!=nezap_zac_spoju) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene zacatky spoju != 0.\n");
		}
		if (0!=nezap_kon_spoju) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nezapojene konce spoju != 0.\n");
		}
		if (akt_vstup!=pocet_vstupu) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nemame vsechny g vstupy.\n");
		}
		if (akt_vystup!=pocet_vystupu) {
			fprintf_s(stderr,"WRN: proved_kontrolu(): nemame vsechny g vystupy.\n");
		}
	}

}
void Tobvod::pojmenuj_vse() {
// jednoduchej princip .
// nejdrive se pojmenujou vstupy a vystupy a nastavi se jim named na 1.
// pak se jde podle seznamu od zacatku do konce a na vystupu obyc hradla pojmenovava podle citace spoje.
// pri branchi se kopiruje nazev vstupu na vsytupy.
// pokud narazi na named spoj tak ho nepojmenovava a pokud je na vystupu branche tak vstup prejmenuje podle nej i vsechny vstupy.
// 2 gvystupy z jednoho branche by nemeli nastat.
	int i,pom;
	Thradlo *hr;
	Tuzel *uz;
	int citac_spoju=1;
	for (i=0;i<pocet_vstupu;++i) { 
		sprintf_s(Vstupy[i]->nazev,DELKA_NAZVU_SPOJE,"i%d",i+1);
		Vstupy[i]->named=1;
	}
	for (i=0;i<pocet_vystupu;++i) {
		sprintf_s(Vystupy[i]->nazev,DELKA_NAZVU_SPOJE,"o%d",i+1);
		Vystupy[i]->named=1;
	}
	uz=seznam_zac;
	while (uz) {
		hr=uz->hradlo;
		hr->vypln_nazev(1);
		if (hr->typ==BRANCH) {
			pom=-1;
			for (i=0;i<hr->pocet_vystupu;++i) {
				if (hr->vystupy[i]->vystup) pom=i;
				else {
				sprintf_s(hr->vystupy[i]->nazev,DELKA_NAZVU_SPOJE,"%s",hr->vstupy[0]->nazev);
				hr->vystupy[i]->named=1;
				}
			}
			if (pom!=-1) {
				for (i=0;i<hr->pocet_vystupu;++i) {
					sprintf_s(hr->vystupy[i]->nazev,DELKA_NAZVU_SPOJE,"%s",hr->vystupy[pom]->nazev);
				}
				sprintf_s(hr->vstupy[0]->nazev,DELKA_NAZVU_SPOJE,"%s",hr->vystupy[pom]->nazev);
			}
		}
		else {
			if ( hr->vystupy[0]->named==0) sprintf_s(hr->vystupy[0]->nazev,DELKA_NAZVU_SPOJE,"q%d",citac_spoju++);
			hr->vystupy[0]->named=1;
		}
		uz=uz->next;
	}
}

void Tobvod::spocti_fitness() {
// pocita fitness - prenastavi vahy podle toho jestli byla zvolena prislusna optimalizace.
// ve fitness se taky projevuje stari obvodu, aby nedochazelo k fluktuaci nejlepsiho vysledku ponevadz quicksort neni satbilni.
	int urv,i;
	double urovne=0;
	double stari=0;
	double con=0;
	double obs=0;
	double tes=0;
	double inf=0;
	double d1;
	this->stat->vypocti_hodnoty();
	if (this->zadane_urovne!=-1) { // vypocet slozky s relanymi urovnemi
		urv=this->zadane_urovne-this->realne_urovne-1;
		urv=abs(urv)+1;
		urovne=(double)1/urv;
	}
	else vahy[0]=0;
	if (this->zadane_cg!=-1) {		// vypocet slozky na rozdil v poctu hradel
		d1=0;
		for(i=0;i<POCET_TYPU_HRADEL;++i) {
			d1+=abs(stat->zhr_cnt[i]-stat->hr_cnt[i]);
		}
		inf=1-((d1/(2*pocet_hradel))*4);		// d1 nebude nikdy vetsi nez 2*pocethr, trojak je koeficient pac d1 se bude pohybovat nekde kolem 1/5 pochr.
	}
	else vahy[1]=0;
	if (this->zadana_controlabilita!=-1) { // slozka controlabilita
		con=1-abs(this->zadana_controlabilita-this->celkova_controlabilita);
	}
	else vahy[2]=0;
	if (this->zadana_observabilita!=-1) {	// slozka observabilita
		obs=1-abs(this->zadana_observabilita-this->celkova_observabilita);
	}
	else vahy[3]=0;
	if (this->zadana_testabilita!=-1) {		// slozka testabilita
		tes=1-abs(this->zadana_testabilita-this->celkova_testabilita);
	}
	else vahy[4]=0;
	stari=hlavni->cislovani_obvodu-this->id-1;
	stari=signum(stari);
	vfitness =(double) vahy[0]*urovne+vahy[1]*inf+vahy[2]*con+vahy[3]*obs+vahy[4]*tes+0.0001*stari;
}
int Thradlo::test_pripojeni_vstupu(Thradlo *hr) {
//	testuje jestli muzem na this hradlo pripojit vystup z hradla hr. 0-muzem 
// jde o to aby na this hradle nevedli 2 vstupy ze stejnyho branche.
// projdem vsehcny vstupy a kontrolujem vuci hr
	int i;
	if (hr==NULL) return 0;
	if (hr->uroven>=this->uroven) return 3;
	for (i=0;i<this->zapojene_vstupy;++i) {
		if (this->vstupy[i]->zac==hr) return 1;
	}
	return 0;
}
int Thradlo::test_pripojeni_vstupu(Tspoj *sp) {\
// kontroluje vstupy this vuci hradlu hr, ktere je bud na vstupu spoje sp nebo na jeho vystupu.
// nebo kontroluje jestli sp nenei pripojena na this.
	int i;
	Thradlo * hr;
	hr = NULL;
	if (this==NULL) return 5;
	if (sp->zac_uroven>=this->uroven) return 3;
	if (sp->vetveni!=0) {	// spoj je vetvenej budem kontrolovat vuci konci spoje.
		hr=sp->kon;
		if (hr->typ!= BRANCH) {
			fprintf_s(stderr,"WRN: test_pripojeni_vstupu(Tspoj *sp): sp ma nastavene vetveni>0 && kon!=BRANCH !!\n");
			return 2;
		}
	}
	if ((sp->zac!=NULL) && (sp->zac_uroven%2==0)) {	// spoj vede z branche budem kontrolovat vuci branchi
		hr=sp->zac;
		if (hr->typ!= BRANCH) {
			fprintf_s(stderr,"WRN: test_pripojeni_vstupu(Tspoj *sp): sp ma nastavene zac_uroven%2==0 && zac!=BRANCH !!\n");
			return 3;
		}
	}
	for (i=0;i<this->zapojene_vstupy;++i) {
		if (this->vstupy[i]==sp) return 1;
		if ((hr!=NULL) && (vstupy[i]->zac==hr)) return 1;
	}
	return 0;
}
int Thradlo::zmensi_hradlo() {

// Zmensi hardlo o 1 vstup. Pokud jsou vsechny vstupy zapojeny- neprovede, pokud ma jen 2 vstupy- neporvede.
// Rozdi je u BRANCHE tam kdyz ma 2 vystupy a alespon 1 nezapojeny, tak to hradlo zrusi, vynda ze Obvod::seznam_zac a vystupni hranu zrusi a vstupni prepoji tam kam vedal vystupni. resi vsechny problemy vcetne jestli jsou spoje vstup/vystup.
// Taktez neresi branch pokud ma jen jeden vystup - to by podle koncepce nemelo nastat.

	Tspoj *sp,*sp2;
	Thradlo *hr;
	if (this==NULL) {
		fprintf(stderr,"WRN: zmensi_hradlo(): volano na hr==NULL!!! - neprovedeno\n");
		return 2;
	}
	if (typ==BRANCH) {		// budem zmensovat pocet vystupu u branche
		if (pocet_vystupu==1) {
			fprintf(stderr,"WRN: zmensi_hradlo(): BRANCH a pouze 1 vystup - neprovedeno\n");
			return 2;
		}
		if (zapojene_vystupy==pocet_vystupu) {
			fprintf(stderr,"WRN: zmensi_hradlo(): BRANCH a zadnej neobsazenej vystup - neprovedeno\n");
			return 3;
		}
		this->vystupy[--pocet_vystupu]=NULL;
		this->vypln_nazev();
		if (this->vstupy[0]!=NULL) this->vstupy[0]->vetveni--;
		obvod->nezap_vystupy_hradel--;
		if (pocet_vystupu==1) {	// budem rusit celej branch neni uz treba poresit vstupy/vystupy
			sp=this->odeber_vstup();
			sp2=this->odeber_vystup();
			if (sp2!=NULL) {
				if ((sp2->vystup==1)&&(sp!=NULL)) {
					delete sp2;
					sp->preved_na_vystup();
				}
				else {
					hr=sp2->odpoj_od_vstupu();
					delete sp2;
					if(sp!=NULL) {
						if (hr!=NULL) sp->pripoj_na_vstup(hr);
						else delete sp;
					}
				}
			}
			obvod->seznam_vyndej_hradlo(this);
			delete this;
		}
	}
	else {	// budem zmensovat hradlo o 1 vstup
		if (pocet_vstupu<=2) {
			fprintf(stderr,"WRN: zmensi_hradlo(): HRADLO ma pouze 2 nebo min vstupu - neprovedeno\n");
			return 2;
		}
		if (zapojene_vstupy==pocet_vstupu) {
			fprintf(stderr,"WRN: zmensi_hradlo(): HRADLO a zadnej neobsazenej vstup - neprovedeno\n");
			return 3;
		}
		this->vstupy[--pocet_vstupu]=NULL;
		this->vypln_nazev();
		obvod->nezap_vstupy_hradel--;
	}
	return 0;
}
void Thlavni::zaloz_generaci() {
// fce zalozi generaci do pole generace pouziva metodu vygeneruj obvod, pokud se to nepodari zkousi znova a znova dokud neni pole plne
	int i;
	int ret=0;
	vypocitany_pocet_jedincu=(int) 0.08*zadana_velikost_populace;
	for(i=0;i<hlavni->zadana_velikost_populace;++i) {
		generace[i]= new Tobvod;
		generace[i]->preber_vstupni_hodnoty(obvod1);
		ret = generace[i]->vygeneruj_obvod();
		if (ret!=0) {
			delete generace[i--];
		}
#ifdef ZAPNUTE_KONTROLY
		if (ret=0) generace[i]->proved_kontrolu(1);
#endif
	}
	qsort( generace, hlavni->zadana_velikost_populace, sizeof(Tobvod *),porovnej_obvod_fitness );

}

int Thlavni::nova_generace() {
// funkce vytvari novou generaci krizenim a mutaci z pole generace, na konci vypocte fitness vsech setridi a nahradi starou generaci novou.
// podrobnejsi info v kodu 
	int i,j,ret;					// pomocne
	int crossline,pom;				// kkolikaty hradlem delime obvody
	int crossuroven1,crossuroven2;;	// crossline prevedena na uroven v obvodu 1 resp 2.
	int r1,r3;					// pomocne na generovani nahod
	int rodic1,rodic2;			// rodicove
	int velikost=0;				// aktualni velikost generace
	int mazem=0;				// jestli obvod mazem nebo ne
	int pokusy;
	int counter;				// pomocny counter na pocitani nezapojenejch vstupu branchu v druhy casti. nema zadnou fci
	int sp_cnt,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt,spzal;  // pocitadla k polim
	Tspoj **sp_pole,**spzaloha;	// pole spoju kde si vedem jake spoje muzem pred danym hradlem delit, jeho zaloha
	double d1;
	Thradlo **hrp1,**hrp2,**hrp3,**hrp4,**hrpp1,**hrpp2;	// pole hradel vysvetleno pri alokovani
	Thradlo *hr,*hr2;			// pomocne ukazatele
	Tspoj *sp,*sp2;
	Tobvod *ov;
	Tobvod ** generace2;		// pole nove vytvarene generace
	Tuzel *uz,*uz2;				// pomocne ukazatele

	generace2 = new Tobvod * [hlavni->zadana_velikost_populace];
	// kopirujeme elitismus
	while (velikost<POCET_ELITISMU) {
		generace2[velikost]=new Tobvod;
		generace2[velikost]=generace[velikost];
		generace[velikost]->spocti_fitness();
		velikost++;
	}		// elitismus prekopirovan,
	// generujeme nove nahodne jedince
	while (velikost<POCET_ELITISMU+hlavni->vypocitany_pocet_jedincu) {
		generace2[velikost]=new Tobvod;
		generace2[velikost]->preber_vstupni_hodnoty(hlavni->obvod1);
		ret = generace2[velikost++]->vygeneruj_obvod();
		if (ret!=0) {
			delete generace2[--velikost];
		}
	}
	// novy nahodni jedinci vygenerovani.

	// vybereme par na krizeni turnajem ze konstanty - protoze jsou setrideny tak berem mensi index...
	while (velikost<hlavni->zadana_velikost_populace)	{
		if (((velikost-POCET_ELITISMU-hlavni->vypocitany_pocet_jedincu)%2)&&(mazem==0)) {	// delame 2 deti ze stejnejch rodicu se stejnou crossline ale opacne.
			r3=rodic2;
			rodic2=rodic1;
			rodic1=r3;
		}
		else { 
			mazem=0;
			// 1. turnaj
			rodic1=random(hlavni->zadana_velikost_populace);
			for (i=1;i<GEN_POCET_TURNAJU;++i) {
				r3=random(hlavni->zadana_velikost_populace);
				rodic1=min(r3,rodic1);
			}
			// 2. turnaj
			rodic2=random(hlavni->zadana_velikost_populace);
			for (i=1;i<GEN_POCET_TURNAJU;++i) {
				r3=random(hlavni->zadana_velikost_populace);
				rodic2=min(r3,rodic2);
			}
			r3=random(10000);
			d1=((double)r3)/10000;
			d1=0.1+d1*0.8;	// crossline bude mezi 10% a 90% obvodu aby jsme meli co napojovat
			crossline=(int)((d1*obvod1->pocet_hradel)+0.5);

		}

		// muzou se vybrat klidne dva stejni rodice, ponevadz budem delit celej obvod v jednom miste a nahodne ho zpatky propojime ( budem muset mozna rusit vetveni nebo pridavat)
		//  jdeme krizit
		ov=new Tobvod;
		ov->preber_vstupni_hodnoty(hlavni->obvod1);
		ov->init();
		hrpp1 = new Thradlo *[generace[rodic1]->cislovani_hradel];	// pole ktere nam prevede stare id hradla na ukazatel novyho Kvuli zapojovani spoju, rodic1
		hrpp2 = new Thradlo *[generace[rodic2]->cislovani_hradel];	// pole ktere nam prevede stare id hradla na ukazatel novyho. Kvuli zapojovani spoju rodic2
		for(i=0;i<generace[rodic1]->cislovani_hradel;++i) hrpp1[i]=NULL;
		for(i=0;i<generace[rodic2]->cislovani_hradel;++i) hrpp2[i]=NULL;
		i=0;

#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obvod:%d z rodicu c. %d a %d\n",ov->id,rodic1,rodic2);
#endif

		uz = generace[rodic1]->seznam_zac;
		uz2 = generace[rodic2]->seznam_zac;
		while ((i<crossline) || (uz2->hradlo->typ==BRANCH)) {			// dojedem az na prvni hradlo za crossline ktere neni branch pac ten branch by patril k hradlu z prvni casti
			if (uz2->hradlo->typ!=BRANCH) i++;
			uz2 = uz2->next;
		}
		crossuroven2=uz2->hradlo->uroven;
		i=0;
		mazem=0;
		while (i<crossline) {	// bereme hradla z prvniho rodice a vytvarime jejich kopie v novem obvode.
			hr=uz->hradlo;
			j=hr->typ!=BRANCH?hr->pocet_vstupu:hr->pocet_vystupu;
			hr2= new Thradlo(ov,hr->typ,j);
			hr2->uroven=hr->uroven;
			if (hrpp1[hr->uid]!=NULL) {
				fprintf_s(stderr,"ERR: nova_generace(): zapisujeme do pole na index uid ale uz je obsazen !!\n");
			}
			hrpp1[hr->uid]=hr2;	// zde si ukladame ukazatel na nove vytvorene hradlo s indexem uid hradla od rodice. kvuli zapojovani spoju z rodice 1
			ov->seznam_vloz_hradlo(hr2);
			if (hr->typ!=BRANCH) i++;
			uz=uz->next;
		}
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d hotovo 1.cast hradel\n",ov->id);
		ov->vypis_hradla(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu();
#endif
		crossuroven1=uz->hradlo->uroven;
		while (uz2!=NULL) {	// dojedeme hradla z druhyho rodice
			hr=uz2->hradlo;
			j=hr->typ!=0?hr->pocet_vstupu:hr->pocet_vystupu;
			hr2= new Thradlo(ov,hr->typ,j);
			hr2->uroven=hr->uroven;
			if (hrpp2[hr->uid]!=NULL) {
				fprintf_s(stderr,"ERR: nova_generace(): zapisujeme do pole na index uid ale uz je obsazen !!\n");
			}
			hrpp2[hr->uid]=hr2;		// zase si ukladame ukazatele do pole
			ov->seznam_vloz_hradlo(hr2);
			if (hr->typ!=BRANCH) i++;
			uz2=uz2->next;
		}
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d hotovo 2.cast hradel\n",ov->id);
		ov->vypis_hradla(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu();
#endif
		// mame hradla ted zapojime spoje z 1. rodice
		sp=generace[rodic1]->Spoje;
		while (sp) {
			if (sp->kon_uroven<crossuroven1) {			// spoj konci v prvni casti - budem "kopirovat"
				sp2 = new Tspoj(ov,sp->zac_uroven,sp->vstup,sp->vystup);
				if (sp->vstup==0) sp2->pripoj_na_vystup(hrpp1[sp->zac->uid]);	// prepojujem podle uid pripojenejch hradel
				if (sp->vystup==0) sp2->pripoj_na_vstup(hrpp1[sp->kon->uid]);
			}
			sp=sp->next;
		}
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d hotovo 1.cast spoju\n",ov->id);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu();
#endif
		sp=generace[rodic2]->Spoje;
		// to same se spojema z druheho rodice ktere jsou cele v druhe casti
		while (sp) {
			if (sp->zac_uroven>=crossuroven2) {
				sp2 = new Tspoj(ov,sp->zac_uroven,sp->vstup,sp->vystup);
				if (sp->vstup==0) sp2->pripoj_na_vystup(hrpp2[sp->zac->uid]);
				if (sp->vystup==0) sp2->pripoj_na_vstup(hrpp2[sp->kon->uid]);
			}
			sp=sp->next;
		}
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu();
#endif
		delete [] hrpp1;  // pole na prevod uz nepotrebujem
		delete [] hrpp2;
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d hotova 2.cast spoju\n",ov->id);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
		// projdem vsechny hradla a udelame si seznam hran na deleni, scvrknem/vyhodime nezapojene branche, udelame se seznam nezapojenejch vystupu/vstupu hradel
		hrp1 = new Thradlo * [generace[rodic1]->celkem_spoju];	// viz nize.
		hrp2 = new Thradlo * [generace[rodic1]->celkem_spoju];	// 
		hrp3 = new Thradlo * [generace[rodic2]->celkem_spoju];	// 
		hrp4 = new Thradlo * [generace[rodic2]->celkem_spoju];	// 
		sp_pole = new Tspoj * [generace[rodic1]->celkem_spoju+generace[rodic2]->celkem_spoju];
		spzaloha =  new Tspoj*[generace[rodic1]->celkem_spoju+generace[rodic2]->celkem_spoju];  // pole spoju pred vetvenim. pro nahodnej vyber vetveni.
		for (i=0;i<generace[rodic1]->celkem_spoju;++i) {
			hrp1[i]=NULL;
			hrp2[i]=NULL;
		}
		for (i=0;i<generace[rodic2]->celkem_spoju;++i) {
			hrp3[i]=NULL;
			hrp4[i]=NULL;
		}
		for (i=0;i<generace[rodic1]->celkem_spoju+generace[rodic2]->celkem_spoju;++i) {
			sp_pole[i]=NULL;
			spzaloha[i]=NULL;
		}
		sp_cnt=0;
		hr1_cnt=0;
		hr2_cnt=0;
		hr3_cnt=0;
		hr4_cnt=0;
		uz=ov->seznam_zac;
		// hrp1 - vede volne vystupy hradel z 1.casti
		// hrp2 - vede volne vystupy z branchu v 1.casti pripadne abychom mohli zmensovat nezapojene branche
		// hrp3 - vede volne vstupy do hradel/(branchu) v 2.casti -  branche by se ve spravnem zapojeni obvodu nemeli zde objevit - counter to pocita
		// hrp4 - vede vsechny branche v 2. casti, tolikrat kolik maji vystupu-1. kvuli moznym redukcim branchu abychom zapojili vsechny vystupy z hrp1.
		// sp_pole - vede ktere op hrany v prvni casti lze jeste rozdelit - omezeno maximalnim_vetvenim.
		for (i=0;i<ov->akt_vstup;++i) {	// pridame do sp_pole gvstupy
			if (ov->Vstupy[i]->vetveni+1<ov->maximalni_vetveni) sp_pole[sp_cnt++]=ov->Vstupy[i];
		}
		counter = 0;
		while (uz) {
			hr=uz->hradlo;
			if (hr->uroven<crossuroven1) {	// jsme pred delenim - hledame hrany na deleni, hledame nezapo vystupy hradel, hledame nezapojene branche vypnujeme hrp1,hrp2, sp_pole
				if (hr->typ!=BRANCH) {
					if (hr->zapojene_vystupy!=hr->pocet_vystupu) {
						for(i=0;i<hr->pocet_vystupu-hr->zapojene_vystupy;++i) {
							hrp1[hr1_cnt++]=hr;
						}
					}
					for(i=0;i<hr->zapojene_vystupy;++i) {
						if (hr->vystupy[i]->vetveni+1<ov->maximalni_vetveni) sp_pole[sp_cnt++]=hr->vystupy[i];
					}
				}
				else {		// mame branch
					pom=0;
					if (hr->zapojene_vystupy==0) { pom=1;hrp1[hr1_cnt++]=hr; }	// pokud nema zapojenej ani jeden vystup , tak jeden musime zapojit. takze ho zaradime do hrp1.
					if (hr->zapojene_vystupy!=hr->pocet_vystupu) {
						for(i=0;i<hr->pocet_vystupu-hr->zapojene_vystupy-pom;++i) hrp2[hr2_cnt++]=hr;
					}
				}
			}
			else if (hr->uroven>=crossuroven2) { // prochazime druhou cast noveho obvodu budem vypnovat hrp3,hrp4.
				if (hr->zapojene_vstupy!=hr->pocet_vstupu) {
					if (hr->typ==BRANCH) counter++;
					for(i=0;i<hr->pocet_vstupu-hr->zapojene_vstupy;++i) hrp3[hr3_cnt++]=hr;
				}			
				if (hr->typ==BRANCH) {
					pom=1;
					for (i=0;i<hr->pocet_vystupu;++i) { // jeden spoj nemuzem pocitat ani zadnej vystup;
						if (hr->vystupy[i]->vystup) pom=0;
						else {
							if (i<hr->pocet_vystupu-pom) hrp4[hr4_cnt++]=hr;
						}
					}
				}
			}
			uz=uz->next;
		}
		if (counter>0) {
			fprintf_s(stderr,"WRN: nova_generace(): v druhe casti je branch ktery nema zapojeny vstup!\n");				// jen kvuli breakpointu jestli nekdy nastane - nemelo by
		}
		// mame vytvoreny pole ted budem tvorit spoje a zapojovat mezi sebou obe casti. nejprve poresime nezapojeny glob vstupy pak budem zapojovat hrp1 s hrp3.
		// pokud dojde hrp3 mrknem na gvystupy pak budem muset rusit branche v 2.casti z hrp4 a zapojit do zbytku hrp1. pokud nepujde tak rusime celej obvod.
		// pokud dojde hrp1, tak berem z hrp2. pokud dojde hrp2 tak budem delit z sp_pole. pokud dojde hrp3, tak mame spojeno.
		// zbytek branchu v hrp2 budem muset smrsknout, muzou se timpadem i zrusit

#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d pripraveny hrpole\n",ov->id);
		fprintf_s(stderr,"UPD: nova_generace(): maz:%d a_vst:%d a_vyst:%d hr1:%d hr2:%d hr3:%d hr4:%d\n",mazem,ov->akt_vstup,ov->akt_vystup,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif


		while (ov->akt_vstup!=ov->pocet_vstupu) {
			if (hr3_cnt) {		// muzem zapojovat primo na nejakej vstup v druhy casti
				r1=random(hr3_cnt);
				hr2=hrp3[r1];
				hrp3[r1]=hrp3[--hr3_cnt];
				hrp3[hr3_cnt]=NULL;
				sp = new Tspoj(ov,-1,1);
				sp->pripoj_na_vstup(hr2);
				if (hr2->typ==BRANCH) {			//nemel by bejt branch,ale kdyby
					hr2->predsad_hradlo();
				}
				if (ov->maximalni_vetveni>1) sp_pole[sp_cnt++]=sp;
			}
			else if (hr4_cnt) {			// nemame volnej vstup zkusime branche.
				pokusy=POCET_POKUSU;
				do {
					r1=random(hr4_cnt);
					hr2=hrp4[r1];
					sp=hr2->odeber_vystup_mimoglob();
				} while ((sp==NULL) && (--pokusy>0));
				if (sp!=NULL) {
					hrp4[r1]=hrp4[--hr4_cnt];
					hrp4[hr4_cnt]=NULL;
					hr2->zmensi_hradlo();
					sp->preved_na_vstup();
					if (ov->maximalni_vetveni>1) sp_pole[sp_cnt++]=sp;
				}
				else goto mazem;
			}
			else goto mazem;
		}

#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d zapojeny vsechny Vstupy\n",ov->id);
		fprintf_s(stderr,"UPD: nova_generace(): maz:%d a_vst:%d a_vyst:%d hr1:%d hr2:%d hr3:%d hr4:%d\n",mazem,ov->akt_vstup,ov->akt_vystup,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu();
#endif

		while(hr3_cnt) {	// mame nezapojeny vstupy v druhy casti
			r1=random(hr3_cnt);
			hr2=hrp3[r1];
			hrp3[r1]=hrp3[--hr3_cnt];
			hrp3[hr3_cnt]=NULL;
			if (hr1_cnt) {	// spojujeme hradlo-hradlo
				r1=random(hr1_cnt);
				hr=hrp1[r1];
				hrp1[r1]=hrp1[--hr1_cnt];
				hrp1[hr1_cnt]=NULL;
				sp= new Tspoj(ov,hr->uroven);
				sp->pripoj_na_vystup(hr);
				sp->pripoj_na_vstup(hr2);
				if (hr2->typ==BRANCH) {
					hr2->predsad_hradlo();
				}
				if ((ov->maximalni_vetveni>1) && (sp->op==1)) sp_pole[sp_cnt++]=sp;
			}
			else if (hr2_cnt) { //spojujeme branch-hradlo
				pokusy=POCET_POKUSU;
				do {
					r1=random(hr2_cnt);
					hr=hrp2[r1];
				} while ((hr2->test_pripojeni_vstupu(hr)!=0) && (--pokusy>0));
				if (hr2->test_pripojeni_vstupu(hr)==0) {
					hrp2[r1]=hrp2[--hr2_cnt];
					hrp2[hr2_cnt]=NULL;
					sp=new Tspoj(ov,hr->uroven);
					sp->pripoj_na_vystup(hr);
					sp->pripoj_na_vstup(hr2);
					if (hr2->typ==BRANCH) {
						hr2->predsad_hradlo();  // zapojime BRN-BRN - coz bychom nemeli
					}
				}
				else goto mazem;	// mazem celej obvod a jedem znovu krizeni
			}
			else if (sp_cnt>0){ // budem vetvit
				memcpy(spzaloha,sp_pole,sizeof(Tspoj*)*sp_cnt);
				spzal=sp_cnt;
				while (spzal>0) {
					r1=random(spzal);
					sp2=spzaloha[r1];
					if (hr->test_pripojeni_vstupu(sp2)!=0) {
						spzaloha[r1]=spzaloha[--spzal];
					}
					else { break;
					}
				}
				if (spzal>0) {
					sp=sp2->Rozvetvi();
					if (sp2->vetveni+1>=ov->maximalni_vetveni) {
						for(i=0;i<sp_cnt;i++) {
							if (sp_pole[i]==sp2) break;
						}
						if (i==sp_cnt) {
							fprintf_s(stderr,"WRN: nova_generace(): Vetvenej spoj neni v spoj_poli !!!\n");
						}
						sp_pole[i]=sp_pole[--sp_cnt];
					}
					sp->pripoj_na_vstup(hr2);
					if (hr2->typ==BRANCH) {
						hr2->predsad_hradlo(); // nemelo by nastat - nemeli bychom mit v druhy casti nezap vstupy BRN
					}

				}
				else goto mazem;
			}
			else goto mazem;
		}	// dosly vstupy v druhy casti budem resit co zbylo v prvni casti
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d zapojeny vsechny vstupy hradel v druhy casti(vsude)\n",ov->id);
		fprintf_s(stderr,"UPD: nova_generace(): maz:%d a_vst:%d a_vyst:%d hr1:%d hr2:%d hr3:%d hr4:%d\n",mazem,ov->akt_vstup,ov->akt_vystup,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu(0);
#endif

		while (hr1_cnt) {		// mame nezap vystupy - budem hledat vetveny spoje v druhy casti a zmensovat. nebo volnej glob vystup.
			r1=random(hr1_cnt);
			hr=hrp1[r1];
			hrp1[r1]=hrp1[--hr1_cnt];
			hrp1[hr1_cnt]=NULL;
			if (ov->akt_vystup!=ov->pocet_vystupu) {
				sp = new Tspoj(ov,hr->uroven,0,1);
				sp->pripoj_na_vystup(hr);
				if ((ov->maximalni_vetveni>1) && (sp->op==1)) sp_pole[sp_cnt++]=sp;
			}
			else if (hr4_cnt) {  // mame odkud brat
				pokusy=POCET_POKUSU;			
				do {
					r1=random(hr4_cnt);
					hr2=hrp4[r1];
					sp=hr2->odeber_vystup_mimoglob();
				} while ((sp==NULL) && (--pokusy>0));
				if (sp!=NULL) { 
					hrp4[r1]=hrp4[--hr4_cnt];
					hrp4[hr4_cnt]=NULL;
					hr2->zmensi_hradlo();
					sp->pripoj_na_vystup(hr);
					if (ov->maximalni_vetveni>1) sp_pole[sp_cnt++]=sp;
				}
				else goto mazem;
			}
			else goto mazem ;
		}
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d zapojeny vsechny vystupy hradel v prvni casti(vsude)\n",ov->id);
		fprintf_s(stderr,"UPD: nova_generace(): maz:%d a_vst:%d a_vyst:%d hr1:%d hr2:%d hr3:%d hr4:%d\n",mazem,ov->akt_vstup,ov->akt_vystup,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu(0);
#endif

		while (ov->akt_vystup!=ov->pocet_vystupu) { // dosla vstupy v druhy casti, ale mame nezapojeny glob vystupy
			hr2=NULL;
			if (hr2_cnt) {  // berem nezap branch
				pokusy=POCET_POKUSU;
				do {
					r1=random(hr2_cnt);
					hr2=hrp2[r1];
				} while ((hr2->vstupy[0]->vstup==1) && (--pokusy>0));
				if (hr2->vstupy[0]->vstup!=1) { //pohoda muzem zaplnit branch
					hrp2[r1]=hrp2[--hr2_cnt];
					hrp2[hr2_cnt]=NULL;
					sp2= new Tspoj(ov,hr2->uroven,0,1);
					sp2->pripoj_na_vystup(hr2);
				}
				else {	//budem vetvit
					pokusy=20;
					do {
						r1=random(sp_cnt);
						sp=sp_pole[r1];
					} while ((sp->vstup)&&(--pokusy>0));
					if (sp->vstup!=1) { // ok muzem vetvit
						sp2=sp->Rozvetvi();
						if (sp->vetveni+1>=ov->maximalni_vetveni) {
							sp_pole[r1]=sp_pole[--sp_cnt];
						}
						sp2->preved_na_vystup();
					}
					else goto mazem;
				}
			}
			else { // budem vetvit
					pokusy=POCET_POKUSU;
					do {
						r1=random(sp_cnt);
						sp=sp_pole[r1];
					} while ((sp->vstup)&&(pokusy>0)) ;
					if (sp->vstup!=1) { // ok muzem vetvit
						sp2=sp->Rozvetvi();
						if (sp->vetveni+1>=ov->maximalni_vetveni) {
							sp_pole[r1]=sp_pole[--sp_cnt];
						}
						sp2->preved_na_vystup();
					}
					else goto mazem;
			}
		}
#ifdef LH_GEN
		fprintf_s(stderr,"UPD: nova_generace(): Obv:%d zapojeny vsechny Vystupy obvodu\n",ov->id);
		fprintf_s(stderr,"UPD: nova_generace(): maz:%d a_vst:%d a_vyst:%d hr1:%d hr2:%d hr3:%d hr4:%d\n",mazem,ov->akt_vstup,ov->akt_vystup,hr1_cnt,hr2_cnt,hr3_cnt,hr4_cnt);
		ov->vypis_hradla(stderr);
		ov->vypis_spoje(stderr);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu(0);
#endif
		// nezapojenych vystupu branchu v prvni casti se zbavime smrsknutim branchu
		for (;hr2_cnt>0;) {
			hrp2[--hr2_cnt]->zmensi_hradlo();
			hrp2[hr2_cnt]=NULL;
		}

		if (mazem) {		// nepodarilo se nam zapojit krizeni budem obvod mazat a zkusime znova
mazem:
#ifdef LH_GEN
			fprintf_s(stderr,"UPD: nova_generace(): Obv:%d Mazeme.\n",ov->id);
#endif
			mazem=1;
			delete ov;
		}
		else {
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu(1);
#endif

			r1 = random(100);
			if (r1<PRAVDEPODOBNOST_MUTACE) {
				ov->proved_mutaci();
			}
#ifdef LH_GEN
			fprintf_s(stderr,"UPD: nova_generace(): Obv:%d Pocitam urovne.\n",ov->id);
#endif
#ifdef ZAPNUTE_KONTROLY
		ov->proved_kontrolu(1);
#endif
			ov->spocti_urovne();
#ifdef LH_GEN
			fprintf_s(stderr,"UPD: nova_generace(): Obv:%d Pocitam testabilitu.\n",ov->id);
#endif
			ov->vypocitej_testabilitu_CAMELOT();
#ifdef LH_GEN
			fprintf_s(stderr,"UPD: nova_generace(): Obv:%d Pocitam fitness.\n",ov->id);
#endif
			ov->spocti_fitness();
			generace2[velikost++]=ov;
//			ov->vypis_obvod();
#ifdef LH_GEN
			fprintf_s(stderr,"UPD: nova_generace(): Obv:%d Mame komplet obvod jdem na dalsi.\n",ov->id);
#endif

		} // konec druhe vetve pokud nemazem
	
		delete [] hrp1;
		delete [] hrp2;
		delete [] hrp3;
		delete [] hrp4;
		delete [] sp_pole;
		delete [] spzaloha;
	}		//konec jednoho krizeni
	// mame generaci
#ifdef LH_GEN
	fprintf_s(stderr,"UPD: nova_generace(): Mame celou generaci mazem starou.\n",ov->id);
#endif
	// mazeme vse mimo elitismu.
	for (i=POCET_ELITISMU;i<hlavni->zadana_velikost_populace;++i) {
		delete generace[i];
	}

#ifdef LH_GEN
	fprintf_s(stderr,"UPD: nova_generace(): Jdeme radit novou generaci.\n",ov->id);
#endif

	delete [] generace;
	generace=generace2;
	ov=generace[0];
	qsort( generace, hlavni->zadana_velikost_populace, sizeof(Tobvod *),porovnej_obvod_fitness );
	if (ov==generace[0]) return 0;
	else return 1;
}


void Thlavni::init() {
	this->generace=new Tobvod * [hlavni->zadana_velikost_populace];
	memset(generace,0,sizeof(Tobvod*)*hlavni->zadana_velikost_populace);
}
Tuzel::Tuzel() {
	spoj=NULL;
	hradlo=NULL;
	next=NULL;
	prev=NULL;
}
void Tobvod::spocti_urovne() {	
// funguje jen na hotovej obvod a melo by bejt vsechno zapojeny ;) 
// spocte realne urovne tak ze projizdi od vstupu serazenym polem hradel a za kazde hradlo pricte spojum 1 uroven. v hradle se bere maximalni uroven ze vsech vstupu.
// nakonci bere maximalni uroven ze vsech vystupu.
	int i;
	int uroven;
	int guroven;
	Tuzel *uz;
	Thradlo *hr;
	uroven=-1;
	guroven=-1;
	uz=seznam_zac;
	while (uz) {
		hr=uz->hradlo;
		if (hr->typ!=BRANCH) {
			uroven=hr->vstupy[0]->realna_uroven;
			for (i=1;i<hr->zapojene_vstupy;++i) {
				uroven=max(hr->vstupy[i]->realna_uroven,uroven);
			}
			hr->realna_uroven=++uroven;
			
			for (i=0;i<hr->zapojene_vystupy;++i) {
				hr->vystupy[i]->realna_uroven=uroven;
			}
		}
		else {
			uroven=hr->vstupy[0]->realna_uroven;
			for (i=0;i<hr->zapojene_vystupy;++i) {
				hr->vystupy[i]->realna_uroven=uroven;
			}
		}
		uz=uz->next;
	}
	for (i=0;i<pocet_vystupu;++i) {
		guroven=max(guroven,Vystupy[i]->realna_uroven);
	}
	realne_urovne=guroven;
}
void Tobvod::proved_mutaci(int typ) {
	int i,j,k,l,rnd;
	int pom,pomv;
	int minsp,maxsp;
	int zacb,konb,zacb2,konb2;
	Tspoj **spp,**spz,**spz2;
	int spc,spcz,spcz2;;
	Thradlo **hrp,**hrz,**hrp2;
	int hrc,hrcz,hrc2;
	Tuzel *uz;
	Thradlo *hr,*hr2,*hr3;
	Tspoj *sp,*sp2,*sp3;

	spp = new Tspoj*[this->celkem_hradel+this->pocet_vstupu];	// pole spoju na vetveni. pro nahodnej vyber vetveni. je razenej !!!
	spz =  new Tspoj*[this->celkem_spoju];						// zalohy pole
	spz2 =  new Tspoj*[this->celkem_spoju];						
	spc=spcz=spcz2=0;
	hrp = new Thradlo*[this->celkem_hradel];		// pole vsech branchu
	hrz = new Thradlo*[this->celkem_hradel];		// zaloha
	hrp2 = new Thradlo*[this->celkem_fc_spoju];		// muze mit jinej vyznam v ruznejch mutacich
	hrc=hrcz=hrc2=0;
	// tvorime pole spp,s prihlednutim na spp. a pole hrp
	for (i=0;i<pocet_vstupu;++i) {
		if (Vstupy[i]->vetveni+1<maximalni_vetveni) spp[spc++]=Vstupy[i];
	}
	uz=seznam_zac;
	while (uz) {
		hr=uz->hradlo;
		if (hr->typ==BRANCH) {
			hrp[hrc++]=hr;
		}
		else {
			if (hr->vystupy[0]->vetveni+1<this->maximalni_vetveni) spp[spc++]=hr->vystupy[0];
		}
		uz=uz->next;
	}
	// mame hrp a spp;

	if (typ==0) typ=random(3)+1;
	switch (typ) {
		case 1:					// menime jedno hradlo za jine 
			rnd=random(this->celkem_op_hradel);
			uz=seznam_zac;
			i=0;
			while ((i<=rnd) || ((uz!=NULL) && (uz->hradlo->typ == BRANCH))) {			// dojedem az na prvni hradlo co je nasim vybranym hradlem takze hr= nami vybrane hradlo
				if (uz->hradlo->typ!=BRANCH) {
					hr=uz->hradlo;
					i++;
				}
				uz = uz->next;
			}
			minsp=0;			
			for(j=0;j<spc;++j) {
				if (spp[j]->zac_uroven+1>=hr->uroven) break;	// j-1 je nejvetsi index do pole spp kde je hrana kterou muzem vetvit. takze j= pocet prvku
			}
			pomv=0;	// pomocna
			spcz2=0;	
//			fprintf_s(stderr,"\n\nobv:%4d mut1: hr: id:%2d nazev:%s pocvs:%2d zapvs:%2d\n",id,hr->uid,hr->nazev,hr->pocet_vstupu,hr->zapojene_vstupy);
			for(k=0;k<hr->zapojene_vstupy;++k) {
				if (hr->vstupy[k]->op==1) {
					minsp++;	// minsp=kolik mame zapojenejch nevetvenejch hran na vstupu.
					spz2[spcz2++]=hr->vstupy[k];		// vedem si seznam primo zapojenejch vstupu ve starym hradlu
					if (hr->vstupy[k]->vstup==1) {
						pomv++;
					}
//					fprintf_s(stderr,"     do spcz2:%d pridan spoj %2d s op=%1d zac=%s kon=%s\n",spcz2,hr->vstupy[k]->uid,hr->vstupy[k]->op,hr->vstupy[k]->vstup==0?hr->vstupy[k]->zac->nazev:"VST",hr->vstupy[k]->kon->nazev);
		
				}
				else {
					hrp2[hrc2++]=hr->vstupy[k]->zac;	// vedem si i zapojene hrany ktere vedou z branche
//					fprintf_s(stderr,"   mimo spcz2:%d zustal spoj %2d s op=%1d zac=%s kon=%s\n",spcz2,hr->vstupy[k]->uid,hr->vstupy[k]->op,hr->vstupy[k]->zac->nazev,hr->vstupy[k]->kon->nazev);
				}
			}
			k=minsp;	// minsp kolik musi mit minimalne vstupu nove hraldfo abychom uspesne vyresili zapojenio hran vcetne ruzneho rozvetvovani apod.
			maxsp=j+minsp;  // maxsp - kolik muze mit maximalne vstupu. jsou to primo zapojene vstupy + pocet hran co muzem rozvetvit a zapojit.
			maxsp=max(maxsp,hr->zapojene_vstupy);	// muzem vzdycky zapojit to samy.
			spcz=0;
			// budem si vest vsechny vstupy hradel ktere jsou za nasim a ten vstup vede z branche - pro branch nebudem pocitat vzdy jeden vystup.
			// o to cislo pak muzem zmensit minsp, pripadne nezapojene vstupy ze stareho hradlde muzem prepojit na ony dane vstupy na hradla za nim. a zmensit prislusny branch.
			while (uz!=NULL) {
				hr2=uz->hradlo;
				if (hr2->typ==BRANCH) minsp++;		// za z kazdyho branche musi vest alepson 1 hrana dal.
				for(l=0;l<hr2->zapojene_vstupy;++l) {
					if ((hr2->vstupy[l]->op==0) && (hr2->vstupy[l]!=hr2->vstupy[l]->zac->vystupy[0])){ // jestli je to prvni vystup z branche tak ho nechcem, kvuli moznosti zruseni branche a timpadem smazani i dane hrany.
						for (i=0;i<hrc2;++i) {		// kontrolujem jestli nevede hrana z branche kterej je pripojenej na hr - mohlo by se pri prepojhovani hran toto hradlo zmensit-odstranit a tim by se smazala jedna z hran ktere se museji prepojit.			
							if (hr2->vstupy[l]->zac==hrp2[i]) break;
						}
						if (i==hrc2) {
							minsp--; 
							spz[spcz++]=hr2->vstupy[l];		// vedeme si vsechny vetvene spoje co jsou za hraldem hr dal
						}
					}
				}
				uz=uz->next;
			}
			hr2=NULL;
			// vytvorime nove hradlo do ukazatele hr2
			do {
				if (hr2!=NULL) delete hr2;
				hr2=this->vytvor_nove_hradlo();
			} while ((hr2->pocet_vstupu<minsp) || (hr2->pocet_vstupu>maxsp)); // kontrolujem jeslti pujde zapojit
//			fprintf_s(stderr,"\n    nove hradlo hrid:%2d pocvs:%1d:\n",hr2->uid,hr2->pocet_vstupu);

			hr2->uroven=hr->uroven;
			l=hr->pocet_vstupu;
			sp=hr->odeber_vystup();
			sp->pripoj_na_vystup(hr2);
			while (hr2->zapojene_vstupy<hr2->pocet_vstupu) {	// dokud mame nezaojene vstupy v novem hradle
				if (spcz2>0) {	// prepojime primo zapojene vstupy
					sp=spz2[--spcz2];
					sp->odpoj_od_vstupu();
					sp->pripoj_na_vstup(hr2);
//					fprintf_s(stderr,"     prepojen spcz2=%2d id:%3d s op=%1d zas=%s kon=%s\n",spcz2,sp->uid,sp->op,sp->vstup==0?sp->zac->nazev:"VST",sp->vystup==0?sp->kon->nazev:"VYS");
				}
				else if (hr->zapojene_vstupy>0) {		// prepojime zbyle spoje ze stareho
					sp=hr->odeber_vstup();
					sp->pripoj_na_vstup(hr2);
//					fprintf_s(stderr,"     prep non spcz2=%2d id:%3d s op=%1d zac=%s kon=%s\n",spcz2,sp->uid,sp->op,sp->vstup==0?sp->zac->nazev:"VST",sp->vystup==0?sp->kon->nazev:"VYS");
				}
				else {						// pokud uz nam ve starem nezbyly tak budem rozpojovat
					while (j>0) {			//  mame co delit
						rnd=random(j);
						sp3=spp[rnd];
						if (hr2->test_pripojeni_vstupu(sp3)!=0) {		// testujem jestli to jde - melo by.
							spp[rnd]=spp[--j];							// zaroven vyndavame uz vetvene spoje
						}
						else { break;
						}
					}
					if (j>0) {			// mame co delit :)
//						fprintf_s(stderr,"     vetvime   pcz2=%2d id:%3d s op=%1d zac=%s kon=%s\n",spcz2,sp3->uid,sp3->op,sp3->zac!=NULL?sp3->zac->nazev:"VSTUP",sp3->vystup==0?sp3->kon->nazev:"VYS");
						sp=sp3->Rozvetvi();
						if (sp3->vetveni+1>=maximalni_vetveni) spp[rnd]=spp[--j];
						sp->pripoj_na_vstup(hr2);
//						fprintf_s(stderr,"     rozvetven pcz2=%2d id:%3d s op=%1d zac=%s kon=%s\n",spcz2,sp3->uid,sp3->op,sp3->zac!=NULL?sp3->zac->nazev:"VSTUP",sp3->vystup==0?sp3->kon->nazev:"VYS");
//						fprintf_s(stderr,"            na pcz2=%2d id:%3d s op=%1d zac=%s kon=%s\n",spcz2,sp->uid,sp->op,sp->zac->nazev,sp->vystup==0?sp->kon->nazev:"VYS");
					}
					else {				// nemame co delit musime zmensit vygenerovane hradlo. ale nemeli bychom se sem dostat
						hr2->zmensi_hradlo();	// nemelo by se to sem dostat.
					}
				}
			}			// mame zapojeny cely novy hradlo
//			fprintf_s(stderr,"  Cele hradlo zapojeno zbylych spoju na starem hradle: %2d\n",hr->zapojene_vstupy);
			while (hr->zapojene_vstupy>0) {			// jeste je neco zapojenyho do staryho
				for(i=0;i<hr->zapojene_vstupy;++i) {
					sp=hr->vstupy[i];
//					fprintf_s(stderr,"  zbylo spcz2:%d zustal spoj %2d s i:%1d o:%1d zac=%s kon=%s\n",spcz2,sp->uid,sp->vstup,sp->vystup,sp->zac!=NULL?sp->zac->nazev:"NULL",sp->kon!=NULL?sp->kon->nazev:"NULL");
				}
				if (spcz2>0) {		// mame primo zapojene vstupy budem vybirat ze vstupu hradel za nasim odpojovat od branche a branch zmensime
					sp2=spz2[--spcz2];
					sp2->odpoj_od_vstupu();
//					fprintf_s(stderr,"      odpojili jsme sp2 id=%2d i:%1d o:%1d zac=%s\n",sp2->uid,sp2->vstup,sp2->vystup,sp2->zac!=NULL?sp2->zac->nazev:"NULL");
					rnd=random(spcz);
					sp=spz[rnd];
					spz[rnd]=spz[--spcz];
//					fprintf_s(stderr,"      vybrano    sp sid:%2d i:%1d o:%1d zac=%s kon%s\n", sp->uid,sp->vstup,sp->vystup,sp->zac!=NULL?sp->zac->nazev:"NULL",sp->kon!=NULL?sp->kon->nazev:"NULL");
					hr3=sp->odpoj_od_vystupu();
//					fprintf_s(stderr,"      zmensujeme hr3 id:%2d n:%s. I id:%2d io:%d%d %s O id:%2d io:%d%d %s\n", hr3->uid,hr3->nazev,hr3->vstupy[0]->uid,hr3->vstupy[0]->vstup,hr3->vstupy[0]->vystup,hr3->vstupy[0]->zac!=NULL?hr3->vstupy[0]->zac->nazev:"NULL",hr3->vystupy[0]->uid,hr3->vystupy[0]->vstup,hr3->vystupy[0]->vystup,hr3->vystupy[0]->kon!=NULL?hr3->vystupy[0]->kon->nazev:"NULL");
					sp3=hr3->vstupy[0];
					hr3->zmensi_hradlo();
//					fprintf_s(stderr,"      zmenseno   sp3 sid:%2d i:%1d o:%1d zac=%s kon%s\n", sp3->uid,sp3->vstup,sp3->vystup,sp3->zac!=NULL?sp3->zac->nazev:"NULL",sp3->kon!=NULL?sp3->kon->nazev:"NULL");
					hr3=sp->odpoj_od_vstupu();
					delete sp;
					sp2->pripoj_na_vstup(hr3);
//					fprintf_s(stderr,"      prepojen   sp2 sid:%2d i:%1d o:%1d zac=%s kon%s\n done\n", sp2->uid,sp2->vstup,sp2->vystup,sp2->zac!=NULL?sp2->zac->nazev:"NULL",sp2->kon!=NULL?sp2->kon->nazev:"NULL");
					
				}
				else {		// mame zapojeny spoje z branche budem mazat a zmensovat BRN
					sp=hr->odeber_vstup();
//					fprintf_s(stderr,"      vybrano sp a odpojeno sid:%2d i:%1d o:%1d zac=%s kon%s\n", sp->uid,sp->vstup,sp->vystup,sp->zac!=NULL?sp->zac->nazev:"NULL",sp->kon!=NULL?sp->kon->nazev:"NULL");
					hr3=sp->odpoj_od_vystupu();
//					fprintf_s(stderr,"      zmensujeme hr3 id:%2d n:%s. I id:%2d io:%d%d %s O id:%2d io:%d%d %s\n", hr3->uid,hr3->nazev,hr3->vstupy[0]->uid,hr3->vstupy[0]->vstup,hr3->vstupy[0]->vystup,hr3->vstupy[0]->zac!=NULL?hr3->vstupy[0]->zac->nazev:"NULL",hr3->vystupy[0]->uid,hr3->vystupy[0]->vstup,hr3->vystupy[0]->vystup,hr3->vystupy[0]->kon!=NULL?hr3->vystupy[0]->kon->nazev:"NULL");
					sp3=hr3->vstupy[0];
					hr3->zmensi_hradlo();
//					fprintf_s(stderr,"      zmenseno   sp3 sid:%2d i:%1d o:%1d zac=%s kon%s\n", sp3->uid,sp3->vstup,sp3->vystup,sp3->zac!=NULL?sp3->zac->nazev:"NULL",sp3->kon!=NULL?sp3->kon->nazev:"NULL");
					delete sp;
				}
			}
			this->seznam_vloz_hradlo(hr2);
			this->seznam_vyndej_hradlo(hr);
			delete hr;

			break;
		case 2:
			// budem krizit 2 vystupy hran, pozor aby nevznikla hrana BRANCH-BRANCH nebo IN-OUT
			spcz=0;
			sp=Spoje;
			while (sp!=NULL) {
				spz[spcz++]=sp;
				sp=sp->next;
			}
			// do spz si udelame seznam vsech spoju a nahodne jedno vyberem
			rnd=random(spcz);
			sp=spz[rnd];
			zacb=konb=0;
			if ((sp->op==1) && (sp->fc==0)) konb=1;	// jeslti konci branchem
			if ((sp->op==0) && (sp->fc==1)) zacb=1;	// jestli zacina branchem
			spz[rnd]=spz[--spcz];	// hranu vyndame
			while (spcz>0) {		// zkousime nahodne vybrat hranu na krizeni
				pom=0;
				rnd=random(spcz);
				sp2=spz[rnd];
				zacb2=konb2=0;
				if ((sp2->op==1) && (sp2->fc==0)) konb2=1;		// hrana vede do vetveni
				if ((sp2->op==0) && (sp2->fc==1)) zacb2=1;		// hrana vede z vetveni
				if ((sp->zac_uroven>=sp2->kon_uroven) || (sp->kon_uroven<=sp2->zac_uroven)) pom=1; 
				else if (sp2->vystup==1) pom=1;
				else if ((sp->vystup==1) && (sp2->vstup==1)) pom=1;		// nemuzem vstup-vystup
				else if (((zacb==1) && (konb2==1)) || ((zacb2==1) && (konb==1))) pom=1; // nemuzem branch-branch
				else if ((zacb==1) && (sp2->vystup==0) && (sp2->kon->test_pripojeni_vstupu(sp->zac)!=0)) pom=1; // nemuzem aby do 1 hradla vedly 2 "stejny" spoje
				else if ((zacb2==1) && (sp->vystup==0) && (sp->kon->test_pripojeni_vstupu(sp2->zac)!=0)) pom=1;	// to samy

				if (pom==0) break;	// povedlo se nam ji vybrat
				spz[rnd]=spz[--spcz];	// jinak hranu vyradime z vyberu a zkusime dal.
			} 
			if (spcz>0) {  // menime vystupy hran	
				hr=sp->odpoj_od_vstupu();
				hr2=sp2->odpoj_od_vstupu();
				sp->pripoj_na_vstup(hr2);
				if (hr==NULL) sp2->preved_na_vystup();
				else sp2->pripoj_na_vstup(hr);
				if (konb==1) hr->predsad_hradlo();
				if (konb2==1) hr2->predsad_hradlo();
			}
			break;	// pokud se nam ji nepodari vybrat tak nemutujem
		case 3:
			// presouvame cast branche jinam.
			if (hrc==0) break;	// neni branch
			rnd=random(hrc);
			hr=hrp[rnd];
			j=pom=hr->pocet_vystupu;
			pom=random(pom-1)+1;   // pom kolik ma zustat spoju v branchi;
			while (j>pom) {			// mame jeste co presouvat
				sp=hr->odeber_vystup();
				for(i=0;i<spc;++i) {	// i je index na vsechny spoje co muzem vetvit 
					if (spp[i]->zac_uroven+1>=sp->kon_uroven) break;
				}
				memcpy(spz,spp,sizeof(Tspoj*)*spc);	// udelame zalohu
				spcz=spc;
				hr2=sp->odpoj_od_vstupu();		// odpojime ji i od vstupu a smazem - misto ni vytvorime novou hranu
				delete sp;
				sp=hr->vstupy[0];
				hr->zmensi_hradlo();		// zmensime hradlo
				while (i>0) {		// pokud mame jeste moznost neco vetvit
					rnd=random(i);
					sp3=spz[rnd];
					if ((hr2!=NULL) && (hr2->test_pripojeni_vstupu(sp3)!=0)) {
						spz[rnd]=spz[--i];		// pokud nemuzem vetvit task odeberem ze zalohy
					}
					else { break;
					}
				}
				if (i>0) {		// vybrali jsme neco co lze vetvit
					sp2=sp3->Rozvetvi();			// rozvetvime a kdyz presahnem maximalni vetveni tak smaznem z pole
					if (sp3->vetveni+1>=maximalni_vetveni) {
						for(i=0;i<spc;++i) {
							if (spp[i]==sp3) break;
						}
						for (k=i;k<spc;k++) {
							spp[k]=spp[k+1];
						}
						spc--;
					}
					if (hr2!=NULL) sp2->pripoj_na_vstup(hr2);	// resime jeslit to nebyl gvystup
					else sp2->preved_na_vystup();
					j--;
				}
				else {		// nenasli jsme vhodnyho kandidata na vetveni vratime hranu zpatky 
					sp3=sp->Rozvetvi();
					if (hr2!=NULL) sp3->pripoj_na_vstup(hr2);
					else sp3->preved_na_vystup();
					pom++;
				}

			}
	}
	delete [] spp;
	delete [] spz;
	delete [] spz2;
	delete [] hrp;
	delete [] hrz;
}
void Tobvod::preber_vstupni_hodnoty(Tobvod * obv) {
	pocet_hradel=obv->pocet_hradel;
	pocet_vstupu=obv->pocet_vstupu;
	pocet_vystupu=obv->pocet_vystupu;
	zadane_urovne=obv->zadane_urovne;
	zadana_controlabilita=obv->zadana_controlabilita;
	zadana_observabilita=obv->zadana_observabilita;
	zadana_testabilita=obv->zadana_testabilita;
	maximalni_vetveni=obv->maximalni_vetveni;
	memcpy(typy_gen_max,obv->typy_gen_max,sizeof(int)*POCET_TYPU_HRADEL);
	memcpy(typy_gen_p,obv->typy_gen_p,sizeof(int)*POCET_TYPU_HRADEL);
	memcpy(vahy,obv->vahy,sizeof(double)*POCET_TYPU_VAH);
	typy_gen_pk=obv->typy_gen_pk;
	zadane_info=obv->zadane_info;
	zadane_cg=obv->zadane_cg;
}


int Tspoj::spocti_controlabilitu_SCOAP() {
	int i,j,n;
	if (this==NULL) {
		fprintf(stderr,"WRN: Tspoj::spocti_controlabilitu(): volano na spoj==NULL!!\n");
		return 5;
	}
	if (vstup) {
		cc0=1;
		cc1=1;
		return 0;
	}
	if (!zac) {
		fprintf(stderr,"WRN: Tspoj::spocti_controlabilitu(): spoj neni pripojenej na zadnej vystup!\n");
		return 1;
	}
	
	switch (zac->typ) {
		case -1: 
			return 2;
		case BRANCH:
			cc0=zac->vstupy[0]->cc0;
			cc1=zac->vstupy[0]->cc1;
			break;
		case AND:
		case NAND:
			for(i=0,n=zac->vstupy[0]->cc0;i<zac->pocet_vstupu;++i) {
				n=min(n,zac->vstupy[i]->cc0);
			}
			cc0=n+1;
			for(i=0,n=0;i<zac->pocet_vstupu;++i) {
				n+=zac->vstupy[i]->cc1;
			}
			cc1=n+1;
			if (zac->typ==NAND) {
				n=cc0;
				cc0=cc1;
				cc1=n;
			}
			break;
		case OR:
		case NOR:
			for(i=0,n=zac->vstupy[0]->cc1;i<zac->pocet_vstupu;++i) {
				n=min(n,zac->vstupy[i]->cc1);
			}
			cc1=n+1;
			for(i=0,n=0;i<zac->pocet_vstupu;++i) {
				n+=zac->vstupy[i]->cc0;
			}
			cc0=n+1;
			if (zac->typ==NOR) {
				n=cc0;
				cc0=cc1;
				cc1=n;
			}
			break;
		case XOR:
		case XNOR:
			if (zac->pocet_vstupu!=2) return 4;
			n=zac->vstupy[0]->cc0+zac->vstupy[1]->cc0;
			j=zac->vstupy[0]->cc1+zac->vstupy[1]->cc1;
			cc0=min(n,j)+1;
			n=zac->vstupy[0]->cc1+zac->vstupy[1]->cc0;
			j=zac->vstupy[0]->cc0+zac->vstupy[1]->cc1;
			cc1=min(n,j)+1;
			if (zac->typ==XNOR) {
				n=cc0;
				cc0=cc1;
				cc1=n;
			}
			break;
		case NOT:
			cc0=zac->vstupy[0]->cc1+1;
			cc1=zac->vstupy[0]->cc0+1;
	}
	return 0;
}
int Thradlo::spocti_controlabilitu_SCOAP() {	
	int i,j;
	for (i=0;i<pocet_vystupu;++i) {
		j=vystupy[i]->spocti_controlabilitu_SCOAP();
		if (j) return 1;
	}
	return 0;
}
int Thradlo::spocti_controlabilitu_CAMELOT() {	
	int i;
	double d;
	if (typ==BRANCH) {
		for (i=0;i<zapojene_vystupy;++i) vystupy[i]->cy=vstupy[0]->cy;
	}
	else {
		d=0;
		for (i=0;i<zapojene_vstupy;++i) d+=vstupy[i]->cy;
		d/=zapojene_vstupy;
		vystupy[0]->cy=ctf*d;
	}
	return 0;
}
int Thradlo::spocti_observabilitu_SCOAP() {
	int i,j;
	for (i=0;i<pocet_vstupu;++i) {
		j=vstupy[i]->spocti_observabilitu_SCOAP();
		if (j) return 1;
	}
	return 0;
}		
int Thradlo::spocti_observabilitu_CAMELOT() {
	int i;
	double d;
	if (typ==BRANCH) {
		d=vystupy[0]->oy;
		for (i=1;i<zapojene_vystupy;++i) d=min(vystupy[i]->oy,d);
		vstupy[0]->oy=d;
		vstupy[0]->ty=d*vstupy[0]->cy;
	}
	else if (typ==NOT) {
		vstupy[0]->oy=vystupy[0]->oy*otf;
		vstupy[0]->ty=vstupy[0]->oy*vstupy[0]->cy;
	}
	else {
		d=0;
		for (i=0;i<zapojene_vstupy;++i) d+=vstupy[i]->cy;
		for (i=0;i<zapojene_vstupy;++i) {
			vstupy[i]->oy=((d-vstupy[i]->cy)/(zapojene_vstupy-1))*otf*vystupy[0]->oy;
			vstupy[i]->ty=vstupy[i]->oy*vstupy[i]->cy;
		}
	}
	return 0;
}
int Tspoj::spocti_observabilitu_SCOAP() {
	int i,j,n;
	if (vystup==1) {
		co=0;
		return 0;
	}
	if (kon==NULL) {
		fprintf_s(stderr,"WRN: Tspoj::spocti_observabilitu(): spoj neni pripojenej na zadnej vstup!\n");
		return 1;
	}
	switch (kon->typ) {
		case -1: 
			fprintf_s(stderr,"WRN: Tspoj::spocti_observabilitu(): typ koncovyho hradla== -1 !!\n");
			return 2;
		case BRANCH:
			for(i=0,n=kon->vystupy[0]->co;i<kon->pocet_vystupu;++i) {
				n=min(n,kon->vystupy[i]->co);
			};
			co=n;
			break;
		case AND:
		case NAND:
			co=kon->vystupy[0]->co-this->cc1+1;
			for (i=0;i<kon->pocet_vstupu;++i) co+=kon->vstupy[i]->cc1;
			break;
		case OR:
		case NOR:
			co=kon->vystupy[0]->co-this->cc1+1;
			for (i=0;i<kon->pocet_vstupu;++i) co+=kon->vstupy[i]->cc0;
			break;
		case XOR:
		case XNOR:
			if (this==kon->vstupy[0]) {
				n = kon->vstupy[1]->cc0;
				j = kon->vstupy[1]->cc1;
			}
			else {
				n = kon->vstupy[0]->cc0;
				j = kon->vstupy[0]->cc1;
			}
			co=kon->vystupy[0]->co+min(n,j)+1;
			break;
		case NOT:
			co=kon->vystupy[0]->co+1;
	}
	return 0;
}



void Thradlo::vypocti_koeficienty() {
// vypocte koeficienty tohoto hradla pro CAMELOT podl navodu.
	double d;
	int n0,n1;
	int nsp,nip;
	switch (typ) {
		case AND:
		case NOR:
			n1=1;
			n0=(1<<pocet_vstupu)-1;
			nsp=1;
			nip=(1<<(pocet_vstupu-1))-1;
			break;
		case NAND:
		case OR:
			n0=1;
			n1=(1<<pocet_vstupu)-1;
			nip=1;
			nsp=(1<<(pocet_vstupu-1))-1;
			break;
		case XOR:
		case XNOR:
		case NOT:
			n0=1<<(pocet_vstupu-1);
			n1=n0;
			nsp=1;
			nip=0;
			break;
	}
	if (typ==BRANCH) {
		this->ctf=1;
		this->otf=1;
	}
	else {
		d=abs(n0-n1);
		this->ctf=1-(d/(n0+n1));
		d=nsp;
		this->otf=d/(nsp+nip);
	}
}
void Tobvod::vypocitej_testabilitu_CAMELOT() {
// vypocita testabilitu metodou CAMELOT podle navodu
	Tuzel *spom;
	Tspoj *sp;
	int i,j;
	double avg_cy,avg_oy,avg_ty;

	spom=seznam_zac;
	for (i=0;i<pocet_vstupu;++i) Vstupy[i]->cy=1;
	while (spom) {
		spom->hradlo->spocti_controlabilitu_CAMELOT();
		spom=spom->next;
	}
	// pocitame observabilitu - musi bejt vypocitana predem controlabilita
	for (i=0;i<pocet_vystupu;++i) { 
		Vystupy[i]->oy=1;
		Vystupy[i]->ty=Vystupy[i]->cy;
	}
	spom=seznam_kon;
	while (spom) {
		spom->hradlo->spocti_observabilitu_CAMELOT();
		spom=spom->prev;
	}
	sp=Spoje;
	j=0;
	avg_cy=avg_oy=avg_ty=0;
	while(sp) {
		j++;
		avg_cy+=sp->cy;
		avg_oy+=sp->oy;
		avg_ty+=sp->ty;
		sp=sp->next;
	}
	celkova_controlabilita=avg_cy/j;
	celkova_observabilita=avg_oy/j;
	celkova_testabilita=avg_ty/j;

#ifdef LH_GEN
	fprintf_s(stderr,"UPD: Obv:%d vypocitej_testabilitu(int typ): Vypocitano.\n",this->id);
#endif
}
void Tobvod::vypocitej_testabilitu_SCOAP(int typ) {
	Tuzel *spom;
	int i,j;
	double min_c0,max_c0,avg_c0;
	double min_c1,max_c1,avg_c1;
	double min_to,max_to,avg_to;


	if (typ&1) {	// pocitame controlabilitu vsech spoju
		spom=seznam_zac;
		for (i=0;i<pocet_vstupu;++i) {
			Vstupy[i]->cc0=1;
			Vstupy[i]->cc1=1;
		}
		while (spom) {
			spom->hradlo->spocti_controlabilitu_SCOAP();
			spom=spom->next;
		}
		min_c0=max_c0=Vystupy[0]->cc0;
		min_c1=max_c1=Vystupy[0]->cc1;
		avg_c0=avg_c1=0;
		for (i=0;i<pocet_vystupu;++i) {
			max_c0=max(Vystupy[i]->cc0,max_c0);
			min_c0=min(Vystupy[i]->cc0,min_c0);
			max_c1=max(Vystupy[i]->cc1,max_c1);
			min_c1=min(Vystupy[i]->cc1,min_c1);
			avg_c0+=Vystupy[i]->cc0;
			avg_c1+=Vystupy[i]->cc1;
		}
	}
	j=0;
	if (typ&2) {	// pocitame observabilitu - musi bejt vypocitana predem controlabilita
		for (i=0;i<pocet_vystupu;++i) {
			Vystupy[i]->co=1;
		}
		spom=seznam_kon;
		j=pocet_vstupu;
		while (spom) {
			spom->hradlo->spocti_observabilitu_SCOAP();
			if (spom->hradlo->typ==BRANCH) j--;	// ubirame vstup do branche
			j+=spom->hradlo->pocet_vystupu;
			spom=spom->prev;
		}
		max_to=Vstupy[0]->co;
		min_to=Vstupy[0]->co;
		avg_to=0;
		for (i=0;i<pocet_vstupu;++i) {
			max_to=max(Vstupy[i]->co,max_to);
			min_to=min(Vstupy[i]->co,min_to);
			avg_to+=Vstupy[i]->co;
		}
	}
	avg_c0/=pocet_vystupu;
	avg_c1/=pocet_vystupu;
	avg_to/=pocet_vstupu;


#ifdef LH_GEN
	fprintf_s(stderr,"UPD: Obv:%d vypocitej_testabilitu(int typ): Vypocitano.\n",this->id);
#endif

}
Tobvod & Tobvod::operator= (const Tobvod & src) {
	int i;
	Thradlo **hr_pole,**hrp;
	Thradlo *hr,*hr2;
	Tspoj *sp,*sp2;
	Tspoj **spp;
	Tuzel * uz,*uz2;
	hr_pole = new Thradlo * [src.cislovani_hradel];	// pole ktere nam prevede stare id hradla na ukazatel novyho. Kvuli zapojovani
	hrp = new Thradlo * [src.celkem_hradel];		// kvuli otoceni seznamu hradel;
	spp = new Tspoj * [src.celkem_spoju];			// kvuli otoceni seznamu spoju;
	// mazeme spojovej razenej seznam
	uz=this->seznam_zac;
	seznam_zac=NULL;
	seznam_kon=NULL;
	while (uz!=NULL) {
		uz2=uz->next;
		delete uz;
		uz=uz2;
	}
	// mazeme vsechny spoje
	while (Spoje!=NULL) {
		delete Spoje;
	}
	// mazeme vsechny hradla
	while (Hradla!=NULL) {
		delete Hradla;
	}
	if (Vstupy) delete [] Vstupy;
	if (Vystupy) delete [] Vystupy;

	Vstupy = new Tspoj * [src.pocet_vstupu];
	Vystupy = new Tspoj * [src.pocet_vystupu];
	for(i=0;i<src.pocet_vstupu;Vstupy[i++]=NULL);
	for(i=0;i<src.pocet_vystupu;Vystupy[i++]=NULL);
	for(i=0;i<src.celkem_spoju;spp[i++]=NULL);
	for(i=0;i<src.celkem_hradel;hrp[i++]=NULL);
	for(i=0;i<src.cislovani_hradel;hr_pole[i++]=NULL);

	this->preber_vstupni_hodnoty((Tobvod *)&src);
	hr = src.Hradla;
	i=src.celkem_hradel;
	while (hr) {
		hrp[--i]=hr;
		hr=hr->next;
	}
	for (i=0;i<src.celkem_hradel;++i) {
		hr=hrp[i];
		hr2 = new Thradlo(this,hr->typ,2);
		*hr2=*hr;
		this->seznam_vloz_hradlo(hr2);
		hr_pole[hr->uid]=hr2;
		hr=hr->next;
	}
	sp= src.Spoje;
	i=src.celkem_spoju;
	while (sp) {
		spp[--i]=sp;
		sp=sp->next;
	}
	for (i=0;i<src.celkem_spoju;++i) {
		sp = spp[i];
		sp2 = new Tspoj(this,sp->zac_uroven,0,0);
		*sp2=*sp;
		if (sp->vstup) sp2->preved_na_vstup();
		else sp2->pripoj_na_vystup(hr_pole[sp->zac->uid]);
		if (sp->vystup) sp2->preved_na_vystup();
		else sp2->pripoj_na_vstup(hr_pole[sp->kon->uid]);
		sp=sp->next;
	}
	memcpy(typy_gen_max_k,src.typy_gen_max_k,POCET_TYPU_HRADEL*sizeof(double));
	typy_gen_pk=src.typy_gen_pk;
	memcpy(typy_gen_p,src.typy_gen_p,POCET_TYPU_HRADEL*sizeof(int));
	delete [] hr_pole;
	delete [] hrp;
	delete [] spp;
	akt_vstup=src.akt_vstup;
	akt_vystup=src.akt_vystup;
	max_uroven=src.max_uroven;
	cislovani_spoju=src.cislovani_spoju;
	cislovani_hradel=src.cislovani_hradel;
	celkem_spoju=src.celkem_spoju;			
	celkem_op_spoju=src.celkem_op_spoju;	
	celkem_hradel=src.celkem_hradel;		
	celkem_op_hradel=src.celkem_op_hradel;	
	celkem_fc_spoju=src.celkem_fc_spoju;	
	nezap_vstupy_hradel=src.nezap_vstupy_hradel;
	nezap_vystupy_hradel=src.nezap_vystupy_hradel;
	nezap_zac_spoju=src.nezap_zac_spoju;
	nezap_kon_spoju=src.nezap_kon_spoju;
	realne_urovne=src.realne_urovne;
	celkova_controlabilita=src.celkova_controlabilita;
	celkova_observabilita=src.celkova_observabilita;
	celkova_testabilita=src.celkova_testabilita;
	vfitness=src.vfitness;
	id=src.id;
	return (*this);
}
Tspoj & Tspoj::operator= ( const Tspoj & src )
{
	memcpy(nazev,src.nazev,DELKA_NAZVU_SPOJE);
	uid=src.uid;
	enabled=src.enabled;
	valid=src.valid;
	vetveni=src.vetveni;
	vstup=src.vstup;
	vystup=src.vystup;
	op=src.op;
	realna_uroven=src.realna_uroven;
	fc=src.fc;
	zac_uroven=src.zac_uroven;
	kon_uroven=src.kon_uroven;
	pres_pocet_urovni=src.pres_pocet_urovni;
	return  ( *this );
}

Thradlo & Thradlo::operator =(const Thradlo &src) {
	int i;
	memcpy(nazev,src.nazev,DELKA_NAZVU_HRADLA);
	uid=src.uid;
	enabled=src.enabled;
	valid=src.valid;
	pocet_vstupu=src.pocet_vstupu;
	pocet_vystupu=src.pocet_vystupu;
	typ=src.typ;
	uroven=src.uroven;
	realna_uroven=src.realna_uroven;
	delete [] vstupy;
	delete [] vystupy;
	vstupy = new Tspoj * [pocet_vstupu];
	vystupy = new Tspoj * [pocet_vystupu];
	for (i=0;i<pocet_vstupu;++i) {
		vstupy[i] = NULL;
	}
	for (i=0;i<pocet_vystupu;++i) {
		vystupy[i] = NULL;
	}
	return (*this);


}
int Thradlo::prirad_volnej_vstup(Tspoj *spoj) {
// na volnej vstup hradla this pripoji volnej vstup.
// udrzuje integritu dat obvodu
	int i;
	if (this->pocet_vstupu==this->zapojene_vstupy) {
		fprintf_s(stderr,"WRN: prirad_volnej_vstup(Tspoj *spoj): chceme pripojit ale zapojene_vstupy == pocet_vstupu - neprovedeno\n");
		return 1;
	}
	if (spoj==NULL) {
		fprintf_s(stderr,"WRN: prirad_volnej_vstup(Tspoj *spoj): spoj == NULL !! - neprovedeno\n");
		return 2;
	}
	this->vstupy[this->zapojene_vstupy++] = spoj;
	spoj->kon = this;
	spoj->kon_uroven = this->uroven;
	spoj->pres_pocet_urovni = spoj->kon_uroven-spoj->zac_uroven;
	if (typ!=BRANCH) {
		if (this->realna_uroven<=spoj->realna_uroven) {
			i=this->realna_uroven=spoj->realna_uroven+1;
			if (i>this->obvod->realne_urovne) this->obvod->realne_urovne=i;
		}
	}
	else {
		this->realna_uroven=spoj->realna_uroven;
		spoj->vetveni=this->pocet_vystupu-1;
	}
	obvod->nezap_vstupy_hradel--;
	obvod->nezap_kon_spoju--;
	if (typ!=BRANCH) {
		obvod->celkem_fc_spoju++;
		spoj->fc=1;
	}
	return 0;
}
int Thradlo::prirad_volnej_vystup(Tspoj *spoj) {
// udrzuje integritu dat obvodu
	int i;
	if (this->pocet_vystupu==this->zapojene_vystupy) {
		fprintf_s(stderr,"WRN: prirad_volnej_vystup(Tspoj *spoj): chceme pripojit ale zapojene_vystupy == pocet_vystupu - neprovedeno\n");
		return 1;
	}
	if (spoj==NULL) {
		fprintf_s(stderr,"WRN: prirad_volnej_vystup(Tspoj *spoj): spoj == NULL! - neprovedeno\n");
		return 2;
	}
	this->vystupy[this->zapojene_vystupy++] = spoj;
	spoj->zac = this;
	spoj->zac_uroven = this->uroven;
	spoj->pres_pocet_urovni = spoj->kon_uroven-spoj->zac_uroven;
	spoj->realna_uroven=this->realna_uroven;
	i=spoj->realna_uroven;
	if (i>this->obvod->realne_urovne) this->obvod->realne_urovne=i;
	obvod->nezap_vystupy_hradel--;
	obvod->nezap_zac_spoju--;
	if (this->typ!=BRANCH) {
		obvod->celkem_op_spoju++;
		spoj->op=1;
	}
	return 0;
}
void Tobvod::seznam_vloz_hradlo(Thradlo *hr) {
// vlozi hradlo hr do razeneho seznamu obvod->seznam_zac
	Tuzel *spom,*spom2;

	if (!seznam_zac) {
		spom = new Tuzel;
		spom->hradlo=hr;
		seznam_zac=spom;
		seznam_kon=spom;
		seznam_pocet++;
		return;
	}
	spom = seznam_zac;
	while ((spom) && (spom->hradlo->uroven<hr->uroven)) {	
		spom=spom->next;		
	}
	if (spom) {		// nejsme na konci seznamu radime novej uzel pred spom
		spom2 = new Tuzel;
		if (spom->prev) {			// neni zacatek seznamu
			spom2->prev=spom->prev;
			spom->prev->next=spom2;
		}
		else {		// zacatek seznamu 
			seznam_zac=spom2;
		}
		spom->prev=spom2;
		spom2->next=spom;
		spom2->hradlo=hr;
	}					// jsem na konci seznamu novej prvek radime nakonec
	else { seznam_kon->next=new Tuzel;
		seznam_kon->next->prev=seznam_kon;
		seznam_kon=seznam_kon->next;
		seznam_kon->hradlo=hr;
	}
	seznam_pocet++;
	return;
}
void Tobvod::seznam_vyndej_hradlo(Thradlo *hr) {
	Tuzel *spom;

	if (seznam_zac==NULL) {
		fprintf_s(stderr,"WRN: seznam_vyndej_hradlo(Thradlo *hr): seznam je prazdny - neprovedeno\n");
		return;
	}
	spom = seznam_zac;
	while ((spom) && (spom->hradlo!=hr)) spom=spom->next;
	if (spom== NULL) {
		fprintf_s(stderr,"WRN: seznam_vyndej_hradlo(Thradlo *hr): v seznamu neni hradlo hr - neprovedeno\n");
		return;
	}
	if (seznam_zac==seznam_kon) {  // jeden prvek v seznamu
		delete seznam_zac;
		seznam_zac=NULL;
		seznam_kon=NULL;
		seznam_pocet--;
		return;
	}
	if (spom==seznam_zac)  { // prvni prvek
		seznam_zac=spom->next;
		seznam_zac->prev=NULL;

	}
	else if (spom==seznam_kon) {	// posledni prvek
		seznam_kon=spom->prev;
		seznam_kon->next=NULL;
	}
	else {
		spom->prev->next=spom->next;
		spom->next->prev=spom->prev;
	}
	delete spom;
	seznam_pocet--;
	return;
}


int Tspoj::pripoj_na_vstup(Thradlo *hr) {
	if (hr!=NULL) return hr->prirad_volnej_vstup(this);
	fprintf_s(stderr,"WRN: pripoj_na_vstup(Thradlo *hr): hr==NULL! - neprovedeno\n");
	return 5;
}
int Tspoj::pripoj_na_vystup(Thradlo *hr) {
	if (hr!=NULL) return hr->prirad_volnej_vystup(this);
	fprintf_s(stderr,"WRN: pripoj_na_vystup(Thradlo *hr): hr==NULL! - neprovedeno\n");
	return 5;
}
Thradlo * Tspoj::odpoj_od_vstupu() {
// odpoji spoj od vstup hradla a vrati ho
// pokud je spoj gvystup tak ho zrusi a smaze z pole obvod->Vystupy
// udrzuje integritu dat.
	Thradlo * hr;
	int i;
	hr = kon;
	if (hr!=NULL) {
		hr->odeber_vstup(this);
		return hr;
	}
	if (this->vystup==1) {

		this->vystup=0;
		this->kon_uroven=-1;
		this->pres_pocet_urovni=-1;
		obvod->nezap_kon_spoju++;
		obvod->celkem_fc_spoju--;
		this->fc=0;
		for (i=0;i<obvod->akt_vystup;++i) {
			if (obvod->Vystupy[i]==this) break;
		}
		if (i>=obvod->akt_vystup) {
			fprintf_s(stderr,"WRN: odpoj_od_vstupu(): this je gvystup ale neni v obvod->Vystupy !! - pokracujem\n");
		}
		else {
			obvod->Vystupy[i]=obvod->Vystupy[--obvod->akt_vystup];

		}
		this->co=-1;
		return NULL;

	}
//	fprintf_s(stderr,"WRN: odpoj_od_vstupu(): this->kon==NULL! - neprovedeno\n");
	return NULL;
}
Thradlo * Tspoj::odpoj_od_vystupu() {
// podobne jako odpoj_od_vstupu odpojuje i glob vstup.
	Thradlo * hr;
	int i;
	hr = zac;
	if (hr!=NULL) {
		hr->odeber_vystup(this);
		return hr;
	}
	if (this->vstup==1) {
		this->vstup=0;
		this->zac_uroven=-1;
		this->pres_pocet_urovni=-1;
		obvod->nezap_zac_spoju++;
		this->op = 0;
		obvod->celkem_op_spoju--;
		for (i=0;i<obvod->akt_vstup;++i) {
			if (obvod->Vstupy[i]==this) break;
		}
		if (i>=obvod->akt_vstup) {
			fprintf_s(stderr,"WRN: odpoj_od_vystupu(): this je gvstup ale neni v obvod->Vstupy !! - pokracujem\n");
		}
		else {
			obvod->Vstupy[i]=obvod->Vstupy[--obvod->akt_vstup];
		}
		this->cy=0;
		return NULL;
	}
//	fprintf_s(stderr,"WRN: odpoj_od_vystupu(): this->zac==NULL! - neprovedeno\n");

	return NULL;
}
int Thradlo::odeber_vstup(Tspoj *spoj) {
	int j;
	Tspoj *sp;
	if (this->zapojene_vstupy==0) {
		fprintf_s(stderr,"WRN: odeber_vstup(Tspoj *spoj): Nejsou zadne zapojene vstupy - neprovedeno\n");
		return 1;
	}
	if (spoj==NULL) {
		fprintf_s(stderr,"WRN: odeber_vstup(Tspoj *spoj): spoj == NULL !!\n");
		return 2;
	}
	for (j=0;j<this->zapojene_vstupy;++j) {
		if (this->vstupy[j] == spoj) {
			sp = this->odeber_vstup(j);
			if (sp == spoj) return 0;
			else {
				fprintf_s(stderr,"WRN: odeber_vstup(Tspoj *spoj): odebrali jsme spoj kterej neni jako parametr.\n");
				return 3;
			}
		}
	}
	fprintf_s(stderr,"WRN: odeber_vstup(Tspoj *spoj): nenasli jsme spoj mezi zapojenymi.\n");
	return 2;
}
int Thradlo::odeber_vystup(Tspoj *spoj) {
	int j;
	Tspoj *sp;
	if (this->zapojene_vystupy==0) {
		fprintf_s(stderr,"WRN: odeber_vystup(Tspoj *spoj): Nejsou zadne zapojene vystupy - neprovedeno\n");
		return 1;
	}
	if (spoj==NULL) {
		fprintf_s(stderr,"WRN: odeber_vystup(Tspoj *spoj): spoj == NULL !!\n");
		return 2;
	}
	for (j=0;j<this->zapojene_vystupy;++j) {
		if (this->vystupy[j] == spoj) {
			sp = this->odeber_vystup(j);
			if (sp == spoj) return 0;
			else {
				fprintf_s(stderr,"WRN: odeber_vystup(Tspoj *spoj): odebrali jsme spoj kterej neni jako parametr.\n");
				return 3;
			}
		}
	}
	fprintf_s(stderr,"WRN: odeber_vystup(Tspoj *spoj): nenasli jsme spoj mezi zapojenymi.\n");
	return 2;
}
Tspoj * Thradlo::odeber_vystup() {
// odebere nahodnej vystup
	if (this->zapojene_vystupy)	return this->odeber_vystup(random(this->zapojene_vystupy));
	fprintf_s(stderr,"WRN: odeber_vystup(): neni ani 1 zapojeny vystup - neprovedeno\n");
	return NULL;
}
Tspoj * Thradlo::odeber_vstup() {
	if (this->zapojene_vstupy)	return this->odeber_vstup(random(this->zapojene_vstupy));
	fprintf_s(stderr,"WRN: odeber_vystup(): neni ani 1 zapojeny vystup - neprovedeno\n");
	return NULL;
}
Tspoj * Thradlo::odeber_vystup_mimoglob() {
// odpoji nahodnej vystup kterej neni glob vystup
	int * pole;
	int i;
	int j=0;
	Tspoj * sp;

	if (zapojene_vystupy!=pocet_vystupu) {
		fprintf_s(stderr,"WRN: odeber_vystup_mimoglob(): zapojenejch vystupu < pocet_vystupu. Melo by bejt zapojeno vsechno! \n");
	}
	pole = new int [pocet_vystupu];
	for (i=0;i<zapojene_vystupy;++i) {
		if (vystupy[i]->vystup!=1) pole[j++]=i;
	}
	if (j==0) {
		fprintf_s(stderr,"WRN: odeber_vystup_mimoglob(): neni zadnej vystup mimo napojenejch na glob - neprovedeno\n");
		delete [] pole;
		return NULL;
	}
	sp =  this->odeber_vystup(pole[random(j)]);
	delete [] pole;
	return sp;
}
Tspoj * Thradlo::odeber_vystup(int n) {
	Tspoj * spoj;
	if ((n>=this->zapojene_vystupy) || (n<0) ) return NULL;
	spoj = this->vystupy[n];
	if (spoj!=NULL) {
		spoj->zac = NULL;
		spoj->realna_uroven = -1;
		spoj->zac_uroven = -1;
		spoj->pres_pocet_urovni = -1;
		obvod->nezap_vystupy_hradel++;
		obvod->nezap_zac_spoju++;
		this->zapojene_vystupy--;
		if (this->typ!=BRANCH) {
			obvod->celkem_op_spoju--;
			spoj->op=0;
		}
		this->vystupy[n]=this->vystupy[this->zapojene_vystupy];
		this->vystupy[this->zapojene_vystupy]=NULL;
	}
	return spoj;
}
Tspoj * Thradlo::odeber_vstup(int n) {
	Tspoj * spoj;
	if ((n>=this->zapojene_vstupy) || (n<0) ) return NULL;
	spoj = this->vstupy[n];
	if (spoj) {
		spoj->vetveni=0;
		spoj->kon = NULL;
		spoj->kon_uroven = -1;
		spoj->pres_pocet_urovni = -1;
		obvod->nezap_vstupy_hradel++;
		obvod->nezap_kon_spoju++;
		if (this->typ!=BRANCH) {
			obvod->celkem_fc_spoju--;
			spoj->fc=0;
		}
		this->zapojene_vstupy--;
		this->vstupy[n]=this->vstupy[this->zapojene_vstupy];
		this->vstupy[this->zapojene_vstupy]=NULL;
	}
	else fprintf_s(stderr,"WRN: odeber_vstup(int n): odebirame vstup kterej == NULL - neprovedeno\n");
	return spoj;
}
int Thradlo::zvys_uroven_inasl(int n) {
	int i;
	int count=1;
	Tspoj * tmps;
	this->uroven += n;
	this->valid=0;
	for(i=0;i<this->pocet_vstupu;++i) {
		tmps = this->vstupy[i];
		tmps->kon_uroven += n;
		tmps->pres_pocet_urovni += n;
	}
	for(i=0;i<this->pocet_vystupu;++i) {
		tmps = this->vystupy[i];
		tmps->zac_uroven += n;
		tmps->pres_pocet_urovni -= n;
		if (tmps->kon->valid) count += tmps->kon->zvys_uroven_inasl(n);
	}
	return this->zvaliduj_inasl();
}
int Thradlo::zvaliduj_inasl() {
	int i;
	int count=1;
	Tspoj * tmps;
	this->valid=1;
	for(i=0;i<this->pocet_vystupu;++i) {
		tmps = this->vystupy[i];
		if (tmps->kon->valid == 0 ) count += tmps->kon->zvaliduj_inasl();
	}
	return count;
}


void Tobvod::vypis_vse(FILE *fil) {
#ifdef LADICI_HLASENI
	this->vypis_obvod(fil);
#ifdef LH_VYPIS_HRADEL
	this->vypis_hradla(fil);
#endif
#ifdef LH_VYPIS_SPOJU
	this->vypis_spoje(fil);
#endif
#ifdef LH_INFO_HLASENI
	this->vypis_info(fil);
#endif
#endif
}
void Thradlo::vypis(FILE *fil) {
	int i;
	fprintf_s(fil,"%9s - e:%d, v:%d, u:%3d, i:%2d, o:%2d uid:%2d ru:%2d\n",this->nazev,this->enabled,this->valid,this->uroven,this->pocet_vstupu,this->pocet_vystupu,this->uid,this->realna_uroven);
	fprintf_s(fil,"           IN:");
	for (i=0;i<this->zapojene_vstupy;++i) {
		fprintf_s(fil," (%3s_%3d_%d%d)",this->vstupy[i]->nazev,this->vstupy[i]->zac_uroven,this->vstupy[i]->enabled,this->vstupy[i]->valid);
	}
	fprintf_s(fil,"\n          OUT:");
	for (i=0;i<this->zapojene_vystupy;++i) {
		fprintf_s(fil," (%3s_%3d_%d%d)",this->vystupy[i]->nazev,this->vystupy[i]->zac_uroven,this->vystupy[i]->enabled,this->vystupy[i]->valid);
	}
	fprintf_s(fil,"\n");
}

void Thlavni::help() {																			   
fprintf_s( stderr, "syntax: \n");
fprintf_s( stderr, "   gennetwork -i n -o n -n n [-l n] [-c n] [-m g n] [-p g n] [-s x] [-tc d]\n");
fprintf_s( stderr, "             [-to d] [-tt d] [-w x d] [-g n] [-info] [-cg] [-G] [file_name]\n\n" );
fprintf_s( stderr, "   in all options n,g,x stands for integer; d stands for double.\n" );
fprintf_s( stderr, "   To specify set of GATES in all parameters: Use sum of associated numbers.\n" );
fprintf_s( stderr, "   Numbers are :\n");
fprintf_s( stderr, "          1-AND, 2-NAND, 4-OR, 8-NOR, 16-XOR, 32-XNOR, 64-NOT\n" );
fprintf_s( stderr, "      Example: All gates but XOR and XNOR: 1001111b=79. Use: 79 as g\n\n" );
fprintf_s( stderr, " Necessary parameters:\n\n");
fprintf_s( stderr, "  -i n .... Specify the number of network inputs.\n" );						   //
fprintf_s( stderr, "  -o n .... Specify the number of network outputs.\n" );
fprintf_s( stderr, "  -n n .... Specify the number of network gates.\n\n" );
fprintf_s( stderr, " Optional parameters:\n\n");
fprintf_s( stderr, "  -l n .... Specify the gate levels in network.\n\n" );
fprintf_s( stderr, "  -c n .... Specify the maximum number of branches from one line.\n");
fprintf_s( stderr, "       Use this parameter witch care, because low settings (n<3) can lead to\n"); //
fprintf_s( stderr, "       unability of generating any network and program may stay in deadlock\n");
fprintf_s( stderr, "       or unexpectadly crash. Default settings is 255.\n\n" );
fprintf_s( stderr, "  -m g n .. Specify maximum fan-in n of gates of type n. Default is 2 for all\n");
fprintf_s( stderr, "       applicable gates.\n" );
fprintf_s( stderr, "       Example: To set NOR & OR maximum fan-in to 3. Use: -m 12 3\n\n" );
fprintf_s( stderr, "  -p g n .. Specify the propability of generated gates of type n. Default is 5\n");
fprintf_s( stderr, "       for all gates. Propability for gate type x is counted like :\n");
fprintf_s( stderr, "       P(x) = n(x)/SUM(n(i)). i stands for all gates.\n");
fprintf_s( stderr, "       Probality set to 0 will lead to not generating this type of gate.\n");
fprintf_s( stderr, "       Example 1: To set Propability AND about 50%%. Use: -p 1 30.\n");
fprintf_s( stderr, "       P(AND) = 30/(30+5+5+5+5+5+5) = 0.5 = 50%% .\n");
fprintf_s( stderr, "       Example 2: To generate only AND,NAND,OR,NOR gates. Use -p 112 0\n\n" );
fprintf_s( stderr, "  -s x .... Specify the output format. You can use any combination of\n" );
fprintf_s( stderr, "       x=1-BENCH, 2-BLIF, 4-SLIF. Default is set to BENCH with BLIF.\n");
fprintf_s( stderr, "       Example: To use all formats use -s 7.\n" );
fprintf_s( stderr, "       Every format appends own extension to specified file_name.\n\n" );
fprintf_s( stderr, "  -tc d ... Specify desired circuit controlability [0-1].\n" );
fprintf_s( stderr, "  -to d ... Specify desired circuit observability [0-1].\n" );
fprintf_s( stderr, "  -tt d ... Specify desired circuit testability [0-1].\n" );                 //
fprintf_s( stderr, "       The method CAMELOT is used for computing above parameters.\n\n");
fprintf_s( stderr, "  -w x d .. Specify weight d of property x in fitness function. Properties: \n" );
fprintf_s( stderr, "       1-levels,2-# of gates,4-controlability,8-observability,16-testability\n" );
fprintf_s( stderr, "       Default weight is 1.00 and is aplicable only if associated parameter\n");
fprintf_s( stderr, "       is set. For example if you set weight of network levels, but you dont\n" );
fprintf_s( stderr, "       specify the number of levels with parameter -l n. The weight will be 0.\n\n");
fprintf_s( stderr, "  -g n .... Specify the number of generations which must survive the best\n");
fprintf_s( stderr, "       network to end searching and exit the programm. Default is 50.\n\n");
fprintf_s( stderr, "  -G n .... Specify the number of generations after which the program ends\n");
fprintf_s( stderr, "       Default is not set. The program will run until the condition set\n");
fprintf_s( stderr, "       with parameter -g is not satisfied.\n\n");
fprintf_s( stderr, "  -P n .... Specify how big is population of netwroks in genethic algorithm\n");
fprintf_s( stderr, "       Default is 80. Its the optimal proven setting.\n\n");
fprintf_s( stderr, "  -cg ..... Turns on the optimalization criterion that checks number of \n");
fprintf_s( stderr, "      all generated gate types. Number is computed from their propability.\n\n");
fprintf_s( stderr, "  -info ... Turn on printing of the parameters of generated network at the end\n");
fprintf_s( stderr, "       of the program to stderr. Also prints info in output file.\n\n");
fprintf_s( stderr, "  file_name . Specify the file name for formatted output of network. You can\n");
fprintf_s( stderr, "       use parameter -s to specify which output will be generated. If you do\n");
fprintf_s( stderr, "       not specify the file name. All output will be generated in stdout.\n\n\n");
fprintf_s( stderr, "  Take note, that some combination of parameters can lead to impossibility to\n");
fprintf_s( stderr, "  create the network. In that case the program may unexpectedly exit, crash or\n");
fprintf_s( stderr, "  stay in deadlock. In that case reconsider the parameters you used. Mostly\n");
fprintf_s( stderr, "  its caused by -c, then by -l with -n or by -i with -n with -o.\n" );
}
Tobvod::Tobvod() {
	this->maximalni_vetveni = 255;
	this->id=hlavni->cislovani_obvodu++;
	this->vfitness = -1;
	this->pocet_vstupu = -1;
	this->akt_vstup = 0;
	this->akt_vystup = 0;
	this->pocet_vystupu = -1;
	this->pocet_hradel = -1;
	this->zadane_urovne = -1;
	this->cislovani_spoju = 1;
	this->cislovani_hradel = 1;
	this->Spoje=NULL;
	this->Hradla=NULL;
	this->celkem_hradel = 0;
	this->celkem_op_hradel = 0;
	this->celkem_spoju = 0;
	this->celkem_op_spoju = 0;
	this->celkem_fc_spoju = 0;
	this->nezap_vstupy_hradel = 0;
	this->nezap_vystupy_hradel = 0;
	this->nezap_zac_spoju = 0;
	this->nezap_kon_spoju = 0;
	this->Vstupy = NULL;
	this->Vystupy = NULL;
	this->seznam_kon = NULL;
	this->seznam_zac = NULL;
	this->seznam_pocet = 0;
	this->typy_gen_max = new int [POCET_TYPU_HRADEL];
	this->typy_gen_max_k = new double [POCET_TYPU_HRADEL];
	this->vahy= new double [POCET_TYPU_VAH];
	this->typy_gen_p = new int [POCET_TYPU_HRADEL];
	for(int i=0;i<POCET_TYPU_VAH;++i) {
		vahy[i]=-1;
	}
	for(int i=0;i<POCET_TYPU_HRADEL;++i) {
		typy_gen_max[i]=DEFAULT_MAX_VSTUPY_HRADEL;
		typy_gen_p[i]=-1;
	}
	typy_gen_pk=0;
	this->stat = new Tinfo(this);
	this->celkova_controlabilita = -1;
	this->celkova_observabilita = -1;
	this->celkova_testabilita = -1;
	this->zadana_controlabilita = -1;
	this->zadana_observabilita = -1;
	this->zadana_testabilita = -1;
	this->zadane_info=-1;
	this->zadane_cg=-1;
}
Tobvod::~Tobvod() {
	Tuzel *uz,*uz2;
	
	// mazeme spojovej razenej seznam
	uz=this->seznam_zac;
	seznam_zac=NULL;
	seznam_kon=NULL;
	while (uz!=NULL) {
		uz2=uz->next;
		delete uz;
		uz=uz2;
	}
	// mazeme vsechny spoje
	while (Spoje!=NULL) {
		delete Spoje;
	}
	// mazeme vsechny hradla
	while (Hradla!=NULL) {
		delete Hradla;
	}
	delete [] typy_gen_p;
	delete [] typy_gen_max;
	delete [] typy_gen_max_k;
	delete stat;
	delete [] vahy;
	if (Vstupy!=NULL) delete [] Vstupy;
	if (Vystupy!=NULL) delete [] Vystupy;


}
void Tobvod::UlozINFO(FILE * f) {
	int i,j=0;
	fprintf_s(f,"# %4d inputs\n# %4d outputs\n# %4d interior lines\n# %3d levels of gates\n",pocet_vstupu,pocet_vystupu,celkem_fc_spoju-pocet_vystupu,realne_urovne+1);
	fprintf_s(f,"# %4.2f avg branches of lines, %2d maximum branching of one line\n",stat->spoj_avg,stat->spoj_max);
	fprintf_s(f,"# CAMELOT: %5.3f controlability, %5.3f observability, %5.3f testability\n",celkova_controlabilita,celkova_observabilita,celkova_testabilita);
	fprintf_s(f,"#  ALL: %4d, %4.2f avg fan-in, %2d maximum fan-in \n",stat->h_cnt,stat->h_avg,stat->h_max);
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		if (stat->hr_cnt[i]>0) {
			fprintf_s(f,"# %4s: %4d, %4.2f avg fan-in, %2d maximum fan-in \n",poradi_na_nazev[i],stat->hr_cnt[i],stat->hr_avg[i],stat->hr_max[i]);
		}
	}
}

void Tobvod::UlozSLIF(char * fname) {
	FILE * f;
	int i,j,k,l,m;
	char strs[5000];
	char str2[500];
	Thradlo *hr;
	Tuzel *uz;
	
	if ( fname != 0 ) fopen_s(&f,fname, "wt" );
	else f = stdout;

	
  // nejdrive pojmenujem spoje; PRi vetveni budou mit stejnej nazev;
// hradla mame serazeny budem resit jen op hradla, branche nemusime pac mame vetveny spoje stejne pojmenovany.
// vypiseme nejdriv omacku kolem.
	if (zadane_info!=-1) this->UlozINFO(f);
	fprintf_s( f, ".model main ;\n");
	fprintf_s( f, ".inputs ");
	for (i=0;i<pocet_vstupu;++i) { 
		fprintf_s( f,"%s ",Vstupy[i]->nazev);
	}
	fprintf_s( f,";\n.outputs ");
	for (i=0;i<pocet_vystupu;++i) { 
		fprintf_s( f,"%s ",Vystupy[i]->nazev);
	}
	fprintf_s( f,";\n");
	// resime hradla

	uz=seznam_zac;
	for(uz=seznam_zac;uz!=NULL;uz=uz->next) {
		hr=uz->hradlo;
		if (hr->typ==BRANCH) continue;
		fprintf_s( f, "%s = ",hr->vystupy[0]->nazev);
		switch (hr->typ) {
			case AND:
				for(i=0;i<hr->pocet_vstupu;++i) fprintf_s(f,"%s ",hr->vstupy[i]->nazev);
				break;
			case NAND:
				fprintf_s(f,"( ");
				for(i=0;i<hr->pocet_vstupu;++i) fprintf_s(f,"%s ",hr->vstupy[i]->nazev);
				fprintf_s(f,")' ");
				break;
			case OR:
				fprintf_s(f,"%s ",hr->vstupy[0]->nazev);
				for(i=1;i<hr->pocet_vstupu;++i) fprintf_s(f,"+ %s ",hr->vstupy[i]->nazev);
				break;
			case NOR:
				fprintf_s(f,"( %s ",hr->vstupy[0]->nazev);
				for(i=1;i<hr->pocet_vstupu;++i) fprintf_s(f,"+ %s ",hr->vstupy[i]->nazev);
				fprintf_s(f,")' ");
				break;
			case XOR:
			case XNOR:
				memset(strs,0,5000);
				m=1<<hr->pocet_vstupu;
				for(i=0;i<m;++i) {
					l=0;
					k=1;
					memset(str2,0,500);
					for(j=0;j<hr->pocet_vstupu;++j) {
						strcat_s(str2,500,hr->vstupy[j]->nazev);
						if(i&k) {
							l++;
						}
						else {
							strcat_s(str2,500,"'");
						}
						strcat_s(str2,500," ");
						k=k<<1;
					}
					if (((hr->typ==XOR) && (l%2==1)) || ((hr->typ==XNOR) && (l%2==0))) {
						strcat_s(strs,5000,str2);
						if (i<m-2) strcat_s(strs,5000,"+ ");
					}
				}
				fprintf_s(f,"%s",strs);
				break;
			case NOT:
				fprintf_s(f,"%s' ",hr->vstupy[0]->nazev);
				break;
		}
		fprintf_s(f,";\n");
	}
	fprintf_s(f,".endmodel main ;");
	if (f!=stdout) fclose(f);
}

void Tobvod::UlozBLIF(char * fname) {
	FILE * f;
	int i,j,k,l;
	Thradlo *hr;
	Tuzel *uz;
	char strs[32];
	
	if ( fname != 0 ) fopen_s(&f,fname, "wt" );
	else f = stdout;
	if (zadane_info!=-1) this->UlozINFO(f);

	fprintf_s( f, ".model main\n");
	fprintf_s( f, ".inputs ");
	for (i=0;i<pocet_vstupu;++i) { 
		fprintf_s( f,"%s ",Vstupy[i]->nazev);
	}
	fprintf_s( f,"\n.outputs ");
	for (i=0;i<pocet_vystupu;++i) { 
		fprintf_s( f,"%s ",Vystupy[i]->nazev);
	}
	fprintf_s( f,"\n");
	// resime hradla

	uz=seznam_zac;
	for(uz=seznam_zac;uz!=NULL;uz=uz->next) {
		hr=uz->hradlo;
		if (hr->typ==BRANCH) continue;
		fprintf_s( f,".names ");
		for(i=0;i<hr->pocet_vstupu;++i) {
			fprintf_s(f,"%s ",hr->vstupy[i]->nazev);
		}
		fprintf_s(f,"%s \n",hr->vystupy[0]->nazev);
		switch (hr->typ) {
			case AND:
				for(i=0;i<hr->pocet_vstupu;++i) fprintf_s(f,"1");
				fprintf_s(f," 1\n");
				break;
			case NAND:
				for(i=0;i<hr->pocet_vstupu;++i) {
					for (j=0;j<i;j++) fprintf_s(f,"-");
					fprintf_s(f,"0");
					for (j=i+1;j<hr->pocet_vstupu;j++) fprintf_s(f,"-");
					fprintf_s(f," 1\n");
				}
				break;
			case OR:
				for(i=0;i<hr->pocet_vstupu;++i) {
					for (j=0;j<i;j++) fprintf_s(f,"-");
					fprintf_s(f,"1");
					for (j=i+1;j<hr->pocet_vstupu;j++) fprintf_s(f,"-");
					fprintf_s(f," 1\n");
				}
				break;
			case NOR:
				for(i=0;i<hr->pocet_vstupu;++i) fprintf_s(f,"0");
				fprintf_s(f," 1\n");
				break;
			case XOR:
			case XNOR:
				memset(strs,0,32);
				for(i=0;i<1<<hr->pocet_vstupu;++i) {
					l=0;
					k=1;
					for(j=0;j<hr->pocet_vstupu;++j) {
						if(i&k) {
							strs[j]= '1';
							l++;
						}
						else {
							strs[j]= '0';
						}
						k=k<<1;
					}
					strs[j++]=' ';
					if (((hr->typ==XOR) && (l%2==1)) || ((hr->typ==XNOR) && (l%2==0))) {
						strs[j++]='1';
						strs[j]=0;
						fprintf_s(f,"%s\n",strs);
					}
				}
				break;
			case NOT:
				fprintf_s(f,"0 1\n");
				break;
		}
	}
	fprintf_s(f,".end\n");
	if (f!=stdout) fclose(f);
}
void Tobvod::UlozBENCH(char * fname) {
	FILE * f;
	int i;
	Thradlo *hr;
	Tuzel *uz;
	
	if ( fname != 0 ) fopen_s(&f,fname, "wt" );
	else f = stdout;
	
	if (zadane_info!=-1) this->UlozINFO(f);
	for (i=0;i<pocet_vstupu;++i) { 
		fprintf_s( f,"INPUT(%s)\n",Vstupy[i]->nazev);
	}
	fprintf_s( f,"\n");
	for (i=0;i<pocet_vystupu;++i) { 
		fprintf_s( f,"OUTPUT(%s)\n",Vystupy[i]->nazev);
	}
	fprintf_s( f,"\n");
	// resime hradla

	uz=seznam_zac;
	for(uz=seznam_zac;uz!=NULL;uz=uz->next) {
		hr=uz->hradlo;
		if (hr->typ==BRANCH) continue;
		fprintf_s( f, "%s = %s(%s",hr->vystupy[0]->nazev,hr->nazev,hr->vstupy[0]->nazev);
		for(i=1;i<hr->pocet_vstupu;++i) fprintf_s(f,", %s",hr->vstupy[i]->nazev);
		fprintf_s(f,")\n");
	}
	if (f!=stdout) fclose(f);
}
void Tobvod::UlozVSE(Thlavni * hl) {
	char s1[DELKA_NAZVU_SOUBORU];
	char s2[DELKA_NAZVU_SOUBORU];
	char s3[DELKA_NAZVU_SOUBORU];
		
	if ( hl->output_file != 0 ) {
		sprintf_s(s1,DELKA_NAZVU_SOUBORU,"%s.bench",hl->output_file);
		sprintf_s(s2,DELKA_NAZVU_SOUBORU,"%s.blif",hl->output_file);
		sprintf_s(s3,DELKA_NAZVU_SOUBORU,"%s.slif",hl->output_file);
		if (hl->typy_ukladani & BENCH) this->UlozBENCH(s1);
		if (hl->typy_ukladani & BLIF) this->UlozBLIF(s2);
		if (hl->typy_ukladani & SLIF) this->UlozSLIF(s3);
	}
	else {
		if (hl->typy_ukladani & BENCH) this->UlozBENCH(NULL);
		if (hl->typy_ukladani & BLIF) this->UlozBLIF(NULL);
		if (hl->typy_ukladani & SLIF) this->UlozSLIF(NULL);
	}
}
Thradlo * Tobvod::vytvor_nove_hradlo(int pnot) {			// pnot urcuje pravdepodobnost tvorby hradla NOT zbytek nahody deleno rovnomerne
	Thradlo * hr=NULL;
	double d1,d2;
	int i,j,k;
	int rnd;
	if (pnot!=0) {
		pnot=1;
		rnd=random(this->typy_gen_pk-this->typy_gen_p[POCET_TYPU_HRADEL-1]);
	}
	else rnd=random(this->typy_gen_pk);
	j=0;
	for(i=0;i<POCET_TYPU_HRADEL-pnot;i++) {	
		j+=this->typy_gen_p[i];
		if (rnd<j) break;
	}
	k = 1 << i;	// typ generovaneho hradla
	d1=0;
	d2=drandom()*typy_gen_max_k[i];
	j=1;
	if ((k&NOT)==0)		// pocitame pravdepodobnost vyskytu vicevstupovych hradel
		for (j=1;j<typy_gen_max[i];j++) {
			d1+= ((double)typy_gen_max[i]-1)/j;
			if (d2<d1) break;
		}
	hr = new Thradlo(this,k,j+1);

	return hr;
}
void Tobvod::vypis_spoje(FILE *fil) {
	Tspoj *tmps;
	tmps = this->Spoje;
	fprintf_s(fil,"SPOJE:\n");
	while (tmps) {
		tmps->vypis(fil);
		tmps = tmps->next;
	}
}
void Tobvod::vypis_hradla(FILE *fil) {
	Thradlo *tmph;
	tmph = this->Hradla;
	fprintf_s(fil,"HRADLA:\n");
	while (tmph) {
		tmph->vypis(fil);
		tmph = tmph->next;
	}
}
void Tobvod::vypis_obvod(FILE *fil) {
	fprintf_s(fil,"OBV:%4d CH:%2d COH:%2d CS:%2d RU:%2d CY:%5.3f OY:%5.3f T:%5.3f FIT:%6.3f\n",this->id,this->celkem_hradel,this->celkem_op_hradel,this->celkem_spoju,this->realne_urovne,this->celkova_controlabilita,this->celkova_observabilita,this->celkova_testabilita,vfitness);
//	fprintf_s(fil,"OBV:%2d CH:%2d COH:%2d CS:%2d RU:%2d N<H:%2d N>H:%2d N<S:%2d N>S:%2d I:%2d O:%2d\n",this->id,this->celkem_hradel,this->celkem_op_hradel,this->celkem_spoju,this->realne_urovne,this->nezap_vstupy_hradel,this->nezap_vystupy_hradel,this->nezap_zac_spoju,this->nezap_kon_spoju,this->akt_vstup,this->akt_vystup);
//	fprintf_s(fil,"        CY:%1.3f OY:%1.3f T:%1.3f FIT:%1.3f\n",this->celkova_controlabilita,this->celkova_observabilita,this->celkova_testabilita,vfitness);

}
void Tobvod::vypis_info(FILE *fil) {
	int i;
	fprintf_s(stderr," Parameters set:\n");
	if (zadane_urovne!=-1) fprintf_s(stderr, " %3d levels of gates\n",zadane_urovne);
	if (maximalni_vetveni!=255) fprintf_s(stderr, " %2d maximum branching\n",maximalni_vetveni);
	if (zadana_controlabilita!=-1) fprintf_s(stderr, " %5.3f controlability\n",zadana_controlabilita);
	if (zadana_observabilita!=-1) fprintf_s(stderr, " %5.3f observability\n",zadana_observabilita);
	if (zadana_testabilita!=-1) fprintf_s(stderr, " %5.3f testability\n",zadana_testabilita);
	if (zadane_cg!=-1) {
		for (i=0;i<POCET_TYPU_HRADEL;++i) {
			if (stat->zhr_cnt[i]>0) {
				fprintf_s(stderr," %4.1f %s,",stat->zhr_cnt[i],poradi_na_nazev[i]);
			}
		}
	}
	fprintf_s(stderr,"\n");
	fprintf_s(stderr," Generated network information: \n");
	fprintf_s(stderr," %4d inputs, %4d outputs, %4d interior lines, %3d levels of gates\n",pocet_vstupu,pocet_vystupu,celkem_fc_spoju-pocet_vystupu,realne_urovne+1);
	fprintf_s(stderr," %4.2f avg branches of lines, %2d maximum branching\n",stat->spoj_avg,stat->spoj_max);
	fprintf_s(stderr," %5.3f controlability, %5.3f observability, %5.3f testability\n",celkova_controlabilita,celkova_observabilita,celkova_testabilita);
	fprintf_s(stderr,"  ALL: %4d, %4.2f avg fan-in, %2d maximum fan-in \n",stat->h_cnt,stat->h_avg,stat->h_max);
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		if (stat->hr_cnt[i]>0) {
			fprintf_s(stderr," %4s: %4d, %4.2f avg fan-in, %2d maximum fan-in \n",poradi_na_nazev[i],stat->hr_cnt[i],stat->hr_avg[i],stat->hr_max[i]);
		}
	}
	//stat->vypis(fil);
}
Thlavni::Thlavni() {
	this->output_file=NULL;
	this->cislovani_obvodu=1;
	this->obvod1=NULL;
	this->generace=NULL;
	this->output_file=NULL;
	this->typy_ukladani= BENCH|BLIF;
	this->zadanej_pocet_generaci=POCET_GENERACI;
	this->zadanej_total_generaci=-1;
	this->zadana_velikost_populace=VELIKOST_POPULACE;
	this->vypocitany_pocet_jedincu=-1;
}
Thlavni::~Thlavni() {
	if (generace!=NULL) {
		for (int i=0;i<hlavni->zadana_velikost_populace;++i) {
			if (generace[i]!=NULL) delete generace[i];
		}
	delete [] generace;
	}
	delete obvod1;
}

Thradlo::Thradlo() {
	this->valid = 0;
	this->enabled = 0;
	this->pocet_vstupu = -1;
	this->pocet_vystupu = -1;
	this->zapojene_vstupy = 0;
	this->zapojene_vystupy = 0;
	this->typ = -1;
	this->uroven = -1;
	this->vstupy = NULL;
	this->realna_uroven = -1;
	this->vystupy = NULL;
	this->nazev = new char[DELKA_NAZVU_HRADLA];
	this->next = NULL;
	this->obvod=NULL;
	this->uid = -1;
	ctf=-1;
	otf=-1;
	

}
Thradlo::Thradlo(Tobvod *obv,int typ, int count) {
	int brk=1;
	this->obvod=obv;
	this->obvod->celkem_hradel++;
	this->uid=this->obvod->cislovani_hradel++;
	this->valid = 1;
	this->enabled = 1;
	this->uroven = -1;
	this->realna_uroven = -1;
	this->vstupy = NULL;
	this->vystupy = NULL;
	this->nazev = new char[DELKA_NAZVU_HRADLA];
	memset(nazev,0,DELKA_NAZVU_HRADLA);
	this->zapojene_vstupy = 0;
	this->zapojene_vystupy = 0;
	ctf=-1;
	otf=-1;
	this->next = obvod->Hradla;
	obvod->Hradla = this;
	this->typ = typ;

	switch (typ) {
		case BRANCH: this->pocet_vstupu = 1; //  BRANCH
			this->pocet_vystupu = count;
			break;
		case AND:
		case NAND:
		case OR:
		case NOR:
		case XOR:
		case XNOR:
			this->pocet_vstupu = count;
			this->pocet_vystupu = 1;
			obvod->celkem_op_hradel++;
			break;
		case NOT: 
			this->pocet_vstupu = 1;
			this->pocet_vystupu = 1;
			obvod->celkem_op_hradel++;
			break;
		default: brk=0;
			this->pocet_vstupu = -1;
			this->pocet_vystupu = -1;
			this->typ = -1;
			break;
	}
	if (brk) {
		this->vstupy = new Tspoj * [this->pocet_vstupu];
		this->vystupy = new Tspoj * [this->pocet_vystupu];
		memset(vstupy,0,sizeof(Tspoj*)*this->pocet_vstupu);
		memset(vystupy,0,sizeof(Tspoj*)*this->pocet_vystupu);
		obvod->nezap_vstupy_hradel += this->pocet_vstupu;
		obvod->nezap_vystupy_hradel += this->pocet_vystupu;
		this->vypln_nazev();
		this->vypocti_koeficienty();
	}
}

Thradlo::~Thradlo() {
	Thradlo *hr;
	delete [] this->nazev;
	if (this->vstupy != NULL) {
		for (;this->zapojene_vstupy>0;) delete this->odeber_vstup(0);
	}
	delete [] this->vstupy;
	if (this->vystupy != NULL) {
		for (;this->zapojene_vystupy>0;) delete this->odeber_vystup(0);
	}
	delete [] this->vystupy;
	if (this->obvod) {		// ma prirazen obvod - budem ho mazat ze spoj seznamu obvodu.
		this->obvod->nezap_vstupy_hradel-=this->pocet_vstupu;
		this->obvod->nezap_vystupy_hradel-=this->pocet_vystupu;
		this->obvod->celkem_hradel--;
		if (typ!=BRANCH) obvod->celkem_op_hradel--;
		hr=this->obvod->Hradla;
		if (hr==this) {
			obvod->Hradla=hr->next;
			hr->next=NULL;
		}
		else {
			while ((hr->next) && (hr->next!=this)) hr=hr->next;
			if (hr->next) {
				hr->next=this->next;
			}
			else {
				fprintf_s(stderr,"WRN: ~Thradlo(): v seznamu obvod->Hradla nenalezen !\n");
			}
		}
	}
}
void Thradlo::vypln_nazev(int gen_id) {
	char strs[DELKA_NAZVU_HRADLA];
	memset(nazev,0,DELKA_NAZVU_HRADLA);
	if (typ!=BRANCH) strcpy_s(this->nazev,DELKA_NAZVU_HRADLA,poradi_na_nazev[typ_na_poradi(typ)]);
	if (gen_id==0) { 
		if (typ==BRANCH) sprintf_s(strs,DELKA_NAZVU_HRADLA,"BRN%d_%d",this->pocet_vystupu,this->uid);
		else sprintf_s(strs,DELKA_NAZVU_HRADLA, "%d_%d",this->pocet_vstupu,this->uid);
		strcat_s(this->nazev,DELKA_NAZVU_HRADLA,strs);
	}
}
int Thradlo::predsad_hradlo() {
// posune hradlo presne na uroven +1 jeho vstupu. 
	Tspoj *sp;
	if (this->typ!=BRANCH) {
		fprintf_s(stderr,"WRN: predsad_hradlo(): volano na hradlo != BRANCH - neprovedeno\n");
		return 1;
	}
	sp=this->vstupy[0];
	if (sp==NULL) {
		fprintf_s(stderr,"WRN: predsad_hradlo(): hradlo nema zapojenej vstup! - neprovedeno\n");
		return 1;
	}
	obvod->seznam_vyndej_hradlo(this);
	this->uroven=sp->zac_uroven+1;
	obvod->seznam_vloz_hradlo(this);
	sp=this->odeber_vstup();
	this->prirad_volnej_vstup(sp);
	for (int i=0;i<this->zapojene_vystupy;++i) {
		sp=this->vystupy[i];
		sp->zac_uroven=this->uroven;
		sp->pres_pocet_urovni=sp->kon_uroven-sp->zac_uroven;
	}
	return 0;
}
void Tspoj::vypis(FILE *fil) {
	if (this->zac == NULL) fprintf_s(fil,"    NaN %d,xxx <--- ",this->vstup);
	else fprintf_s(fil,"%9s,%3d <--- ",this->zac->nazev,this->zac->realna_uroven);
	fprintf_s(fil,"%3d- %3s v:%1d c0:%2d c1:%2d ob:%2d -%4d",this->zac_uroven,this->nazev,this->vetveni,this->cc0,this->cc1,this->co,this->kon_uroven);
	if (this->kon == NULL) fprintf_s(fil," ---> xxx,%d NaN \n",this->vystup);
	else fprintf_s(fil," ---> %3d,%s\n",this->kon->realna_uroven,this->kon->nazev);
}
void Tspoj::Tinit() {
	this->enabled = 0;
	this->valid = 0;
	this->vetveni = 0;
	this->vstup = 0;
	this->vystup = 0;
	this->op = 0;
	this->fc = 0;
	this->zac_uroven = -1;
	this->realna_uroven = -1;
	this->kon_uroven = -1;
	this->cc0 = -1;
	this->cc1 = -1;
	this->co = -1;
	this->pres_pocet_urovni = 0;
	this->zac = NULL;
	this->kon = NULL;
	this->nazev = new char[DELKA_NAZVU_SPOJE];
	this->named = 0;
	this->next = NULL;
	this->uid = -1;
	this->obvod=NULL;
}
Thradlo * Tspoj::preved_na_vystup() {
	Thradlo *hr;
	hr=this->kon;
	if (hr) {
		fprintf_s(stderr,"WRN: preved_na_vystup(): Prevadenej spoj je zapojenej na nejakej vstup !! - odpojime \n");
		hr->odeber_vstup(this);
	}
	this->vystup=1;
	this->kon_uroven=MAX_UROVNI_SPOJU;
	this->pres_pocet_urovni=this->kon_uroven-this->zac_uroven;
	obvod->nezap_kon_spoju--;
	obvod->celkem_fc_spoju++;
	this->fc=1;
	obvod->Vystupy[obvod->akt_vystup++]=this;
	this->co=0;

	return hr;
}
Thradlo * Tspoj::preved_na_vstup() {
	Thradlo *hr;
	hr=this->zac;
	if (hr) {
		fprintf_s(stderr,"WRN: preved_na_vystup(): Prevadenej spoj je zapojenej na nejakej vstup !! - odpojime \n");
		hr->odeber_vystup(this);
	}
	this->vstup=1;
	this->zac_uroven=-1;
	this->pres_pocet_urovni=this->kon_uroven-this->zac_uroven;
	obvod->nezap_zac_spoju--;
	this->op = 1;
	obvod->celkem_op_spoju++;
	obvod->Vstupy[obvod->akt_vstup++]=this;
	this->cc0=1;
	this->cc1=1;
	return hr;
}
Tspoj::Tspoj() {
	this->Tinit();
}
Tspoj::Tspoj(Tobvod *obv,int urv,int vst,int vyst) {
	this->Tinit();
	this->obvod=obv;
	this->uid = this->obvod->cislovani_spoju++;
	this->obvod->celkem_spoju++;

	this->zac_uroven = urv;
	if (vst) {
		obvod->celkem_op_spoju++;
		this->vstup=1;
		this->op=1;
		obvod->Vstupy[obvod->akt_vstup++]=this;
		this->cc0=1;
		this->cc1=1;
	}
	else obvod->nezap_zac_spoju++;
	if (vyst) {
		this->kon_uroven = MAX_UROVNI_SPOJU;
		obvod->celkem_fc_spoju++;
		this->vystup = 1;
		this->fc=1;
		this->co=0;
		obvod->Vystupy[obvod->akt_vystup++]=this;
	}
	else obvod->nezap_kon_spoju++;
	sprintf_s(this->nazev,DELKA_NAZVU_SPOJE,"%d",this->uid);
	this->next = obvod->Spoje;
	obvod->Spoje = this;
	
}
Tspoj::~Tspoj() {
	Tspoj *sp;
	this->odpoj_od_vstupu();
	this->odpoj_od_vystupu();
	if (nazev!=NULL) delete this->nazev;
	if (this->obvod) {		// ma prirazen obvod - budem ho mazat ze spoj seznamu obvodu.
		sp=this->obvod->Spoje;
		if (sp!=NULL) {
		if (sp==this) {
			obvod->Spoje=sp->next;
			sp->next=NULL;
		}
		else {
			while ((sp->next) && (sp->next!=this)) sp=sp->next;
			if (sp->next) {
				sp->next=this->next;
			}
			else {
				fprintf_s(stderr,"WRN: ~Tspoj(): v seznamu obvod->Spoje nenalezen !\n");
			}
		}}
		obvod->celkem_spoju--;
		obvod->nezap_kon_spoju--;
		obvod->nezap_zac_spoju--;

	}
	
}
int Thradlo::zvetsi_hradlo() {
	Tspoj ** spp;
	if (this==NULL) {
		fprintf_s(stderr,"WRN: zvetsi_hradlo(): volano na NULL - neprovedeno.\n");
		return 1;
	}
	if (this->typ==BRANCH) {
		if (this->pocet_vystupu>=obvod->maximalni_vetveni) {
			fprintf_s(stderr,"WRN: zvetsi_hradlo(): BRANCH uz ma vystupu jako maximalni vetveni! - neprovedeno.\n");
			return 2;
		}
		spp = new Tspoj*[this->pocet_vystupu+1];
		memcpy(spp,vystupy,sizeof(Tspoj*)*(pocet_vystupu));
		spp[pocet_vystupu++] = NULL;
		obvod->nezap_vystupy_hradel++;
		if (vstupy[0]!=NULL) vstupy[0]->vetveni++;
		delete [] this->vystupy;
		this->vystupy = spp;
	}
	else {			// pridavame dalsi vstup
		if (this->pocet_vstupu>=obvod->typy_gen_max[typ_na_poradi(this->typ)]) {
			fprintf_s(stderr,"WRN: zvetsi_hradlo(): HRADLO uz ma maximalni mnozstvi vstupu! - neprovedeno.\n");
			return 3;
		}
		spp = new Tspoj*[this->pocet_vstupu+1];
		memcpy(spp,vstupy,sizeof(Tspoj*)*(pocet_vstupu));
		spp[pocet_vstupu++] = NULL;
		obvod->nezap_vstupy_hradel++;
		delete [] this->vstupy;
		this->vstupy = spp;
	}
	this->vypln_nazev();
	return 0;
}
Tspoj * Tspoj::Rozvetvi() {
	Thradlo *tmph,*hr;
	Tspoj *tmps2;
	if (((this->zac_uroven % 2)== 1) || (this->vstup==1)) {	// hrana je bud glob. vstup a nebo je napojena primo na vystup z obyc hradla
		if (vetveni>0) {				// hrana uz je vetvena -> pridame do branche dalsi vetev
			tmph = this->kon;
			tmph->zvetsi_hradlo();
			tmps2 = new Tspoj(this->obvod,tmph->uroven);	// novej spoj a pripojime ho
			tmps2->pripoj_na_vystup(tmph);
			return tmps2;
		}
		else {	// hrana se nevetvi, rozdelime ji na 2 a pridame branch a dalsi hranu (muze to bejt i vystup)
			hr=this->odpoj_od_vstupu();
			tmph= new Thradlo(this->obvod,0,2);
			tmph->uroven = this->zac_uroven+1;
			obvod->seznam_vloz_hradlo(tmph);
			this->pripoj_na_vstup(tmph);
			tmps2 = new Tspoj(this->obvod,tmph->uroven);
			tmps2->pripoj_na_vystup(tmph);
			if (hr!=NULL) tmps2->pripoj_na_vstup(hr);
			else tmps2->preved_na_vystup();
		
			tmps2 = new Tspoj(this->obvod,this->zac_uroven+1);
			tmps2->pripoj_na_vystup(tmph);
			return tmps2;		
		}
	}
	else {	//chceme rozvetvovat hranu ktera uz vede z branche -> budem rozsirovat branch
			tmph = this->zac;
			tmph->zvetsi_hradlo();
			tmps2 = new Tspoj(this->obvod,tmph->uroven);
			tmph->prirad_volnej_vystup(tmps2);
			return tmps2;
	}
	return NULL;
}
void Tobvod::init() {
	int i,j,k,l;
	double d1;
	// predgenerujem pole typu hradel podle zadani;
	j=1;
	typy_gen_pk=0;
	for (i=0;i<POCET_TYPU_VAH;++i) {
		if (this->vahy[i]==-1) this->vahy[i]=1;
	}
	for (i=0;i<POCET_TYPU_HRADEL;++i) {
		if (this->typy_gen_p[i]==-1) this->typy_gen_p[i]=DEFAULT_P_HRADEL;
		typy_gen_pk+=typy_gen_p[i];
		if (j&NOT) this->typy_gen_max[i]=1;
		j=j<<1;
		d1=0;
		l=typy_gen_max[i]-1;
		for (k=1;k<typy_gen_max[i];k++) {
			d1+=(double)l/k;
		}
		typy_gen_max_k[i]=d1;
	}
	max_uroven=1;
	Vstupy = new Tspoj * [pocet_vstupu];
	Vystupy = new Tspoj * [pocet_vystupu];
	memset(Vstupy,0,sizeof(Thradlo*)*pocet_vstupu);
	memset(Vystupy,0,sizeof(Thradlo*)*pocet_vystupu);
}
int Tobvod::vygeneruj_obvod() {
	// spoje maj uroven predchazejiciho hradla..
	// vstupy -1, branche maj urovne sudy 0,2,4...
	// obyc hradla lichy - tim pozname u urovne spoje jestli se vetvi nebo ne.
	// vytvorime vstupy a vystupy a pojmenujeme je
	int i,pom3,rnd,volnejch,j,pokusy;
	int hrmin,hrmax;
	double d1;
	int r1,r2,r3,rr;
	int gpokusy;
	Tspoj *sp,*sp2;
	Thradlo *hr,*hr2;
	Tspoj **spoj_pole,**spzaloha;
	int sp_cnt,spzal;
	int hr_cnt,hrzal;
	Thradlo **hr_pole,**hrzaloha;
	hr=NULL;
	i=0;
	this->init();

	spoj_pole = new Tspoj*[this->pocet_hradel+this->pocet_vstupu];  // pole spoju pred vetvenim. pro nahodnej vyber vetveni.
	spzaloha =  new Tspoj*[this->pocet_hradel+this->pocet_vstupu];  // pole spoju pred vetvenim. pro nahodnej vyber vetveni. zaloha
	sp_cnt=0;
	hr_pole = new Thradlo*[this->pocet_hradel];		// pole volnejch vystupu na hradlech
	hrzaloha = new Thradlo*[this->pocet_hradel];		// pole volnejch vystupu na hradlech zaloha
	hr_cnt=0;
	spzal=sp_cnt;
	hrzal=hr_cnt;
	i=0;
	gpokusy=POCET_POKUSU;
	while ((this->akt_vstup<this->pocet_vstupu)&&(gpokusy>0)) {
		// delame zalohu sp a hr poli kvuli pripadnemu smazani hradla
		hr = this->vytvor_nove_hradlo();
		hr->uroven=max_uroven;
		max_uroven += 2;
		seznam_vloz_hradlo(hr);
		rnd=random(100);
		if (rnd<90) { // prvni spoj s 90% pravdepodobnosti pripojime primo na gvstup
			sp = new Tspoj(this,-1,1);
			sp->pripoj_na_vstup(hr);
			if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;

		}
		for (;(hr!=NULL)&&(hr->zapojene_vstupy<hr->pocet_vstupu);) {	// dokud nemame zapojene vsechny vstupy nebo jsme nesmazali hradlo
			rnd=random(100);
			j=1+2+4;			// co vsechno ma kontrolovat, 1=gvstup,2=primej vystup z hradla,4=deleni libovolne hrany
			if (rnd<40) {			// novej gvstup
				if (this->akt_vstup<this->pocet_vstupu) {
					sp = new Tspoj(this,-1,1);
					sp->pripoj_na_vstup(hr);
					if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
					j=8;		// pripojili jsme
				}
				else {		// nemuzeme zapojit uz novej gvstup proto tu moznost odeberem 1 a nebudeme dal zkoumat
					j-=1;		
					rnd=random(60)+40;	// zaroven prepocitame nahodu pac se 30% a 30% delame moznost 2 a 4, ale 
				}
			}
			if ((rnd<70) && (j&2)) {	// zapojujeme vystup z hradla
				if (hr_cnt>0) {
					r1=random(hr_cnt);
					hr2=hr_pole[r1];
					hr_pole[r1]=hr_pole[--hr_cnt];
					sp = new Tspoj(this,hr2->uroven);
					sp->pripoj_na_vystup(hr2);
					sp->pripoj_na_vstup(hr);
					if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
					j=8;	//zapojeno
				}
				else j-=2;		// nemuzeme zapojit primo hradlo tazke tu moznost odeberem a nebudeme dal zkouset
			}
			if (j&4) {		// zkousime rozdelit libovolny spoj
				if (sp_cnt>0) {
					pokusy=POCET_POKUSU;
					do {
						r1=random(sp_cnt);
						sp2=spoj_pole[r1];
					} while ((hr->test_pripojeni_vstupu(sp2)!=0) && (--pokusy>0));
					if (pokusy>0) {
						sp=sp2->Rozvetvi();
						if (sp2->vetveni+1>=maximalni_vetveni) {
							spoj_pole[r1]=spoj_pole[--sp_cnt];
						}
						sp->pripoj_na_vstup(hr);
						j=8;
					}
					else j-=4;
				}
				else j-=4;
			}
			if ((j&1) && (this->akt_vstup<this->pocet_vstupu)) {	// zkousime jeste gvstupy
				sp = new Tspoj(this,-1,1);
				sp->pripoj_na_vstup(hr);
				if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
				j=8;
			}
			if ((j&2) && (hr_cnt>0)) {		// jeste jsme nezkouseli zapjit na vystupy hradla a mame nejaky volny
				r1=random(hr_cnt);
				hr2=hr_pole[r1];
				hr_pole[r1]=hr_pole[--hr_cnt];
				sp = new Tspoj(this,hr2->uroven);
				sp->pripoj_na_vystup(hr2);
				sp->pripoj_na_vstup(hr);
				if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
				j=8;
			}
			// pokud j&8 == 0 tak se nam nepodarilo nic zapojit budem zmensovat hradlo nebo ho maznem.
			if ((j&8)==0) {	// nepodarilo se nam ho zapojit
				if (hr->zmensi_hradlo()!=0) {
					seznam_vyndej_hradlo(hr);
					delete hr;
					hr=NULL;
					max_uroven -= 2;
					gpokusy--;
				}
			}
			else {		// podarilo se nam vstup hradla nekam zapojit

			}
		}	// konec for cyklu na zapojeni vsech vstupu
		if (hr!=NULL) { //podarilo se zapojit vsechno udelame zalohu 
			hr_pole[hr_cnt++]=hr;
			memcpy(hrzaloha,hr_pole,sizeof(Thradlo*)*hr_cnt);
			memcpy(spzaloha,spoj_pole,sizeof(Tspoj*)*sp_cnt);
			spzal=sp_cnt;
			hrzal=hr_cnt;

		}
		else { // hradlo jsme smazali obnovime hr_pole a spoj_pole
			memcpy(hr_pole,hrzaloha,sizeof(Thradlo*)*hrzal);
			memcpy(spoj_pole,spzaloha,sizeof(Tspoj*)*spzal);
			sp_cnt=spzal;
			hr_cnt=hrzal;
		}
	}
	// pokud gpokusy>0 tak mame vsechno ok jinak budem rusti celej obvod..
	if (gpokusy==0) {
		fprintf_s(stderr,"WRN: vygeneruj_obvod(): 20x jsme smazali nemohli umistit nove hradlo - obvod nevytvoren\n");
		delete [] spoj_pole;
		delete [] hr_pole;
		delete [] spzaloha;
		delete [] hrzaloha;
		return 1;
	}

//	this->vypis_obvod();
//	this->vypis_hradla();
//	this->vypis_spoje();

	// doplnujeme hradla do poctu zadanych
	rr=random(20)+70;	//	pomer v procentech vystupy zapojeny primo na hradla/vystupy z vetvy (resp. op/fc) budem se toulat kolem neho
						//  ta se bude linearne zvedat od 0 v prubehu pridavani hradel;
	// mame pripraveny spoje v poli spoj_pole i volne vystupy hradel v hr_pole
	
	d1=(double)rr*(double)this->pocet_vystupu/100;
	volnejch=(int) (d1+0.5);		// kolik ma bejt zapojenejch g.vystupu na vystupy hradel.
	r1 = this->pocet_hradel-this->celkem_op_hradel;			// kolik hradel musime doplnit.
	while (r1>0) {
		r3 = hr_cnt-volnejch;			// rozdil kolik ma bejt vs kolik mame. kladne cislo potrebujeme vic vystupu z hr zaporne potrebujeme jich min.
		r2=2-r1+r3;
		hrmin = max(0,r2);		// kolik musime minimalne zapojit vstupu z hr_pole;
		hrmax = r1+r3;			// kolik muzem maximalne zapojit vstupu z hr_pole;
		hrmax = min(hrmax,hr_cnt);
		if (hrmax < hrmin) {
			fprintf_s(stderr,"WRN: vygeneruj_obvod(): nemame jak zapojit nove hradlo - obvod nevytvoren\n");
			delete [] spzaloha;
			delete [] hrzaloha;
			delete [] spoj_pole;
			delete [] hr_pole;
			return 1;
		}
		if (hrmin>1) hr = vytvor_nove_hradlo(1);	// musime zapojit vic jak jeden vstup z hr_pole - nebudem generovat NOT.
		else hr = vytvor_nove_hradlo();
		hr->uroven=max_uroven;
		max_uroven += 2;
		seznam_vloz_hradlo(hr);
		while (hr->zapojene_vstupy<hr->pocet_vstupu) {
			pom3=hr->pocet_vstupu-hr->zapojene_vstupy;
			if (pom3<=hrmin)	// musime zbytek dopojit z hr_pole
				for(;hrmin>0;) {
					rnd=random(hr_cnt);
					hr2=hr_pole[rnd];
					hr_pole[rnd]=hr_pole[--hr_cnt];
					sp = new Tspoj(this,hr2->uroven);
					sp->pripoj_na_vystup(hr2);
					sp->pripoj_na_vstup(hr);
					hrmin--;
					hrmax--;
					if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
				}
			else {			// budem zapojovat nahodne bud hr_pole nebo vetvit;
				rnd=random(hr->pocet_vstupu);
				if (((rnd<1) || (sp_cnt==0)) && (hrmax>0)) {		// budem zapojovat z hr
					rnd=random(hr_cnt);
					hr2=hr_pole[rnd];
					hr_pole[rnd]=hr_pole[--hr_cnt];
					sp = new Tspoj(this,hr2->uroven);
					sp->pripoj_na_vystup(hr2);
					sp->pripoj_na_vstup(hr);
					hrmin--;
					hrmax--;
					if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
				}
				else if (sp_cnt>0) {				// budem vetvit a kontrolovat zapojeni
					memcpy(spzaloha,spoj_pole,sizeof(Tspoj*)*sp_cnt);
					spzal=sp_cnt;
					while (spzal>0) {
						rnd=random(spzal);
						sp2=spzaloha[rnd];
						if (hr->test_pripojeni_vstupu(sp2)!=0) {
							spzaloha[rnd]=spzaloha[--spzal];
						}
						else { break;
						}
					}
					if (spzal>0) {
						sp=sp2->Rozvetvi();
						if (sp2->vetveni+1>=maximalni_vetveni) {
							spzaloha[rnd]=spzaloha[--spzal];
							for(i=0;i<sp_cnt;i++) {
								if (spoj_pole[i]==sp2) break;
							}
							if (i==sp_cnt) {
								fprintf_s(stderr,"WRN: vygeneruj_obvod(): Vetvenej spoj neni v spoj_poli !!!\n");
							}
							spoj_pole[i]=spoj_pole[--sp_cnt];
						}
						sp->pripoj_na_vstup(hr);
					}
					else if (hrmax>0) {
						rnd=random(hr_cnt);
						hr2=hr_pole[rnd];
						hr_pole[rnd]=hr_pole[--hr_cnt];
						sp = new Tspoj(this,hr2->uroven);
						sp->pripoj_na_vystup(hr2);
						sp->pripoj_na_vstup(hr);
						hrmin--;
						hrmax--;
						if (maximalni_vetveni>1) spoj_pole[sp_cnt++]=sp;
					}
					else {
						fprintf_s(stderr,"WRN: vygeneruj_obvod(): 20x jsme nemohli zapojit nove hradlo - obvod nevytvoren\n");
						delete [] spzaloha;
						delete [] hrzaloha;
						delete [] spoj_pole;
						delete [] hr_pole;
						return 1;
					}
				}
				else {
					fprintf_s(stderr,"WRN: vygeneruj_obvod(): nemame jak zapojit volne vstupy na novem hradle - obvod nevytvoren\n");
					delete [] spzaloha;
					delete [] hrzaloha;
					delete [] spoj_pole;
					delete [] hr_pole;
					return 1;
				}
			}
		}
		hr_pole[hr_cnt++]=hr;
		r1 = this->pocet_hradel-this->celkem_op_hradel;			// kolik hradel musime doplnit.
//		this->vypis_vse(stdout);
//		this->vypis_spoje();
	}

//	 mame vygenerovany vsechny hradla
	for(i=0;i<this->pocet_vystupu;++i) {
		if (hr_cnt) {								// zapojujeme volne vystupy z hradel na glob. vystupy
			rnd = random(hr_cnt);
			hr=hr_pole[rnd];
			hr_pole[rnd]=hr_pole[--hr_cnt];   // presouvame z konce pole volnej vystup na jinou pozici

			sp = new Tspoj(this,hr->uroven,0,1);
			hr->prirad_volnej_vystup(sp);
		}
		else if (sp_cnt) {									// musime zapojit ostatni g.vystupy vetvenim libovolneho spoje mimo vstupu
			rnd=random(sp_cnt);
			while (spoj_pole[rnd]->vstup==1) rnd=random(sp_cnt);
			sp = spoj_pole[rnd];
			sp2=sp->Rozvetvi();
			if (sp->vetveni+1>=maximalni_vetveni) {
				spoj_pole[rnd]=spoj_pole[--sp_cnt];
			}

			sp2->preved_na_vystup();
		}
		else {
			fprintf_s(stderr,"WRN: vygeneruj_obvod(): pri zapojovani vystupu jsme nenasli dost spoju na deleni - obvod nevytvoren\n");
			delete [] spzaloha;
			delete [] hrzaloha;
			delete [] spoj_pole;
			delete [] hr_pole;
			return 1;
		}

//		this->vypis_vse(stdout);
	}
	delete [] spzaloha;
	delete [] hrzaloha;
	delete [] hr_pole;
	delete [] spoj_pole;
//***************  HOTOVO zapojen minimalni obvod - neresena pocet urovni.. *****************

	this->vypocitej_testabilitu_CAMELOT();	
	this->spocti_fitness();
	this->spocti_urovne();
//	this->vypis_obvod();
	return 0;
}
int main( int argc, char * argv[] )
{
	int i,j,k,pocet_generaci,pom,pom2,ret;
	int celkem_generaci=0;
	double d1;
	int cas;
	struct timeb t2, t1;

	ftime(&t2);
	cas=((int) t2.time)*1000+t2.millitm;
	srand(t2.millitm);

	fprintf_s( stderr, "Network Generator 0.9, (c) May 2008\n\n" );
	hlavni = new Thlavni();
	hlavni->obvod1 = new Tobvod();
	i=1;
	while ( i != argc )	{
		if ( argv[i] [0] == '-' ) {
			if ( strcmp(argv[i], "-i") == 0) {
				hlavni->obvod1->pocet_vstupu = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-o") == 0) {
				hlavni->obvod1->pocet_vystupu = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-n") == 0) {
				hlavni->obvod1->pocet_hradel = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-l") == 0) {
				hlavni->obvod1->zadane_urovne = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-s") == 0) {
				hlavni->typy_ukladani = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-g") == 0) {
				hlavni->zadanej_pocet_generaci = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-G") == 0) {
				hlavni->zadanej_total_generaci = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-P") == 0) {
				hlavni->zadana_velikost_populace = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-cg") == 0) {
				hlavni->obvod1->zadane_cg = 1;
			}
			else if ( strcmp(argv[i], "-c") == 0) {
				hlavni->obvod1->maximalni_vetveni = atoi( argv[++i] );
			}
			else if ( strcmp(argv[i], "-m") == 0) {
				pom = atoi( argv[++i] );
				pom2 = atoi( argv[++i] );
				j=1;
				for (k=0;k<POCET_TYPU_HRADEL;++k) {
					if (j&pom) hlavni->obvod1->typy_gen_max[k]=pom2;
					j=j<<1;
				}
			}
			else if ( strcmp(argv[i], "-p") == 0) {
				pom = atoi( argv[++i] );
				pom2 = atoi( argv[++i] );
				j=1;
				for (k=0;k<POCET_TYPU_HRADEL;++k) {
					if (j&pom) hlavni->obvod1->typy_gen_p[k]=pom2;
					j=j<<1;
				}
			}
			else if ( strcmp(argv[i], "-tc") == 0) {
				hlavni->obvod1->zadana_controlabilita = atof( argv[++i] );
			}
			else if ( strcmp(argv[i], "-to") == 0) {
				hlavni->obvod1->zadana_observabilita = atof( argv[++i] );
			}
			else if ( strcmp(argv[i], "-tt") == 0) {
				hlavni->obvod1->zadana_testabilita = atof( argv[++i] );
			}
			else if ( strcmp(argv[i], "-info") == 0) {
				hlavni->obvod1->zadane_info = 1;
			}
			else if ( strcmp(argv[i], "-w") == 0) {
				pom = atoi( argv[++i] );
				d1 = atoi( argv[++i] );
				j=1;
				for (k=0;k<POCET_TYPU_VAH;++k) {
					if (j&pom) hlavni->obvod1->vahy[k]=d1;
					j=j<<1;
				}
			}
			else {
				fprintf_s( stderr, "Unknown parameter %s\n", argv[i] );
				exit(1);
			}
		}
		else  hlavni->output_file = argv[i];
		i++;
	}
	
	if ( hlavni->obvod1->pocet_vstupu == -1 || hlavni->obvod1->pocet_vystupu == -1 || hlavni->obvod1->pocet_hradel == -1 ) { 
		hlavni->help();
		exit(1);
	}

	// mame nacteny hodnoty, budem generovat prvni populaci nahodne
	
	hlavni->init();
	if ((hlavni->obvod1->zadana_controlabilita==-1) && (hlavni->obvod1->zadana_observabilita==-1) \
		&& (hlavni->obvod1->zadana_testabilita==-1) && (hlavni->obvod1->zadane_cg==-1) \
		&& (hlavni->obvod1->zadane_urovne==-1)) { // nemame optimalizacni kriterium.
			fprintf_s(stderr," No optimalization criterion was given - generating random network.\n");
			ret=0;
			do {
				if (ret!=0) delete hlavni->generace[0];
				hlavni->generace[0]= new Tobvod;
				hlavni->generace[0]->preber_vstupni_hodnoty(hlavni->obvod1);
				ret = hlavni->generace[0]->vygeneruj_obvod();
			} while (ret!=0);
	}
	else {
		fprintf_s(stderr," Generating initial population with random networks...\n");
		hlavni->zaloz_generaci();
		pocet_generaci=0;
		fprintf_s(stderr," Starting optimalization\n Program ends when is no change through %d last generations",hlavni->zadanej_pocet_generaci);
		if (hlavni->zadanej_total_generaci!=-1) fprintf_s(stderr, "\n or there is %d generations total.",hlavni->zadanej_total_generaci);
		fprintf_s(stderr,"\n Netid:%4d fitness:%5.2f - *",hlavni->generace[0]->id,hlavni->generace[0]->vfitness);
		while ((pocet_generaci<hlavni->zadanej_pocet_generaci) && (++celkem_generaci!=hlavni->zadanej_total_generaci)) {
			pom= hlavni->nova_generace();
			if (pom!=0) {
				fprintf_s(stderr,"\n Netid:%4d fitness:%5.2f - *",hlavni->generace[0]->id,hlavni->generace[0]->vfitness);
				pocet_generaci=0;
			}
			else {
				fprintf_s(stderr,"*");
				pocet_generaci++;
			}
//			fprintf_s(stdout,"%0.5f\n",hlavni->generace[0]->vfitness);
//			hlavni->generace[0]->vypis_obvod();
		}
		fprintf_s(stderr,"\n");
	}
	
	ftime(&t1);
	cas=((int) t1.time)*1000+t1.millitm-((int)t2.time)*1000-t2.millitm;

	if (hlavni->generace[0]->zadane_info!=-1) {
		hlavni->generace[0]->vypis_info();
	}

#ifdef VYPIS_CASU
printf("Program bezel: %.3f sekund.",(float)cas/1000);
#endif

	hlavni->generace[0]->pojmenuj_vse();
	hlavni->generace[0]->UlozVSE(hlavni);
	delete hlavni;
	return 0;
}