Skip to content

Commit a12b502

Browse files
test: validate implementation against Julia test fixtures
PR-URL: #5847 Reviewed-by: Athan Reines <[email protected]>
1 parent 90f8a26 commit a12b502

File tree

7 files changed

+153
-32
lines changed

7 files changed

+153
-32
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
julia 1.5
2+
JSON 0.21

lib/node_modules/@stdlib/math/base/special/kernel-cos/test/fixtures/julia/large_negative.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

lib/node_modules/@stdlib/math/base/special/kernel-cos/test/fixtures/julia/large_positive.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/usr/bin/env julia
2+
#
3+
# @license Apache-2.0
4+
#
5+
# Copyright (c) 2025 The Stdlib Authors.
6+
#
7+
# Licensed under the Apache License, Version 2.0 (the "License");
8+
# you may not use this file except in compliance with the License.
9+
# You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
19+
import JSON
20+
21+
"""
22+
gen( domain, name )
23+
24+
Generate fixture data and write to file.
25+
26+
# Arguments
27+
28+
* `domain`: domain
29+
* `name::AbstractString`: output filename
30+
31+
# Examples
32+
33+
``` julia
34+
julia> x = range( -1000.0, stop = 1000.0, length = 2001 );
35+
julia> gen( x, \"data.json\" );
36+
```
37+
"""
38+
function gen( domain, name )
39+
x = collect( domain );
40+
y = cos.( x );
41+
42+
# Store data to be written to file as a collection:
43+
data = Dict([
44+
("x", x),
45+
("expected", y)
46+
]);
47+
48+
# Based on the script directory, create an output filepath:
49+
filepath = joinpath( dir, name );
50+
51+
# Write the data to the output filepath as JSON:
52+
outfile = open( filepath, "w" );
53+
write( outfile, JSON.json(data) );
54+
write( outfile, "\n" );
55+
close( outfile );
56+
end
57+
58+
# Get the filename:
59+
file = @__FILE__;
60+
61+
# Extract the directory in which this file resides:
62+
dir = dirname( file );
63+
64+
# Values within the defined domain:
65+
x = range( -pi/4.0, stop = pi/4.0, length = 1000 )
66+
gen( x, "small_range.json" );
67+
68+
# Positive values outside the defined domain:
69+
x = range( 40.0*pi/4.0, stop = 200*pi/4.0, length = 1000 )
70+
gen( x, "large_positive.json" );
71+
72+
# Negative values outside the defined domain:
73+
x = range( -200*pi/4.0, stop = -40*pi/4.0, length = 1000 )
74+
gen( x, "large_negative.json" );

lib/node_modules/@stdlib/math/base/special/kernel-cos/test/fixtures/julia/small_range.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

lib/node_modules/@stdlib/math/base/special/kernel-cos/test/test.js

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,17 @@
2222

2323
var tape = require( 'tape' );
2424
var isnan = require( '@stdlib/math/base/assert/is-nan' );
25-
var linspace = require( '@stdlib/array/base/linspace' );
2625
var rempio2 = require( '@stdlib/math/base/special/rempio2' );
27-
var PI = require( '@stdlib/constants/float64/pi' );
28-
var cos = require( '@stdlib/math/base/special/cos' );
2926
var kernelCos = require( './../lib' );
3027

3128

29+
// FIXTURES //
30+
31+
var smallRange = require( './fixtures/julia/small_range.json' );
32+
var largePositive = require( './fixtures/julia/large_positive.json' );
33+
var largeNegative = require( './fixtures/julia/large_negative.json' );
34+
35+
3236
// TESTS //
3337

3438
tape( 'main export is a function', function test( t ) {
@@ -39,52 +43,56 @@ tape( 'main export is a function', function test( t ) {
3943

4044
tape( 'the function returns `NaN` if provided `NaN` for either parameter', function test( t ) {
4145
var v = kernelCos( NaN, 0.0 );
42-
t.equal( isnan( v ), true, 'returns NaN' );
46+
t.equal( isnan( v ), true, 'returns expected value' );
4347

4448
v = kernelCos( 4.0, NaN );
45-
t.equal( isnan( v ), true, 'returns NaN' );
49+
t.equal( isnan( v ), true, 'returns expected value' );
4650

4751
v = kernelCos( NaN, NaN );
48-
t.equal( isnan( v ), true, 'returns NaN' );
52+
t.equal( isnan( v ), true, 'returns expected value' );
4953
t.end();
5054
});
5155

5256
tape( 'the function evaluates the cosine for input values on the interval `[-pi/4, pi/4]`', function test( t ) {
57+
var expected;
5358
var values;
5459
var out;
5560
var x;
5661
var i;
5762

58-
values = linspace( -PI/4.0, PI/4.0, 1000 );
63+
values = smallRange.x;
64+
expected = smallRange.expected;
5965
for ( i = 0; i < values.length; i++ ) {
6066
x = values[ i ];
6167
out = kernelCos( x, 0.0 );
62-
t.strictEqual( out, cos( x ), 'returns expected value' );
68+
t.strictEqual( out, expected[ i ], 'returns expected value' );
6369
}
6470
t.end();
6571
});
6672

6773
tape( 'the function can be used to compute the cosine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (positive)', function test( t ) {
74+
var expected;
6875
var values;
6976
var out;
7077
var x;
7178
var y;
7279
var n;
7380
var i;
7481

75-
values = linspace( 40.0*PI/4.0, 200*PI/4.0, 1000 );
76-
y = new Array( 2 );
82+
values = largePositive.x;
83+
expected = largePositive.expected;
84+
y = [ 0.0, 0.0 ];
7785
for ( i = 0; i < values.length; i++ ) {
7886
x = values[ i ];
7987
n = rempio2( x, y );
8088
switch ( n & 3 ) {
8189
case 0:
8290
out = kernelCos( y[ 0 ], y[ 1 ] );
83-
t.strictEqual( out, cos( x ), 'returns expected value' );
91+
t.strictEqual( out, expected[ i ], 'returns expected value' );
8492
break;
8593
case 2:
8694
out = -kernelCos( y[ 0 ], y[ 1 ] );
87-
t.strictEqual( out, cos( x ), 'returns expected value' );
95+
t.strictEqual( out, expected[ i ], 'returns expected value' );
8896
break;
8997
default:
9098
break;
@@ -94,26 +102,28 @@ tape( 'the function can be used to compute the cosine for input values outside o
94102
});
95103

96104
tape( 'the function can be used to compute the cosine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (negative)', function test( t ) {
105+
var expected;
97106
var values;
98107
var out;
99108
var x;
100109
var y;
101110
var n;
102111
var i;
103112

104-
values = linspace( -200.0*PI/4.0, -40.0*PI/4.0, 1000 );
105-
y = new Array( 2 );
113+
values = largeNegative.x;
114+
expected = largeNegative.expected;
115+
y = [ 0.0, 0.0 ];
106116
for ( i = 0; i < values.length; i++ ) {
107117
x = values[ i ];
108118
n = rempio2( x, y );
109119
switch ( n & 3 ) {
110120
case 0:
111121
out = kernelCos( y[ 0 ], y[ 1 ] );
112-
t.strictEqual( out, cos( x ), 'returns expected value' );
122+
t.strictEqual( out, expected[ i ], 'returns expected value' );
113123
break;
114124
case 2:
115125
out = -kernelCos( y[ 0 ], y[ 1 ] );
116-
t.strictEqual( out, cos( x ), 'returns expected value' );
126+
t.strictEqual( out, expected[ i ], 'returns expected value' );
117127
break;
118128
default:
119129
break;

lib/node_modules/@stdlib/math/base/special/kernel-cos/test/test.native.js

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,9 @@
2323
var resolve = require( 'path' ).resolve;
2424
var tape = require( 'tape' );
2525
var isnan = require( '@stdlib/math/base/assert/is-nan' );
26-
var linspace = require( '@stdlib/array/base/linspace' );
26+
var abs = require( '@stdlib/math/base/special/abs' );
27+
var EPS = require( '@stdlib/constants/float64/eps' );
2728
var rempio2 = require( '@stdlib/math/base/special/rempio2' );
28-
var PI = require( '@stdlib/constants/float64/pi' );
29-
var cos = require( '@stdlib/math/base/special/cos' );
3029
var tryRequire = require( '@stdlib/utils/try-require' );
3130

3231

@@ -38,6 +37,13 @@ var opts = {
3837
};
3938

4039

40+
// FIXTURES //
41+
42+
var smallRange = require( './fixtures/julia/small_range.json' );
43+
var largePositive = require( './fixtures/julia/large_positive.json' );
44+
var largeNegative = require( './fixtures/julia/large_negative.json' );
45+
46+
4147
// TESTS //
4248

4349
tape( 'main export is a function', opts, function test( t ) {
@@ -48,52 +54,66 @@ tape( 'main export is a function', opts, function test( t ) {
4854

4955
tape( 'the function returns `NaN` if provided `NaN` for either parameter', opts, function test( t ) {
5056
var v = kernelCos( NaN, 0.0 );
51-
t.equal( isnan( v ), true, 'returns NaN' );
57+
t.equal( isnan( v ), true, 'returns expected value' );
5258

5359
v = kernelCos( 4.0, NaN );
54-
t.equal( isnan( v ), true, 'returns NaN' );
60+
t.equal( isnan( v ), true, 'returns expected value' );
5561

5662
v = kernelCos( NaN, NaN );
57-
t.equal( isnan( v ), true, 'returns NaN' );
63+
t.equal( isnan( v ), true, 'returns expected value' );
5864
t.end();
5965
});
6066

6167
tape( 'the function evaluates the cosine for input values on the interval `[-pi/4, pi/4]`', opts, function test( t ) {
68+
var expected;
6269
var values;
6370
var out;
6471
var x;
6572
var i;
6673

67-
values = linspace( -PI/4.0, PI/4.0, 1000 );
74+
values = smallRange.x;
75+
expected = smallRange.expected;
6876
for ( i = 0; i < values.length; i++ ) {
6977
x = values[ i ];
7078
out = kernelCos( x, 0.0 );
71-
t.strictEqual( out, cos( x ), 'returns expected value' );
79+
t.strictEqual( out, expected[ i ], 'returns expected value' );
7280
}
7381
t.end();
7482
});
7583

7684
tape( 'the function can be used to compute the cosine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (positive)', opts, function test( t ) {
85+
var expected;
7786
var values;
87+
var delta;
88+
var tol;
7889
var out;
7990
var x;
8091
var y;
8192
var n;
8293
var i;
8394

84-
values = linspace( 40.0*PI/4.0, 200*PI/4.0, 1000 );
85-
y = new Array( 2 );
95+
values = largePositive.x;
96+
expected = largePositive.expected;
97+
y = [ 0.0, 0.0 ];
8698
for ( i = 0; i < values.length; i++ ) {
8799
x = values[ i ];
88100
n = rempio2( x, y );
89101
switch ( n & 3 ) {
90102
case 0:
91103
out = kernelCos( y[ 0 ], y[ 1 ] );
92-
t.strictEqual( out, cos( x ), 'returns expected value' );
104+
t.strictEqual( out, expected[ i ], 'returns expected value' );
93105
break;
94106
case 2:
95107
out = -kernelCos( y[ 0 ], y[ 1 ] );
96-
t.strictEqual( out, cos( x ), 'returns expected value' );
108+
if ( out === expected[ i ] ) {
109+
t.strictEqual( out, expected[ i ], 'returns expected value' );
110+
} else {
111+
delta = abs( out - expected[ i ] );
112+
113+
// NOTE: the tolerance here is larger than for the JavaScript implementation due to compiler optimizations which may be performed resulting in result divergence. For discussion, see https://github.com/stdlib-js/stdlib/pull/2298#discussion_r1624765205
114+
tol = EPS * abs( expected[ i ] );
115+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
116+
}
97117
break;
98118
default:
99119
break;
@@ -103,26 +123,38 @@ tape( 'the function can be used to compute the cosine for input values outside o
103123
});
104124

105125
tape( 'the function can be used to compute the cosine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (negative)', opts, function test( t ) {
126+
var expected;
106127
var values;
128+
var delta;
129+
var tol;
107130
var out;
108131
var x;
109132
var y;
110133
var n;
111134
var i;
112135

113-
values = linspace( -200.0*PI/4.0, -40.0*PI/4.0, 1000 );
114-
y = new Array( 2 );
136+
values = largeNegative.x;
137+
expected = largeNegative.expected;
138+
y = [ 0.0, 0.0 ];
115139
for ( i = 0; i < values.length; i++ ) {
116140
x = values[ i ];
117141
n = rempio2( x, y );
118142
switch ( n & 3 ) {
119143
case 0:
120144
out = kernelCos( y[ 0 ], y[ 1 ] );
121-
t.strictEqual( out, cos( x ), 'returns expected value' );
145+
t.strictEqual( out, expected[ i ], 'returns expected value' );
122146
break;
123147
case 2:
124148
out = -kernelCos( y[ 0 ], y[ 1 ] );
125-
t.strictEqual( out, cos( x ), 'returns expected value' );
149+
if ( out === expected[ i ] ) {
150+
t.strictEqual( out, expected[ i ], 'returns expected value' );
151+
} else {
152+
delta = abs( out - expected[ i ] );
153+
154+
// NOTE: the tolerance here is larger than for the JavaScript implementation due to compiler optimizations which may be performed resulting in result divergence. For discussion, see https://github.com/stdlib-js/stdlib/pull/2298#discussion_r1624765205
155+
tol = EPS * abs( expected[ i ] );
156+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
157+
}
126158
break;
127159
default:
128160
break;

0 commit comments

Comments
 (0)