package ec.gp.semantic.initialization;

import java.util.*;

import ec.*;
import ec.gp.*;
import ec.gp.koza.*;
import ec.gp.semantic.*;
import ec.gp.semantic.func.*;
import ec.util.*;

/**
 * Probabilistic Geometric Semantic Initializer. It iteratively generates new individuals and accepts them depending on
 * the given probability distribution w.r.t. the distance to target.
 * 
 * @author Tomasz Pawlak
 * 
 */
public abstract class PGSI extends GPNodeBuilder {

	private final static Parameter DEFAULT_BASE = new Parameter("PGSI");
	private final static String BASE_BUILDER = "baseBuilder";

	private GPNodeBuilder baseBuilder = new HalfBuilder();


	@Override
	public Parameter defaultBase() {
		return DEFAULT_BASE;
	}

	@Override
	public void setup(EvolutionState state, Parameter base) {
		super.setup(state, base);

		ParameterDatabase db = state.parameters;

		this.baseBuilder = (GPNodeBuilder) db.getInstanceForParameter(base.push(BASE_BUILDER), defaultBase().push(BASE_BUILDER), GPNodeBuilder.class);
		this.baseBuilder.setup(state, base.push(BASE_BUILDER));
	}

	@Override
	public GPNode newRootedTree(EvolutionState state, GPType type, int thread, GPNodeParent parent, GPFunctionSet set, int argposition,
			int requestedSize) {

		SimpleNodeBase<?> candidate = null;
		SimpleNodeBase<?> accepted = null;
		ISemantics candidateSemantics = null;

		ISemanticProblem<?> problem = (ISemanticProblem<?>) state.evaluator.p_problem;
		ISemantics target = problem.getTargetSemantics();



		do {

			candidate = (SimpleNodeBase<?>) this.baseBuilder.newRootedTree(state, type, thread, parent, set, argposition, requestedSize);
			candidateSemantics = candidate.getSemantics();


		} while (this.probability(target.distanceTo(candidateSemantics)) > state.random[thread].nextDouble());


		assert candidate != null;

		return candidate;
	}

	protected abstract double probability(double distance);
}
