[docs]classTableLattice:""" A class for performing interpolation over a lattice of data points using Delaunay triangulation. This class is useful for interpolating data stored in an OPAT object, which contains index vectors and associated data cards. It builds a Delaunay triangulation of the index vectors and allows querying for interpolated data cards based on a given query vector. Parameters ---------- opat : OPAT The OPAT object containing index vectors and associated data cards. Attributes ---------- opat : OPAT The OPAT object passed during initialization. opatSize : Tuple[int, int] The size of the OPAT object (dimensions of the data). indexVectors : List[FloatVectorIndex] The list of index vectors from the OPAT object. triangulation : scipy.spatial.Delaunay The Delaunay triangulation built from the index vectors. Examples -------- >>> from opatio.base.opat import OPAT >>> from opatio.lattice.tableLattice import TableLattice >>> opat = OPAT(...) # Initialize OPAT object >>> lattice = TableLattice(opat) >>> query_vector = FloatVectorIndex(...) # Create a query vector >>> result_card = lattice.get(query_vector) >>> print(result_card) """def__init__(self,opat:OPAT):""" Initialize the TableLattice object. This method sets up the OPAT object, retrieves its size and index vectors, and builds the Delaunay triangulation. Parameters ---------- opat : OPAT The OPAT object containing index vectors and associated data cards. """self.opat:OPAT=opatself.opatSize:Tuple[int,int]=opat.size()self.indexVectors:List[FloatVectorIndex]=opat.indexVectorsself._build_delaunay()
[docs]defget(self,query:FloatVectorIndex)->DataCard:""" Interpolate a data card based on a query vector using barycentric weights. This method finds the simplex containing the query vector, calculates barycentric weights, and interpolates the associated data cards of the simplex vertices to produce a result data card. Parameters ---------- query : FloatVectorIndex The index vector to query for interpolation. Returns ------- DataCard The interpolated data card. Raises ------ ValueError If the query point is not contained in any simplex. IndexError If a vertex ID is out of bounds for the index vectors. Examples -------- >>> query_vector = FloatVectorIndex(...) # Create a query vector >>> result_card = lattice.get(query_vector) >>> print(result_card) """simplexID:int=self._find_containing_simplex(query)ifsimplexIDisNone:raiseValueError("Query point is not contained in any simplex.")vertexIDs=self.triangulation.simplices[simplexID]verticies:List[DataCard]=[]forvertexIDinvertexIDs:ifvertexID<0orvertexID>=len(self.indexVectors):raiseIndexError(f"Vertex ID {vertexID} is out of bounds for index vectors.")verticies.append(self.opat[self.indexVectors[vertexID].vector])tagOkay:bool=True# Check if all DataCards have the same tagstags=set(verticies[0].keys())forDCinverticies:ifset(DC.keys())!=tags:tagOkay=Falsebreakdim:int=self.opatSize[0]transform:np.ndarray=self.triangulation.transform[simplexID]offset:np.ndarray=transform[dim]matrix_d:np.ndarray=transform[:dim]delta:np.ndarray=query.vector-offsetbary_partial:np.ndarray=matrix_d.dot(delta)last_weight:float=1.0-bary_partial.sum()weights:np.ndarray=np.concatenate([bary_partial,np.array([last_weight])])# shape (dim+1,)resultCard:DataCard=DataCard()resultCard.header=verticies[0].header# copy header from the first vertexfortagintags:#get column names and row names from the datacard's indexcolumnName:str=verticies[0].index[tag].columnNamerowName:str=verticies[0].index[tag].rowName# Start a fresh OPATTable for this tag# Copy columnValues and rowValues from the first vertex’s tablefirstTable=verticies[0][tag]# Allocate zero‐array matching the shape of firstTable.dataaccumulator:np.ndarray=np.zeros_like(firstTable.data)# Accumulate weighted sum over all verticesforw,DCinzip(weights,verticies):srcTable:OPATTable=DC[tag]accumulator+=w*srcTable.data# Attach the interpolated table under this tagresultTable:OPATTable=OPATTable(firstTable.columnValues,firstTable.rowValues,accumulator)resultCard.add_table(tag,resultTable,columnName=columnName,rowName=rowName)returnresultCard
def_build_delaunay(self):""" Build the Delaunay triangulation for the index vectors. This method constructs a Delaunay triangulation using the index vectors from the OPAT object. It ensures that the triangulation is valid and raises an error if the points are collinear. Raises ------ ValueError If the Delaunay triangulation fails due to invalid or collinear points. Examples -------- >>> lattice._build_delaunay() """points:np.ndarray=np.zeros(shape=(self.opatSize[1],self.opatSize[0]),dtype=np.float64)fori,ivinenumerate(self.indexVectors):points[i]=iv.vectortry:self.triangulation=Delaunay(points)exceptValueErrorase:raiseValueError("Failed to create Delaunay triangulation. Ensure that the index vectors are valid and not collinear.")fromedef_find_containing_simplex(self,query:FloatVectorIndex)->int:""" Find the index of the simplex that contains the query point. This method uses the Delaunay triangulation to locate the simplex containing the query vector. Parameters ---------- query : FloatVectorIndex The index vector to query. Returns ------- int The index of the containing simplex, or None if the query point is not contained in any simplex. Examples -------- >>> simplex_index = lattice._find_containing_simplex(query_vector) >>> print(simplex_index) """simplex_index=self.triangulation.find_simplex(query.vector)returnsimplex_indexifsimplex_index>=0elseNone