def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" #It's similar to joinFactor, first get unconditionedSet and conditionedSet #then construct a newFactor to return unconditionedSet = factor.unconditionedVariables() unconditionedSet.remove(eliminationVariable) conditionedSet = factor.conditionedVariables() newFactor = Factor(unconditionedSet, conditionedSet, factor.variableDomainsDict()) #all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. for assignment in factor.getAllPossibleAssignmentDicts(): newFactor.setProbability( assignment, newFactor.getProbability(assignment) + factor.getProbability(assignment)) return newFactor
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" unconditionedVariables = [x for x in factor.unconditionedVariables() if x != eliminationVariable] conditionedVariables = [x for x in factor.conditionedVariables()] domainDict = dict() for k,v in factor.variableDomainsDict().items(): if not (k == eliminationVariable): domainDict[k] = v retFactor = Factor(unconditionedVariables, conditionedVariables, domainDict) for assignmentDict in factor.getAllPossibleAssignmentDicts(): prob = factor.getProbability(assignmentDict) preProb = retFactor.getProbability(assignmentDict) retFactor.setProbability(assignmentDict, preProb+prob) retFactor = retFactor.specializeVariableDomains(factor.variableDomainsDict()) return retFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" unconditioned = evidenceDict.keys() new_domain = bayesNet.getReducedVariableDomains(evidenceDict) new_factor = Factor(queryVariables, unconditioned, new_domain) for x in range(0, numSamples): assignment_dict = {} sample = [1] linearized_var = bayesNet.linearizeVariables() for var in linearized_var: var_cpt = bayesNet.getCPT(var) if var in unconditioned: assignment_dict[var] = evidenceDict[var] sample.append(var_cpt.getProbability(assignment_dict)) else: assignment_dict[var] = sampleFromFactor(var_cpt, assignment_dict)[var] prob = reduce(lambda x, y: x*y, sample) new_factor.setProbability(assignment_dict, new_factor.getProbability(assignment_dict) + prob) new_factor = normalize(new_factor) return new_factor
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) uc = [] c = [] for v in factor.unconditionedVariables(): if v != eliminationVariable: uc += [v] for v in factor.conditionedVariables(): if v != eliminationVariable: c += [v] newFactor = Factor(set(uc), set(c), factor.variableDomainsDict()) for a in factor.getAllPossibleAssignmentDicts(): val = factor.getProbability(a) + newFactor.getProbability(a) newFactor.setProbability(a, val) return newFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) new_f = Factor(queryVariables, evidenceDict.keys(), bayesNet.getReducedVariableDomains(evidenceDict)) for i in range(numSamples): w = 1 cur = dict() for variable in bayesNet.linearizeVariables(): if variable in evidenceDict: cur[variable] = evidenceDict.get(variable) w *= bayesNet.getCPT(variable).getProbability(cur) else: cur.update(sampleFromFactor(bayesNet.getCPT(variable), cur)) new_f.setProbability(cur, w + new_f.getProbability(cur)) new_f = normalize(new_f) return new_f
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) else: new_condition = factor.conditionedVariables() new_uncondition = factor.unconditionedVariables() - set([eliminationVariable]) eliminate_factor = Factor(new_uncondition, new_condition, factor.variableDomainsDict()) # print(factor.unconditionedVariables(),eliminationVariable) # print(eliminate_factor) for assignment in factor.getAllPossibleAssignmentDicts(): small_assign = get_new_assig(assignment, eliminate_factor) if eliminate_factor.getProbability(small_assign) != 0: eliminate_factor.setProbability(small_assign, factor.getProbability(assignment)+eliminate_factor.getProbability(small_assign)) else: eliminate_factor.setProbability(small_assign, factor.getProbability(assignment)) return eliminate_factor
def eliminate(factor, eliminationVariable): """ Question 2: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" tmp = factor.unconditionedVariables() unconditionedVars = [x for x in tmp if x != eliminationVariable] newFactor = Factor(unconditionedVars, factor.conditionedVariables(), factor.variableDomainsDict()) for assignmentDict in factor.getAllPossibleAssignmentDicts(): prob = newFactor.getProbability(assignmentDict) + factor.getProbability(assignmentDict) newFactor.setProbability(assignmentDict, prob) return newFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 7: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" linearVars = bayesNet.linearizeVariables() # queryVariables are unconditional variables newFactor = Factor(queryVariables, evidenceDict.keys(), bayesNet.getReducedVariableDomains(evidenceDict)) #keys of evidenceDict are the conditional vars for sample in range(numSamples): weight = 1 assignment = dict() for variable in linearVars: if variable in evidenceDict: assignment[variable] = evidenceDict.get(variable) weight *= bayesNet.getCPT(variable).getProbability(assignment) else: assignment.update(sampleFromFactor(bayesNet.getCPT(variable), assignment)) newFactor.setProbability(assignment, weight + newFactor.getProbability(assignment)) return normalize(newFactor)
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) currentFactorsList = bayesNet.getAllCPTsWithEvidence(evidenceDict) newFactor = Factor(queryVariables, evidenceDict.keys(), currentFactorsList[0].variableDomainsDict()) for _ in range(numSamples): w = 1.0 conditionedAssignments = {} for variable in bayesNet.linearizeVariables(): if variable in evidenceDict: conditionedAssignments[variable] = evidenceDict[variable] w = w * bayesNet.getCPT(variable).getProbability(conditionedAssignments) else: conditionedAssignments.update(sampleFromFactor(bayesNet.getCPT(variable), conditionedAssignments)) newFactor.setProbability(conditionedAssignments, w + newFactor.getProbability(conditionedAssignments)) return normalize(newFactor)
def eliminate(factor, eliminationVariable): """ Question 2: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" unconditioned = set() conditioned = set() for eachVar in factor.unconditionedVariables(): if (not eachVar == eliminationVariable): unconditioned.add(eachVar) for eachVar in factor.conditionedVariables(): conditioned.add(eachVar) # build a new blank factor variableDomainsDict = factor.variableDomainsDict() newFactor = Factor(unconditioned, conditioned, variableDomainsDict) # eliminate the given variables assignmentDicts = factor.getAllPossibleAssignmentDicts() for assignment in assignmentDicts: oldProb = factor.getProbability(assignment) newProb = newFactor.getProbability(assignment) newFactor.setProbability(assignment, oldProb + newProb) return newFactor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [set(factor.unconditionedVariables()) for factor in factors] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ("unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" # print "@@@@@@factorlength ", len(factors) # print "@@@@@@@factor 1", factors[0] # print "@@@@@@@factor 2", factors[1] # print "@@@@@@@variableDomainsDict ", Factor.variableDomainsDict(factors[0]), len(Factor.variableDomainsDict(factors[0])) # print "@@@@@@@conditionedVariables ", Factor.conditionedVariables(factors[0]) # print "@@@@@@@getAllPossibleAssignmentDicts ", Factor.getAllPossibleAssignmentDicts(factors[0]) # print "@@@@@@@oneassignmentdict ", Factor.getAllPossibleAssignmentDicts(factors[0])[0], Factor.getAllPossibleAssignmentDicts(factors[0])[0].get("W") # print "@@@@@@@getProbability ", Factor.getProbability(factors[0], Factor.getAllPossibleAssignmentDicts(factors[0])[0]) #Factor.getAllPossibleAssignmentDicts(factors[0]) joinedConditionedVariables = set() joinedUnconditionedVariables = set() for factor in factors: for condVar in factor.conditionedVariables(): joinedConditionedVariables.add(condVar) for uncondVar in factor.unconditionedVariables(): joinedUnconditionedVariables.add(uncondVar) # joinedConditionedVariables.union(factor.conditionedVariables()) # joinedUnconditionedVariables.union(factor.unconditionedVariables()) # print "@@@@@factor.unconditionedVariables() ", factor.unconditionedVariables(), type(factor.unconditionedVariables()) # print "@@@@joinedConditionedVariables ", joinedConditionedVariables # print "@@@@joinedUnconditionedVariables ", joinedUnconditionedVariables # print "@@@@factor.conditionedVariables() ", factor.conditionedVariables() # print "@@@@factor.unconditionedVariables() ", factor.unconditionedVariables() # joinedUnconditionedVariables.remove(eliminationVariable) # reducedFactor = Factor(reducedUnconditionedVariables, factor.conditionedVariables(), factor.variableDomainsDict()) for uncondVar in joinedUnconditionedVariables: if uncondVar in joinedConditionedVariables: joinedConditionedVariables.remove(uncondVar) # print "@@@@@@joinedUnconditionedVariables ", joinedUnconditionedVariables # print "@@@@@@joinedConditionedVariables ", joinedConditionedVariables joinedFactor = Factor(joinedUnconditionedVariables, joinedConditionedVariables, factors[0].variableDomainsDict()) # print "@@@@joinedFactor.unconditionedVariables() ", joinedFactor.unconditionedVariables() # print "@@@@joinedFactor.conditionedVariables() ", joinedFactor.conditionedVariables() for joinedAssignment in joinedFactor.getAllPossibleAssignmentDicts(): # print "@@@@joinedAssignment ", joinedAssignment factorAssignmentProduct = 1 for factor in factors: # print "probability of ", joinedAssignment, Factor.getProbability(factor, joinedAssignment) factorAssignmentProduct = factorAssignmentProduct * Factor.getProbability(factor, joinedAssignment) Factor.setProbability(joinedFactor, joinedAssignment, factorAssignmentProduct) return joinedFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" # create a conditionedAssignments dict conditionedAssignments = {} #print conditionedAssignments #print bayesNet.getCPT() variableList = bayesNet.linearizeVariables() evidenceList = set(evidenceDict.keys()) # build a new blank factor variableDomainsDict = bayesNet.getReducedVariableDomains(evidenceDict) #print variableDomainsDict #print queryVariables #print evidenceList newFactor = Factor(queryVariables, evidenceList, variableDomainsDict) #print newFactor # sample numSamples times for idx in range(numSamples): weight = 1.0 assignmentDict = {} for variable in variableList: factor = bayesNet.getCPT(variable) #print factor if (variable in evidenceList): assignmentDict[variable] = evidenceDict[variable] prob = factor.getProbability(assignmentDict) #print 'Prob: ', prob weight *= prob else: newDict = sampleFromFactor(factor, assignmentDict) # update assignment dict for key in newDict: assignmentDict[key] = newDict[key] #print 'new assignment dict: ', assignmentDict # what to do with final Assignment and weight? finalAssignment = assignmentDict #print finalAssignment currentProb = newFactor.getProbability(finalAssignment) newProb = currentProb + weight newFactor.setProbability(finalAssignment, newProb) # normalize queryConditionedOnEvidence = normalize(newFactor) return queryConditionedOnEvidence
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" # create return factor newFactor = Factor(queryVariables, evidenceDict, bayesNet.variableDomainsDict()) reducedVariableDomains = bayesNet.getReducedVariableDomains(evidenceDict) newFactor = newFactor.specializeVariableDomains(reducedVariableDomains) for i in range(numSamples): weight = 1.0 allAssignments = {} allAssignments.update(evidenceDict) for var in bayesNet.linearizeVariables(): tmpCPT = bayesNet.getCPT(var) if var in evidenceDict: # accumulate weight weight *= tmpCPT.getProbability(allAssignments) else: newAssignment = sampleFromFactor(tmpCPT, allAssignments) allAssignments.update(newAssignment) # accumulate sample p = newFactor.getProbability(allAssignments) newFactor.setProbability(allAssignments, p + weight) return normalize(newFactor) util.raiseNotDefined()
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 7: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" 'sample = None' setsOfUnconditioned = set(queryVariables) setsOfConditioned = set(evidenceDict.keys()) vDD = bayesNet.getReducedVariableDomains(evidenceDict) newFactor = Factor(setsOfUnconditioned, setsOfConditioned, vDD) sample = evidenceDict.copy() for i in range(numSamples): weight = 1.0 for v in bayesNet.linearizeVariables(): f = bayesNet.getCPT(v) 'f = f.specializeVariableDomains(vDD)' if v in evidenceDict.keys(): weight = weight * f.getProbability(sample) '''s = 0.0 sumAD = 0.0 for ad in f.getAllPossibleAssignmentDicts(): if all(item in ad.items() for item in evidenceDict.items()): s += f.getProbability(ad) sumAD += f.getProbability(ad) weight = weight * s / sumAD''' else: sample.update(sampleFromFactor(f, sample)) newFactor.setProbability(sample, newFactor.getProbability(sample) + weight) sample = evidenceDict.copy() 'sample = None' 'pdb.set_trace()' '''totalSum = sum(sampleDict.values()) all(item in aD.items() for item in ad.items()):''' newFactor = normalize(newFactor) return newFactor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) # "*** YOUR CODE HERE ***" # util.raiseNotDefined() unconVars = set() conVars = set() varMap = {} def factorizer(factVariables, condi, varsy): for p in factVariables: if condi(p): varsy.add(p) varMap[p] = factor.variableDomainsDict()[p] [ factorizer(f.unconditionedVariables(), lambda x: (x not in unconVars), unconVars) for f in factors ] [ factorizer(f.conditionedVariables(), lambda x: (x not in unconVars and x not in conVars), conVars) for f in factors ] nuFact = Factor(list(unconVars), list(conVars), varMap) [ nuFact.setProbability(n, float(1.0)) for n in nuFact.getAllPossibleAssignmentDicts() ] for factor in factors: for n in nuFact.getAllPossibleAssignmentDicts(): for fm in factor.getAllPossibleAssignmentDicts(): works = True for var in fm.keys(): works = fm[var] == n[var] if not works: break if works: nuFact.setProbability( n, factor.getProbability(fm) * nuFact.getProbability(n)) break return nuFact
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" # Unconditioned Set of unconditionedVariables ucs = {""} ucs.clear() # Conditioned Set of conditionedVariables cs = {""} cs.clear() # set default probability defaultProbability = 1.0 # removes the unconditionedVariable from the conditioned variable set def removeUCVfromCS(uv, cs): if uv in cs: cs.remove(uv) # the union of unconditioned set with unconditioned variable def uniteUCS(ucs, uv): return ucs.union(uv) # the union of condiitoned set with conditioned variable def uniteCS(cs, cv): return cs.union(cv) # product of the corresponding rows of the input factors def product(jfp, fp): return jfp * fp for factor in factors: ucs = uniteUCS(ucs, factor.unconditionedVariables()) cs = uniteCS(cs, factor.conditionedVariables()) for unconditionedVariable in ucs: removeUCVfromCS(unconditionedVariable, cs) joinedFactor = Factor(ucs, cs, factor.variableDomainsDict()) assignments = joinedFactor.getAllPossibleAssignmentDicts() for assign in assignments: joinedFactor.setProbability(assign, defaultProbability) for factor in factors: prob = product(joinedFactor.getProbability(assign), factor.getProbability(assign)) joinedFactor.setProbability(assign, prob) return joinedFactor util.raiseNotDefined()
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] setsOfConditioned = [ set(factor.conditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" # Combine conditioned/unconditioned variables(sets) conditionedList = set() unconditionedList = set() for s in setsOfConditioned: conditionedList = conditionedList | s for s in setsOfUnconditioned: unconditionedList = unconditionedList | s conditionedList = conditionedList - unconditionedList conditionedList = list(conditionedList) unconditionedList = list(unconditionedList) # Define new factor with variables. newFactor = Factor(unconditionedList, conditionedList, factor.variableDomainsDict()) # Initialize probability to 1.0 for assignment in newFactor.getAllPossibleAssignmentDicts(): newFactor.setProbability(assignment, 1.0) # Calculate joined probability(multiplying accumulatively). for factor in factors: for assignment in newFactor.getAllPossibleAssignmentDicts(): items = list(assignment.items()) for oldAssignment in factor.getAllPossibleAssignmentDicts(): oldItems = list(oldAssignment.items()) find = False for o in oldItems: if o not in items: find = True break if find: continue newFactor.setProbability( assignment, newFactor.getProbability(assignment) * factor.getProbability(oldAssignment)) # Return. return newFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" # print ("evidence",evidenceDict) unconditioned = evidenceDict.keys() sampleToWeightList = [] #list of tuples, each tuple is of type(dictionary, weight) weights = [] count = 0 reduced = bayesNet.getReducedVariableDomains(evidenceDict) # itemsToRemove =[] # for item in reduced: # print item # if (item not in queryVariables) or (item not in evidenceDict): # print "removed" # itemsToRemove.append(item) # for item in itemsToRemove: # reduced.pop(item) # print ("reduced", reduced) # print ("queryVariables", queryVariables) # print("linearized", bayesNet.linearizeVariables()) # print ("BAYES NET") # print bayesNet sample = {} while count != numSamples: sample = {} weight = 1 for variable in bayesNet.linearizeVariables(): # print ("variable", variable) # print("sample", sample) factor = bayesNet.getCPT(variable) if variable in evidenceDict.keys(): # print ("presample", sample) sample.update({variable: evidenceDict[variable]}) # print("post", sample) prob = factor.getProbability(sample) # print ("prob", prob) weight = weight * prob else: assignmentDict = sampleFromFactor(factor, sample) sample.update(assignmentDict) # print ("appended", assignmentDict) # print (sample) # print "==========" tup = (sample, weight) sampleToWeightList.append(tup) count += 1 # print("====================================") # conditioned = queryVariables # conditionedFactor = Factor(queryVariables, [], bayesNet.variableDomainsDict()) # print "conditionedFactor" # print conditionedFactor # conditionedDomain = conditionedFactor.variableDomainsDict() # print ("conditionedDomain", conditionedDomain) # unconditionedFactor = Factor(unconditioned, [], bayesNet.variableDomainsDict()) # unconditionedDomain = unconditionedFactor.variableDomainsDict() # print "unconditionedFactor" # print unconditionedFactor # print ("unconditionedDomain", unconditionedDomain) # print "AAAAAAA" # print sampleToWeightList answer = Factor(queryVariables, unconditioned, reduced) #print ("answer domain ", answer.variableDomainsDict()) for assignment in answer.getAllPossibleAssignmentDicts(): print assignment sum0 = 0 for tup in sampleToWeightList: if all(item in tup[0].items() for item in assignment.items()): #if "assignment" is a subset of the sample, which is stored in the tuple in the list of tuples sum0 += tup[1] # print ("sum0", sum0) # print ("set assignment:") # print assignment # print "to be " # print answer.getProbability(assignment) + sum0 answer.setProbability(assignment, answer.getProbability(assignment) + sum0) # print answer answer = normalize(answer) return answer
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" linearizeVars = bayesNet.linearizeVariables() varDomainsDict = bayesNet.variableDomainsDict() # create a new factor queryEvidenceDomainsDict = {} for query in queryVariables: queryEvidenceDomainsDict[query] = varDomainsDict[query] for evidence, value in evidenceDict.items(): queryEvidenceDomainsDict[evidence] = [value] sampleFactor = Factor(queryVariables, evidenceDict, queryEvidenceDomainsDict) #number of samples to take for x in xrange(1,numSamples+1): w = 1.0 sampleVars = {} #vars set and encountered so far, including both the unconditioned and conditioned variables for var in linearizeVars: if var in evidenceDict.keys(): #if var is an evidence variable factor = bayesNet.getCPT(var) sampleVars[var] = evidenceDict[var] probability = factor.getProbability(sampleVars) w = w * probability else: #take a sample sampleDict = sampleFromFactor(bayesNet.getCPT(var), sampleVars) sampleVars.update(sampleDict) #update the corresponding row in the factor sampleFactor.setProbability(sampleVars, w+(sampleFactor.getProbability(sampleVars))) return normalize(sampleFactor) util.raiseNotDefined()
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" new_uncond = [] new_cond = [] new_var_domain = {} for i in factors: for j in i.unconditionedVariables(): if j not in new_uncond: new_uncond.append(j) for i in factors: for j in i.conditionedVariables(): if j not in new_cond and j not in new_uncond: new_cond.append(j) for i in factors: new_var_domain = dict(new_var_domain.items() + i.variableDomainsDict().items()) new_factor = Factor(new_uncond, new_cond, new_var_domain) assignments = new_factor.getAllPossibleAssignmentDicts() for assignment in assignments: new_factor.setProbability(assignment, 1) for assignment in assignments: for factor in factors: p = new_factor.getProbability(assignment) * factor.getProbability( assignment) new_factor.setProbability(assignment, p) return new_factor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) uc = [] c = [] for factor in factors: for var in factor.unconditionedVariables(): uc += [var] for factor in factors: for var in factor.conditionedVariables(): if var not in uc: c += [var] joinedFactor = Factor(set(uc), set(c), factors[0].variableDomainsDict()) for a in joinedFactor.getAllPossibleAssignmentDicts(): joinedFactor.setProbability(a, 1) for a in joinedFactor.getAllPossibleAssignmentDicts(): for factor in factors: newprob = factor.getProbability(a) * joinedFactor.getProbability(a) joinedFactor.setProbability(a, newprob) return joinedFactor
def normalize(factor): """ Question 5: Your normalize implementation Input factor is a single factor. The set of conditioned variables for the normalized factor consists of the input factor's conditioned variables as well as any of the input factor's unconditioned variables with exactly one entry in their domain. Since there is only one entry in that variable's domain, we can either assume it was assigned as evidence to have only one variable in its domain, or it only had one entry in its domain to begin with. This blurs the distinction between evidence assignments and variables with single value domains, but that is alright since we have to assign variables that only have one value in their domain to that single value. Return a new factor where the sum of the all the probabilities in the table is 1. This should be a new factor, not a modification of this factor in place. If the sum of probabilities in the input factor is 0, you should return None. This is intended to be used at the end of a probabilistic inference query. Because of this, all variables that have more than one element in their domain are assumed to be unconditioned. There are more general implementations of normalize, but we will only implement this version. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion variableDomainsDict = factor.variableDomainsDict() for conditionedVariable in factor.conditionedVariables(): if len(variableDomainsDict[conditionedVariable]) > 1: print "Factor failed normalize typecheck: ", factor raise ValueError, ("The factor to be normalized must have only one " + \ "assignment of the \n" + "conditional variables, " + \ "so that total probability will sum to 1\n" + str(factor)) "*** YOUR CODE HERE ***" domain = factor.variableDomainsDict() conVars = [a for a in factor.conditionedVariables()] unconVars = factor.unconditionedVariables() newunconVars = [] eleVars = [] for var in unconVars: if len(domain[var]) == 1: conVars.append(var) eleVars.append(var) else: newunconVars.append(var) res = Factor(newunconVars, conVars, factor.variableDomainsDict()) probList = [ factor.getProbability(a) for a in factor.getAllPossibleAssignmentDicts() ] if sum(probList) < 1e-10: return None for assignment in res.getAllPossibleAssignmentDicts(): res.setProbability(assignment, factor.getProbability(assignment) / sum(probList)) for var in eleVars: tmpSum = 0. for assignment in res.getAllPossibleAssignmentDicts(): if superDict(assignment, {var: domain[var][0]}): tmpSum += res.getProbability(assignment) for assignment in res.getAllPossibleAssignmentDicts(): res.setProbability(assignment, res.getProbability(assignment) / tmpSum) return res
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" # Combine conditioned/unconditioned variables(sets) conditionedList = list( factor.conditionedVariables().difference(eliminationVariable)) unconditionedList = list( factor.unconditionedVariables().difference(eliminationVariable)) if eliminationVariable in unconditionedList: unconditionedList.remove(eliminationVariable) if eliminationVariable in conditionedList: conditionedList.remove(eliminationVariable) # Define new factor with variables. newFactor = Factor(unconditionedList, conditionedList, factor.variableDomainsDict()) # Iterate through new factor and assign probability. for assignment in factor.getAllPossibleAssignmentDicts(): items = list(assignment.items()) for assign in newFactor.getAllPossibleAssignmentDicts(): newItems = list(assign.items()) find = False for o in newItems: if o not in items: find = True break if find: continue newFactor.setProbability( assign, newFactor.getProbability(assign) + factor.getProbability(assignment)) # Return. return newFactor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" unconVars = [] varDomainDict = {} for factor in factors: for var in factor.unconditionedVariables(): if var not in unconVars and var not in unconVars: unconVars.append(var) if var not in varDomainDict: varDomainDict[var] = factor.variableDomainsDict()[var] conVars = [] for factor in factors: for var in factor.conditionedVariables(): if var not in unconVars and var not in conVars: conVars.append(var) if var not in varDomainDict: varDomainDict[var] = factor.variableDomainsDict()[var] res = Factor(unconVars, conVars, varDomainDict) for assignment in res.getAllPossibleAssignmentDicts(): res.setProbability(assignment, 1.) for factor in factors: factorAssigns = factor.getAllPossibleAssignmentDicts() for assignment in res.getAllPossibleAssignmentDicts(): for factorAssign in factorAssigns: if superDict(assignment, factorAssign): res.setProbability( assignment, factor.getProbability(factorAssign) * res.getProbability(assignment)) return res
def eliminate(factor, eliminationVariable): """ Question 2: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(("eliminate", eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ( "Elimination variable is not an unconditioned variable " + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + "\nunconditionedVariables:" + str(factor.unconditionedVariables()) ) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ( "Factor has only one unconditioned variable, so you " + "can't eliminate \nthat variable.\n" + "eliminationVariable:" + str(eliminationVariable) + "\n" + "unconditionedVariables: " + str(factor.unconditionedVariables()) ) "*** YOUR CODE HERE ***" unconditioned = set() conditioned = set() for eachVar in factor.unconditionedVariables(): if not eachVar == eliminationVariable: unconditioned.add(eachVar) for eachVar in factor.conditionedVariables(): conditioned.add(eachVar) # build a new blank factor variableDomainsDict = factor.variableDomainsDict() newFactor = Factor(unconditioned, conditioned, variableDomainsDict) # eliminate the given variables assignmentDicts = factor.getAllPossibleAssignmentDicts() for assignment in assignmentDicts: oldProb = factor.getProbability(assignment) newProb = newFactor.getProbability(assignment) newFactor.setProbability(assignment, oldProb + newProb) return newFactor
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) newConditionedVars = set() newUnconditionedVars = set() for c in factor.conditionedVariables(): newConditionedVars.add(c) for u in factor.unconditionedVariables(): newUnconditionedVars.add(u) for u in newUnconditionedVars: if u in newConditionedVars: newConditionedVars.remove(u) if eliminationVariable in newConditionedVars: newConditionedVars.remove(eliminationVariable) if eliminationVariable in newUnconditionedVars: newUnconditionedVars.remove(eliminationVariable) NewFactor = Factor(newUnconditionedVars, newConditionedVars, factor.variableDomainsDict()) for d in factor.getAllPossibleAssignmentDicts(): #add the probs where the d is the same minus elim var newDict = dict(d) newDict.pop(eliminationVariable) prob = NewFactor.getProbability(newDict)+factor.getProbability(d) NewFactor.setProbability(newDict, prob) return NewFactor
def inferenceByLikelihoodWeightingSampling(bayesNet, queryVariables, evidenceDict, numSamples): """ Question 6: Inference by likelihood weighted sampling This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by performing likelihood weighting sampling. It should sample numSamples times. In order for the autograder's solution to match yours, your outer loop needs to iterate over the number of samples, with the inner loop sampling from each variable's factor. Use the ordering of variables provided by BayesNet.linearizeVariables in your inner loop so that the order of samples matches the autograder's. There are typically many linearization orders of a directed acyclic graph (DAG), however we just use a particular one. The sum of the probabilities should sum to one (so that it is a true conditional probability, conditioned on the evidence). bayesNet: The Bayes Net on which we are making a query. queryVariables: A list of the variables which are unconditioned in the inference query. evidenceDict: An assignment dict {variable : value} for the variables which are presented as evidence (conditioned) in the inference query. numSamples: The number of samples that should be taken. Useful functions: sampleFromFactor normalize BayesNet.getCPT BayesNet.linearizeVariables """ sampleFromFactor = sampleFromFactorRandomSource(randomSource) "*** YOUR CODE HERE ***" #create return factor newFactor = Factor(queryVariables, evidenceDict, bayesNet.variableDomainsDict()) reducedVariableDomains = bayesNet.getReducedVariableDomains(evidenceDict) newFactor = newFactor.specializeVariableDomains(reducedVariableDomains) for i in range(numSamples): weight = 1.0 allAssignments = {} allAssignments.update(evidenceDict) for var in bayesNet.linearizeVariables(): tmpCPT = bayesNet.getCPT(var) if var in evidenceDict: #accumulate weight weight *= tmpCPT.getProbability(allAssignments) else: newAssignment = sampleFromFactor(tmpCPT, allAssignments) allAssignments.update(newAssignment) #accumulate sample p = newFactor.getProbability(allAssignments) newFactor.setProbability(allAssignments, p + weight) return normalize(newFactor) util.raiseNotDefined()
def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) "*** YOUR CODE HERE ***" # since we only can eliminate unconditional variables unconditionedVar = factor.unconditionedVariables() unconditionedVar.remove(eliminationVariable) newFactor = Factor(unconditionedVar, factor.conditionedVariables(), factor.variableDomainsDict()) for assign in newFactor.getAllPossibleAssignmentDicts(): prob = 0.0 for eliminate in factor.variableDomainsDict()[eliminationVariable]: old_assign = assign print "1", old_assign old_assign[eliminationVariable] = eliminate print "2", old_assign prob = prob + Factor.getProbability(factor, old_assign) Factor.setProbability(newFactor, assign, prob) return newFactor
def eliminateWithCallTracking(callTrackingList=None): def eliminate(factor, eliminationVariable): """ Question 4: Your eliminate implementation Input factor is a single factor. Input eliminationVariable is the variable to eliminate from factor. eliminationVariable must be an unconditioned variable in factor. You should calculate the set of unconditioned variables and conditioned variables for the factor obtained by eliminating the variable eliminationVariable. Return a new factor where all of the rows mentioning eliminationVariable are summed with rows that match assignments on the other variables. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # autograder tracking -- don't remove if not (callTrackingList is None): callTrackingList.append(('eliminate', eliminationVariable)) # typecheck portion if eliminationVariable not in factor.unconditionedVariables(): print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Elimination variable is not an unconditioned variable " \ + "in this factor\n" + "eliminationVariable: " + str(eliminationVariable) + \ "\nunconditionedVariables:" + str(factor.unconditionedVariables())) if len(factor.unconditionedVariables()) == 1: print "Factor failed eliminate typecheck: ", factor raise ValueError, ("Factor has only one unconditioned variable, so you " \ + "can't eliminate \nthat variable.\n" + \ "eliminationVariable:" + str(eliminationVariable) + "\n" +\ "unconditionedVariables: " + str(factor.unconditionedVariables())) joinedConditionedVariables = set() joinedUnconditionedVariables = set() for factor in factors: for condVar in factor.conditionedVariables(): joinedConditionedVariables.add(condVar) for uncondVar in factor.unconditionedVariables(): joinedUnconditionedVariables.add(uncondVar) # joinedConditionedVariables.union(factor.conditionedVariables()) # joinedUnconditionedVariables.union(factor.unconditionedVariables()) # print "@@@@@factor.unconditionedVariables() ", factor.unconditionedVariables(), type(factor.unconditionedVariables()) # print "@@@@joinedConditionedVariables ", joinedConditionedVariables # print "@@@@joinedUnconditionedVariables ", joinedUnconditionedVariables # print "@@@@factor.conditionedVariables() ", factor.conditionedVariables() # print "@@@@factor.unconditionedVariables() ", factor.unconditionedVariables() # joinedUnconditionedVariables.remove(eliminationVariable) # reducedFactor = Factor(reducedUnconditionedVariables, factor.conditionedVariables(), factor.variableDomainsDict()) for uncondVar in joinedUnconditionedVariables: if uncondVar in joinedConditionedVariables: joinedConditionedVariables.remove(uncondVar) # print "@@@@@@joinedUnconditionedVariables ", joinedUnconditionedVariables # print "@@@@@@joinedConditionedVariables ", joinedConditionedVariables joinedFactor = Factor(joinedUnconditionedVariables, joinedConditionedVariables, factors[0].variableDomainsDict()) # print "@@@@joinedFactor.unconditionedVariables() ", joinedFactor.unconditionedVariables() # print "@@@@joinedFactor.conditionedVariables() ", joinedFactor.conditionedVariables() for joinedAssignment in joinedFactor.getAllPossibleAssignmentDicts(): # print "@@@@joinedAssignment ", joinedAssignment factorAssignmentProduct = 1 for factor in factors: # print "probability of ", joinedAssignment, Factor.getProbability(factor, joinedAssignment) factorAssignmentProduct = factorAssignmentProduct * Factor.getProbability( factor, joinedAssignment) Factor.setProbability(joinedFactor, joinedAssignment, factorAssignmentProduct) return joinedFactor
def normalize(factor): """ Question 5: Your normalize implementation Input factor is a single factor. The set of conditioned variables for the normalized factor consists of the input factor's conditioned variables as well as any of the input factor's unconditioned variables with exactly one entry in their domain. Since there is only one entry in that variable's domain, we can either assume it was assigned as evidence to have only one variable in its domain, or it only had one entry in its domain to begin with. This blurs the distinction between evidence assignments and variables with single value domains, but that is alright since we have to assign variables that only have one value in their domain to that single value. Return a new factor where the sum of the all the probabilities in the table is 1. This should be a new factor, not a modification of this factor in place. If the sum of probabilities in the input factor is 0, you should return None. This is intended to be used at the end of a probabilistic inference query. Because of this, all variables that have more than one element in their domain are assumed to be unconditioned. There are more general implementations of normalize, but we will only implement this version. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion variableDomainsDict = factor.variableDomainsDict() for conditionedVariable in factor.conditionedVariables(): if len(variableDomainsDict[conditionedVariable]) > 1: print "Factor failed normalize typecheck: ", factor raise ValueError, ("The factor to be normalized must have only one " + \ "assignment of the \n" + "conditional variables, " + \ "so that total probability will sum to 1\n" + str(factor)) "*** YOUR CODE HERE ***" conditionedVar = [] unconditionedVar = [] for condition in factor.conditionedVariables(): if condition not in conditionedVar: conditionedVar.append(condition) for unconditioned in factor.unconditionedVariables(): if unconditioned not in (unconditionedVar): unconditionedVar.append(unconditioned) prob_sum = 0.0 for assign in factor.getAllPossibleAssignmentDicts(): prob_sum = prob_sum + Factor.getProbability(factor, assign) if prob_sum == 0: return None # add with one entry for var in unconditionedVar: if len(factor.variableDomainsDict() [var]) == 1 and var not in conditionedVar: conditionedVar.append(var) unconditionedVar = [ var for var in unconditionedVar if var not in conditionedVar ] newFactor = Factor(unconditionedVar, conditionedVar, factor.variableDomainsDict()) for assign in newFactor.getAllPossibleAssignmentDicts(): prob = Factor.getProbability(factor, assign) / prob_sum Factor.setProbability(newFactor, assign, prob) return newFactor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion factors = list(factors) setsOfUnconditioned = [set(factor.unconditionedVariables()) for factor in factors] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print ("Factor failed joinFactors typecheck: ", factor) raise ValueError ("unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" joinedConditionedVariables = set() joinedUnconditionedVariables = set() for factor in factors: for condVar in factor.conditionedVariables(): joinedConditionedVariables.add(condVar) for uncondVar in factor.unconditionedVariables(): joinedUnconditionedVariables.add(uncondVar) for uncondVar in joinedUnconditionedVariables: if uncondVar in joinedConditionedVariables: joinedConditionedVariables.remove(uncondVar) joinedFactor = Factor(joinedUnconditionedVariables, joinedConditionedVariables, factors[0].variableDomainsDict()) for joinedAssignment in joinedFactor.getAllPossibleAssignmentDicts(): factorAssignmentProduct = 1 for factor in factors: factorAssignmentProduct = factorAssignmentProduct * Factor.getProbability(factor, joinedAssignment) Factor.setProbability(joinedFactor, joinedAssignment, factorAssignmentProduct) return joinedFactor
def joinFactors(factors): """ Question 3: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" conditionedVar = [] unconditionedVar = [] for factor in factors: for condition in factor.conditionedVariables(): if condition not in conditionedVar: conditionedVar.append(condition) for unconditioned in factor.unconditionedVariables(): if unconditioned not in (unconditionedVar): unconditionedVar.append(unconditioned) print factors print unconditionedVar print conditionedVar conditionedVar = [ var for var in conditionedVar if var not in unconditionedVar ] """for var in unconditionedVar: if var in conditionedVar: conditionedVar.remove(var)""" newFactor = Factor(unconditionedVar, conditionedVar, factors[0].variableDomainsDict()) for assign in newFactor.getAllPossibleAssignmentDicts(): prob = 1.0 for factor in factors: prob = prob * Factor.getProbability(factor, assign) Factor.setProbability(newFactor, assign, prob) return newFactor
def joinFactors(factors): """ Question 1: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [set(factor.unconditionedVariables()) for factor in factors] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ("unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) "*** YOUR CODE HERE ***" factor1 = factors[0] totalUnconditionedVars = set() totalConditionedVars = set() varsToDomain = {} for factor in factors: for uncon in factor.unconditionedVariables(): if uncon not in totalUnconditionedVars: totalUnconditionedVars.add(uncon) varsToDomain[uncon] = factor.variableDomainsDict()[uncon] for factor in factors: for con in factor.conditionedVariables(): if con not in totalUnconditionedVars and con not in totalConditionedVars: totalConditionedVars.add(con) varsToDomain[con] = factor.variableDomainsDict()[con] newFactor = Factor(list(totalUnconditionedVars), list(totalConditionedVars), varsToDomain) for ass in newFactor.getAllPossibleAssignmentDicts(): newFactor.setProbability(ass, float(1.0)) for factor in factors: asses = newFactor.getAllPossibleAssignmentDicts() for ass in asses: for facAss in factor.getAllPossibleAssignmentDicts(): pro = factor.getProbability(facAss) works = True for var in facAss.keys(): if facAss[var] != ass[var]: works = False break if works: newFactor.setProbability(ass, newFactor.getProbability(ass) * pro) break return newFactor
def joinFactors(factors): """ Question 1: Your join implementation Input factors is a list of factors. You should calculate the set of unconditioned variables and conditioned variables for the join of those factors. Return a new factor that has those variables and whose probability entries are product of the corresponding rows of the input factors. You may assume that the variableDomainsDict for all the input factors are the same, since they come from the same BayesNet. joinFactors will only allow unconditionedVariables to appear in one input factor (so their join is well defined). Hint: Factor methods that take an assignmentDict as input (such as getProbability and setProbability) can handle assignmentDicts that assign more variables than are in that factor. Useful functions: Factor.getAllPossibleAssignmentDicts Factor.getProbability Factor.setProbability Factor.unconditionedVariables Factor.conditionedVariables Factor.variableDomainsDict """ # typecheck portion setsOfUnconditioned = [ set(factor.unconditionedVariables()) for factor in factors ] if len(factors) > 1: intersect = reduce(lambda x, y: x & y, setsOfUnconditioned) if len(intersect) > 0: print "Factor failed joinFactors typecheck: ", factor raise ValueError, ( "unconditionedVariables can only appear in one factor. \n" + "unconditionedVariables: " + str(intersect) + "\nappear in more than one input factor.\n" + "Input factors: \n" + "\n".join(map(str, factors))) factor1 = factors[0] totalUnconditionedVars = set() totalConditionedVars = set() varsToDomain = {} for factor in factors: for uncon in factor.unconditionedVariables(): if uncon not in totalUnconditionedVars: totalUnconditionedVars.add(uncon) varsToDomain[uncon] = factor.variableDomainsDict()[uncon] for factor in factors: for con in factor.conditionedVariables(): if con not in totalUnconditionedVars and con not in totalConditionedVars: totalConditionedVars.add(con) varsToDomain[con] = factor.variableDomainsDict()[con] newFactor = Factor(list(totalUnconditionedVars), list(totalConditionedVars), varsToDomain) for ass in newFactor.getAllPossibleAssignmentDicts(): newFactor.setProbability(ass, float(1.0)) for factor in factors: asses = newFactor.getAllPossibleAssignmentDicts() for ass in asses: for facAss in factor.getAllPossibleAssignmentDicts(): pro = factor.getProbability(facAss) works = True for var in facAss.keys(): if facAss[var] != ass[var]: works = False break if works: newFactor.setProbability( ass, newFactor.getProbability(ass) * pro) break return newFactor