def __project_observations(self):

        for evidence_var in self.query.evidence_variables:
            appearing_factors = utils.appearing_factors(evidence_var.observed_variable, self.relevant_factors)

            while(appearing_factors):
                observation.project_observation(appearing_factors, evidence_var, self.relevant_factors, self.eliminated_factors, self.initial_factors, self.query.evidence_variables)
def __min_fill(variables, relevant_factors):
    """
    Min. Fill: Devuelve el nodo que al eliminarlo introducira el menor numero de conexiones nuevas.

    @type  variables: set
    @param variables: Conjunto de variables ocultas que quedan en la red bayesiana.

    @type  relevant_factors: list
    @param relevant_factors: Lista de factores relevantes de la red bayesiana.

    @rtype:  Node
    @return: Nodo a eliminar segun la heuristica.
    """
    minimum = float("inf")
    elimination_variable = None

    for var in variables:
        new_edges_count = 0
        appearing_factors = utils.appearing_factors(var, relevant_factors)

        for f1 in appearing_factors:
            f1_position = appearing_factors.index(f1)
            appearing_factors_size = len(appearing_factors)

            for f2 in range(f1_position + 1, appearing_factors_size):
                f2_factors = appearing_factors[f2].factors
                intersection_size = len(set(f1.factors) & set(f2_factors))
                new_edges_count += (len(f1.factors) - intersection_size) * (len(f2_factors) - intersection_size)

        if new_edges_count < minimum:
            minimum = new_edges_count
            elimination_variable = var

    return elimination_variable
def __min_factor(variables, relevant_factors):
    """
    Min. Factor: Devuelve el nodo de menor peso, siendo el peso de cada nodo el producto del cardinal del dominio de sus vecinos.

    @type  variables: set
    @param variables: Conjunto de variables ocultas que quedan en la red bayesiana.

    @type  relevant_factors: list
    @param relevant_factors: Lista de factores relevantes de la red bayesiana.

    @rtype:  Node
    @return: Nodo a eliminar segun la heuristica.
    """
    minimum = float('inf')
    elimination_variable = None

    for var in variables:
        neighbors = set(list(itertools.chain.from_iterable([f.factors for f in utils.appearing_factors(var, relevant_factors)])))
        neighbors.remove(var)
        weight = 1

        for n in neighbors:
            weight *= len(n.domain)

        if weight < minimum:
            minimum = weight
            elimination_variable = var

    return elimination_variable
def __min_degree(variables, relevant_factors):
    """
    Min. Degree: Devuelve el nodo con el menor numero de conexiones.

    @type  variables: set
    @param variables: Conjunto de variables ocultas que quedan en la red bayesiana.

    @type  relevant_factors: list
    @param relevant_factors: Lista de factores relevantes de la red bayesiana.

    @rtype:  Node
    @return: Nodo a eliminar segun la heuristica.
    """
    new_factor_length = lambda var: len(set(itertools.chain.from_iterable([f.factors for f in utils.appearing_factors(var, relevant_factors)])))
    return min(variables, key=new_factor_length)