From 3df0b6ba76ffab1e1c73140c583d07c30fac38a4 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Thu, 9 Jan 2025 14:53:32 +0400 Subject: [PATCH] feat(builtins): implement GCD calculation and resampling resolution logic for time sync --- src/if-run/builtins/time-sync/index.ts | 54 +++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/if-run/builtins/time-sync/index.ts b/src/if-run/builtins/time-sync/index.ts index 0c1ecfb2..763c0d3c 100644 --- a/src/if-run/builtins/time-sync/index.ts +++ b/src/if-run/builtins/time-sync/index.ts @@ -483,6 +483,57 @@ export const TimeSync = PluginFactory({ }, [] as PluginParams[]); /** Implementation */ + /** + * Calculates the greatest common divisor (GCD) of two numbers using the Euclidean algorithm. + */ + const greatestCommonDivisor = (a: number, b: number): number => { + while (b !== 0) { + [a, b] = [b, a % b]; + } + + return a; + }; + + /** + * Calculates the greatest common divisor (GCD) of an array of numbers. + */ + const calculateGCD = (numbers: number[]) => + numbers.reduce((acc, val) => greatestCommonDivisor(acc, val)); + + /** + * Returns an array of unique values from the given array. + */ + const getUniqueValues = (arr: number[]) => Array.from(new Set(arr)); + + /** + * Finds the most efficient resampling resolution based on the given inputs and user-defined interval. + * + * This function calculates the greatest common divisor (GCD) of the combined unique values from: + * - A: All unique values of (timestamp + duration) for each input. + * - B: All unique values of (next timestamp - current timestamp + duration) for each input. + */ + const findResamplingResolution = ( + inputs: PluginParams[], + userInterval: number + ): number => { + const A: number[] = []; + const B: number[] = []; + + for (let i = 0; i < inputs.length - 1; i++) { + const currentTimestamp = parseDate(inputs[i].timestamp).toMillis(); + const nextTimestamp = parseDate(inputs[i + 1].timestamp).toMillis(); + + A.push(currentTimestamp + inputs[i].duration); + B.push(nextTimestamp - currentTimestamp + inputs[i].duration); + } + + const uniqueA = getUniqueValues(A); + const uniqueB = getUniqueValues(B); + const combined = [...uniqueA, ...uniqueB, userInterval]; + + return calculateGCD(combined); + }; + const timeParams = { startTime: DateTime.fromISO(config['start-time'] as string), endTime: DateTime.fromISO(config['end-time'] as string), @@ -490,8 +541,9 @@ export const TimeSync = PluginFactory({ allowPadding: config['allow-padding'], upsamplingResolution: config['upsampling-resolution'] ? config['upsampling-resolution'] - : 1, + : findResamplingResolution(inputs, config.interval), }; + validateIntervalForResample( timeParams.interval, timeParams.upsamplingResolution,