Skip to content

Commit b62a24d

Browse files
test: validate implementation against Julia test fixtures
PR-URL: #5944 Reviewed-by: Athan Reines <[email protected]>
1 parent 01a2787 commit b62a24d

File tree

7 files changed

+149
-18
lines changed

7 files changed

+149
-18
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-tan/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-tan/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 = tan.( 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-tan/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-tan/test/test.js

Lines changed: 19 additions & 9 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 tan = require( '@stdlib/math/base/special/tan' );
2926
var kernelTan = 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 ) {
@@ -60,54 +64,60 @@ tape( 'the function returns `NaN` if provided `NaN` for `x` or `y`', function te
6064
});
6165

6266
tape( 'the function evaluates the tangent for input values inside of `[-pi/4, pi/4]`', function test( t ) {
67+
var expected;
6368
var values;
6469
var out;
6570
var x;
6671
var i;
6772

68-
values = linspace( -PI/4.0, PI/4.0, 1000 );
73+
values = smallRange.x;
74+
expected = smallRange.expected;
6975
for ( i = 0; i < values.length; i++ ) {
7076
x = values[ i ];
7177
out = kernelTan( x, 0.0, 1 );
72-
t.strictEqual( out, tan( x ), 'returns expected value' );
78+
t.strictEqual( out, expected[ i ], 'returns expected value' );
7379
}
7480
t.end();
7581
});
7682

7783
tape( 'the function can be used to compute the tangent for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (positive)', function test( t ) {
84+
var expected;
7885
var values;
7986
var out;
8087
var x;
8188
var y;
8289
var n;
8390
var i;
8491

85-
values = linspace( 40.0*PI/4.0, 200*PI/4.0, 1000 );
92+
values = largePositive.x;
93+
expected = largePositive.expected;
8694
y = [ 0.0, 0.0 ];
8795
for ( i = 0; i < values.length; i++ ) {
8896
x = values[ i ];
8997
n = rempio2( x, y );
9098
out = kernelTan( y[ 0 ], y[ 1 ], 1 - ( (n&1)<<1 ) );
91-
t.strictEqual( out, tan( x ), 'returns expected value' );
99+
t.strictEqual( out, expected[ i ], 'returns expected value' );
92100
}
93101
t.end();
94102
});
95103

96104
tape( 'the function can be used to compute the tangent 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
out = kernelTan( y[ 0 ], y[ 1 ], 1 - ( (n&1)<<1 ) );
110-
t.strictEqual( out, tan( x ), 'returns expected value' );
120+
t.strictEqual( out, expected[ i ], 'returns expected value' );
111121
}
112122
t.end();
113123
});

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

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,19 @@
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 tan = require( '@stdlib/math/base/special/tan' );
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

32+
// FIXTURES //
33+
34+
var smallRange = require( './fixtures/julia/small_range.json' );
35+
var largePositive = require( './fixtures/julia/large_positive.json' );
36+
var largeNegative = require( './fixtures/julia/large_negative.json' );
37+
38+
3339
// VARIABLES //
3440

3541
var kernelTan = tryRequire( resolve( __dirname, './../lib/native.js' ) );
@@ -69,54 +75,90 @@ tape( 'the function returns `NaN` if provided `NaN` for `x` or `y`', opts, funct
6975
});
7076

7177
tape( 'the function evaluates the tangent for input values inside of `[-pi/4, pi/4]`', opts, function test( t ) {
78+
var expected;
7279
var values;
80+
var delta;
81+
var tol;
7382
var out;
7483
var x;
7584
var i;
7685

77-
values = linspace( -PI/4.0, PI/4.0, 1000 );
86+
values = smallRange.x;
87+
expected = smallRange.expected;
7888
for ( i = 0; i < values.length; i++ ) {
7989
x = values[ i ];
8090
out = kernelTan( x, 0.0, 1 );
81-
t.strictEqual( out, tan( x ), 'returns expected value' );
91+
if ( out === expected[ i ] ) {
92+
t.strictEqual( out, expected[ i ], 'returns expected value' );
93+
} else {
94+
delta = abs( out - expected[ i ] );
95+
96+
// 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
97+
tol = EPS * abs( expected[ i ] );
98+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
99+
}
82100
}
83101
t.end();
84102
});
85103

86104
tape( 'the function can be used to compute the tangent for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (positive)', opts, function test( t ) {
105+
var expected;
87106
var values;
107+
var delta;
108+
var tol;
88109
var out;
89110
var x;
90111
var y;
91112
var n;
92113
var i;
93114

94-
values = linspace( 40.0*PI/4.0, 200*PI/4.0, 1000 );
115+
values = largePositive.x;
116+
expected = largePositive.expected;
95117
y = [ 0.0, 0.0 ];
96118
for ( i = 0; i < values.length; i++ ) {
97119
x = values[ i ];
98120
n = rempio2( x, y );
99121
out = kernelTan( y[ 0 ], y[ 1 ], 1 - ( (n&1)<<1 ) );
100-
t.strictEqual( out, tan( x ), 'returns expected value' );
122+
if ( out === expected[ i ] ) {
123+
t.strictEqual( out, expected[ i ], 'returns expected value' );
124+
} else {
125+
delta = abs( out - expected[ i ] );
126+
127+
// 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
128+
tol = EPS * abs( expected[ i ] );
129+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
130+
}
101131
}
102132
t.end();
103133
});
104134

105135
tape( 'the function can be used to compute the tangent for input values outside of `[-pi/4, pi/4]` after argument reduction via `rempio2` (negative)', opts, function test( t ) {
136+
var expected;
106137
var values;
138+
var delta;
139+
var tol;
107140
var out;
108141
var x;
109142
var y;
110143
var n;
111144
var i;
112145

113-
values = linspace( -200.0*PI/4.0, -40.0*PI/4.0, 1000 );
146+
values = largeNegative.x;
147+
expected = largeNegative.expected;
114148
y = [ 0.0, 0.0 ];
115149
for ( i = 0; i < values.length; i++ ) {
116150
x = values[ i ];
117151
n = rempio2( x, y );
118152
out = kernelTan( y[ 0 ], y[ 1 ], 1 - ( (n&1)<<1 ) );
119-
t.strictEqual( out, tan( x ), 'returns expected value' );
153+
if ( out === expected[ i ] ) {
154+
t.strictEqual( out, expected[ i ], 'returns expected value' );
155+
} else {
156+
delta = abs( out - expected[ i ] );
157+
158+
// 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
159+
tol = EPS * abs( expected[ i ] );
160+
t.ok( delta <= tol, 'within tolerance. x: '+x+'. out: '+out+'. E: '+expected[i]+'. tol: '+tol+'. Δ: '+delta+'.' );
161+
}
120162
}
121163
t.end();
122164
});

0 commit comments

Comments
 (0)