Spooky / quantum /map.py
JavideuS's picture
Deploy 888d5f7
e516f1f verified
Raw
History Blame Contribute Delete
7.7 kB
import numpy as np
class Grid:
def __init__(self, M, N, obstacles=None, terrain=None, elevation=None,
materials=None, materials_data=None, resolution=1.0, name="unnamed"):
self.M = M
self.N = N
self.moves = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 4-connectivity
self.obstacles = obstacles or []
self.terrain = terrain # 2D numpy array of material indices (optional)
self.elevation = elevation # 2D numpy array of heights (optional)
# List: index → material_name
self.materials = materials if materials is not None else []
self.materials_data = materials_data if materials_data is not None else {}
self.adjacency = self.build_adjacency()
self.name = name
self.resolution = resolution # meters per grid cell
@classmethod
def from_dict(cls, grid_dict):
"""
Create a Grid instance from a dictionary (for config file setup).
It receives problem section from config file
and extracts grid parameters.
"""
M = grid_dict["grid"]["M"]
N = grid_dict["grid"]["N"]
obstacles = grid_dict["grid"]["obstacles"]
materials = grid_dict.get("materials", [])
materials_data = grid_dict.get("materials_data", {})
return cls(M, N, obstacles=obstacles, materials=materials,
materials_data=materials_data,
name=grid_dict.get("name", "unnamed"))
@classmethod
def from_hdf5_data(cls, map_data, materials_data=None, name=None):
"""
Create Grid from HDF5-loaded data dict.
Args:
map_data: dict from load_map_from_hdf5()
"""
M = map_data['grid']['M']
N = map_data['grid']['N']
obstacles = map_data['grid']['obstacles']
# Optional layers
terrain_grid = map_data.get('terrain_grid')
elevation_grid = map_data.get('elevation_grid')
materials = map_data.get('materials', []) # if you pass material list
resolution = map_data.get('resolution', 1.0)
return cls(
M=M,
N=N,
obstacles=obstacles,
terrain=terrain_grid,
elevation=elevation_grid,
materials=materials,
materials_data=materials_data,
resolution=resolution,
name=name or map_data.get('name', 'unnamed')
)
def to_dict(self):
"""
Convert the grid instance to a dictionary representation.
"""
return {
"M": self.M,
"N": self.N,
"obstacles": self.obstacles,
"adjacency": self.adjacency,
}
def build_adjacency(self):
adjacency = {}
for i in range(self.M):
for j in range(self.N):
# Skip if the position is in obstacles
# if (i, j) in self.obstacles:
# continue
neighbors = []
for di, dj in self.moves:
ni, nj = i + di, j + dj
if 0 <= ni < self.M and 0 <= nj < self.N:
# Skip if the position is in obstacles
if (ni, nj) in self.obstacles:
continue
neighbors.append((ni, nj))
adjacency[(i, j)] = neighbors
return adjacency
def get_terrain_at(self, i, j):
"""Get material index at cell (i,j)"""
if self.terrain is not None:
return self.terrain[i, j]
return None
def get_elevation_at(self, i, j):
"""Get elevation at cell (i,j)"""
if self.elevation is not None:
return self.elevation[i, j]
return None
def get_material_name(self, index):
"""Convert material index to name"""
if self.materials is None or len(self.materials) == 0:
return "unknown"
if 0 <= index < len(self.materials):
return self.materials[index]
return "unknown"
def get_unique_materials_in_map(self):
"""Get list of material names actually present in this map"""
if self.terrain is not None:
unique_indices = np.unique(self.terrain)
return [self.get_material_name(idx) for idx in unique_indices]
return []
def get_material_cost(self, index):
"""Get cost of material by index"""
name = self.get_material_name(index)
return self.materials_data[name].get("cost", 6.0)
def get_color(self, index):
"""Get color of material by name"""
name = self.get_material_name(index)
return self.materials_data[name].get("color", "white")
class Graph:
"""Graph representation for pathfinding problems."""
def __init__(self, nodes, edges, weights=None, name="unnamed"):
"""
Initialize a graph with nodes and edges.
Args:
nodes: List of (x, y) coordinates or node data
edges: List of (i, j) or (i, j, weight) tuples
weights: Optional edge weights (if not provided in edges)
name: Graph name
"""
self.nodes = nodes
self.edges = edges
self.weights = weights or {}
self.name = name
self.adjacency = self._build_adjacency()
def _build_adjacency(self):
"""Build adjacency list from edges."""
adjacency = {}
for i in range(len(self.nodes)):
adjacency[i] = set()
for edge in self.edges:
if len(edge) == 2:
i, j = edge
i = int(i)
j = int(j)
weight = 1.0
else:
i, j, weight = edge
i = int(i)
j = int(j)
weight = float(weight)
if i < len(self.nodes) and j < len(self.nodes):
adjacency[i].add((j, weight))
# For undirected graphs, add both directions
adjacency[j].add((i, weight))
return adjacency
@classmethod
def from_hdf5_data(cls, graph_data, name=None):
"""Create Graph from HDF5-loaded data dict."""
nodes = graph_data.get('nodes', [])
edges = graph_data.get('edges', [])
resolution = graph_data.get('resolution', 1.0)
return cls(
nodes=nodes,
edges=edges,
name=name or graph_data.get('name', 'unnamed')
)
def get_node_position(self, node_id):
"""Get (x, y) position of a node."""
if 0 <= node_id < len(self.nodes):
return tuple(self.nodes[node_id])
return None
def get_node_from_position(self, position):
"""Get node index from (x, y) position."""
for idx, pos in enumerate(self.nodes):
if tuple(pos) == tuple(position):
return idx
return None
def get_edge_weight(self, i, j):
"""Get weight of edge between nodes i and j."""
for edge in self.edges:
if len(edge) == 2:
if (edge[0] == i and edge[1] == j) or (edge[0] == j and edge[1] == i):
return 1.0
else:
if (edge[0] == i and edge[1] == j) or (edge[0] == j and edge[1] == i):
return edge[2]
return float('inf') # No edge exists
def to_dict(self):
"""Convert to dictionary representation."""
return {
"nodes": self.nodes,
"edges": self.edges,
"name": self.name
}