/* 
 * Thomas Pantzer: t_polynom.cc, v0.4.7  8.6.99 16:32 
 * 
 * 
 * Copyright 1999 by Thomas Pantzer
 * 
 * Permission to use, copy, modify, and distribute this software for noncommercial 
 * use and without fee is hereby granted, provided that the above copyright notice 
 * appear in all copies and that both that copyright notice and this permission 
 * notice appear in supporting documentation, and that the name of the Author not be 
 * used in advertising or publicity pertaining to distribution of the software 
 * without specific, written prior permission. The Author makes no representations about
 * the suitability of this software for any purpose.  It is provided "as is" 
 * without expressed or implied warranty. 
 * 
 * 
 * pantec@isys2.informatik.uni-leipzig.de   (Thomas Pantzer) 
 * 
 */


#include "copyright.h"


#include "t_polynom.h"


#define POLY_DEBUG

#ifdef POLY_DEBUG

#include <stdio.h>
#include <string.h>

#endif

void t_parameter::Init(double l, int u)
{
	update = u;
	logstep = l;
	counter = 0;
}

double t_parameter::Get(void)
{
	return Value;
}

double t_parameter::Real(void)
{
	return Shadow;
}

void t_parameter::Set(double d)
{
	Value = d;
	Shadow = d;
	logV = d;
}

void t_parameter::Assign(void)
{
	if ((counter % update) == 0)	
	   Value = Shadow;

	counter++;
}

void t_parameter::AddS(double d)
{
	Shadow += d;
	logV += ((Shadow - logV)/logstep);
}

void t_parameter::AddV(double d)
{
	saved = Value;
	Value += d;
}


void t_parameter::Reset(void)
{
	Value = saved;
}



double leftside(int j)
{
	if (((j > 2) && (j < 7)) || ((j > 10) && (j < 15)))
	   return 1.0;

	return -1.0;
}


int mirror8(int i)
{
	switch(i % 8)
	  {
	   case 0: return 5;
	   case 1: return 4;
	   case 2: return 3;
	   case 3: return 2;
	   case 4: return 1;
	   case 5: return 0;
	   case 6: return 7;
	   case 7: return 6;
	  }
	
	return 0;
}

int mirror(int i)
{
	if (i<8)
	   return mirror8(i);

	return mirror8(i-8) + 8;
}

int next(int i)
{
	if (i<8)
	   return ((i+1) % 8);

	return ((((i-8)+1) % 8) + 8);
}



void t_Polynom::BatchParm(int s)
{
	if (s < 1)
	   return;		

	for (int i=0; i<nparams; i++)
	   for (int j=0; j<nargs; j++)
	     {
	      int k = Index(i,j);
	      _C[k].update = s;	
	     } 
}

double t_Polynom::Result(double arg[])
{
	double S = 0.0;

//	fprintf(stderr,"%d,%d,%d",C[0].used,true,false);

	for (int i=0; i<nparams; i++)
	  {
	   for (int j=0; j<nargs; j++)
	     {
	      int k = Index(i,j);

#ifdef POLYDEBUG
	      char st[256];
	      sprintf(st,"%g",S);		
	      if ((strcmp(st,"NaN") == 0) || (strcmp(st,"Inf") == 0))
	         {
	          fprintf(stderr,"index(%d,%d) is %s, arg[%d]=%g, C[%d].Val=%g\n",
					i,j,st,j,arg[j],k,C[k].Value);
		 }
#endif

	      double d;	
		      	
	      if (_C[k].used == true)
		 switch (i)
        	   {
		    case 0:	
//	              if ((C[k].Value  != 0.0) && (arg[j] != 0.0))
//			 fprintf(stderr,"%g\t",C[k].Value - arg[j]); 

//		      S += (leftside(j) * arg[j] * (arg[j] - C[k].Value));		
		      S += (/*leftside(j) * */ arg[j] * _C[k].Get());	
		      break;

		    case 1: 
		      d = (arg[j] * arg[next(j)]);
		      d *= (arg[j] - arg[next(j)]);	
		      S += (leftside(j) * _C[k].Get() * d);      
		      break;

		    case 2: 
		      d = (arg[j] * arg[mirror(j)]);
		      d *= (arg[j] - arg[mirror(j)]);	
		      S += (leftside(j) * _C[k].Get() * d);    
		      break;
/*
		    case 3: 
		      S += (leftside(j) * C[k].Value * arg[j]);	    
		      break;

		    case 4: 
		      S += (leftside(j) * C[k].Value * (arg[j] - arg[next(j)]));      
		      break;

		    case 5: 
		      S += (leftside(j) * C[k].Value * (arg[j] * arg[mirror(j)]));    
		      break;
*/
		    default:
		      fprintf(stderr,"wrong case label (%d)\n",i);	
	              break;  
		   }


//	      fprintf(stderr,"%g, %g, %d\t",arg[j],C[k].Value,C[k].used); 		     
	     }	
//	   fprintf(stderr,"\n"); 		     
	  }


//	if (S != 0.0)	
//           fprintf(stderr,"S:%g\n",S);
		
	return S;
}



int t_Polynom::Index(int i, int j)
{
	return ((i*nargs) + j);
}


void t_Polynom::Done(void)
{
	if (LP != NULL)
	   {
	    LP->Done();
	    delete LP;
	   } 
	
	if (HP != NULL)
	   {
	    HP->Done();
	    delete HP;  
           }

	delete [] _C;
	delete [] dc;
	nparams = 0;
	nargs = 0; 
}

void t_Polynom::GetMem(void)
{
	int size = nargs*nparams;
	_C = new t_parameter [size];
	dc = new double [size];

	for (int i=0; i<size; i++)
          _C[i].Init(25,100);
}

void t_Polynom::Init(int np, int na)
{
	nargs = na;
	nparams = np;

	GetMem();

	for (int j=0; j<nargs; j++)
          {
	   for (int i=0; i<nparams; i++)
	     {
	      int k = Index(i,j);	
	      _C[k].Set(0.0);
	      _C[k].used = false;
	     }
	  }           

	LP = new t_Polynom;
	HP = new t_Polynom;

	LP->Init(this);
	HP->Init(this);
}


void t_Polynom::Init(t_Polynom *P)
{
	if (P == NULL)
	   return;

	nargs = P->nargs;
	nparams = P->nparams;

	GetMem();
	Reset(P);	
}

void t_Polynom::Reset(t_Polynom *P)
{
	if (P == NULL)
	   return;

	for (int j=0; j<nargs; j++)
          {
	   for (int i=0; i<nparams; i++)
	     {
	      int k = Index(i,j);	
	      _C[k].Set(P->_C[k].Real());
	      _C[k].used = P->_C[k].used;
	     }
	  }           
}


double t_Polynom::AddVal(int i, int j, double d)
{
	return AddVal(Index(i,j),d);
}

void t_Polynom::SetVal(int i, int j, double d)
{
	SetVal(Index(i,j),d);
}

void t_Polynom::UseVal(int i, int j, char d)
{
	UseVal(Index(i,j),d);
}

double t_Polynom::AddVal(int idx, double d)
{
	
	double old = _C[idx].Get();
	_C[idx].AddV(d);
	return old;
}

void t_Polynom::SetVal(int idx, double d)
{
	_C[idx].Set(d);
}

void t_Polynom::UseVal(int idx, char d)
{
	_C[idx].used = d;
}

void t_Polynom::Grad(double x_arg[], double h, double epsilon, double damp, char wake)
{
	LP->Reset(this);
	HP->Reset(this);

	for (int j=0; j<nargs; j++)
	  for (int i=0; i<nparams; i++)
	    {	
	     int k = Index(i,j); 

	     LP->_C[k].AddV(-h);
	     HP->_C[k].AddV(+h);

	     dc[k] = ((HP->Result(x_arg) - LP->Result(x_arg))/(2.0*h));

	     LP->_C[k].Reset();
	     HP->_C[k].Reset();
            }	

	for (int i=0; i<nparams; i++)
	  for (int j=0; j<nargs; j++)
	    {
	     if ((j < 8) && wake)
		continue;  // IRED nur an der Wand lernen

	     int k = Index(i,j);

	     if (_C[k].used == true) 
		{
		 double D = _C[k].Real() * damp * x_arg[j % 8];
		 _C[k].AddS( - (dc[k] * epsilon)); 
		 _C[k].AddS( - D );

		 _C[k].Assign();
	        } 
	    }
}



double t_Polynom::C_Val(int i, int j)
{
	return _C[Index(i,j)].Get();
}

char t_Polynom::C_used(int i, int j)
{
	return _C[Index(i,j)].used;
}

double t_Polynom::C_logV(int i, int j)
{
	return _C[Index(i,j)].logV;
}













/**/
/**/
/**/
/**/
/**/
/**/
/**/
/**/
/*****  End Of File  ****************************/
