@@ -22,8 +22,8 @@ import warnings
2222cdef extern from " EMD.h" :
2323 int EMD_wrap(int n1,int n2, double * X, double * Y,double * D, double * G, double * alpha, double * beta, double * cost, uint64_t maxIter, double * alpha_init, double * beta_init) nogil
2424 int EMD_wrap_omp(int n1,int n2, double * X, double * Y,double * D, double * G, double * alpha, double * beta, double * cost, uint64_t maxIter, int numThreads) nogil
25- int EMD_wrap_sparse(int n1, int n2, double * X, double * Y, uint64_t n_edges, uint64_t * edge_sources, uint64_t * edge_targets, double * edge_costs, uint64_t * flow_sources_out, uint64_t * flow_targets_out, double * flow_values_out, uint64_t * n_flows_out, double * alpha, double * beta, double * cost, uint64_t maxIter) nogil
26- int EMD_wrap_lazy(int n1, int n2, double * X, double * Y, double * coords_a, double * coords_b, int dim, int metric, double * G, double * alpha, double * beta, double * cost, uint64_t maxIter) nogil
25+ int EMD_wrap_sparse(int n1, int n2, double * X, double * Y, uint64_t n_edges, uint64_t * edge_sources, uint64_t * edge_targets, double * edge_costs, uint64_t * flow_sources_out, uint64_t * flow_targets_out, double * flow_values_out, uint64_t * n_flows_out, double * alpha, double * beta, double * cost, uint64_t maxIter, double * alpha_init, double * beta_init ) nogil
26+ int EMD_wrap_lazy(int n1, int n2, double * X, double * Y, double * coords_a, double * coords_b, int dim, int metric, double * G, double * alpha, double * beta, double * cost, uint64_t maxIter, double * alpha_init, double * beta_init ) nogil
2727 cdef enum ProblemType: INFEASIBLE, OPTIMAL, UNBOUNDED, MAX_ITER_REACHED
2828
2929
@@ -233,7 +233,9 @@ def emd_c_sparse(np.ndarray[double, ndim=1, mode="c"] a,
233233 np.ndarray[uint64_t , ndim = 1 , mode = " c" ] edge_sources,
234234 np.ndarray[uint64_t , ndim = 1 , mode = " c" ] edge_targets,
235235 np.ndarray[double , ndim = 1 , mode = " c" ] edge_costs,
236- uint64_t max_iter ):
236+ uint64_t max_iter ,
237+ np.ndarray[double , ndim = 1 , mode = " c" ] alpha_init= None ,
238+ np.ndarray[double , ndim = 1 , mode = " c" ] beta_init= None ):
237239 """
238240 Sparse EMD solver using cost matrix in COO (Coordinate) sparse format.
239241
@@ -255,6 +257,10 @@ def emd_c_sparse(np.ndarray[double, ndim=1, mode="c"] a,
255257 Cost for each edge (non-zero values in COO format)
256258 max_iter : uint64_t
257259 Maximum number of iterations
260+ alpha_init : (n1,) array, float64, optional
261+ Initial dual variables for sources (warmstart)
262+ beta_init : (n2,) array, float64, optional
263+ Initial dual variables for targets (warmstart)
258264
259265 Returns
260266 -------
@@ -287,6 +293,12 @@ def emd_c_sparse(np.ndarray[double, ndim=1, mode="c"] a,
287293 cdef np.ndarray[double , ndim= 1 , mode= " c" ] alpha = np.zeros(n1)
288294 cdef np.ndarray[double , ndim= 1 , mode= " c" ] beta = np.zeros(n2)
289295
296+ cdef double * alpha_init_ptr = NULL
297+ cdef double * beta_init_ptr = NULL
298+ if alpha_init is not None and beta_init is not None :
299+ alpha_init_ptr = < double * > alpha_init.data
300+ beta_init_ptr = < double * > beta_init.data
301+
290302 with nogil:
291303 result_code = EMD_wrap_sparse(
292304 n1, n2,
@@ -295,7 +307,8 @@ def emd_c_sparse(np.ndarray[double, ndim=1, mode="c"] a,
295307 < uint64_t* > edge_sources.data, < uint64_t* > edge_targets.data, < double * > edge_costs.data,
296308 < uint64_t* > flow_sources.data, < uint64_t* > flow_targets.data, < double * > flow_values.data,
297309 & n_flows_out,
298- < double * > alpha.data, < double * > beta.data, & cost, max_iter
310+ < double * > alpha.data, < double * > beta.data, & cost, max_iter,
311+ alpha_init_ptr, beta_init_ptr
299312 )
300313
301314 # Trim to actual number of flows
@@ -308,7 +321,7 @@ def emd_c_sparse(np.ndarray[double, ndim=1, mode="c"] a,
308321
309322@ cython.boundscheck (False )
310323@ cython.wraparound (False )
311- def emd_c_lazy (np.ndarray[double , ndim = 1 , mode = " c" ] a, np.ndarray[double , ndim = 1 , mode = " c" ] b, np.ndarray[double , ndim = 2 , mode = " c" ] coords_a, np.ndarray[double , ndim = 2 , mode = " c" ] coords_b, str metric = ' sqeuclidean' , uint64_t max_iter = 100000 ):
324+ def emd_c_lazy (np.ndarray[double , ndim = 1 , mode = " c" ] a, np.ndarray[double , ndim = 1 , mode = " c" ] b, np.ndarray[double , ndim = 2 , mode = " c" ] coords_a, np.ndarray[double , ndim = 2 , mode = " c" ] coords_b, str metric = ' sqeuclidean' , uint64_t max_iter = 100000 , np.ndarray[ double , ndim = 1 , mode = " c " ] alpha_init = None , np.ndarray[ double , ndim = 1 , mode = " c " ] beta_init = None ):
312325 """ Solves the Earth Movers distance problem with lazy cost computation from coordinates."""
313326 cdef int n1 = coords_a.shape[0 ]
314327 cdef int n2 = coords_b.shape[0 ]
@@ -339,6 +352,13 @@ def emd_c_lazy(np.ndarray[double, ndim=1, mode="c"] a, np.ndarray[double, ndim=1
339352 a = np.ones((n1,)) / n1
340353 if not len (b):
341354 b = np.ones((n2,)) / n2
355+
356+ cdef double * alpha_init_ptr = NULL
357+ cdef double * beta_init_ptr = NULL
358+ if alpha_init is not None and beta_init is not None :
359+ alpha_init_ptr = < double * > alpha_init.data
360+ beta_init_ptr = < double * > beta_init.data
361+
342362 with nogil:
343- result_code = EMD_wrap_lazy(n1, n2, < double * > a.data, < double * > b.data, < double * > coords_a.data, < double * > coords_b.data, dim, metric_code, < double * > G.data, < double * > alpha.data, < double * > beta.data, < double * > & cost, max_iter)
363+ result_code = EMD_wrap_lazy(n1, n2, < double * > a.data, < double * > b.data, < double * > coords_a.data, < double * > coords_b.data, dim, metric_code, < double * > G.data, < double * > alpha.data, < double * > beta.data, < double * > & cost, max_iter, alpha_init_ptr, beta_init_ptr )
344364 return G, cost, alpha, beta, result_code
0 commit comments