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. """ # 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)) condVars = factor.conditionedVariables() unCondVars = factor.unconditionedVariables() for var in factor.unconditionedVariables(): if len(variableDomainsDict[var]) == 1: condVars.add(var) unCondVars.remove(var) newFactor = Factor(unCondVars, condVars, variableDomainsDict) probSum = 0.0 for assignment in newFactor.getAllPossibleAssignmentDicts(): probSum += factor.getProbability(assignment) for assignment in newFactor.getAllPossibleAssignmentDicts(): normalizedProb = factor.getProbability(assignment) / probSum newFactor.setProbability(assignment, normalizedProb) 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))) 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())) #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 ***" 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 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 """ # 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 ***" unCondVar = factor.unconditionedVariables() unCondVar.remove(eliminationVariable) condVar = factor.conditionedVariables() varDomainsDict = factor.variableDomainsDict() result = Factor(unCondVar, condVar, varDomainsDict) for assignmentDict in result.getAllPossibleAssignmentDicts(): prob = 0 for eliminationValue in varDomainsDict[eliminationVariable]: assignmentDictCopy = assignmentDict assignmentDictCopy[eliminationVariable] = eliminationValue prob += factor.getProbability(assignmentDictCopy) result.setProbability(assignmentDict, prob) return result
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 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 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)) unconditioned_variables = set(filter(lambda var: len(factor.variableDomainsDict()[var]) != 1, factor.unconditionedVariables())) conditioned_variables = set(factor.conditionedVariables()).union(filter(lambda var: len(factor.variableDomainsDict()[var]) == 1, factor.unconditionedVariables())) normalized = Factor(unconditioned_variables, conditioned_variables, factor.variableDomainsDict()) total_prob = sum([factor.getProbability(ass) for ass in factor.getAllPossibleAssignmentDicts()]) for ass in normalized.getAllPossibleAssignmentDicts(): normalized.setProbability(ass, factor.getProbability(ass) / total_prob) return normalized
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] setsOfConditioned = [set(factor.conditionedVariables()) for factor in factors] factors_domains = [factor.variableDomainsDict() 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))) else: final_uncondition = reduce(lambda x, y: x | y, setsOfUnconditioned) final_condition = reduce(lambda x, y: x | y, setsOfConditioned)-final_uncondition final_domain = reduce(lambda x, y: dict(x.items()+y.items()), factors_domains) new_factor = Factor(final_uncondition, final_condition,final_domain) for assign_large in new_factor.getAllPossibleAssignmentDicts(): assign_large_prob = 1 for small_factor in factors: # print(small_factor) assign_large_prob *= small_factor.getProbability(get_new_assig(assign_large,small_factor)) new_factor.setProbability(assign_large,assign_large_prob) return new_factor else: return factors[0]
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 ***" conVars = factor.conditionedVariables() unconVars = [ a for a in factor.unconditionedVariables() if a != eliminationVariable ] res = Factor(unconVars, conVars, factor.variableDomainsDict()) for assignment in res.getAllPossibleAssignmentDicts(): for factorAssign in factor.getAllPossibleAssignmentDicts(): if superDict(factorAssign, assignment): 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 ***" variableDomains = factor.variableDomainsDict() conditionedVariables = factor.conditionedVariables() unconditionedVariables = factor.unconditionedVariables() if eliminationVariable in conditionedVariables: conditionedVariables.remove(eliminationVariable) if eliminationVariable in unconditionedVariables: unconditionedVariables.remove(eliminationVariable) del variableDomains[eliminationVariable] newFactor = Factor(unconditionedVariables, conditionedVariables, variableDomains) newAssignments = newFactor.getAllPossibleAssignmentDicts() assignments = factor.getAllPossibleAssignmentDicts() for newAssignment in newAssignments: runningProbability = 0 for assignment in assignments: if isSubset(assignment, newAssignment): runningProbability += factor.getProbability(assignment) newFactor.setProbability(newAssignment, runningProbability) 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())) 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 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 ***" unconditionals, conditionals, variableDomainsDict = getVariablesFromAllFactors(factors) newFactor = Factor(unconditionals, conditionals, variableDomainsDict) for unconditional in unconditionals: toRemove = [] newFactor = Factor(unconditionals, conditionals, variableDomainsDict) possAssigns = newFactor.getAllPossibleAssignmentDicts() newFactor = initiateProbsToOne(newFactor, possAssigns) for factor in factors: factorUnconditionals = factor.unconditionedVariables() factorConditionals = factor.conditionedVariables() if unconditional in factorUnconditionals and not unconditional in factorConditionals: toRemove.append(factor) assignments = factor.getAllPossibleAssignmentDicts() for assignment in assignments: for possAssign in possAssigns: newFactor = adjustProbability(possAssign, assignment, newFactor, factor) factors = purgeFactors(toRemove, factors, 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 ***" 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 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())) new_unconditioned = factor.unconditionedVariables() new_unconditioned.remove(eliminationVariable) new_Factor = Factor(new_unconditioned, factor.conditionedVariables(), factor.variableDomainsDict()) for j in new_Factor.getAllPossibleAssignmentDicts(): probabilitySum = 0 for i in new_Factor.variableDomainsDict().get(eliminationVariable): j[eliminationVariable] = i currentProb = factor.getProbability(j) probabilitySum += currentProb del j[eliminationVariable] new_Factor.setProbability(j, probabilitySum) return new_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 ***" #uncondVarSet = set() condVarSet = factor.conditionedVariables() uncondVarSet = factor.unconditionedVariables() uncondVarSet.remove(eliminationVariable) #removes elimination variable newFactor = Factor(uncondVarSet, condVarSet, factor.variableDomainsDict()) for assignment in newFactor.getAllPossibleAssignmentDicts(): probSum = 0 for val in factor.variableDomainsDict()[eliminationVariable]: assignment[eliminationVariable] = val probSum += factor.getProbability(assignment) #obtain probability of all assignments affiliated to entry add to other rows it matches with newFactor.setProbability(assignment, probSum) return 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 ***" new_unconditioned = factor.unconditionedVariables() new_unconditioned.remove(eliminationVariable) new_Factor = Factor(new_unconditioned,factor.conditionedVariables(), factor.variableDomainsDict()) for j in new_Factor.getAllPossibleAssignmentDicts(): probabilitySum = 0 for i in new_Factor.variableDomainsDict().get(eliminationVariable): j[eliminationVariable] = i currentProb = factor.getProbability(j) probabilitySum += currentProb del j[eliminationVariable] new_Factor.setProbability(j, probabilitySum) 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())) 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 joinTwoFactors(factor1,factor2): conditionedVariables = set(factor1.conditionedVariables()) | set(factor2.conditionedVariables()) unconditionedVariables = set(factor1.unconditionedVariables()) | set(factor2.unconditionedVariables()) conditionedVariables = conditionedVariables - unconditionedVariables newFactor = Factor(list(unconditionedVariables),list(conditionedVariables),factor1.variableDomainsDict()) for assignment in newFactor.getAllPossibleAssignmentDicts(): variables1 = set(factor1.unconditionedVariables()) | set(factor1.conditionedVariables()) assignment1 = {key:value for key,value in assignment.items() if key in variables1} prob1 = factor1.getProbability(assignment1) variables2 = set(factor2.unconditionedVariables()) | set(factor2.conditionedVariables()) assignment2 = {key:value for key,value in assignment.items() if key in variables2} prob2 = factor2.getProbability(assignment2) newFactor.setProbability(assignment,prob1*prob2) 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 ***" conditionedVariables = set(factors[0].conditionedVariables()) unconditionedVariables = set(factors[0].unconditionedVariables()) variableDomainsDict = factors[0].variableDomainsDict() print(conditionedVariables) print(unconditionedVariables) print(variableDomainsDict) print(factors[0]) returnFactor = factors[0] for i in range(1, len(factors)): conditionedVariables = conditionedVariables | set( factors[i].conditionedVariables()) unconditionedVariables = unconditionedVariables | set( factors[i].unconditionedVariables()) conditionedVariables = conditionedVariables.difference( unconditionedVariables) newFactor = Factor(unconditionedVariables, conditionedVariables, variableDomainsDict) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = returnFactor.getProbability( assignment) * factors[i].getProbability(assignment) newFactor.setProbability(assignment, prob) returnFactor = newFactor return returnFactor
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 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 """ 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 ***" domains = factor.variableDomainsDict() unconditioned = factor.unconditionedVariables() conditioned = factor.conditionedVariables() for variable, domain in domains.items(): if len(domain) == 1: if variable not in conditioned and variable in unconditioned: conditioned.add(variable) if variable in unconditioned: unconditioned.remove(variable) newFactor = Factor(unconditioned, conditioned, factor.variableDomainsDict()) possibleDicts = newFactor.getAllPossibleAssignmentDicts() total = 0 for p in possibleDicts: prob = factor.getProbability(p) total = total + prob for p in possibleDicts: prob = factor.getProbability(p) newFactor.setProbability(p, prob/total) return newFactor
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 ***" uncondVarSet = set() condVarSet = set() for factor in factors: for uncond in factor.unconditionedVariables(): uncondVarSet.add(uncond) for factor in factors: for cond in factor.conditionedVariables(): if cond not in uncondVarSet: condVarSet.add(cond) newFactor = Factor(uncondVarSet, condVarSet, factors[0].variableDomainsDict()) #factor[0] for assignment in newFactor.getAllPossibleAssignmentDicts(): probability = 1 for factor in factors: probability *= factor.getProbability(assignment) # retrieves the value from that factor in table to use to compute new value newFactor.setProbability(assignment, probability) #displays result on to table 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
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 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 [{'W': 'sun'}, {'W': 'rain'}] Factor.getProbability factor.getProbability({'W': 'sun'}) Factor.setProbability factor.setProbability({'W': 'sun'}, probability): Factor.unconditionedVariables ['W'] Factor.conditionedVariables [] Factor.variableDomainsDict {'D': ['wet', 'dry'], 'W': ['sun', 'rain']} P(unconditioned|conditioned) """ # 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 ***" setsOfUnconditioned = [set(factor.unconditionedVariables()) for factor in factors] setsOfUnconditioned = reduce(lambda x, y: x | y, setsOfUnconditioned) setsOfConditioned = [set(factor.conditionedVariables()) for factor in factors] setsOfConditioned = reduce(lambda x, y: x | y, setsOfConditioned) overlap = setsOfUnconditioned.intersection(setsOfConditioned) # print setsOfUnconditioned # print setsOfConditioned # print overlap setsOfUnconditioned = setsOfUnconditioned.union(overlap) setsOfConditioned = setsOfConditioned.difference(overlap) # print 'NEW unconditioned' # print setsOfUnconditioned # print 'NEW conditioned' # print setsOfConditioned domain = factor.variableDomainsDict() for factor in factors: domain.update(factor.variableDomainsDict()) newFactor = Factor(setsOfUnconditioned, setsOfConditioned, domain) for assignments in newFactor.getAllPossibleAssignmentDicts(): listP = [factor.getProbability(assignments) for factor in factors] probability = 1 for p in listP: probability *= p newFactor.setProbability(assignments, probability) return 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 ***" #print factor unconditioned = factor.unconditionedVariables() conditioned = factor.conditionedVariables() for item in unconditioned: if item == eliminationVariable: unconditioned.remove(item) for item in conditioned: if item == eliminationVariable: conditioned.remove(item) variableDomainsDict = factor.variableDomainsDict() newFactor = Factor(unconditioned, conditioned, factor.variableDomainsDict()) # print "newFactor" # print newFactor for newPossibleAssignment in newFactor.getAllPossibleAssignmentDicts(): # print("new possible assignment", newPossibleAssignment) assignment = 0 for possibleAssignment in factor.getAllPossibleAssignmentDicts(): if all(item in possibleAssignment.items() for item in newPossibleAssignment.items()): #check if newpossibleassignment is a subset of possibleassignment # print("possible assignment", possibleAssignment) prob = factor.getProbability(possibleAssignment) # print("prob", prob) assignment += prob newFactor.setProbability(newPossibleAssignment, assignment) 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 ***" setOfUnconditioned = set() setOfConditioned = set() setofVariableDomainDist = dict() for factor in factors: setOfConditioned = setOfConditioned | factor.conditionedVariables() setOfUnconditioned = setOfUnconditioned | factor.unconditionedVariables() distVa = factor.variableDomainsDict() setofVariableDomainDist = dict(setofVariableDomainDist, **distVa) setOfConditioned = setOfConditioned - (setOfConditioned & setOfUnconditioned) result = Factor(setOfUnconditioned, setOfConditioned, setofVariableDomainDist) for assignment in result.getAllPossibleAssignmentDicts(): prob = 1 for factor in factors: assignmentCopy = dict() for variable in assignment: if (variable in (factor.unconditionedVariables() | factor.conditionedVariables())): assignmentCopy[variable] = assignment[variable] prob = prob * factor.getProbability(assignmentCopy) result.setProbability(assignment, prob) return result
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())) unconditionedVariables = factor.unconditionedVariables() conditionedVariables = factor.conditionedVariables() if eliminationVariable in unconditionedVariables: unconditionedVariables.remove(eliminationVariable) if eliminationVariable in conditionedVariables: conditionedVariables.remove(eliminationVariable) # Assume that the variableDomainsDict for all the input factors are the same eliminatedFactor = Factor(unconditionedVariables, \ conditionedVariables, \ factor.variableDomainsDict()) oldAssignments = factor.getAllPossibleAssignmentDicts() for assignment in eliminatedFactor.getAllPossibleAssignmentDicts(): prob = 0 for o in oldAssignments: c = o.copy() c.pop(eliminationVariable) if assignment == c: prob += factor.getProbability(o) eliminatedFactor.setProbability(assignment, prob) return eliminatedFactor
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 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 ***" # If the sum of probabilities in the input factor is 0, # you should return None. variableDomainsDict = factor.variableDomainsDict() unconditioned = factor.unconditionedVariables() conditioned = factor.conditionedVariables() prob_sum = 0 old_assignments = factor.getAllPossibleAssignmentDicts() for row in old_assignments: prob_sum += factor.getProbability(row) if prob_sum == 0: return None for var in unconditioned: if len(variableDomainsDict[var]) == 1: conditioned.add(var) unconditioned = [var for var in unconditioned if var not in conditioned] newFactor = Factor(unconditioned, conditioned, variableDomainsDict) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = factor.getProbability(assignment) newFactor.setProbability(assignment, prob / prob_sum) 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 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))) total_conditioned_variables = set() total_unconditioned_variables = set() mega_variable_domains = {} for factor in factors: mega_variable_domains.update(factor.variableDomainsDict()) for factor in factors: for unc_var in factor.unconditionedVariables(): total_unconditioned_variables.add(unc_var) for con_var in factor.conditionedVariables(): total_conditioned_variables.add(con_var) total_conditioned_variables.difference_update(total_unconditioned_variables) new_factor = Factor(total_unconditioned_variables, total_conditioned_variables, mega_variable_domains) for ass in new_factor.getAllPossibleAssignmentDicts(): multiple = 1 for factor in factors: multiple *= factor.getProbability(ass) Factor.setProbability(new_factor, ass, multiple) return new_factor
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 ***" #It takes a Factor as input and normalizes it, that is, it scales all of the entries in the Factor such that the # sum of the entries in the Factor is 1. If the sum of probabilities in the input factor is 0, you should return None. #**If sum of p = 0, return none variableDomainsDict = factor.variableDomainsDict() uncond = factor.unconditionedVariables() cond = factor.conditionedVariables() sum = 0 old = factor.getAllPossibleAssignmentDicts() for row in old: sum += factor.getProbability(row) if sum == 0: return None for var in uncond: if len(variableDomainsDict[var]) == 1: cond.add(var) uncond = [var for var in uncond if var not in cond] """Return a new factor where the sum of the all the probabilities in the table is 1.""" newFactor = Factor(uncond, cond, variableDomainsDict) for assignment in newFactor.getAllPossibleAssignmentDicts(): prob = factor.getProbability(assignment) newFactor.setProbability(assignment, prob / sum) return 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 ***" new_unconditioned = factor.unconditionedVariables() new_unconditioned.remove(eliminationVariable) new_coditioned = factor.conditionedVariables() new_domain = {} for key in factor.variableDomainsDict().iterkeys(): if (key != eliminationVariable): new_domain[key] = factor.variableDomainsDict()[key] # new_domain = factor.variableDomainsDict() new_factor = Factor(new_unconditioned, new_coditioned, new_domain) all_new_pos = new_factor.getAllPossibleAssignmentDicts() all_old_pos = factor.getAllPossibleAssignmentDicts() for assignment in all_new_pos: prob = 0; for elim_pos in factor.variableDomainsDict()[eliminationVariable]: temp_assignment = assignment temp_assignment[eliminationVariable] = elim_pos prob += factor.getProbability(temp_assignment) new_factor.setProbability(assignment, prob) 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())) "*** 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 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 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 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 ***" unconditionedVariables = factor.unconditionedVariables() unconditionedVariables.remove(eliminationVariable) newFactor = Factor(unconditionedVariables, factor.conditionedVariables(), factor.variableDomainsDict()) factorAssignments = factor.getAllPossibleAssignmentDicts() for each in newFactor.getAllPossibleAssignmentDicts(): probability = 0 for originalEach in factorAssignments: if set(each.items()).issubset(set(originalEach.items())): probability += factor.getProbability(originalEach) newFactor.setProbability(each, probability) return newFactor util.raiseNotDefined()
def joinFactors(factors): """ Question 3: Your join implementation Changes to UC Berkeley CS188's base code written by Will Park. 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 ***" unionOfUnconditioned = reduce(lambda x, y: x | y, setsOfUnconditioned) setsOfConditioned = [ set(factor.conditionedVariables()) for factor in factors ] unionOfConditioned = reduce(lambda x, y: x | y, setsOfConditioned) for unconditionedVar in unionOfUnconditioned: if unconditionedVar in unionOfConditioned: unionOfConditioned.remove(unconditionedVar) newFactor = Factor(unionOfUnconditioned, unionOfConditioned, factors[0].variableDomainsDict()) for assignment in newFactor.getAllPossibleAssignmentDicts(): probs = [factor.getProbability(assignment) for factor in factors] prob = reduce(lambda x, y: x * y, probs) newFactor.setProbability(assignment, prob) return newFactor
def inferenceByVariableElimination(bayesNet, queryVariables, evidenceDict, eliminationOrder): """ Question 4: Your inference by variable elimination implementation This function should perform a probabilistic inference query that returns the factor: P(queryVariables | evidenceDict) It should perform inference by interleaving joining on a variable and eliminating that variable, in the order of variables according to eliminationOrder. See inferenceByEnumeration for an example on how to use these functions. You need to use joinFactorsByVariable to join all of the factors that contain a variable in order for the autograder to recognize that you performed the correct interleaving of joins and eliminates. If a factor that you are about to eliminate a variable from has only one unconditioned variable, you should not eliminate it and instead just discard the factor. This is since the result of the eliminate would be 1 (you marginalize all of the unconditioned variables), but it is not a valid factor. So this simplifies using the result of eliminate. 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. eliminationOrder: The order to eliminate the variables in. Hint: BayesNet.getAllCPTsWithEvidence will return all the Conditional Probability Tables even if an empty dict (or None) is passed in for evidenceDict. In this case it will not specialize any variable domains in the CPTs. Useful functions: BayesNet.getAllCPTsWithEvidence normalize eliminate joinFactorsByVariable joinFactors """ # this is for autograding -- don't modify joinFactorsByVariable = joinFactorsByVariableWithCallTracking(callTrackingList) eliminate = eliminateWithCallTracking(callTrackingList) if eliminationOrder is None: # set an arbitrary elimination order if None given eliminationVariables = bayesNet.variablesSet() - set(queryVariables) -\ set(evidenceDict.keys()) eliminationOrder = sorted(list(eliminationVariables)) "*** YOUR CODE HERE ***" # evidenceVariablesSet = set(evidenceDict.keys()) # queryVariablesSet = set(queryVariables) # print evidenceVariablesSet # print queryVariables # print eliminationOrder currentFactorsList = bayesNet.getAllCPTsWithEvidence(evidenceDict) for elim_var in eliminationOrder: currentFactorsList, joinedFactor = joinFactorsByVariable(currentFactorsList, elim_var) if (len(joinedFactor.unconditionedVariables()) > 1): elim_factor = eliminate(joinedFactor, elim_var) currentFactorsList.append(elim_factor) fullJointOverQueryAndEvidence = joinFactors(currentFactorsList) queryConditionedOnEvidence = normalize(fullJointOverQueryAndEvidence) set_of_unconditioned = set(queryVariables) set_Of_variables = set(queryConditionedOnEvidence.variables()) variable_domains = queryConditionedOnEvidence.variableDomainsDict() set_of_conditioned = set_Of_variables - set_of_unconditioned new_factor = Factor(list(set_of_unconditioned), list(set_of_conditioned), variable_domains) all_possible_assignments = new_factor.getAllPossibleAssignmentDicts() for assignment in all_possible_assignments: prob = queryConditionedOnEvidence.getProbability(assignment) new_factor.setProbability(assignment, prob) #print queryConditionedOnEvidence.unconditionedVariables() #print queryConditionedOnEvidence.conditionedVariables() 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))) "*** 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 ***" initSumProbs = 0.0 #initial sum of all entry probs for assignment in factor.getAllPossibleAssignmentDicts(): initSumProbs = initSumProbs + factor.getProbability(assignment) listOfOneEntryVars = [] # list of unconditioned variables with exactly 1 entry in their domains for variable in factor.unconditionedVariables(): if len(factor.variableDomainsDict()[variable]) == 1: listOfOneEntryVars.append(variable) newUnconditionedVars = set() newConditionedVars = set() for variable in factor.conditionedVariables(): newConditionedVars.add(variable) for variable in listOfOneEntryVars: newConditionedVars.add(variable) for variable in factor.unconditionedVariables(): if variable not in listOfOneEntryVars: newUnconditionedVars.add(variable) normalizedFactor = Factor(newUnconditionedVars, newConditionedVars, factor.variableDomainsDict()) for assignment in normalizedFactor.getAllPossibleAssignmentDicts(): normalizedProb = factor.getProbability(assignment) / initSumProbs normalizedFactor.setProbability(assignment, normalizedProb) return normalizedFactor
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 ***" set_of_unconditioned = set(factors[0].unconditionedVariables()) set_Of_variables = set(factors[0].variables()) variable_domains = factors[0].variableDomainsDict() for factor in factors[1:]: for var in factor.variables(): set_Of_variables.add(var) for var in factor.unconditionedVariables(): set_of_unconditioned.add(var) set_of_conditioned = set_Of_variables - set_of_unconditioned new_factor = Factor(list(set_of_unconditioned), list(set_of_conditioned), variable_domains) #print isinstance(new_factor, Factor) all_possible_assignments = new_factor.getAllPossibleAssignmentDicts() for assignment in all_possible_assignments: prob = factors[0].getProbability(assignment) for factor in factors[1:]: prob = prob * factor.getProbability(assignment) #print prob new_factor.setProbability(assignment, prob) return new_factor
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 ***" # Unconditioned variables with exactly one entry in their domain become # conditioned variables newConditionedVariables = set([v for v in \ factor.variableDomainsDict() if \ v in factor.unconditionedVariables() and \ len(factor.variableDomainsDict()[v]) == 1]) normalizedFactor = Factor(factor.unconditionedVariables() - \ newConditionedVariables, factor.conditionedVariables() | \ newConditionedVariables, factor.variableDomainsDict()) probSum = sum([factor.getProbability(assignment) for assignment in \ factor.getAllPossibleAssignmentDicts()]) if probSum == 0: return None # Set normalized probabilities for assignment in normalizedFactor.getAllPossibleAssignmentDicts(): normalizedFactor.setProbability(assignment, factor.getProbability(assignment) / \ probSum) return normalizedFactor
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)) ) "*** 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 = [] conditioned = [] variableDomainsDict = {} if factors and len(factors) > 0: variableDomainsDict = factors[0].variableDomainsDict() for f in factors: temp_unconditioned = f.unconditionedVariables() temp_conditioned = f.conditionedVariables() unconditioned.extend(temp_unconditioned) for conditioned_var in temp_conditioned: if conditioned_var not in conditioned: conditioned.append(conditioned_var) conditioned = [var for var in conditioned if var not in unconditioned] newFactor = Factor(unconditioned, conditioned, variableDomainsDict) assignments = newFactor.getAllPossibleAssignmentDicts() for assignment in assignments: prob = 1 for factor in factors: prob *= factor.getProbability(assignment) newFactor.setProbability(assignment, 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 ***" # for factor in factors: # print factor # get the unconditioned and conditioned variables. unconditioned = set() conditioned = set() for factor in factors: for eachVar in factor.unconditionedVariables(): unconditioned.add(eachVar) # only variables not unconditioned will be considered conditioned for factor in factors: for eachVar in factor.conditionedVariables(): if not eachVar in unconditioned: conditioned.add(eachVar) # build a new blank factor variableDomainsDict = factors[0].variableDomainsDict() newFactor = Factor(unconditioned, conditioned, variableDomainsDict) # test assignmentDicts assignmentDicts = newFactor.getAllPossibleAssignmentDicts() for assignment in assignmentDicts: prob = 1.0 for factor in factors: prob *= factor.getProbability(assignment) newFactor.setProbability(assignment, prob) # print newFactor 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 ***" 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 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))) listOfUnconditioned = [] for factor in factors: for variable in factor.unconditionedVariables(): if variable not in listOfUnconditioned: listOfUnconditioned.append(variable) listOfConditioned = [] for factor in factors: for variable in factor.conditionedVariables(): if variable not in listOfUnconditioned and variable not in listOfConditioned: listOfConditioned.append(variable) newFactor = Factor(listOfUnconditioned, listOfConditioned, factors[0].variableDomainsDict()) for assignment in newFactor.getAllPossibleAssignmentDicts(): possibility = 1 for factor in factors: possibility = possibility * factor.getProbability(assignment) newFactor.setProbability(assignment, possibility) return newFactor