/*=========================================================================*/
/* Failas FI.C */
/* Realizuoja "PORTFELIO" uzdavinio skaiciavimus */
/* Skaiciavimo metodas, naudingumo funkcija ir banku rodikliai */
/* nurodomi duomenu faile DUOMENYS.DAT */
/*=========================================================================*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "fi.H"

#define PRAD_SUMA 10000
#define BSK 10
#define IT 10000

FILE *fff;
int number_of_variables=8;

static double maxSuma=-PRAD_SUMA*10.0;
static k=-1;

/*=========================================================================*/
/* Perskaitomi pradiniai duomenys is failo DUOMENYS.DAT	*/
/*=========================================================================*/
int SkaitytiDuomenis(double a[BSK],double p[BSK],int m,const double *x,
										 double xx[BSK],double visoX,double *visoXX,
										 int *Metodas,double *p00,double *p05,double *p10,
										 double *p15, double *p20,int *Uz)	{
	char bName[80];
	char *fVardas1="duomenys.dat";		/* suderinamumui su UNIX */
	char *fVardas2="DUOMENYS.DAT";
	char *fVardas3="Duomenys.dat";
	char *fVardas4="Duomenys.Dat";
	FILE *g;
	int i;

	g=fopen(fVardas1,"rt");
	if(g==NULL)	g=fopen(fVardas2,"rt");
	if(g==NULL)	g=fopen(fVardas3,"rt");
	if(g==NULL)	g=fopen(fVardas4,"rt");
	if(g==NULL) return 0;

	fscanf(g,"%s\n",bName);		/* nuskaitomas pirmos eilutes komentaras */
	fscanf(g,"%d\n",Metodas);
	fscanf(g,"%s\n",bName);		/* nuskaitomas trecios eilutes komentaras */
	fscanf(g,"%s%lf\n",bName,p00);
	fscanf(g,"%s%lf\n",bName,p05);
	fscanf(g,"%s%lf\n",bName,p10);
	fscanf(g,"%s%lf\n",bName,p15);
	fscanf(g,"%s%lf\n",bName,p20);
	fscanf(g,"%s\n",bName);		/* nuskaitomas devintos eilutes komentaras */
	fscanf(g,"%d\n",Uz);
	fscanf(g,"%s\n",bName);	  /* nuskaitomas vienuoliktos eilutes komentaras */

	for(i=1;i<m+1;i++)	{
		xx[i]=(x[i-1]/visoX)*PRAD_SUMA;
		*visoXX=*visoXX+xx[i];
		fscanf(g,"%s%lf%lf\n",bName,&p[i],&a[i]);
	}
	fclose(g);
	return 1;
}

/*=========================================================================*/
/* Randama u(z) reiksme	*/
/*=========================================================================*/
double RastiUz(double z,int Uz,double visoXX,double p00,double p05,
							 double p10,double p15, double p20)	{
	double retVal=0.0;

	if(Uz==1)		/* jei U(z)=z */
		return z;

	if(z==0.0)
		retVal=p00;
	if(z==visoXX*0.5)
		retVal=p05*p10;
	if(z==visoXX)
		retVal=p10;
	if(z==visoXX*1.5)
		retVal=p15*(1-p10)+p10;
	if(z==visoXX*2.0)
		retVal=p20;
	if(z<visoXX*0.5)
		retVal=(z*p05/(visoXX*0.5))*p10;
	if((z>visoXX*0.5)&&(z<visoXX))
		retVal=(z*p10/visoXX)*p10;
	if((z>visoXX)&&(z<visoXX*1.5))
		retVal=((z*p15/(visoXX*1.5))*(1-p10))+p10;
	if(z>visoXX*1.5)
		retVal=((z*p20/(visoXX*2.0))*(1-p10))+p10;
	return retVal;
}

/*=========================================================================*/
/* Randama U(p)	*/
/*=========================================================================*/
double RastiUp(int Metodas, double xx[10],double a[10],double p[10],
							 int i,int m,double visoXX,double p00,double p05,
							 double p10,double p15, double p20,int Uz)	{
	double P,z,d,randVal;
	int j,k;

	z=0;
	P=1;
	if(Metodas==1)	{			/* MonteKarlo metodas */
		for(i=1;i<=m;i++)	{
			randVal=(double)rand()/RAND_MAX;
			if (randVal<=p[i])
				z+=(1+a[i])*xx[i];
			else
				z+=0.8*xx[i];
		 }
	}
	if(Metodas==2)	{			/* Tikslus metodas */
		for(j=1;j<=m;j++)	{
			if(i&(1<<(j-1)))
				z+=(a[j]+1)*xx[j];
			else
				z+=0.8*xx[j];		/* jei bankas bankrutuoja galioja draudimas */

			if(i&(1<<(j-1)))
				P*=p[j];  		/* bankas islieka */
			else
				P*=1-p[j];		/* bankas bankrutuoja */
		}
	}

	k++;
	if(z>maxSuma)	{
		maxSuma=z;
		fprintf(fff,"k = %5d  max = %5.2lf\t",k,maxSuma);
		fprintf(fff,"x = [%4.2lf, %4.2lf, %4.2lf, %4.2lf, %4.2lf]\n",xx[1],xx[2],xx[3],xx[4],xx[5]);
	}
	d=RastiUz(z,Uz,visoXX,p00,p05,p10,p15,p20);
	return d*P;
}

/*=========================================================================*/
/* Pagrindine skaiciavimus realizuojanti funkcija */
/*=========================================================================*/
double fi(const double *xx,int dim)	{
	double a[BSK];		/*	banko palukanos	(10 - banku skaicius)*/
	double p[BSK];		/*	banko nesubankrutavimo tikimybe	*/
	double U,Up,visoXX,visoX,xxx[BSK],retVal;
	int	i,m,Metodas,Uz;
	double p00,p05,p10,p15,p20;
	int n;

	n=dim;
	if(k==-1)	{
		fff=fopen("wwwwwwww.dat","wt");
		fclose(fff);
		k=0;
	}
	fff=fopen("wwwwwwww.dat","at+");

	for(i=0;i<BSK;i++) {
		a[i]=0.0;
		p[i]=0.0;
		xxx[i]=0.0;
	}
	Metodas=1;	/* pagal nutylejima - MonteKarlo metodas */
	m=n;
	visoX=0;
	visoXX=0;
	for(i=0;i<n;i++)
		visoX+=xx[i];
	if(visoX==0)
		return 0; 	/* neimanomas pradiniu duomenu normalizavimas */

	SkaitytiDuomenis(a,p,m,xx,xxx,visoX,&visoXX,&Metodas,&p00,&p05,&p10,&p15,&p20,&Uz);

	if(Metodas==1)	{			/* Monte Karlo metodas */
		U=0;
		for(i=1;i<=IT;i++)
			U+=RastiUp(Metodas,xxx,a,p,i,m,visoXX,p00,p05,p10,p15,p20,Uz);
		U=(double)U/IT;
		retVal=U;
	}

	if(Metodas==2)	{			/* Tikslus metodas */
		Up=0;
		for(i=0;i<pow(2,number_of_variables);i++)	/* perrenkami visi 7 bankai */
			Up+=RastiUp(Metodas,xxx,a,p,i,m,visoXX,p00,p05,p10,p15,p20,Uz);
		retVal=Up;
	}
	fclose(fff);
	return (-1)*retVal;
}

/*=========================================================================*/
/*	Definition of constraints	*/
/*	ng > 0 - calculates all constaints	*/
/*	ng < 0  - calculates only constraint with number (-ng)	*/
/*=========================================================================*/
void constr(const double *x,int n,double *g,int ng)	{
	double x1=x[0];
	double x2=x[1];
	double x3=x1*x1;
	double x4=x2*x2;

	n=n;
	if(ng>0) {
		g[0]=25.-x3-x4;
		g[1]=10.*x1-x3+10.*x2-x4-34.;
		g[2]=x1;
		g[3]=x2;
	}
	else {
		ng=-ng;
		switch(ng) {
			case 1:		g[0]=25.-x3-x4;									break;
			case 2:		g[1]=10.*x1-x3+10.*x2-x4-34.;		break;
			case 3:		g[2]=x1;												break;
			case 4:		g[3]=x2;												break;
		}
	}
}

