From 3df0b6ba76ffab1e1c73140c583d07c30fac38a4 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Thu, 9 Jan 2025 14:53:32 +0400 Subject: [PATCH 1/5] 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 0c1ecfb22..763c0d3cf 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, From cde21d43b02c27d317bf34b2d492ab28262c1c18 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Wed, 29 Jan 2025 12:28:56 +0400 Subject: [PATCH 2/5] test(builtins): enhance error messages for upsampling resolution compatibility checks --- src/__tests__/if-run/builtins/time-sync.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/__tests__/if-run/builtins/time-sync.test.ts b/src/__tests__/if-run/builtins/time-sync.test.ts index 58863272b..0dcdb1eb7 100644 --- a/src/__tests__/if-run/builtins/time-sync.test.ts +++ b/src/__tests__/if-run/builtins/time-sync.test.ts @@ -945,7 +945,7 @@ describe('builtins/time-sync:', () => { expect(result).toStrictEqual(expectedResult); }); - it('should throw an error if the upsampling resolution is not compatible with the interval', async () => { + it('should throw an error if the upsampling resolution is not compatible with the interval (interval is bigger than upsampling).', async () => { const basicConfig = { 'start-time': '2023-12-12T00:00:00.000Z', 'end-time': '2023-12-12T00:00:03.000Z', @@ -970,7 +970,7 @@ describe('builtins/time-sync:', () => { } }); - it('should throw an error if the upsampling resolution is not compatible with paddings', async () => { + it('should throw an error if the upsampling resolution is not compatible with paddings (interval is equal to upsampling).', async () => { const basicConfig = { 'start-time': '2023-12-12T00:00:00.000Z', 'end-time': '2023-12-12T00:00:12.000Z', From 29901a8b24fbae48b2bdce72a73dce990c428d11 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Wed, 29 Jan 2025 12:29:17 +0400 Subject: [PATCH 3/5] fix(builtins): add missing line for metrics processing in time sync --- src/if-run/builtins/time-sync/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/if-run/builtins/time-sync/index.ts b/src/if-run/builtins/time-sync/index.ts index 763c0d3cf..8634b2123 100644 --- a/src/if-run/builtins/time-sync/index.ts +++ b/src/if-run/builtins/time-sync/index.ts @@ -216,6 +216,7 @@ export const TimeSync = PluginFactory({ timeStep: number ) => { const metrics = Object.keys(input); + return metrics.reduce((acc, metric) => { if (metric === 'timestamp') { acc[metric] = From 6e3bef3f7927ee6acaca10261759cfc1a5181531 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Wed, 29 Jan 2025 12:29:59 +0400 Subject: [PATCH 4/5] fix(lib): improve function documentation for traverse method --- src/if-run/lib/compute.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/if-run/lib/compute.ts b/src/if-run/lib/compute.ts index f77b1b995..50664de5c 100644 --- a/src/if-run/lib/compute.ts +++ b/src/if-run/lib/compute.ts @@ -26,7 +26,8 @@ const { const childNames = new Set(); /** - * Traverses all child nodes based on children grouping. + * Traverses through the children nodes and computes each child node. + * It also adds the child name to the `childNames` set. */ const traverse = async (children: any, params: ComputeParams) => { for (const child in children) { From 43c5d173853274302dcb0de086ca09723a5982e4 Mon Sep 17 00:00:00 2001 From: Narek Hovhannisyan Date: Wed, 29 Jan 2025 13:32:51 +0400 Subject: [PATCH 5/5] fix(builtins): add logging for upsampling resolution in time sync --- src/if-run/builtins/time-sync/index.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/if-run/builtins/time-sync/index.ts b/src/if-run/builtins/time-sync/index.ts index 8634b2123..dfcca7780 100644 --- a/src/if-run/builtins/time-sync/index.ts +++ b/src/if-run/builtins/time-sync/index.ts @@ -535,14 +535,17 @@ export const TimeSync = PluginFactory({ return calculateGCD(combined); }; + const upsamplingResolution = + config['upsampling-resolution'] || + findResamplingResolution(inputs, config.interval); + console.log(`Choosen upsampling resolution is ${upsamplingResolution}\n`); + const timeParams = { startTime: DateTime.fromISO(config['start-time'] as string), endTime: DateTime.fromISO(config['end-time'] as string), interval: config.interval, allowPadding: config['allow-padding'], - upsamplingResolution: config['upsampling-resolution'] - ? config['upsampling-resolution'] - : findResamplingResolution(inputs, config.interval), + upsamplingResolution, }; validateIntervalForResample(