package svm;

import java.util.Map.Entry;

import base.DenseVector;
import base.SparseVector;
import base.Structure;

public class Constraint<X extends Structure, Y extends Structure>
{
	public DenseVector phi;
	public double loss;

	public int lastUsed;

	public Constraint(int sizePhi)
	{
		phi = new DenseVector(sizePhi);
		loss = 0;
		lastUsed = 0;
	}

	public void addConstraint(X x, Y y, Y ybar, double factor, double loss, SVMStruct<X, Y> svm,
			SVMStructInstance<X, Y> instance)
	{
		SparseVector phi1 = instance.phi(x, y);
		SparseVector phi2 = instance.phi(x, ybar);
		for(Entry<String, Double> e : phi1.entrySet())
		{
			if(svm.wMap.containsKey(e.getKey()))
			{
				int i = svm.wMap.get(e.getKey());
				double c = factor * e.getValue();

				//as little synchronization as possible :D I guess I cannot block on just one array element
				synchronized (phi)
				{
					phi.x[i] += c;
				}

			}
		}
		for(Entry<String, Double> e : phi2.entrySet())
		{
			if(svm.wMap.containsKey(e.getKey()))
			{
				int i = svm.wMap.get(e.getKey());
				double c = factor * e.getValue();
				synchronized (phi)
				{
					phi.x[i] -= c;
				}
			}
		}
		synchronized (this)
		{
			this.loss += loss;
		}

	}

	public void finalizeConstraint(int n)
	{
		loss /= n;
		for(int i = 0; i < phi.length(); i++)
		{
			phi.x[i] /= n;
		}
	}
}
