Skip to content

Commit 90f8a26

Browse files
test: validate implementation against Julia test fixtures
PR-URL: #5942 Reviewed-by: Athan Reines <kgryte@gmail.com>
1 parent b62a24d commit 90f8a26

File tree

7 files changed

+175
-28
lines changed

7 files changed

+175
-28
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-sin/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-sin/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 = sin.( 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-sin/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-sin/test/test.js

Lines changed: 24 additions & 14 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 sin = require( '@stdlib/math/base/special/sin' );
2926
var kernelSin = 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 = kernelSin( NaN, 0.0 );
42-
t.equal( isnan( v ), true, 'returns NaN' );
46+
t.equal( isnan( v ), true, 'returns expected value' );
4347

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

4751
v = kernelSin( 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 sine 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 = kernelSin( x, 0.0 );
62-
t.strictEqual( out, sin( 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 sine 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 );
82+
values = largePositive.x;
83+
expected = largePositive.expected;
7684
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 = kernelSin( y[ 0 ], y[ 1 ] );
83-
t.strictEqual( out, sin( x ), 'returns expected value' );
91+
t.strictEqual( out, expected[ i ], 'returns expected value' );
8492
break;
8593
case 2:
8694
out = -kernelSin( y[ 0 ], y[ 1 ] );
87-
t.strictEqual( out, sin( 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 sine for input values outside of
94102
});
95103

96104
tape( 'the function can be used to compute the sine 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 );
113+
values = largeNegative.x;
114+
expected = largeNegative.expected;
105115
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 = kernelSin( y[ 0 ], y[ 1 ] );
112-
t.strictEqual( out, sin( x ), 'returns expected value' );
122+
t.strictEqual( out, expected[ i ], 'returns expected value' );
113123
break;
114124
case 2:
115125
out = -kernelSin( y[ 0 ], y[ 1 ] );
116-
t.strictEqual( out, sin( 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-sin/test/test.native.js

Lines changed: 72 additions & 14 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' );
2726
var rempio2 = require( '@stdlib/math/base/special/rempio2' );
28-
var PI = require( '@stdlib/constants/float64/pi' );
29-
var sin = require( '@stdlib/math/base/special/sin' );
27+
var abs = require( '@stdlib/math/base/special/abs' );
28+
var EPS = require( '@stdlib/constants/float64/eps' );
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,84 @@ 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 = kernelSin( NaN, 0.0 );
51-
t.equal( isnan( v ), true, 'returns NaN' );
57+
t.equal( isnan( v ), true, 'returns expected value' );
5258

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

5662
v = kernelSin( 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 sine for input values on the interval `[-pi/4, pi/4]`', opts, function test( t ) {
68+
var expected;
6269
var values;
70+
var delta;
71+
var tol;
6372
var out;
6473
var x;
6574
var i;
6675

67-
values = linspace( -PI/4.0, PI/4.0, 1000 );
76+
values = smallRange.x;
77+
expected = smallRange.expected;
6878
for ( i = 0; i < values.length; i++ ) {
6979
x = values[ i ];
7080
out = kernelSin( x, 0.0 );
71-
t.strictEqual( out, sin( x ), 'returns expected value' );
81+
if ( out === expected[ i ] ) {
82+
t.strictEqual( out, expected[ i ], 'returns expected value' );
83+
} else {
84+
delta = abs( out - expected[ i ] );
85+
86+
// 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
87+
tol = EPS * abs( expected[ i ] );
88+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
89+
}
7290
}
7391
t.end();
7492
});
7593

7694
tape( 'the function can be used to compute the sine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (positive)', opts, function test( t ) {
95+
var expected;
7796
var values;
97+
var delta;
98+
var tol;
7899
var out;
79100
var x;
80101
var y;
81102
var n;
82103
var i;
83104

84-
values = linspace( 40.0*PI/4.0, 200*PI/4.0, 1000 );
105+
values = largePositive.x;
106+
expected = largePositive.expected;
85107
y = [ 0.0, 0.0 ];
86108
for ( i = 0; i < values.length; i++ ) {
87109
x = values[ i ];
88110
n = rempio2( x, y );
89111
switch ( n & 3 ) {
90112
case 0:
91113
out = kernelSin( y[ 0 ], y[ 1 ] );
92-
t.strictEqual( out, sin( x ), 'returns expected value' );
114+
if ( out === expected[ i ] ) {
115+
t.strictEqual( out, expected[ i ], 'returns expected value' );
116+
} else {
117+
delta = abs( out - expected[ i ] );
118+
119+
// 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
120+
tol = EPS * abs( expected[ i ] );
121+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
122+
}
93123
break;
94124
case 2:
95125
out = -kernelSin( y[ 0 ], y[ 1 ] );
96-
t.strictEqual( out, sin( x ), 'returns expected value' );
126+
if ( out === expected[ i ] ) {
127+
t.strictEqual( out, expected[ i ], 'returns expected value' );
128+
} else {
129+
delta = abs( out - expected[ i ] );
130+
131+
// 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
132+
tol = EPS * abs( expected[ i ] );
133+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
134+
}
97135
break;
98136
default:
99137
break;
@@ -103,26 +141,46 @@ tape( 'the function can be used to compute the sine for input values outside of
103141
});
104142

105143
tape( 'the function can be used to compute the sine for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (negative)', opts, function test( t ) {
144+
var expected;
106145
var values;
146+
var delta;
147+
var tol;
107148
var out;
108149
var x;
109150
var y;
110151
var n;
111152
var i;
112153

113-
values = linspace( -200.0*PI/4.0, -40.0*PI/4.0, 1000 );
154+
values = largeNegative.x;
155+
expected = largeNegative.expected;
114156
y = [ 0.0, 0.0 ];
115157
for ( i = 0; i < values.length; i++ ) {
116158
x = values[ i ];
117159
n = rempio2( x, y );
118160
switch ( n & 3 ) {
119161
case 0:
120162
out = kernelSin( y[ 0 ], y[ 1 ] );
121-
t.strictEqual( out, sin( x ), 'returns expected value' );
163+
if ( out === expected[ i ] ) {
164+
t.strictEqual( out, expected[ i ], 'returns expected value' );
165+
} else {
166+
delta = abs( out - expected[ i ] );
167+
168+
// 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
169+
tol = EPS * abs( expected[ i ] );
170+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
171+
}
122172
break;
123173
case 2:
124174
out = -kernelSin( y[ 0 ], y[ 1 ] );
125-
t.strictEqual( out, sin( x ), 'returns expected value' );
175+
if ( out === expected[ i ] ) {
176+
t.strictEqual( out, expected[ i ], 'returns expected value' );
177+
} else {
178+
delta = abs( out - expected[ i ] );
179+
180+
// 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
181+
tol = EPS * abs( expected[ i ] );
182+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
183+
}
126184
break;
127185
default:
128186
break;

0 commit comments

Comments
 (0)