def test_missing_scenario_name(self): G = networkx.DiGraph() G.add_node("R", name="Root") G.add_node("C") G.add_edge("R", "C", weight=1) with self.assertRaises(KeyError): ScenarioTreeModelFromNetworkX(G, scenario_name_attribute="name")
def test_bundles(self): G = networkx.DiGraph() G.add_node("r") for i in range(4): G.add_node("u" + str(i), bundle=i % 2) G.add_edge("r", "u" + str(i)) model = ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None) self.assertEqual(sorted(list(model.Stages)), sorted(["Stage1", "Stage2"])) self.assertEqual(sorted(list(model.Nodes)), sorted(["r", "u0", "u1", "u2", "u3"])) self.assertEqual(sorted(list(model.Children["r"])), sorted(["u0", "u1", "u2", "u3"])) for i in range(4): self.assertEqual(sorted(list(model.Children["u" + str(i)])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted(["u0", "u1", "u2", "u3"])) self.assertEqual(value(model.ConditionalProbability["r"]), 1.0) for i in range(4): self.assertEqual(value(model.ConditionalProbability["u" + str(i)]), 0.25) self.assertEqual(model.Bundling.value, True) self.assertEqual(list(model.Bundles), [0, 1]) for k, bundle_name in enumerate(model.Bundles): self.assertEqual(list(model.BundleScenarios[bundle_name]), ["u" + str(i) for i in range(4) if i % 2 == k]) model.StageCost["Stage1"] = "c1" model.StageCost["Stage2"] = "c2" model.StageVariables["Stage1"].add("x") ScenarioTree(scenariotreeinstance=model)
def test_two_stage(self): G = networkx.DiGraph() G.add_node("Root") G.add_node("Child1") G.add_edge("Root", "Child1", weight=0.8) G.add_node("Child2") G.add_edge("Root", "Child2", weight=0.2) model = ScenarioTreeModelFromNetworkX(G) self.assertEqual(sorted(list(model.Stages)), sorted(["Stage1", "Stage2"])) self.assertEqual(sorted(list(model.Nodes)), sorted(["Root", "Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Root"])), sorted(["Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Child1"])), sorted([])) self.assertEqual(sorted(list(model.Children["Child2"])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted(["Child1", "Child2"])) self.assertEqual(value(model.ConditionalProbability["Root"]), 1.0) self.assertEqual(value(model.ConditionalProbability["Child1"]), 0.8) self.assertEqual(value(model.ConditionalProbability["Child2"]), 0.2) model.StageCost["Stage1"] = "c1" model.StageCost["Stage2"] = "c2" model.StageVariables["Stage1"].add("x") self.assertEqual(model.Bundling.value, False) self.assertEqual(list(model.Bundles), []) self.assertEqual(len(model.BundleScenarios), 0) ScenarioTree(scenariotreeinstance=model)
def test_two_stage_custom_names(self): G = networkx.DiGraph() G.add_node("R", label="Root") G.add_node("C1", label="Child1", scenario="S1") G.add_edge("R", "C1", probability=0.8) G.add_node("C2", label="Child2", scenario="S2") G.add_edge("R", "C2", probability=0.2) model = ScenarioTreeModelFromNetworkX( G, edge_probability_attribute="probability", node_name_attribute="label", stage_names=["T1", "T2"], scenario_name_attribute="scenario") self.assertEqual(sorted(list(model.Stages)), sorted(["T1", "T2"])) self.assertEqual(sorted(list(model.Nodes)), sorted(["Root", "Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Root"])), sorted(["Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Child1"])), sorted([])) self.assertEqual(sorted(list(model.Children["Child2"])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted(["S1", "S2"])) self.assertEqual(value(model.ConditionalProbability["Root"]), 1.0) self.assertEqual(value(model.ConditionalProbability["Child1"]), 0.8) self.assertEqual(value(model.ConditionalProbability["Child2"]), 0.2) model.StageCost["T1"] = "c1" model.StageCost["T2"] = "c2" model.StageVariables["T1"].add("x") self.assertEqual(model.Bundling.value, False) self.assertEqual(list(model.Bundles), []) self.assertEqual(len(model.BundleScenarios), 0) ScenarioTree(scenariotreeinstance=model)
def test_bad_custom_stage_names2(self): G = networkx.DiGraph() G.add_node("R") G.add_node("C1") G.add_edge("R", "C1", weight=1.0) with self.assertRaises(ValueError): ScenarioTreeModelFromNetworkX(G, stage_names=["Stage1", "Stage1"])
def test_bad_weight1(self): G = networkx.DiGraph() G.add_node("R", ) G.add_node("C", ) G.add_edge("R", "C", weight=0.8) with self.assertRaises(ValueError): ScenarioTreeModelFromNetworkX(G)
def test_missing_weight(self): G = networkx.DiGraph() G.add_node("R", name="Root") G.add_node("C", name="Child") G.add_edge("R", "C") with self.assertRaises(KeyError): ScenarioTreeModelFromNetworkX(G)
def test_not_tree(self): G = networkx.DiGraph() G.add_node("1") G.add_node("2") G.add_edge("1", "2") G.add_edge("2", "1") with self.assertRaises(TypeError): ScenarioTreeModelFromNetworkX(G)
def test_two_stage_more_node_attributes(self): G = networkx.DiGraph() G.add_node("Root", cost="c1", variables=["x"], derived_variables=["y"]) G.add_node("Child1", cost="c2", variables=["q"], derived_variables=["z"]) G.add_edge("Root", "Child1", weight=0.8) G.add_node("Child2", cost="c2", variables=["q"], derived_variables=["z"]) G.add_edge("Root", "Child2", weight=0.2) model = ScenarioTreeModelFromNetworkX(G) self.assertEqual(sorted(list(model.Stages)), sorted(["Stage1", "Stage2"])) self.assertEqual(sorted(list(model.Nodes)), sorted(["Root", "Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Root"])), sorted(["Child1", "Child2"])) self.assertEqual(sorted(list(model.Children["Child1"])), sorted([])) self.assertEqual(sorted(list(model.Children["Child2"])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted(["Child1", "Child2"])) self.assertEqual(value(model.ConditionalProbability["Root"]), 1.0) self.assertEqual(value(model.ConditionalProbability["Child1"]), 0.8) self.assertEqual(value(model.ConditionalProbability["Child2"]), 0.2) self.assertEqual(model.StageCost["Stage1"].value, None) self.assertEqual(list(model.StageVariables["Stage1"]), []) self.assertEqual(list(model.StageDerivedVariables["Stage1"]), []) self.assertEqual(model.NodeCost["Root"].value, "c1") self.assertEqual(list(model.NodeVariables["Root"]), ["x"]) self.assertEqual(list(model.NodeDerivedVariables["Root"]), ["y"]) self.assertEqual(model.StageCost["Stage2"].value, None) self.assertEqual(list(model.StageVariables["Stage2"]), []) self.assertEqual(list(model.StageDerivedVariables["Stage2"]), []) self.assertEqual(model.NodeCost["Child1"].value, "c2") self.assertEqual(list(model.NodeVariables["Child1"]), ["q"]) self.assertEqual(list(model.NodeDerivedVariables["Child1"]), ["z"]) self.assertEqual(model.NodeCost["Child2"].value, "c2") self.assertEqual(list(model.NodeVariables["Child2"]), ["q"]) self.assertEqual(list(model.NodeDerivedVariables["Child2"]), ["z"]) self.assertEqual(model.Bundling.value, False) self.assertEqual(list(model.Bundles), []) self.assertEqual(len(model.BundleScenarios), 0) ScenarioTree(scenariotreeinstance=model)
def test_multi_stage(self): G = networkx.balanced_tree(3, 2, networkx.DiGraph()) model = ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None) self.assertEqual(sorted(list(model.Stages)), sorted(["Stage1", "Stage2", "Stage3"])) self.assertEqual(sorted(list(model.Nodes)), sorted([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])) self.assertEqual(sorted(list(model.Children[0])), sorted([1, 2, 3])) self.assertEqual(sorted(list(model.Children[1])), sorted([4, 5, 6])) self.assertEqual(sorted(list(model.Children[2])), sorted([7, 8, 9])) self.assertEqual(sorted(list(model.Children[3])), sorted([10, 11, 12])) self.assertEqual(sorted(list(model.Children[4])), sorted([])) self.assertEqual(sorted(list(model.Children[5])), sorted([])) self.assertEqual(sorted(list(model.Children[6])), sorted([])) self.assertEqual(sorted(list(model.Children[7])), sorted([])) self.assertEqual(sorted(list(model.Children[8])), sorted([])) self.assertEqual(sorted(list(model.Children[9])), sorted([])) self.assertEqual(sorted(list(model.Children[10])), sorted([])) self.assertEqual(sorted(list(model.Children[11])), sorted([])) self.assertEqual(sorted(list(model.Children[12])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted([4, 5, 6, 7, 8, 9, 10, 11, 12])) self.assertEqual(value(model.ConditionalProbability[0]), 1.0) self.assertAlmostEqual(value(model.ConditionalProbability[1]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[2]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[3]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[4]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[5]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[6]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[7]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[8]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[9]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[10]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[11]), 1.0 / 3) self.assertAlmostEqual(value(model.ConditionalProbability[12]), 1.0 / 3) model.StageCost["Stage1"] = "c1" model.StageCost["Stage2"] = "c2" model.StageCost["Stage3"] = "c3" model.StageVariables["Stage1"].add("x") model.StageVariables["Stage2"].add("y") model.StageVariables["Stage3"].add("y") self.assertEqual(model.Bundling.value, False) self.assertEqual(list(model.Bundles), []) self.assertEqual(len(model.BundleScenarios), 0) ScenarioTree(scenariotreeinstance=model)
def test_bundles_incomplete(self): G = networkx.DiGraph() G.add_node("r") for i in range(4): G.add_node("u" + str(i), bundle="B") G.add_edge("r", "u" + str(i)) model = ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None) self.assertEqual(model.Bundling.value, True) self.assertEqual(list(model.Bundles), ["B"]) self.assertEqual(list(model.BundleScenarios["B"]), ["u" + str(i) for i in range(4)]) G.nodes["u0"]["bundle"] = None with self.assertRaises(ValueError): ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None) del G.nodes["u0"]["bundle"] with self.assertRaises(ValueError): ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None)
def test_unbalanced(self): G = networkx.DiGraph() G.add_node("R") G.add_node("0") G.add_node("1") G.add_edge("R", "0") G.add_edge("R", "1") G.add_node("00") G.add_node("01") G.add_edge("0", "00") G.add_edge("0", "01") model = ScenarioTreeModelFromNetworkX(G, edge_probability_attribute=None) self.assertEqual(sorted(list(model.Stages)), sorted(["Stage1", "Stage2", "Stage3"])) self.assertEqual(sorted(list(model.Nodes)), sorted(["R", "0", "1", "00", "01"])) self.assertEqual(sorted(list(model.Children["R"])), sorted(["0", "1"])) self.assertEqual(sorted(list(model.Children["0"])), sorted(["00", "01"])) self.assertEqual(sorted(list(model.Children["1"])), sorted([])) self.assertEqual(sorted(list(model.Children["00"])), sorted([])) self.assertEqual(sorted(list(model.Children["01"])), sorted([])) self.assertEqual(sorted(list(model.Scenarios)), sorted(["00", "01", "1"])) self.assertEqual(value(model.ConditionalProbability["R"]), 1.0) self.assertEqual(value(model.ConditionalProbability["0"]), 0.5) self.assertEqual(value(model.ConditionalProbability["1"]), 0.5) self.assertEqual(value(model.ConditionalProbability["00"]), 0.5) self.assertEqual(value(model.ConditionalProbability["01"]), 0.5) model.StageCost["Stage1"] = "c1" model.StageCost["Stage2"] = "c2" model.StageCost["Stage3"] = "c3" model.StageVariables["Stage1"].add("x") model.StageVariables["Stage2"].add("x") self.assertEqual(model.Bundling.value, False) self.assertEqual(list(model.Bundles), []) self.assertEqual(len(model.BundleScenarios), 0) ScenarioTree(scenariotreeinstance=model)
def get_factory(): tree = networkx.DiGraph() tree.add_node("r", variables=["x"], cost="t0_cost") for i in range(3): tree.add_node("s" + str(i), variables=["Y", "stale", "fixed"], cost="t1_cost", bundle="b" + str(i)) tree.add_edge("r", "s" + str(i), weight=1.0 / 3) model = aml.ConcreteModel() model.x = aml.Var() model.Y = aml.Var([1], bounds=(None, 1)) model.stale = aml.Var(initialize=0.0) model.fixed = aml.Var(initialize=0.0) model.fixed.fix() model.p = aml.Param(mutable=True) model.t0_cost = aml.Expression(expr=model.x) model.t1_cost = aml.Expression(expr=model.Y[1]) model.o = aml.Objective(expr=model.t0_cost + model.t1_cost) model.c = aml.ConstraintList() model.c.add(model.x >= 1) model.c.add(model.Y[1] >= model.p) def _create_model(scenario_name, node_names): m = model.clone() if scenario_name == "s0": m.p.value = 0.0 elif scenario_name == "s1": m.p.value = 1.0 else: assert (scenario_name == "s2") m.p.value = 2.0 return m return ScenarioTreeInstanceFactory(model=_create_model, scenario_tree=tree)
def test_not_enough_stages(self): G = networkx.DiGraph() G.add_node("R") with self.assertRaises(ValueError): ScenarioTreeModelFromNetworkX(G)
def test_empty(self): G = networkx.DiGraph() with self.assertRaises(networkx.NetworkXPointlessConcept): ScenarioTreeModelFromNetworkX(G)
def block_triangularize(matrix, matching=None): """ Computes the necessary information to permute a matrix to block-lower triangular form, i.e. a partition of rows and columns into an ordered set of diagonal blocks in such a permutation. Arguments --------- matrix: A SciPy sparse matrix matching: A perfect matching of rows and columns, in the form of a dict mapping row indices to column indices Returns ------- Two dicts. The first maps each row index to the index of its block in a block-lower triangular permutation of the matrix. The second maps each column index to the index of its block in a block-lower triangular permutation of the matrix. """ nxb = nx.algorithms.bipartite nxc = nx.algorithms.components nxd = nx.algorithms.dag from_biadjacency_matrix = nxb.matrix.from_biadjacency_matrix M, N = matrix.shape if M != N: raise ValueError( "block_triangularize does not currently " "support non-square matrices. Got matrix with shape %s." % (matrix.shape, )) bg = from_biadjacency_matrix(matrix) if matching is None: matching = maximum_matching(matrix) len_matching = len(matching) if len_matching != M: raise ValueError("block_triangularize only supports matrices " "that have a perfect matching of rows and columns. " "Cardinality of maximal matching is %s" % len_matching) # Construct directed graph of rows dg = nx.DiGraph() dg.add_nodes_from(range(M)) for n in dg.nodes: col_idx = matching[n] col_node = col_idx + M # For all rows that share this column for neighbor in bg[col_node]: if neighbor != n: # Add an edge towards this column's matched row dg.add_edge(neighbor, n) # Partition the rows into strongly connected components (diagonal blocks) scc_list = list(nxc.strongly_connected_components(dg)) node_scc_map = {n: idx for idx, scc in enumerate(scc_list) for n in scc} # Now we need to put the SCCs in the right order. We do this by performing # a topological sort on the DAG of SCCs. dag = nx.DiGraph() for i, c in enumerate(scc_list): dag.add_node(i) for n in dg.nodes: source_scc = node_scc_map[n] for neighbor in dg[n]: target_scc = node_scc_map[neighbor] if target_scc != source_scc: dag.add_edge(target_scc, source_scc) # Reverse direction of edge. This corresponds to creating # a block lower triangular matrix. scc_order = list(nxd.lexicographical_topological_sort(dag)) scc_block_map = {c: i for i, c in enumerate(scc_order)} row_block_map = {n: scc_block_map[c] for n, c in node_scc_map.items()} # ^ This maps row indices to the blocks they belong to. # Invert the matching to map row indices to column indices col_row_map = {c: r for r, c in matching.items()} assert len(col_row_map) == M col_block_map = {c: row_block_map[col_row_map[c]] for c in range(N)} return row_block_map, col_block_map