package version11_2_2_1.agnosticMemory;

import version11_2_2_1.Interface.InteractionList;

public class SignatureComponent {

	public float[] signature;					// weights of the signature component
	
	public boolean learned;
	
	public float maxPattern1;					// maximum weight (used to normalize values in displayer)
	
	private float prediction=0;
	
	public SignatureComponent(){
		signature=new float[InteractionList.length+1];
		learned=false;
		for (int i=0;i<InteractionList.length+1;i++) signature[i]=0;
		maxPattern1=0;
	}
	
	/**
	 * predict the result of an interaction in a given context
	 * @param img : environmental context
	 * @return the certitude of success (1->absolute certitude of success, -1-> absolute certitude of failure 
	 */
	public float prediction(int[] img, boolean write){
		float result=0;
		for (int i=0;i<InteractionList.length;i++){
			result+=signature[i]*(float)img[i];
		}
		//bias
		result+=signature[InteractionList.length];
		
		// activation function
		result= (float) ( 1 / (1+exp(-result)))*2-1;
		
		if (write) prediction=result;
		
		return result;
	}
	
	/**
	 * integrate the result of enaction cycle
	 * @param img : environmental context E_{t-1} 
	 * @param output result of enaction (success->1, failure->-1)
	 */
	public void learn(int[] img, float predict){

		//prediction(img, true);
		
		float delta=predict-prediction;

		if (Math.abs(delta)>=0.01){
			maxPattern1=0;
			
			for (int i=0;i<InteractionList.length;i++){
				
				signature[i]+= 0.05 * delta * (float)img[i];
				
				if (Math.abs(signature[i])>maxPattern1) maxPattern1=Math.abs(signature[i]);
			}
			// bias
			signature[InteractionList.length]+= 0.05 * delta * 1;
			
			//if (Math.abs(signature[length-1])>maxPattern1) maxPattern1=Math.abs(signature[length-1]);
			
			// simplification : if bias is sufficient, reduce weight of the same sign
			if (signature[InteractionList.length]>=0.2){
				for (int i=0;i<InteractionList.length;i++){
					if (signature[i]>0){
						if (signature[i]>0.01) signature[i]-=0.01;
						else signature[i]=0;
					}
				}
			}
			if (signature[InteractionList.length]<=-0.2){
				for (int i=0;i<InteractionList.length;i++){
					if (signature[i]<0){
						if (signature[i]<-0.01) signature[i]+=0.01;
						else signature[i]=0;
					}
				}
			}/**/
		}
		learned=true;
	}
	
	public float getPrediction(){
		return prediction;
	}
	
	// fast exp function approximation
	public static double exp(double val) {
	    final long tmp = (long) (1512775 * val + (1072693248 - 60801));
	    return Double.longBitsToDouble(tmp << 32);
	}
	
}
