vibespatial.spatial.distance_metrics_kernels¶
NVRTC kernel sources for Hausdorff and discrete Frechet distance.
Attributes¶
Module Contents¶
- vibespatial.spatial.distance_metrics_kernels.MAX_FRECHET_B = 2048¶
- vibespatial.spatial.distance_metrics_kernels.HAUSDORFF_FP64 = Multiline-String¶
Show Value
"""#define VS_SPATIAL_EPSILON 9.9999999999999998e-13 typedef double compute_t; /* Centered coordinate read: subtract center in fp64, then cast to compute_t. When compute_t is double, this is a no-op identity. When compute_t is float, centering reduces absolute magnitude before the lossy cast. */ #define CX(val) ((compute_t)((val) - center_x)) #define CY(val) ((compute_t)((val) - center_y)) /* Kahan summation helper -- add `val` to `sum` with compensation `c`. */ #define KAHAN_ADD(sum, val, c) do { \ const compute_t _y = (val) - (c); \ const compute_t _t = (sum) + _y; \ (c) = (_t - (sum)) - _y; \ (sum) = _t; \ } while(0) /* Warp-level Kahan reduction for a (sum, compensation) pair. */ #define VS_WARP_FULL_MASK 0xFFFFFFFFu #define WARP_KAHAN_REDUCE(sum, c) do { \ for (int _vs_offset = 16; _vs_offset > 0; _vs_offset >>= 1) { \ const compute_t _vs_shfl_sum = __shfl_down_sync(VS_WARP_FULL_MASK, (sum), _vs_offset); \ const compute_t _vs_shfl_c = __shfl_down_sync(VS_WARP_FULL_MASK, (c), _vs_offset); \ KAHAN_ADD((sum), _vs_shfl_sum - _vs_shfl_c, (c)); \ } \ } while(0) __device__ compute_t hausdorff_sample_x( const double* __restrict__ x, int start, int coord_count, int sample, int densify_steps, double center_x ) { if (coord_count <= 1 || densify_steps <= 1) { return CX(x[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CX(x[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t x0 = CX(x[start + segment]); const compute_t x1 = CX(x[start + segment + 1]); return x0 + (x1 - x0) * t; } __device__ compute_t hausdorff_sample_y( const double* __restrict__ y, int start, int coord_count, int sample, int densify_steps, double center_y ) { if (coord_count <= 1 || densify_steps <= 1) { return CY(y[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CY(y[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t y0 = CY(y[start + segment]); const compute_t y1 = CY(y[start + segment + 1]); return y0 + (y1 - y0) * t; } extern "C" __global__ __launch_bounds__(256, 4) void hausdorff_distance( const double* __restrict__ x_a, const double* __restrict__ y_a, const int* __restrict__ offsets_a, const double* __restrict__ x_b, const double* __restrict__ y_b, const int* __restrict__ offsets_b, double* __restrict__ result, double center_x, double center_y, int densify_steps, int pair_count ) { const int pair = blockIdx.x; if (pair >= pair_count) return; const int a_start = offsets_a[pair]; const int a_end = offsets_a[pair + 1]; const int b_start = offsets_b[pair]; const int b_end = offsets_b[pair + 1]; const int na = a_end - a_start; const int nb = b_end - b_start; if (na == 0 || nb == 0) { if (threadIdx.x == 0) result[pair] = 0.0 / 0.0; /* NaN */ return; } const int tid = threadIdx.x; const int stride = blockDim.x; const int a_samples = (na <= 1 || densify_steps <= 1) ? na : ((na - 1) * densify_steps + 1); const int b_samples = (nb <= 1 || densify_steps <= 1) ? nb : ((nb - 1) * densify_steps + 1); /* Forward direction: max over A of { min over B of dist(a,b) } */ compute_t local_max_forward = (compute_t)0.0; for (int i = tid; i < a_samples; i += stride) { const compute_t ax = hausdorff_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = hausdorff_sample_y( y_a, a_start, na, i, densify_steps, center_y); compute_t min_dist_sq = (compute_t)1e38; for (int j = 0; j < b_samples; j++) { const compute_t bx = hausdorff_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = hausdorff_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const compute_t d_sq = dx * dx + dy * dy; if (d_sq < min_dist_sq) min_dist_sq = d_sq; } const compute_t min_dist = sqrt((double)min_dist_sq); if (min_dist > local_max_forward) local_max_forward = min_dist; } /* Backward direction: max over B of { min over A of dist(b,a) } */ compute_t local_max_backward = (compute_t)0.0; for (int j = tid; j < b_samples; j += stride) { const compute_t bx = hausdorff_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = hausdorff_sample_y( y_b, b_start, nb, j, densify_steps, center_y); compute_t min_dist_sq = (compute_t)1e38; for (int i = 0; i < a_samples; i++) { const compute_t ax = hausdorff_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = hausdorff_sample_y( y_a, a_start, na, i, densify_steps, center_y); const compute_t dx = bx - ax; const compute_t dy = by - ay; const compute_t d_sq = dx * dx + dy * dy; if (d_sq < min_dist_sq) min_dist_sq = d_sq; } const compute_t min_dist = sqrt((double)min_dist_sq); if (min_dist > local_max_backward) local_max_backward = min_dist; } double local_max = (double)((local_max_forward > local_max_backward) ? local_max_forward : local_max_backward); /* Block-wide max reduction via shared memory */ __shared__ double sdata[256]; sdata[tid] = local_max; __syncthreads(); for (int s = blockDim.x >> 1; s > 0; s >>= 1) { if (tid < s && sdata[tid + s] > sdata[tid]) { sdata[tid] = sdata[tid + s]; } __syncthreads(); } if (tid == 0) result[pair] = sdata[0]; } """
- vibespatial.spatial.distance_metrics_kernels.HAUSDORFF_FP32 = Multiline-String¶
Show Value
"""#define VS_SPATIAL_EPSILON 9.9999999999999998e-13 typedef float compute_t; /* Centered coordinate read: subtract center in fp64, then cast to compute_t. When compute_t is double, this is a no-op identity. When compute_t is float, centering reduces absolute magnitude before the lossy cast. */ #define CX(val) ((compute_t)((val) - center_x)) #define CY(val) ((compute_t)((val) - center_y)) /* Kahan summation helper -- add `val` to `sum` with compensation `c`. */ #define KAHAN_ADD(sum, val, c) do { \ const compute_t _y = (val) - (c); \ const compute_t _t = (sum) + _y; \ (c) = (_t - (sum)) - _y; \ (sum) = _t; \ } while(0) /* Warp-level Kahan reduction for a (sum, compensation) pair. */ #define VS_WARP_FULL_MASK 0xFFFFFFFFu #define WARP_KAHAN_REDUCE(sum, c) do { \ for (int _vs_offset = 16; _vs_offset > 0; _vs_offset >>= 1) { \ const compute_t _vs_shfl_sum = __shfl_down_sync(VS_WARP_FULL_MASK, (sum), _vs_offset); \ const compute_t _vs_shfl_c = __shfl_down_sync(VS_WARP_FULL_MASK, (c), _vs_offset); \ KAHAN_ADD((sum), _vs_shfl_sum - _vs_shfl_c, (c)); \ } \ } while(0) __device__ compute_t hausdorff_sample_x( const double* __restrict__ x, int start, int coord_count, int sample, int densify_steps, double center_x ) { if (coord_count <= 1 || densify_steps <= 1) { return CX(x[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CX(x[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t x0 = CX(x[start + segment]); const compute_t x1 = CX(x[start + segment + 1]); return x0 + (x1 - x0) * t; } __device__ compute_t hausdorff_sample_y( const double* __restrict__ y, int start, int coord_count, int sample, int densify_steps, double center_y ) { if (coord_count <= 1 || densify_steps <= 1) { return CY(y[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CY(y[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t y0 = CY(y[start + segment]); const compute_t y1 = CY(y[start + segment + 1]); return y0 + (y1 - y0) * t; } extern "C" __global__ __launch_bounds__(256, 4) void hausdorff_distance( const double* __restrict__ x_a, const double* __restrict__ y_a, const int* __restrict__ offsets_a, const double* __restrict__ x_b, const double* __restrict__ y_b, const int* __restrict__ offsets_b, double* __restrict__ result, double center_x, double center_y, int densify_steps, int pair_count ) { const int pair = blockIdx.x; if (pair >= pair_count) return; const int a_start = offsets_a[pair]; const int a_end = offsets_a[pair + 1]; const int b_start = offsets_b[pair]; const int b_end = offsets_b[pair + 1]; const int na = a_end - a_start; const int nb = b_end - b_start; if (na == 0 || nb == 0) { if (threadIdx.x == 0) result[pair] = 0.0 / 0.0; /* NaN */ return; } const int tid = threadIdx.x; const int stride = blockDim.x; const int a_samples = (na <= 1 || densify_steps <= 1) ? na : ((na - 1) * densify_steps + 1); const int b_samples = (nb <= 1 || densify_steps <= 1) ? nb : ((nb - 1) * densify_steps + 1); /* Forward direction: max over A of { min over B of dist(a,b) } */ compute_t local_max_forward = (compute_t)0.0; for (int i = tid; i < a_samples; i += stride) { const compute_t ax = hausdorff_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = hausdorff_sample_y( y_a, a_start, na, i, densify_steps, center_y); compute_t min_dist_sq = (compute_t)1e38; for (int j = 0; j < b_samples; j++) { const compute_t bx = hausdorff_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = hausdorff_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const compute_t d_sq = dx * dx + dy * dy; if (d_sq < min_dist_sq) min_dist_sq = d_sq; } const compute_t min_dist = sqrt((double)min_dist_sq); if (min_dist > local_max_forward) local_max_forward = min_dist; } /* Backward direction: max over B of { min over A of dist(b,a) } */ compute_t local_max_backward = (compute_t)0.0; for (int j = tid; j < b_samples; j += stride) { const compute_t bx = hausdorff_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = hausdorff_sample_y( y_b, b_start, nb, j, densify_steps, center_y); compute_t min_dist_sq = (compute_t)1e38; for (int i = 0; i < a_samples; i++) { const compute_t ax = hausdorff_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = hausdorff_sample_y( y_a, a_start, na, i, densify_steps, center_y); const compute_t dx = bx - ax; const compute_t dy = by - ay; const compute_t d_sq = dx * dx + dy * dy; if (d_sq < min_dist_sq) min_dist_sq = d_sq; } const compute_t min_dist = sqrt((double)min_dist_sq); if (min_dist > local_max_backward) local_max_backward = min_dist; } double local_max = (double)((local_max_forward > local_max_backward) ? local_max_forward : local_max_backward); /* Block-wide max reduction via shared memory */ __shared__ double sdata[256]; sdata[tid] = local_max; __syncthreads(); for (int s = blockDim.x >> 1; s > 0; s >>= 1) { if (tid < s && sdata[tid + s] > sdata[tid]) { sdata[tid] = sdata[tid + s]; } __syncthreads(); } if (tid == 0) result[pair] = sdata[0]; } """
- vibespatial.spatial.distance_metrics_kernels.FRECHET_FP64 = Multiline-String¶
Show Value
"""#define VS_SPATIAL_EPSILON 9.9999999999999998e-13 typedef double compute_t; /* Centered coordinate read: subtract center in fp64, then cast to compute_t. When compute_t is double, this is a no-op identity. When compute_t is float, centering reduces absolute magnitude before the lossy cast. */ #define CX(val) ((compute_t)((val) - center_x)) #define CY(val) ((compute_t)((val) - center_y)) /* Kahan summation helper -- add `val` to `sum` with compensation `c`. */ #define KAHAN_ADD(sum, val, c) do { \ const compute_t _y = (val) - (c); \ const compute_t _t = (sum) + _y; \ (c) = (_t - (sum)) - _y; \ (sum) = _t; \ } while(0) /* Warp-level Kahan reduction for a (sum, compensation) pair. */ #define VS_WARP_FULL_MASK 0xFFFFFFFFu #define WARP_KAHAN_REDUCE(sum, c) do { \ for (int _vs_offset = 16; _vs_offset > 0; _vs_offset >>= 1) { \ const compute_t _vs_shfl_sum = __shfl_down_sync(VS_WARP_FULL_MASK, (sum), _vs_offset); \ const compute_t _vs_shfl_c = __shfl_down_sync(VS_WARP_FULL_MASK, (c), _vs_offset); \ KAHAN_ADD((sum), _vs_shfl_sum - _vs_shfl_c, (c)); \ } \ } while(0) #define MAX_FRECHET_B 2048 __device__ compute_t frechet_sample_x( const double* __restrict__ x, int start, int coord_count, int sample, int densify_steps, double center_x ) { if (coord_count <= 1 || densify_steps <= 1) { return CX(x[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CX(x[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t x0 = CX(x[start + segment]); const compute_t x1 = CX(x[start + segment + 1]); return x0 + (x1 - x0) * t; } __device__ compute_t frechet_sample_y( const double* __restrict__ y, int start, int coord_count, int sample, int densify_steps, double center_y ) { if (coord_count <= 1 || densify_steps <= 1) { return CY(y[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CY(y[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t y0 = CY(y[start + segment]); const compute_t y1 = CY(y[start + segment + 1]); return y0 + (y1 - y0) * t; } extern "C" __global__ void frechet_distance( const double* __restrict__ x_a, const double* __restrict__ y_a, const int* __restrict__ offsets_a, const double* __restrict__ x_b, const double* __restrict__ y_b, const int* __restrict__ offsets_b, double* __restrict__ result, double center_x, double center_y, int pair_count, int max_b_len, int densify_steps ) { const int pair = blockIdx.x * blockDim.x + threadIdx.x; if (pair >= pair_count) return; const int a_start = offsets_a[pair]; const int a_end = offsets_a[pair + 1]; const int b_start = offsets_b[pair]; const int b_end = offsets_b[pair + 1]; const int na = a_end - a_start; const int nb = b_end - b_start; if (na == 0 || nb == 0) { result[pair] = 0.0 / 0.0; /* NaN */ return; } const int a_samples = (na <= 1 || densify_steps <= 1) ? na : ((na - 1) * densify_steps + 1); const int b_samples = (nb <= 1 || densify_steps <= 1) ? nb : ((nb - 1) * densify_steps + 1); if (b_samples > MAX_FRECHET_B) { /* Too large for local arrays -- return NaN as safe fallback */ result[pair] = 0.0 / 0.0; return; } /* Rolling DP: previous and current rows, each of length nb. For large nb these spill to local memory (L1/L2 cached). */ double prev_row[MAX_FRECHET_B]; double curr_row[MAX_FRECHET_B]; /* Initialize row 0: ca[0][j] = max(ca[0][j-1], d(a_0, b_j)) */ { const compute_t ax = frechet_sample_x( x_a, a_start, na, 0, densify_steps, center_x); const compute_t ay = frechet_sample_y( y_a, a_start, na, 0, densify_steps, center_y); { const compute_t bx = frechet_sample_x( x_b, b_start, nb, 0, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, 0, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; prev_row[0] = sqrt((double)(dx * dx + dy * dy)); } for (int j = 1; j < b_samples; j++) { const compute_t bx = frechet_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); prev_row[j] = (d > prev_row[j - 1]) ? d : prev_row[j - 1]; } } /* Fill rows 1..na-1 */ for (int i = 1; i < a_samples; i++) { const compute_t ax = frechet_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = frechet_sample_y( y_a, a_start, na, i, densify_steps, center_y); /* curr_row[0] = max(prev_row[0], d(a_i, b_0)) */ { const compute_t bx = frechet_sample_x( x_b, b_start, nb, 0, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, 0, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); curr_row[0] = (d > prev_row[0]) ? d : prev_row[0]; } for (int j = 1; j < b_samples; j++) { const compute_t bx = frechet_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); double min_prev = prev_row[j]; /* ca[i-1][j] */ if (curr_row[j - 1] < min_prev) min_prev = curr_row[j - 1]; /* ca[i][j-1] */ if (prev_row[j - 1] < min_prev) min_prev = prev_row[j - 1]; /* ca[i-1][j-1] */ curr_row[j] = (d > min_prev) ? d : min_prev; } /* Swap: prev_row = curr_row */ for (int j = 0; j < b_samples; j++) prev_row[j] = curr_row[j]; } result[pair] = prev_row[b_samples - 1]; } """
- vibespatial.spatial.distance_metrics_kernels.FRECHET_FP32 = Multiline-String¶
Show Value
"""#define VS_SPATIAL_EPSILON 9.9999999999999998e-13 typedef float compute_t; /* Centered coordinate read: subtract center in fp64, then cast to compute_t. When compute_t is double, this is a no-op identity. When compute_t is float, centering reduces absolute magnitude before the lossy cast. */ #define CX(val) ((compute_t)((val) - center_x)) #define CY(val) ((compute_t)((val) - center_y)) /* Kahan summation helper -- add `val` to `sum` with compensation `c`. */ #define KAHAN_ADD(sum, val, c) do { \ const compute_t _y = (val) - (c); \ const compute_t _t = (sum) + _y; \ (c) = (_t - (sum)) - _y; \ (sum) = _t; \ } while(0) /* Warp-level Kahan reduction for a (sum, compensation) pair. */ #define VS_WARP_FULL_MASK 0xFFFFFFFFu #define WARP_KAHAN_REDUCE(sum, c) do { \ for (int _vs_offset = 16; _vs_offset > 0; _vs_offset >>= 1) { \ const compute_t _vs_shfl_sum = __shfl_down_sync(VS_WARP_FULL_MASK, (sum), _vs_offset); \ const compute_t _vs_shfl_c = __shfl_down_sync(VS_WARP_FULL_MASK, (c), _vs_offset); \ KAHAN_ADD((sum), _vs_shfl_sum - _vs_shfl_c, (c)); \ } \ } while(0) #define MAX_FRECHET_B 2048 __device__ compute_t frechet_sample_x( const double* __restrict__ x, int start, int coord_count, int sample, int densify_steps, double center_x ) { if (coord_count <= 1 || densify_steps <= 1) { return CX(x[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CX(x[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t x0 = CX(x[start + segment]); const compute_t x1 = CX(x[start + segment + 1]); return x0 + (x1 - x0) * t; } __device__ compute_t frechet_sample_y( const double* __restrict__ y, int start, int coord_count, int sample, int densify_steps, double center_y ) { if (coord_count <= 1 || densify_steps <= 1) { return CY(y[start + sample]); } const int last_sample = (coord_count - 1) * densify_steps; if (sample >= last_sample) { return CY(y[start + coord_count - 1]); } const int segment = sample / densify_steps; const int step = sample - segment * densify_steps; const compute_t t = (compute_t)step / (compute_t)densify_steps; const compute_t y0 = CY(y[start + segment]); const compute_t y1 = CY(y[start + segment + 1]); return y0 + (y1 - y0) * t; } extern "C" __global__ void frechet_distance( const double* __restrict__ x_a, const double* __restrict__ y_a, const int* __restrict__ offsets_a, const double* __restrict__ x_b, const double* __restrict__ y_b, const int* __restrict__ offsets_b, double* __restrict__ result, double center_x, double center_y, int pair_count, int max_b_len, int densify_steps ) { const int pair = blockIdx.x * blockDim.x + threadIdx.x; if (pair >= pair_count) return; const int a_start = offsets_a[pair]; const int a_end = offsets_a[pair + 1]; const int b_start = offsets_b[pair]; const int b_end = offsets_b[pair + 1]; const int na = a_end - a_start; const int nb = b_end - b_start; if (na == 0 || nb == 0) { result[pair] = 0.0 / 0.0; /* NaN */ return; } const int a_samples = (na <= 1 || densify_steps <= 1) ? na : ((na - 1) * densify_steps + 1); const int b_samples = (nb <= 1 || densify_steps <= 1) ? nb : ((nb - 1) * densify_steps + 1); if (b_samples > MAX_FRECHET_B) { /* Too large for local arrays -- return NaN as safe fallback */ result[pair] = 0.0 / 0.0; return; } /* Rolling DP: previous and current rows, each of length nb. For large nb these spill to local memory (L1/L2 cached). */ double prev_row[MAX_FRECHET_B]; double curr_row[MAX_FRECHET_B]; /* Initialize row 0: ca[0][j] = max(ca[0][j-1], d(a_0, b_j)) */ { const compute_t ax = frechet_sample_x( x_a, a_start, na, 0, densify_steps, center_x); const compute_t ay = frechet_sample_y( y_a, a_start, na, 0, densify_steps, center_y); { const compute_t bx = frechet_sample_x( x_b, b_start, nb, 0, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, 0, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; prev_row[0] = sqrt((double)(dx * dx + dy * dy)); } for (int j = 1; j < b_samples; j++) { const compute_t bx = frechet_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); prev_row[j] = (d > prev_row[j - 1]) ? d : prev_row[j - 1]; } } /* Fill rows 1..na-1 */ for (int i = 1; i < a_samples; i++) { const compute_t ax = frechet_sample_x( x_a, a_start, na, i, densify_steps, center_x); const compute_t ay = frechet_sample_y( y_a, a_start, na, i, densify_steps, center_y); /* curr_row[0] = max(prev_row[0], d(a_i, b_0)) */ { const compute_t bx = frechet_sample_x( x_b, b_start, nb, 0, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, 0, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); curr_row[0] = (d > prev_row[0]) ? d : prev_row[0]; } for (int j = 1; j < b_samples; j++) { const compute_t bx = frechet_sample_x( x_b, b_start, nb, j, densify_steps, center_x); const compute_t by = frechet_sample_y( y_b, b_start, nb, j, densify_steps, center_y); const compute_t dx = ax - bx; const compute_t dy = ay - by; const double d = sqrt((double)(dx * dx + dy * dy)); double min_prev = prev_row[j]; /* ca[i-1][j] */ if (curr_row[j - 1] < min_prev) min_prev = curr_row[j - 1]; /* ca[i][j-1] */ if (prev_row[j - 1] < min_prev) min_prev = prev_row[j - 1]; /* ca[i-1][j-1] */ curr_row[j] = (d > min_prev) ? d : min_prev; } /* Swap: prev_row = curr_row */ for (int j = 0; j < b_samples; j++) prev_row[j] = curr_row[j]; } result[pair] = prev_row[b_samples - 1]; } """