Skip to content

Commit cc0803b

Browse files
committed
feat: add implementation of stats/strided/distances/dcanberra
--- type: pre_commit_static_analysis_report description: Results of running static analysis checks when committing changes. report: - task: lint_filenames status: passed - task: lint_editorconfig status: passed - task: lint_markdown status: na - task: lint_package_json status: na - task: lint_repl_help status: na - task: lint_javascript_src status: na - task: lint_javascript_cli status: na - task: lint_javascript_examples status: na - task: lint_javascript_tests status: passed - task: lint_javascript_benchmarks status: na - task: lint_python status: na - task: lint_r status: na - task: lint_c_src status: na - task: lint_c_examples status: na - task: lint_c_benchmarks status: na - task: lint_c_tests_fixtures status: na - task: lint_shell status: na - task: lint_typescript_declarations status: passed - task: lint_typescript_tests status: na - task: lint_license_headers status: passed ---
1 parent c25b4ea commit cc0803b

1 file changed

Lines changed: 249 additions & 0 deletions

File tree

Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
1+
/**
2+
* @license Apache-2.0
3+
*
4+
* Copyright (c) 2026 The Stdlib Authors.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
'use strict';
20+
21+
// MODULES //
22+
23+
var resolve = require( 'path' ).resolve;
24+
var tape = require( 'tape' );
25+
var Float64Array = require( '@stdlib/array/float64' );
26+
var isAlmostSameValue = require( '@stdlib/assert/is-almost-same-value' );
27+
var tryRequire = require( '@stdlib/utils/try-require' );
28+
29+
30+
// VARIABLES //
31+
32+
var dcanberra = tryRequire( resolve( __dirname, './../lib/ndarray.native.js' ) );
33+
var opts = {
34+
'skip': ( dcanberra instanceof Error )
35+
};
36+
37+
38+
// TESTS //
39+
40+
tape( 'main export is a function', opts, function test( t ) {
41+
t.ok( true, __filename );
42+
t.strictEqual( typeof dcanberra, 'function', 'main export is a function' );
43+
t.end();
44+
});
45+
46+
tape( 'the function has an arity of 7', opts, function test( t ) {
47+
t.strictEqual( dcanberra.length, 7, 'returns expected value' );
48+
t.end();
49+
});
50+
51+
tape( 'the function calculates the canberra distance between two strided arrays', opts, function test( t ) {
52+
var d;
53+
var x;
54+
var y;
55+
56+
x = new Float64Array( [ 4.0, 2.0, -3.0, 5.0, -1.0, 2.0, -5.0, 6.0 ] );
57+
y = new Float64Array( [ 2.0, 6.0, -1.0, -4.0, 8.0, 8.0, 2.0, -3.0 ] );
58+
59+
// Canberra: 2/6 + 4/8 + 2/4 + 9/9 + 9/9 + 6/10 + 7/7 + 9/9 ≈ 5.933
60+
d = dcanberra( x.length, x, 1, 0, y, 1, 0 );
61+
t.strictEqual( isAlmostSameValue( d, 5.933333333333334, 1e-10 ), true, 'returns expected value' );
62+
63+
x = new Float64Array( [ 3.0, -4.0, 1.0 ] );
64+
y = new Float64Array( [ 1.0, -2.0, 3.0 ] );
65+
66+
// Canberra: 2/4 + 2/6 + 2/4 ≈ 1.333
67+
d = dcanberra( x.length, x, 1, 0, y, 1, 0 );
68+
t.strictEqual( isAlmostSameValue( d, 1.3333333333333333, 1e-10 ), true, 'returns expected value' );
69+
70+
t.end();
71+
});
72+
73+
tape( 'if provided an `N` parameter less than or equal to `0`, the function returns `NaN`', opts, function test( t ) {
74+
var d;
75+
var x;
76+
var y;
77+
78+
x = new Float64Array( [ 3.0, -4.0, 1.0 ] );
79+
y = new Float64Array( [ 1.0, -2.0, 3.0 ] );
80+
81+
d = dcanberra( 0, x, 1, 0, y, 1, 0 );
82+
t.strictEqual( isAlmostSameValue( d, NaN, 0 ), true, 'returns expected value' );
83+
84+
d = dcanberra( -4, x, 1, 0, y, 1, 0 );
85+
t.strictEqual( isAlmostSameValue( d, NaN, 0 ), true, 'returns expected value' );
86+
t.end();
87+
});
88+
89+
tape( 'the function supports an `x` stride', opts, function test( t ) {
90+
var d;
91+
var x;
92+
var y;
93+
94+
x = new Float64Array([
95+
2.0, // 0
96+
-3.0,
97+
-5.0, // 1
98+
7.0,
99+
6.0 // 2
100+
]);
101+
y = new Float64Array([
102+
8.0, // 0
103+
2.0, // 1
104+
-3.0, // 2
105+
3.0,
106+
-4.0,
107+
1.0
108+
]);
109+
110+
// Canberra: 6/10 + 7/7 + 9/9 = 2.6
111+
d = dcanberra( 3, x, 2, 0, y, 1, 0 );
112+
t.strictEqual( isAlmostSameValue( d, 2.6, 1e-10 ), true, 'returns expected value' );
113+
t.end();
114+
});
115+
116+
tape( 'the function supports an `x` offset', opts, function test( t ) {
117+
var d;
118+
var x;
119+
var y;
120+
121+
x = new Float64Array([
122+
1.0,
123+
2.0, // 0
124+
3.0,
125+
4.0, // 1
126+
5.0,
127+
6.0 // 2
128+
]);
129+
y = new Float64Array([
130+
6.0, // 0
131+
7.0, // 1
132+
8.0, // 2
133+
9.0,
134+
10.0,
135+
11.0
136+
]);
137+
138+
// Canberra: 4/8 + 3/11 + 2/14 ≈ 0.915
139+
d = dcanberra( 3, x, 2, 1, y, 1, 0 );
140+
t.strictEqual( isAlmostSameValue( d, 0.9155844155844155, 1e-10 ), true, 'returns expected value' );
141+
t.end();
142+
});
143+
144+
tape( 'the function supports a `y` stride', opts, function test( t ) {
145+
var d;
146+
var x;
147+
var y;
148+
149+
x = new Float64Array([
150+
2.0, // 0
151+
-3.0, // 1
152+
-5.0, // 2
153+
7.0,
154+
6.0
155+
]);
156+
y = new Float64Array([
157+
8.0, // 0
158+
2.0,
159+
-3.0, // 1
160+
3.0,
161+
-4.0, // 2
162+
1.0
163+
]);
164+
165+
// Canberra: 6/10 + 0/5 + 1/9 ≈ 0.711
166+
d = dcanberra( 3, x, 1, 0, y, 2, 0 );
167+
t.strictEqual( isAlmostSameValue( d, 0.711111111111111, 1e-10 ), true, 'returns expected value' );
168+
t.end();
169+
});
170+
171+
tape( 'the function supports a `y` offset', opts, function test( t ) {
172+
var d;
173+
var x;
174+
var y;
175+
176+
x = new Float64Array([
177+
1.0, // 0
178+
2.0,
179+
3.0, // 1
180+
4.0,
181+
5.0, // 2
182+
6.0
183+
]);
184+
y = new Float64Array([
185+
6.0,
186+
7.0,
187+
8.0,
188+
9.0, // 0
189+
10.0, // 1
190+
11.0 // 2
191+
]);
192+
193+
// Canberra: 8/10 + 7/13 + 6/16 = ~1.6923
194+
d = dcanberra( 3, x, 2, 0, y, 1, 3 );
195+
t.strictEqual( isAlmostSameValue( d, 1.7134615384615386, 1e-10 ), true, 'returns expected value' );
196+
t.end();
197+
});
198+
199+
tape( 'the function supports negative strides', opts, function test( t ) {
200+
var d;
201+
var x;
202+
var y;
203+
204+
x = new Float64Array([
205+
1.0, // 2
206+
2.0,
207+
3.0, // 1
208+
4.0,
209+
5.0 // 0
210+
]);
211+
y = new Float64Array([
212+
6.0, // 2
213+
7.0, // 1
214+
8.0, // 0
215+
9.0,
216+
10.0
217+
]);
218+
219+
// Canberra: 3/13 + 4/10 + 5/7 ≈ 1.345
220+
d = dcanberra( 3, x, -2, x.length-1, y, -1, 2 );
221+
t.strictEqual( isAlmostSameValue( d, 1.3450549450549452, 1e-10 ), true, 'returns expected value' );
222+
t.end();
223+
});
224+
225+
tape( 'the function supports complex access patterns', opts, function test( t ) {
226+
var d;
227+
var x;
228+
var y;
229+
230+
x = new Float64Array([
231+
1.0, // 0
232+
2.0,
233+
3.0, // 1
234+
4.0,
235+
5.0 // 2
236+
]);
237+
y = new Float64Array([
238+
6.0,
239+
7.0, // 2
240+
8.0, // 1
241+
9.0, // 0
242+
10.0
243+
]);
244+
245+
// Canberra: 8/10 + 5/11 + 2/12 ≈ 1.421
246+
d = dcanberra( 3, x, 2, 0, y, -1, y.length-2 );
247+
t.strictEqual( isAlmostSameValue( d, 1.4212121212121213, 1e-10 ), true, 'returns expected value' );
248+
t.end();
249+
});

0 commit comments

Comments
 (0)