Repository navigation
Conversation
Coverage Report
The above coverage report was generated for the changes in this PR. |
| <section class="notes"> | ||
|
|
||
| - Elements outside of the copied region are left unchanged. | ||
|
|
||
| </section> |
There was a problem hiding this comment.
| <section class="notes"> | |
| - Elements outside of the copied region are left unchanged. | |
| </section> | |
| <section class="notes"> | |
| ### Notes | |
| - Elements outside of the copied region are left unchanged. | |
| </section> |
Whenever <section class="notes"> in the C APIs section contains text, it must include a ### Notes heading right after opening the tag (see e.g. znancount/README.md and zany/README.md).
| stdlib_blas_ext_ztril( arrays ); | ||
| } | ||
| elapsed = tic() - t; | ||
| for ( j = 0; j < len; j++ ) { | ||
| parts.value = dataB[ j ]; | ||
| if ( isnan( parts.parts[ 0 ] ) || isnan( parts.parts[ 1 ] ) ) { | ||
| fprintf( stderr, "should not return NaN\n" ); | ||
| break; | ||
| } | ||
| } |
There was a problem hiding this comment.
This is not what is desired. You a) need to retain an assertion check within the hot loop and b) should be using functional accessors, such as complex/float64/real and complex/float64/imag.
|
Thanks for the feedback. I added the ### Notes heading and moved the |
|
while reviewing the implementation I made few changes following merged PRs convention
|
| * | ||
| * @param iterations number of iterations | ||
| * @param n number of matrix rows and columns | ||
| * @param passed whether the benchmark passed |
There was a problem hiding this comment.
No longer needed.
| * @param passed whether the benchmark passed |
| * @param passed whether the benchmark passed | ||
| * @return elapsed time in seconds | ||
| */ | ||
| static double benchmark( int iterations, int n, int *passed ) { |
There was a problem hiding this comment.
| static double benchmark( int iterations, int n, int *passed ) { | |
| static double benchmark( int iterations, int n ) { |
| shape[ 1 ] = n; | ||
| strides[ 0 ] = (int64_t)n * STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT; | ||
| strides[ 1 ] = STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT; | ||
| kstrides[ 0 ] = STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT; |
There was a problem hiding this comment.
0-d strides should be 0.
| kstrides[ 0 ] = STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT; | |
| kstrides[ 0 ] = 0; |
There was a problem hiding this comment.
This should benchmark the JS implementation directly, as in zwxsa.
| var ztril = require( './../lib/main.js' ); |
There was a problem hiding this comment.
This should match benchmark.js apart from the native wiring (resolve, tryRequire, opts, and ::native in the name), as in zwxsa. Right now the requires are reordered, options is inlined, the @param text and main() are changed, and there's an extra imag check.
| * - a two-dimensional input ndarray corresponding to `A`. | ||
| * - a two-dimensional output ndarray corresponding to `B`. | ||
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. | ||
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. |
There was a problem hiding this comment.
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. | |
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. |
| - a two-dimensional output ndarray corresponding to `B`. | ||
| - a zero-dimensional ndarray specifying the diagonal above which to | ||
| ignore. | ||
| - an int32 scalar ndarray for the diagonal above which to ignore. |
There was a problem hiding this comment.
Please keep the original wording; only the dtype in the example should change.
| - an int32 scalar ndarray for the diagonal above which to ignore. | |
| - a zero-dimensional ndarray specifying the diagonal above which to | |
| ignore. |
|
|
||
| // Specify the array strides (in bytes): | ||
| int64_t strides[] = { 2 * STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT, STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT }; | ||
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; |
There was a problem hiding this comment.
0-d strides should be { 0 }.
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; | |
| int64_t kstrides[] = { 0 }; |
| * - a two-dimensional input ndarray corresponding to `A`. | ||
| * - a two-dimensional output ndarray corresponding to `B`. | ||
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. | ||
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. |
There was a problem hiding this comment.
Same as dtril: only generic → int32 should change.
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. | |
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. |
| * | ||
| * - a two-dimensional input ndarray corresponding to `A`. | ||
| * - a two-dimensional output ndarray corresponding to `B`. | ||
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. |
There was a problem hiding this comment.
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. | |
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. |
| * | ||
| * - a two-dimensional input ndarray corresponding to `A`. | ||
| * - a two-dimensional output ndarray corresponding to `B`. | ||
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. |
There was a problem hiding this comment.
| * - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. | |
| * - a zero-dimensional ndarray specifying the diagonal above which to ignore. |
| - a two-dimensional input ndarray corresponding to `A`. | ||
| - a two-dimensional output ndarray corresponding to `B`. | ||
| - a zero-dimensional ndarray specifying the diagonal above which to ignore. A value equal to zero refers to the main diagonal, greater than zero refers to a diagonal above the main diagonal, and less than zero refers to a diagonal below the main diagonal. | ||
| - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. A value equal to zero refers to the main diagonal, greater than zero refers to a diagonal above the main diagonal, and less than zero refers to a diagonal below the main diagonal. |
There was a problem hiding this comment.
| - a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. A value equal to zero refers to the main diagonal, greater than zero refers to a diagonal above the main diagonal, and less than zero refers to a diagonal below the main diagonal. | |
| - a zero-dimensional ndarray specifying the diagonal above which to ignore. A value equal to zero refers to the main diagonal, greater than zero refers to a diagonal above the main diagonal, and less than zero refers to a diagonal below the main diagonal. |
| int32_t dataK[] = { 0 }; | ||
| int64_t shape[] = { 2, 2 }; | ||
| int64_t strides[] = { 2 * STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT, STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT }; | ||
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; |
There was a problem hiding this comment.
0-d strides should be { 0 }.
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; | |
| int64_t kstrides[] = { 0 }; |
|
|
||
| - `[in] struct ndarray*` a two-dimensional input ndarray corresponding to `A`. | ||
| - `[inout] struct ndarray*` a two-dimensional output ndarray corresponding to `B`. | ||
| - `[in] struct ndarray*` a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. |
There was a problem hiding this comment.
| - `[in] struct ndarray*` a zero-dimensional int32 ndarray specifying the diagonal above which to ignore. | |
| - `[in] struct ndarray*` a zero-dimensional ndarray specifying the diagonal above which to ignore. |
|
|
||
| // Specify the array strides (in bytes): | ||
| int64_t strides[] = { 2 * STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT, STDLIB_NDARRAY_COMPLEX128_BYTES_PER_ELEMENT }; | ||
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; |
There was a problem hiding this comment.
0-d strides should be { 0 }.
| int64_t kstrides[] = { STDLIB_NDARRAY_INT32_BYTES_PER_ELEMENT }; | |
| int64_t kstrides[] = { 0 }; |
| const struct ndarray *A = arrays[ 0 ]; | ||
| const struct ndarray *B = arrays[ 1 ]; | ||
| const struct ndarray *karr = arrays[ 2 ]; | ||
|
|
||
| const int64_t *shape = stdlib_ndarray_shape( A ); | ||
| const CBLAS_INT M = (CBLAS_INT)shape[ 0 ]; | ||
| const CBLAS_INT N = (CBLAS_INT)shape[ 1 ]; | ||
|
|
||
| const CBLAS_INT strideA1 = (CBLAS_INT)stdlib_ndarray_stride_elements( A, 0 ); | ||
| const CBLAS_INT strideA2 = (CBLAS_INT)stdlib_ndarray_stride_elements( A, 1 ); | ||
| const CBLAS_INT offsetA = (CBLAS_INT)stdlib_ndarray_offset_elements( A ); | ||
| const CBLAS_INT strideB1 = (CBLAS_INT)stdlib_ndarray_stride_elements( B, 0 ); | ||
| const CBLAS_INT strideB2 = (CBLAS_INT)stdlib_ndarray_stride_elements( B, 1 ); | ||
| const CBLAS_INT offsetB = (CBLAS_INT)stdlib_ndarray_offset_elements( B ); | ||
|
|
||
| // The typed getter assumes that the output type matches the ndarray dtype: | ||
| if ( stdlib_ndarray_dtype( karr ) != STDLIB_NDARRAY_INT32 ) { | ||
| return; | ||
| } | ||
| int32_t k_value; | ||
| if ( stdlib_ndarray_get_int32( karr, NULL, &k_value ) != 0 ) { | ||
| return; | ||
| } | ||
| const CBLAS_INT k = (CBLAS_INT)k_value; |
There was a problem hiding this comment.
Read k directly, as in zwxsa.
| const struct ndarray *A = arrays[ 0 ]; | |
| const struct ndarray *B = arrays[ 1 ]; | |
| const struct ndarray *karr = arrays[ 2 ]; | |
| const int64_t *shape = stdlib_ndarray_shape( A ); | |
| const CBLAS_INT M = (CBLAS_INT)shape[ 0 ]; | |
| const CBLAS_INT N = (CBLAS_INT)shape[ 1 ]; | |
| const CBLAS_INT strideA1 = (CBLAS_INT)stdlib_ndarray_stride_elements( A, 0 ); | |
| const CBLAS_INT strideA2 = (CBLAS_INT)stdlib_ndarray_stride_elements( A, 1 ); | |
| const CBLAS_INT offsetA = (CBLAS_INT)stdlib_ndarray_offset_elements( A ); | |
| const CBLAS_INT strideB1 = (CBLAS_INT)stdlib_ndarray_stride_elements( B, 0 ); | |
| const CBLAS_INT strideB2 = (CBLAS_INT)stdlib_ndarray_stride_elements( B, 1 ); | |
| const CBLAS_INT offsetB = (CBLAS_INT)stdlib_ndarray_offset_elements( B ); | |
| // The typed getter assumes that the output type matches the ndarray dtype: | |
| if ( stdlib_ndarray_dtype( karr ) != STDLIB_NDARRAY_INT32 ) { | |
| return; | |
| } | |
| int32_t k_value; | |
| if ( stdlib_ndarray_get_int32( karr, NULL, &k_value ) != 0 ) { | |
| return; | |
| } | |
| const CBLAS_INT k = (CBLAS_INT)k_value; | |
| const struct ndarray *A = arrays[ 0 ]; | |
| const struct ndarray *B = arrays[ 1 ]; | |
| int32_t k; | |
| stdlib_ndarray_get_int32( arrays[ 2 ], NULL, &k ); | |
| const CBLAS_INT M = stdlib_ndarray_dimension( A, 0 ); | |
| const CBLAS_INT N = stdlib_ndarray_dimension( A, 1 ); | |
| const CBLAS_INT strideA1 = stdlib_ndarray_stride_elements( A, 0 ); | |
| const CBLAS_INT strideA2 = stdlib_ndarray_stride_elements( A, 1 ); | |
| const CBLAS_INT offsetA = stdlib_ndarray_offset_elements( A ); | |
| const CBLAS_INT strideB1 = stdlib_ndarray_stride_elements( B, 0 ); | |
| const CBLAS_INT strideB2 = stdlib_ndarray_stride_elements( B, 1 ); | |
| const CBLAS_INT offsetB = stdlib_ndarray_offset_elements( B ); |
There was a problem hiding this comment.
@yb175 This is only partly applied. k_value, the (CBLAS_INT) casts on the strides, and const CBLAS_INT k = (CBLAS_INT)k_value; are still there. Please apply the suggestion as is.
| *passed = 1; | ||
| t = tic(); | ||
| for ( i = 0; i < iterations; i++ ) { | ||
| stdlib_blas_ext_ztril( arrays ); | ||
| if ( | ||
| stdlib_complex128_real( dataB[ 0 ] ) != stdlib_complex128_real( dataB[ 0 ] ) || | ||
| stdlib_complex128_imag( dataB[ 0 ] ) != stdlib_complex128_imag( dataB[ 0 ] ) | ||
| ) { | ||
| fprintf( stderr, "should not return NaN\n" ); | ||
| *passed = 0; | ||
| break; | ||
| } | ||
| } | ||
| elapsed = tic() - t; |
There was a problem hiding this comment.
Follow the standard layout, as in dtril.
| *passed = 1; | |
| t = tic(); | |
| for ( i = 0; i < iterations; i++ ) { | |
| stdlib_blas_ext_ztril( arrays ); | |
| if ( | |
| stdlib_complex128_real( dataB[ 0 ] ) != stdlib_complex128_real( dataB[ 0 ] ) || | |
| stdlib_complex128_imag( dataB[ 0 ] ) != stdlib_complex128_imag( dataB[ 0 ] ) | |
| ) { | |
| fprintf( stderr, "should not return NaN\n" ); | |
| *passed = 0; | |
| break; | |
| } | |
| } | |
| elapsed = tic() - t; | |
| t = tic(); | |
| for ( i = 0; i < iterations; i++ ) { | |
| stdlib_blas_ext_ztril( arrays ); | |
| if ( stdlib_complex128_real( dataB[ 0 ] ) != stdlib_complex128_real( dataB[ 0 ] ) || stdlib_complex128_imag( dataB[ 0 ] ) != stdlib_complex128_imag( dataB[ 0 ] ) ) { | |
| printf( "should not return NaN\n" ); | |
| break; | |
| } | |
| } | |
| elapsed = tic() - t; | |
| if ( stdlib_complex128_real( dataB[ 0 ] ) != stdlib_complex128_real( dataB[ 0 ] ) || stdlib_complex128_imag( dataB[ 0 ] ) != stdlib_complex128_imag( dataB[ 0 ] ) ) { | |
| printf( "should not return NaN\n" ); | |
| } |
| double elapsed; | ||
| int count; | ||
| int passing; | ||
| int passed; | ||
| int iter; | ||
| int n; | ||
| int i; | ||
| int j; | ||
|
|
||
| srand( (unsigned int)time( NULL ) ); | ||
| print_version(); | ||
| count = 0; | ||
| passing = 0; | ||
| for ( i = MIN; i <= MAX; i++ ) { | ||
| n = (int)pow( 10.0, (double)i ); | ||
| iter = ITERATIONS / (int)pow( 10.0, (double)(2*(i-1)) ); | ||
| for ( j = 0; j < REPEATS; j++ ) { | ||
| count += 1; | ||
| printf( "# c::%s:size=%d\n", NAME, n*n ); | ||
| elapsed = benchmark( iter, n, &passed ); | ||
| if ( passed ) { | ||
| print_results( iter, elapsed ); | ||
| passing += 1; | ||
| printf( "ok %d benchmark finished\n", count ); | ||
| } else { | ||
| printf( "not ok %d benchmark detected NaN\n", count ); | ||
| } | ||
| } | ||
| } | ||
| print_summary( count, passing ); | ||
| return ( passing == count ) ? 0 : 1; |
There was a problem hiding this comment.
Same here: standard main() layout.
| double elapsed; | |
| int count; | |
| int passing; | |
| int passed; | |
| int iter; | |
| int n; | |
| int i; | |
| int j; | |
| srand( (unsigned int)time( NULL ) ); | |
| print_version(); | |
| count = 0; | |
| passing = 0; | |
| for ( i = MIN; i <= MAX; i++ ) { | |
| n = (int)pow( 10.0, (double)i ); | |
| iter = ITERATIONS / (int)pow( 10.0, (double)(2*(i-1)) ); | |
| for ( j = 0; j < REPEATS; j++ ) { | |
| count += 1; | |
| printf( "# c::%s:size=%d\n", NAME, n*n ); | |
| elapsed = benchmark( iter, n, &passed ); | |
| if ( passed ) { | |
| print_results( iter, elapsed ); | |
| passing += 1; | |
| printf( "ok %d benchmark finished\n", count ); | |
| } else { | |
| printf( "not ok %d benchmark detected NaN\n", count ); | |
| } | |
| } | |
| } | |
| print_summary( count, passing ); | |
| return ( passing == count ) ? 0 : 1; | |
| double elapsed; | |
| int count; | |
| int iter; | |
| int n; | |
| int i; | |
| int j; | |
| // Use the current time to seed the random number generator: | |
| srand( time( NULL ) ); | |
| print_version(); | |
| count = 0; | |
| for ( i = MIN; i <= MAX; i++ ) { | |
| n = pow( 10, i ); | |
| iter = ITERATIONS / pow( 10, 2*(i-1) ); | |
| for ( j = 0; j < REPEATS; j++ ) { | |
| count += 1; | |
| printf( "# c::%s:size=%d\n", NAME, n*n ); | |
| elapsed = benchmark( iter, n ); | |
| print_results( iter, elapsed ); | |
| printf( "ok %d benchmark finished\n", count ); | |
| } | |
| } | |
| print_summary( count, count ); |
|
@yb175 , Left a few suggestions, PTAL; |
|
@yb175 In general, you need to pay much closer attention to how other packages are structured. Only the minimal essential changes should be present among separate similar packages. |
Thanks @kgryte for the feedback , from next time I would carefully observe the merged PRs from the similar packages before opening future PRs 😊 |
| printf( "# total %d\n", total ); | ||
| printf( "# pass %d\n", passing ); | ||
| printf( "#\n" ); | ||
| printf( "# %s\n", passing == total ? "ok" : "not ok" ); |
There was a problem hiding this comment.
| printf( "# %s\n", passing == total ? "ok" : "not ok" ); | |
| printf( "# ok\n" ); |
| } | ||
|
|
||
| /** | ||
| * Prints benchmark results. |
There was a problem hiding this comment.
| * Prints benchmark results. | |
| * Prints benchmarks results. |
| * Returns the current time. | ||
| * | ||
| * @return current time in seconds |
There was a problem hiding this comment.
| * Returns the current time. | |
| * | |
| * @return current time in seconds | |
| * Returns a clock time. | |
| * | |
| * @return clock time |
| * // returns true | ||
| */ | ||
| declare function ztril( arrays: [ complex128ndarray, complex128ndarray, typedndarray<number> ] ): complex128ndarray; | ||
| declare function ztril( arrays: [ complex128ndarray, complex128ndarray, int32ndarray ] ): complex128ndarray; |
There was a problem hiding this comment.
@kgryte Is it okay for k to be int32ndarray here as well ?
|
addressed all other review suggestions . leaving the |
| var bench = require( '@stdlib/bench' ); | ||
| var pow = require( '@stdlib/math/base/special/pow' ); | ||
| var format = require( '@stdlib/string/format' ); | ||
| var Complex128Matrix = require( '@stdlib/ndarray/matrix/complex128' ); | ||
| var uniform = require( '@stdlib/random/array/uniform' ); | ||
| var scalar2ndarray = require( '@stdlib/ndarray/from-scalar' ); | ||
| var isnan = require( '@stdlib/math/base/assert/is-nan' ); | ||
| var real = require( '@stdlib/complex/float64/real' ); | ||
| var tryRequire = require( '@stdlib/utils/try-require' ); |
There was a problem hiding this comment.
Keep the same order as benchmark.js.
| var bench = require( '@stdlib/bench' ); | |
| var pow = require( '@stdlib/math/base/special/pow' ); | |
| var format = require( '@stdlib/string/format' ); | |
| var Complex128Matrix = require( '@stdlib/ndarray/matrix/complex128' ); | |
| var uniform = require( '@stdlib/random/array/uniform' ); | |
| var scalar2ndarray = require( '@stdlib/ndarray/from-scalar' ); | |
| var isnan = require( '@stdlib/math/base/assert/is-nan' ); | |
| var real = require( '@stdlib/complex/float64/real' ); | |
| var tryRequire = require( '@stdlib/utils/try-require' ); | |
| var bench = require( '@stdlib/bench' ); | |
| var uniform = require( '@stdlib/random/array/uniform' ); | |
| var Complex128Matrix = require( '@stdlib/ndarray/matrix/complex128' ); | |
| var isnan = require( '@stdlib/math/base/assert/is-nan' ); | |
| var real = require( '@stdlib/complex/float64/real' ); | |
| var pow = require( '@stdlib/math/base/special/pow' ); | |
| var format = require( '@stdlib/string/format' ); | |
| var scalar2ndarray = require( '@stdlib/ndarray/from-scalar' ); | |
| var tryRequire = require( '@stdlib/utils/try-require' ); |
| var ztril = tryRequire( resolve( __dirname, './../lib/native.js' ) ); | ||
| var opts = { | ||
| 'skip': ( ztril instanceof Error ) | ||
| }; |
There was a problem hiding this comment.
| var ztril = tryRequire( resolve( __dirname, './../lib/native.js' ) ); | |
| var opts = { | |
| 'skip': ( ztril instanceof Error ) | |
| }; | |
| var ztril = tryRequire( resolve( __dirname, './../lib/native.js' ) ); | |
| var opts = { | |
| 'skip': ( ztril instanceof Error ) | |
| }; | |
| var options = { | |
| 'dtype': 'float64' | |
| }; |
| * Creates a benchmark function. | ||
| * | ||
| * @private | ||
| * @param {PositiveInteger} N - number of rows and columns |
There was a problem hiding this comment.
| * @param {PositiveInteger} N - number of rows and columns | |
| * @param {PositiveInteger} N - number of elements along each dimension |
| abuf = uniform( N*N*2, -100.0, 100.0, { | ||
| 'dtype': 'float64' | ||
| }); | ||
| bbuf = uniform( N*N*2, -100.0, 100.0, { | ||
| 'dtype': 'float64' | ||
| }); | ||
| A = new Complex128Matrix( abuf.buffer, 0, N, N ); | ||
| B = new Complex128Matrix( bbuf.buffer, 0, N, N ); |
There was a problem hiding this comment.
| abuf = uniform( N*N*2, -100.0, 100.0, { | |
| 'dtype': 'float64' | |
| }); | |
| bbuf = uniform( N*N*2, -100.0, 100.0, { | |
| 'dtype': 'float64' | |
| }); | |
| A = new Complex128Matrix( abuf.buffer, 0, N, N ); | |
| B = new Complex128Matrix( bbuf.buffer, 0, N, N ); | |
| abuf = uniform( N*N*2, -100.0, 100.0, options ); | |
| bbuf = uniform( N*N*2, -100.0, 100.0, options ); | |
| A = new Complex128Matrix( abuf.buffer, 0, N, N ); | |
| B = new Complex128Matrix( bbuf.buffer, 0, N, N ); | |
Related to #14819.
Description
This pull request:
blas/ext/base/ndarray/ztril, using the existing strided C routine.Related Issues
This pull request has the following related issues:
blas/ext/base/ndarraypackages #14819Questions
The native JS wrapper extracts k from the generic scalar ndarray and passes a float64 scalar ndarray to C, so the existing JS example works. For direct C callers, should stdlib_blas_ext_ztril require a 0-D float64 ndarray for k, or support other numeric dtypes? Since the C function returns void, how would you prefer it to handle an unsupported dtype or unreadable scalar?
Other
No.
Checklist
AI Assistance
If you answered "yes" above, how did you use AI assistance?
Disclosure
I used codex for tests generation and documentation writing , all the changes made by ai are reviewed carefully
@stdlib-js/reviewers