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))) unconditioned = [] conditioned = [] varDomain = {} for factor in factors: varDomain = factor.variableDomainsDict() unconditioned += factor.unconditionedVariables() conditioned = set.union(factor.conditionedVariables(), conditioned) conditioned = set.difference(conditioned, unconditioned) newFactor = Factor(unconditioned, conditioned, varDomain) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = 1 for factor in factors: prob *= factor.getProbability(assignment) newFactor.setProbability(assignment, prob) 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 ***" # Simplify variables setOfUnconditioned = factor.unconditionedVariables() - \ set([eliminationVariable]) eliminatedFactor = Factor(setOfUnconditioned, factor.conditionedVariables(), factor.variableDomainsDict()) # Get product of probabilities for every assignment for assignment in eliminatedFactor.getAllPossibleAssignmentDicts(): probSum = sum([factor.getProbability(a) for a in \ factor.getAllPossibleAssignmentDicts() if \ all(a[var] == assignment[var] for var in \ assignment.keys())]) eliminatedFactor.setProbability(assignment, probSum) return eliminatedFactor
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 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)) uncond_var = factor.unconditionedVariables() cond_var = factor.conditionedVariables() uncond_var_one_value = [x for x in uncond_var if len(variableDomainsDict[x])==1] for i in range(0, len(uncond_var_one_value)): uncond_var.remove(uncond_var_one_value[i]) cond_var.add(uncond_var_one_value[i]) result_fac = Factor(uncond_var,cond_var,variableDomainsDict) prob_total = 0 for assignment in factor.getAllPossibleAssignmentDicts(): prob_total+=factor.getProbability(assignment) for assignment in factor.getAllPossibleAssignmentDicts(): result_fac.setProbability(assignment,factor.getProbability(assignment)/prob_total) return result_fac
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 ***" unconditioned = factor.unconditionedVariables() unconditioned = [ var for var in unconditioned if var != eliminationVariable ] conditioned = factor.conditionedVariables() variableDomainsDict = factor.variableDomainsDict() domain = variableDomainsDict[eliminationVariable] newFactor = Factor(unconditioned, conditioned, variableDomainsDict) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = 0 for elim_val in domain: old_assignment = assignment.copy() old_assignment[eliminationVariable] = elim_val prob += factor.getProbability(old_assignment) newFactor.setProbability(assignment, prob) 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())) #print factor eliminate_domain = factor.variableDomainsDict()[eliminationVariable] unconditionedVariables = [var for var in factor.unconditionedVariables() if var != eliminationVariable] domain = {} for var, dom in factor.variableDomainsDict().iteritems(): if var != eliminationVariable: domain[var] = dom resultingFactor = Factor(unconditionedVariables, factor.conditionedVariables(), domain) for assignment in resultingFactor.getAllPossibleAssignmentDicts(): valProbab = 0 for eliminate_val in eliminate_domain: new_assign = dict(assignment.items() + [(eliminationVariable, eliminate_val)]) valProbab += factor.getProbability(new_assign) resultingFactor.setProbability(assignment, valProbab) return resultingFactor
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 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 jointwo(a, b): aSet = a.unconditionedVariables().union(a.conditionedVariables()) bSet = b.unconditionedVariables().union(b.conditionedVariables()) #gets common dictionary of two factors commonDict = combineDict(a.variableDomainsDict(), b.variableDomainsDict()) #finds unconditioned and conditioned variables in total uncondVar = set() conditionedVar = set() for factor in [a, b]: for unVar in factor.unconditionedVariables(): if unVar not in uncondVar: uncondVar.add(unVar) for condVar in factor.conditionedVariables(): if condVar not in conditionedVar: conditionedVar.add(condVar) #puts condVar intp uncondVar currVar = [con for con in conditionedVar] for c in currVar: if c in uncondVar: uncondVar.add(c) conditionedVar.remove(c) #creates a new factor and gives it the probabilities newFactor = Factor(uncondVar, conditionedVar, commonDict) for combo in newFactor.getAllPossibleAssignmentDicts(): prob = a.getProbability(combo) * b.getProbability(combo) newFactor.setProbability(combo, prob) 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 NOTES: Definition of marginalization; if you have distribution P(A,B|C), P(A=a|C=c)= Sum over b of P(A=a, B=b|C=c) """ # 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())) # construct new factor unconditionedVariables = {v for v in factor.unconditionedVariables() if v != eliminationVariable} marginalizedFactor = Factor(unconditionedVariables, factor.conditionedVariables(), factor.variableDomainsDict()) # calculate marginalized probabilities eliminatedVariableDomain = factor.variableDomainsDict()[eliminationVariable] for assignment in factor.getAllPossibleAssignmentDicts(): marginalizedProbabilities = [] for value in eliminatedVariableDomain: assignment[eliminationVariable] = value marginalizedProbabilities.append(factor.getProbability(assignment)) marginalizedFactor.setProbability(assignment, sum(marginalizedProbabilities)) return marginalizedFactor
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 ***" # Note: "reduced" indicates its the unconditioned variables minus the elimVar, and "full" means its all the starting unconditioned variables reducedUnconditionedVariables = factor.unconditionedVariables() reducedUnconditionedVariables.remove(eliminationVariable) reducedFactor = Factor(reducedUnconditionedVariables, factor.conditionedVariables(), factor.variableDomainsDict()) for reducedAssignment in reducedFactor.getAllPossibleAssignmentDicts(): prob = 0 for elimVarVal in factor.variableDomainsDict( )[eliminationVariable]: fullAssignment = reducedAssignment fullAssignment[eliminationVariable] = elimVarVal prob = prob + factor.getProbability(fullAssignment) reducedFactor.setProbability(reducedAssignment, prob) return reducedFactor
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 ***" # util.raiseNotDefined() varDict, conVariables, unconVariables = factor.variableDomainsDict( ), factor.conditionedVariables(), [] for uncon in factor.unconditionedVariables(): if uncon != eliminationVariable: unconVariables.append(uncon) new = Factor(unconVariables, conVariables, varDict) for each in new.getAllPossibleAssignmentDicts(): probability = 0 for rem in varDict[eliminationVariable]: past = each.copy() past[eliminationVariable] = rem probability += factor.getProbability(past) new.setProbability(each, probability) return new
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] variableDict= factors[0].variableDomainsDict() 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))) setsOfConditioned = [set(factor.conditionedVariables()) for factor in factors] unconditioned_var = list(reduce(lambda x, y: x | y, setsOfUnconditioned)) conditioned_var = list(reduce(lambda x, y: x | y, setsOfConditioned)) conditioned_var = [var for var in conditioned_var if var not in unconditioned_var] result_fac = Factor(unconditioned_var,conditioned_var,variableDict) assignments = result_fac.getAllPossibleAssignmentDicts() for assignment in assignments: prob = 1 for factor in factors: assign_tmp = {key:value for key,value in assignment.items() if key in factor.variablesSet()} prob*= factor.getProbability(assign_tmp) result_fac.setProbability(assignment,prob) return result_fac
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())) unconditioned = factor.unconditionedVariables() unconditioned.remove(eliminationVariable) result = Factor(unconditioned, factor.conditionedVariables(), factor.variableDomainsDict()) for v in result.getAllPossibleAssignmentDicts(): copy = v.copy() s = 0 for e in factor.variableDomainsDict()[eliminationVariable]: copy[eliminationVariable] = e s += factor.getProbability(copy) result.setProbability(v, s) return result
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). """ # 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))) # Calculate the set of unconditioned variables and conditioned # variables for the join of those factors. condVars = set() unCondVars = set() for factor in factors: for var in factor.conditionedVariables(): condVars.add(var) for var in factor.unconditionedVariables(): unCondVars.add(var) # Remove any unconditioned variables from the list of conditioned variables for var in unCondVars: if var in condVars: condVars.remove(var) newFactor = Factor(unCondVars, condVars, factors[0].variableDomainsDict()) # Assign the correct probabilities to each assignment through multiplication for assignment in newFactor.getAllPossibleAssignmentDicts(): chainRuleResult = 1 for factor in factors: chainRuleResult *= factor.getProbability(assignment) newFactor.setProbability(assignment, chainRuleResult) 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 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 ***" uncondVars = set([var for factor in factors for var in factor.unconditionedVariables()]) #self-explanatory condVars = set([var for factor in factors for var in factor.conditionedVariables()]) condVars = condVars.difference(uncondVars) #remove any duplicate vars resultingFactor = Factor(uncondVars,condVars,factors[0].variableDomainsDict()) #create factor based on ^ & ^^ for val in resultingFactor.getAllPossibleAssignmentDicts(): totalProbab = 1 for factor in factors: #calculate probability for each individual assignedment over the full list of factors totalProbab *= factor.getProbability(val) resultingFactor.setProbability(val,totalProbab) return resultingFactor
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())) uncond_var = factor.unconditionedVariables() cond_var = factor.conditionedVariables() uncond_var.remove(eliminationVariable) result_fac = Factor(uncond_var,cond_var,factor.variableDomainsDict()) for assignment in result_fac.getAllPossibleAssignmentDicts(): prob =0 assigns_for_eliminate = factor.variableDomainsDict()[eliminationVariable] for val in assigns_for_eliminate: assignment[eliminationVariable] = val prob+= factor.getProbability(assignment) assignment.pop(eliminationVariable) result_fac.setProbability(assignment,prob) return result_fac
def joinTwoFactors(factor, otherFactor): unconditionedVaribles = factor.unconditionedVariables() | otherFactor.unconditionedVariables() conditionedVaribles = factor.conditionedVariables() | otherFactor.conditionedVariables() conditionedVaribles = conditionedVaribles - unconditionedVaribles retFactor = Factor(list(unconditionedVaribles), list(conditionedVaribles), factor.variableDomainsDict()) for assignmentDict in retFactor.getAllPossibleAssignmentDicts(): prob1 = factor.getProbability(assignmentDict) prob2 = otherFactor.getProbability(assignmentDict) retFactor.setProbability(assignmentDict, prob1*prob2) return retFactor
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. """ # 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())) # Calculate the set of unconditioned and conditioned variables condVars = factor.conditionedVariables() unCondVars = factor.unconditionedVariables() unCondVars.remove(eliminationVariable) # Create a new factor using the new sets newFactor = Factor(unCondVars, condVars, factor.variableDomainsDict()) # Sum over the probabilities of the removed variable for the new factor for assignment in newFactor.getAllPossibleAssignmentDicts(): probSum = 0 for value in factor.variableDomainsDict()[eliminationVariable]: assignment[eliminationVariable] = value probSum += factor.getProbability(assignment) newFactor.setProbability(assignment, probSum) return newFactor
def join(f1, f2, commonVars): jointUncond = f1.unconditionedVariables() | f2.unconditionedVariables() jointCond = (f1.conditionedVariables() | f2.conditionedVariables()) - jointUncond jointFactor = Factor( list(jointUncond), list(jointCond), dict(f2.variableDomainsDict(), **f1.variableDomainsDict())) for a1 in f1.getAllPossibleAssignmentDicts(): for a2 in f2.getAllPossibleAssignmentDicts(): next = False for v in commonVars: if a1[v] != a2[v]: next = True break if not next: prob1 = f1.getProbability(a1) prob2 = f2.getProbability(a2) jointFactor.setProbability(dict(a2, **a1), prob1 * prob2) return jointFactor
def normalize(factor): """ Question 3: 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 ***" conditionedVariables = [] for each in factor.unconditionedVariables(): if len(factor.variableDomainsDict()[each]) == 1: conditionedVariables.append(each) conditionedVariables = list( set(conditionedVariables + list(factor.conditionedVariables()))) unconditionedVariables = [] for each in factor.unconditionedVariables(): if each not in conditionedVariables: unconditionedVariables.append(each) newFactor = Factor(unconditionedVariables, conditionedVariables, factor.variableDomainsDict()) z = 0 for each in factor.getAllPossibleAssignmentDicts(): z += factor.getProbability(each) for each in newFactor.getAllPossibleAssignmentDicts(): newFactor.setProbability(each, factor.getProbability(each) / z) return newFactor util.raiseNotDefined()
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 ***" if len(factors) == 1: return factors.pop() first = factors.pop(0) firstAssignments = first.getAllPossibleAssignmentDicts() second = factors.pop(0) secondAssignments = second.getAllPossibleAssignmentDicts() unconditionedVariables = list(first.unconditionedVariables()) + list( second.unconditionedVariables()) conditionedVariables = list(first.conditionedVariables()) + list( second.conditionedVariables()) conditionedVar = [] for var in conditionedVariables: if var not in unconditionedVariables: conditionedVar.append(var) conditionedVar = list(set(conditionedVar)) newFactor = Factor(unconditionedVariables, conditionedVar, first.variableDomainsDict()) for each in newFactor.getAllPossibleAssignmentDicts(): firstFactor = 0 for firstEach in firstAssignments: if set(firstEach.items()).issubset(set(each.items())): firstFactor = first.getProbability(firstEach) secondFactor = 0 for secondEach in secondAssignments: if set(secondEach.items()).issubset(set(each.items())): secondFactor = second.getProbability(secondEach) probability = firstFactor * secondFactor newFactor.setProbability(each, probability) return joinFactors(factors + [newFactor]) 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 ***" unconditioned = set() conditioned = set() domainDict = dict() for factor in factors: conditioned = conditioned | factor.conditionedVariables() unconditioned = unconditioned | factor.unconditionedVariables() domainDict = dict(domainDict, **factor.variableDomainsDict()) conditioned = conditioned - (conditioned & unconditioned) returnFactor = Factor(unconditioned, conditioned, domainDict) for assignmentDict in returnFactor.getAllPossibleAssignmentDicts(): probability = 1 for factor in factors: assignmentCopy = dict() for variable in assignmentDict: if (variable in (factor.unconditionedVariables() | factor.conditionedVariables())): assignmentCopy[variable] = assignmentDict[variable] probability = probability * factor.getProbability(assignmentCopy) returnFactor.setProbability(assignmentDict, probability) return returnFactor
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 ***" new_unconditioned = factor.unconditionedVariables() new_conditioned = factor.conditionedVariables() new_doamin = factor.variableDomainsDict() temp_set = set() for var in new_unconditioned: if (len(new_doamin[var]) == 1): temp_set.add(var) new_conditioned = new_conditioned | temp_set new_unconditioned = new_unconditioned - temp_set new_factor = Factor(new_unconditioned, new_conditioned, new_doamin) prob = 0 for assignment in factor.getAllPossibleAssignmentDicts(): prob += factor.getProbability(assignment) for assignment in factor.getAllPossibleAssignmentDicts(): new_factor.setProbability(assignment, factor.getProbability(assignment) / prob) 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 NOTES: P(A|B) is the conditional distribution of A given B, and A is conditioned on B. In this project, B is referred to as a "conditioned variable" (since it's being conditioned on), and then A is called "unconditioned." Better terminology might be something like "conditioned on" for B and "not conditioned on" for A. """ # 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))) tempConditionedVariables = set() inputUnconditionedVariables = set() variableDomains = factors[0].variableDomainsDict() # construct factor inputs for factor in factors: for variable in factor.conditionedVariables(): tempConditionedVariables.add(variable) for variable in factor.unconditionedVariables(): inputUnconditionedVariables.add(variable) inputConditionedVariables = {v for v in tempConditionedVariables if v not in inputUnconditionedVariables} joinedFactor = Factor(inputUnconditionedVariables, inputConditionedVariables, variableDomains) # calculate joint probabilities for assignment in joinedFactor.getAllPossibleAssignmentDicts(): probability = 1 for factor in factors: try: probability *= factor.getProbability(assignment) except(ValueError): continue joinedFactor.setProbability(assignment, probability) 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 ***" #P(X|Y) + P(Y) -> P(X,Y) #Product rule, multiply variables not in conditional together. uncond = [] cond = [] variableDomainsDict = {} if len(factors) > 0: variableDomainsDict = factors[0].variableDomainsDict() for f in factors: tempUncond = f.unconditionedVariables() tempCond = f.conditionedVariables() uncond.extend(tempUncond) for conditionedVar in tempCond: if conditionedVar not in cond: cond.append(conditionedVar) #for var in cond: #if var not in cond:aeorhgijoarejh cond = [var for var in cond if var not in uncond] returnedFactor = Factor(uncond, cond, variableDomainsDict) assignments = returnedFactor.getAllPossibleAssignmentDicts() #multiply those not in conditioned for assignment in assignments: p = 1 for factor in factors: p = p * factor.getProbability(assignment) returnedFactor.setProbability(assignment, p) return returnedFactor
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 ***" #util.raiseNotDefined() uncondVar = factor.unconditionedVariables() uncondVar = [var for var in uncondVar if var != eliminationVariable] condVar = factor.conditionedVariables() domainvarDict = factor.variableDomainsDict() umbrella = domainvarDict[eliminationVariable] #new factor with the elimnation var newFactor = Factor(uncondVar, condVar, domainvarDict) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = 0 #parsing for the eliminaion value in the umbrella for elimVal in umbrella: #storing the copy of the assignment val prevassignmentVal = assignment.copy() #eliminating the assignment prevassignmentVal[eliminationVariable] = elimVal #calculating the probability of the assignment prob += factor.getProbability(prevassignmentVal) #setting the probability of the new assignment newFactor.setProbability(assignment, prob) return newFactor
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 ***" #util.raiseNotDefined() domainvarDict = factor.variableDomainsDict() uncondVar = factor.unconditionedVariables() condVar = factor.conditionedVariables() #if the probabilities sum upto 0 then return none probSum = 0 prevassignmentVal = factor.getAllPossibleAssignmentDicts() for row in prevassignmentVal: probSum += factor.getProbability(row) if probSum == 0: return None for var in uncondVar: if len(domainvarDict[var]) == 1: condVar.add(var) uncondVar = [var for var in uncondVar if var not in condVar] newFactor = Factor(uncondVar, condVar, domainvarDict) for assignmentVal in newFactor.getAllPossibleAssignmentDicts(): prob = factor.getProbability(assignmentVal) newFactor.setProbability(assignmentVal, prob / probSum) 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 ***" unconditioned = [] conditioned = [] variableDomainsDict = {} #checking for non empty factors if factors and len(factors) > 0: variableDomainsDict = factors[0].variableDomainsDict() #parsing through all the factors for fac in factors: #initialized temp cond and uncon vars uncondtempVar = fac.unconditionedVariables() condtempVar = fac.conditionedVariables() unconditioned.extend(uncondtempVar) #parsing through the condvars list for currcondVar in condtempVar: #if the current cond var is not in the list if currcondVar not in conditioned: #append it conditioned.append(currcondVar) #initializing the array conditioned = [var for var in conditioned if var not in unconditioned] newFactor = Factor(unconditioned, conditioned, variableDomainsDict) legalAssignments = newFactor.getAllPossibleAssignmentDicts() #parsing through all the assignments for currAssignment in legalAssignments: prob = 1 #parsing through all the factors for factor in factors: #calculating the prob of the current assignment prob *= factor.getProbability(currAssignment) #setting the probability of the curr assignment vs prob newFactor.setProbability(currAssignment, prob) return newFactor