diff --git a/README.md b/README.md index 0530530..f2abd25 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ can be constructed using NumPy arrays and vectors. Utilizing NumPy and matrix operations allows for a much faster construction of the BQM than building it with for-loops. As problem instances become larger and larger, it becomes more and more important to efficiently build the BQM to save time in the -initilization and setup of the model. The chart below demonstrates the savings +initialization and setup of the model. The chart below demonstrates the savings in classical compute time when setting up the BQM for this problem using for-loops versus using efficient NumPy operations in the Leap IDE. diff --git a/demo.py b/demo.py index 7ce9956..ce3be22 100644 --- a/demo.py +++ b/demo.py @@ -28,7 +28,7 @@ import matplotlib.pyplot as plt def read_in_args(): - """ Read in user specified parameters or use defaults.""" + """Read in user specified parameters or use defaults.""" # Set up user-specified optional arguments parser = argparse.ArgumentParser() @@ -67,22 +67,17 @@ def set_up_scenario(w, h, num_poi, num_cs): """Build scenario set up with specified parameters. Args: - w (int): - Width of grid - h (int): - Height of grid - num_poi (int): - Number of points of interest - num_cs (int): - Number of existing charging stations + w (int): Width of grid + h (int): Height of grid + num_poi (int): Number of points of interest + num_cs (int): Number of existing charging stations + Returns: - G (networkx graph): - Grid graph of size w by h - pois (list of tuples of ints): - A fixed set of points of interest - charging_stations (list of tuples of ints): - A fixed set of current charging locations - potential_new_cs_nodes (list of tuples of ints): + G (networkx graph): Grid graph of size w by h + pois (list of tuples of ints): A fixed set of points of interest + charging_stations (list of tuples of ints): + Set of current charging locations + potential_new_cs_nodes (list of tuples of ints): Potential new charging locations """ @@ -109,19 +104,15 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, Args: potential_new_cs_nodes (list of tuples of ints): Potential new charging locations - num_poi (int): - Number of points of interest - pois (list of tuples of ints): - A fixed set of points of interest - num_cs (int): - Number of existing charging stations - charging_stations (list of tuples of ints): - A fixed set of current charging locations - num_new_cs (int): - Number of new charging stations desired + num_poi (int): Number of points of interest + pois (list of tuples of ints): A fixed set of points of interest + num_cs (int): Number of existing charging stations + charging_stations (list of tuples of ints): + Set of current charging locations + num_new_cs (int): Number of new charging stations desired + Returns: - bqm_np (BinaryQuadraticModel): - QUBO model for the input scenario + bqm_np (BinaryQuadraticModel): QUBO model for the input scenario """ # Tunable parameters @@ -169,16 +160,14 @@ def run_bqm_and_collect_solutions(bqm, sampler, potential_new_cs_nodes, **kwargs """Solve the bqm with the provided sampler to find new charger locations. Args: - bqm (BinaryQuadraticModel): - The QUBO model for the problem instance - sampler: - Sampler or solver to be used - potential_new_cs_nodes (list of tuples of ints): + bqm (BinaryQuadraticModel): The QUBO model for the problem instance + sampler: Sampler or solver to be used + potential_new_cs_nodes (list of tuples of ints): Potential new charging locations - **kwargs: - Sampler-specific parameters to be used + **kwargs: Sampler-specific parameters to be used + Returns: - new_charging_nodes (list of tuples of ints): + new_charging_nodes (list of tuples of ints): Locations of new charging stations """ @@ -195,18 +184,15 @@ def printout_solution_to_cmdline(pois, num_poi, charging_stations, num_cs, new_c """Print solution statistics to command line. Args: - pois (list of tuples of ints): - A fixed set of points of interest - num_poi (int): - Number of points of interest - charging_stations (list of tuples of ints): + pois (list of tuples of ints): A fixed set of points of interest + num_poi (int): Number of points of interest + charging_stations (list of tuples of ints): A fixed set of current charging locations - num_cs (int): - Number of existing charging stations - new_charging_nodes (list of tuples of ints): + num_cs (int): Number of existing charging stations + new_charging_nodes (list of tuples of ints): Locations of new charging stations - num_new_cs (int): - Number of new charging stations desired + num_new_cs (int): Number of new charging stations desired + Returns: None. """ @@ -241,14 +227,13 @@ def save_output_image(G, pois, charging_stations, new_charging_nodes): - Blue nodes: new charger locations Args: - G (networkx graph): - Grid graph of size w by h - pois (list of tuples of ints): - A fixed set of points of interest - charging_stations (list of tuples of ints): + G (networkx graph): Grid graph of size w by h + pois (list of tuples of ints): A fixed set of points of interest + charging_stations (list of tuples of ints): A fixed set of current charging locations - new_charging_nodes (list of tuples of ints): + new_charging_nodes (list of tuples of ints): Locations of new charging stations + Returns: None. Output saved to file "map.png". """ diff --git a/demo_numpy.py b/demo_numpy.py index 81710a9..cb616b4 100644 --- a/demo_numpy.py +++ b/demo_numpy.py @@ -22,21 +22,17 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, """Build bqm that models our problem scenario using NumPy. Args: - potential_new_cs_nodes (list of tuples of ints): + potential_new_cs_nodes (list of tuples of ints): Potential new charging locations - num_poi (int): - Number of points of interest - pois (list of tuples of ints): - A fixed set of points of interest - num_cs (int): - Number of existing charging stations - charging_stations (list of tuples of ints): + num_poi (int): Number of points of interest + pois (list of tuples of ints): A fixed set of points of interest + num_cs (int): Number of existing charging stations + charging_stations (list of tuples of ints): A fixed set of current charging locations - num_new_cs (int): - Number of new charging stations desired + num_new_cs (int): Number of new charging stations desired + Returns: - bqm_np (BinaryQuadraticModel): - QUBO model for the input scenario + bqm_np (BinaryQuadraticModel): QUBO model for the input scenario """ # Tunable parameters @@ -56,21 +52,27 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, # Constraint 1: Min average distance to POIs if num_poi > 0: - ct_matrix = np.matmul(nodes_array, pois_array.T)*(-2.) + np.sum(np.square(pois_array), axis=1).astype(float) + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float) + ct_matrix = (np.matmul(nodes_array, pois_array.T)*(-2.) + + np.sum(np.square(pois_array), axis=1).astype(float) + + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float)) linear += np.sum(ct_matrix, axis=1) / num_poi * gamma1 # Constraint 2: Max distance to existing chargers if num_cs > 0: - dist_mat = np.matmul(nodes_array, cs_array.T)*(-2.) + np.sum(np.square(cs_array), axis=1).astype(float) + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float) + dist_mat = (np.matmul(nodes_array, cs_array.T)*(-2.) + + np.sum(np.square(cs_array), axis=1).astype(float) + + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float)) linear += -1 * np.sum(dist_mat, axis=1) / num_cs * gamma2 # Constraint 3: Max distance to other new charging locations if num_new_cs > 1: - dist_mat = ((np.matmul(nodes_array, nodes_array.T)*(-2.) + np.sum(np.square(nodes_array), axis=1)).astype(float) + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float)) * -gamma3 + dist_mat = -gamma3*((np.matmul(nodes_array, nodes_array.T)*(-2.) + + np.sum(np.square(nodes_array), axis=1)).astype(float) + + np.sum(np.square(nodes_array), axis=1).reshape(-1,1).astype(float)) # Constraint 4: Choose exactly num_new_cs new charging locations linear += (1-2*num_new_cs)*gamma4 @@ -78,13 +80,17 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, dist_mat = np.triu(dist_mat, k=1).flatten() quad_col = np.tile(np.arange(len(potential_new_cs_nodes)), len(potential_new_cs_nodes)) - quad_row = np.tile(np.arange(len(potential_new_cs_nodes)), (len(potential_new_cs_nodes),1)).flatten('F') + quad_row = np.tile(np.arange(len(potential_new_cs_nodes)), + (len(potential_new_cs_nodes),1)).flatten('F') q2 = quad_col[dist_mat != 0] q1 = quad_row[dist_mat != 0] q3 = dist_mat[dist_mat != 0] - bqm_np = dimod.BinaryQuadraticModel.from_numpy_vectors(linear=linear, quadratic=(q1, q2, q3), offset=0, vartype=dimod.BINARY) + bqm_np = dimod.BinaryQuadraticModel.from_numpy_vectors(linear=linear, + quadratic=(q1, q2, q3), + offset=0, + vartype=dimod.BINARY) return bqm_np @@ -94,10 +100,18 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, args = demo.read_in_args() # Build large grid graph for city - G, pois, charging_stations, potential_new_cs_nodes = demo.set_up_scenario(args.width, args.height, args.poi, args.chargers) + G, pois, charging_stations, potential_new_cs_nodes = demo.set_up_scenario(args.width, + args.height, + args.poi, + args.chargers) # Build BQM - bqm = build_bqm(potential_new_cs_nodes, args.poi, pois, args.chargers, charging_stations, args.new_chargers) + bqm = build_bqm(potential_new_cs_nodes, + args.poi, + pois, + args.chargers, + charging_stations, + args.new_chargers) # Run BQM on HSS sampler = LeapHybridSampler() @@ -106,7 +120,12 @@ def build_bqm(potential_new_cs_nodes, num_poi, pois, num_cs, charging_stations, new_charging_nodes = demo.run_bqm_and_collect_solutions(bqm, sampler, potential_new_cs_nodes) # Print results to commnand-line for user - demo.printout_solution_to_cmdline(pois, args.poi, charging_stations, args.chargers, new_charging_nodes, args.new_chargers) + demo.printout_solution_to_cmdline(pois, + args.poi, + charging_stations, + args.chargers, + new_charging_nodes, + args.new_chargers) # Create scenario output image demo.save_output_image(G, pois, charging_stations, new_charging_nodes) \ No newline at end of file