Skip to content

Commit c0c0cef

Browse files
committed
Refactor to support casting and codegen options
1 parent c515425 commit c0c0cef

File tree

8 files changed

+329
-35
lines changed

8 files changed

+329
-35
lines changed

lib/node_modules/@stdlib/blas/ddot/README.md

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ The [dot product][dot-product] (or scalar product) is defined as
4747
var ddot = require( '@stdlib/blas/ddot' );
4848
```
4949

50-
#### ddot( x, y )
50+
#### ddot( x, y\[, options] )
5151

5252
Calculates the dot product of vectors `x` and `y`.
5353

@@ -67,20 +67,43 @@ The function has the following parameters:
6767
- **x**: a 1-dimensional [`ndarray`][@stdlib/ndarray/array] or an array-like object. If provided an array-like object or [`ndarray`][@stdlib/ndarray/array] whose underlying data type is **not** `float64`, the value is cast to a 1-dimensional [`ndarray`][@stdlib/ndarray/array] whose data type is `float64`.
6868
- **y**: a 1-dimensional [`ndarray`][@stdlib/ndarray/array] or an array-like object. If provided an array-like object or [`ndarray`][@stdlib/ndarray/array] whose underlying data type is **not** `float64`, the value is cast to a 1-dimensional [`ndarray`][@stdlib/ndarray/array] whose data type is `float64`.
6969

70-
Provided vectors may be either [`ndarrays`][@stdlib/ndarray/array] and array-like objects. For example, the function accepts generic arrays.
70+
The function accepts the following `options`:
71+
72+
- `casting`: specifies the casting rule used to determine acceptable casts. The option may be one of the following values:
73+
74+
- `none`: only allow casting between identical types.
75+
- `equiv`: allow casting between identical and byte swapped types.
76+
- `safe`: only allow ["safe"][@stdlib/ndarray/safe-casts] casts.
77+
- `same-kind`: allow ["safe"][@stdlib/ndarray/safe-casts] casts and casts within the same kind (e.g., between signed integers or between floats).
78+
- `unsafe`: allow casting between all types (including between integers and floats).
79+
80+
Default: `'safe'`.
81+
82+
- `codegen`: `boolean` indicating whether to use code generation. Default: `true`.
83+
84+
Provided vectors may be either [`ndarrays`][@stdlib/ndarray/array] or array-like objects. However, by default, only array-like objects which can be [safely cast][@stdlib/ndarray/safe-casts] to `float64` are supported. In order to operate on numeric data stored in array-like objects which cannot be [safely cast][@stdlib/ndarray/safe-casts], one must explicitly set the `casting` option to `'unsafe'`. For example, because generic arrays can contain arbitrary data (including non-numeric types), thus allowing for potentially "unsafe" casts (e.g., strings representing integer values, such as "big integers", which cannot be accurately stored as double-precision floating-point numbers), one must explicitly set the `casting` option.
7185

7286
```javascript
7387
var x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
7488
var y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
7589

76-
var z = ddot( x, y );
90+
var opts = {
91+
'casting': 'unsafe'
92+
};
93+
var z = ddot( x, y, opts );
7794
// returns -5.0
7895
```
7996

8097
If provided empty vectors, the function returns `0.0`.
8198

8299
```javascript
83-
var z = ddot( [], [] );
100+
var Float64Array = require( '@stdlib/array/float64' );
101+
var array = require( '@stdlib/ndarray/array' );
102+
103+
var x = array( new Float64Array() );
104+
var y = array( new Float64Array() );
105+
106+
var z = ddot( x, y );
84107
// returns 0.0
85108
```
86109

@@ -93,8 +116,9 @@ var z = ddot( [], [] );
93116
## Notes
94117

95118
- `ddot()` provides a higher-level interface to the [BLAS][blas] level 1 function [`ddot`][@stdlib/blas/base/ddot].
96-
- Casting is **not** [safe][@stdlib/ndarray/safe-casts] in order to accommodate generic arrays and array-like objects.
97119
- For best performance, provide 1-dimensional [`ndarrays`][@stdlib/ndarray/array] whose underlying data type is `float64`.
120+
- Options are only applicable when either `x` or `y` is not already an `ndarray` whose underlying data type is `float64`.
121+
- Code generation can boost performance, but may be problematic in browser contexts enforcing a strict [content security policy][mdn-csp] (CSP). If running in or targeting an environment with a CSP, set the `codegen` option to `false`.
98122

99123
</section>
100124

@@ -138,6 +162,8 @@ console.log( z );
138162

139163
[dot-product]: https://en.wikipedia.org/wiki/Dot_product
140164

165+
[mdn-csp]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP
166+
141167
[blas]: http://www.netlib.org/blas
142168

143169
[@stdlib/blas/base/ddot]: https://github.com/stdlib-js/stdlib

lib/node_modules/@stdlib/blas/ddot/benchmark/benchmark.cast.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ var ddot = require( './../lib/main.js' );
3838
* @returns {Function} benchmark function
3939
*/
4040
function createBenchmark( len ) {
41+
var opts;
4142
var x;
4243
var y;
4344
var i;
@@ -48,6 +49,9 @@ function createBenchmark( len ) {
4849
x.push( ( randu()*10.0 ) - 20.0 );
4950
y.push( ( randu()*10.0 ) - 20.0 );
5051
}
52+
opts = {
53+
'casting': 'unsafe'
54+
};
5155
return benchmark;
5256

5357
function benchmark( b ) {
@@ -56,7 +60,7 @@ function createBenchmark( len ) {
5660

5761
b.tic();
5862
for ( i = 0; i < b.iterations; i++ ) {
59-
d = ddot( x, y );
63+
d = ddot( x, y, opts );
6064
if ( isnan( d ) ) {
6165
b.fail( 'should not return NaN' );
6266
}

lib/node_modules/@stdlib/blas/ddot/docs/repl.txt

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11

2-
{{alias}}( x, y )
2+
{{alias}}( x, y[, options] )
33
Computes the dot product of two double-precision floating-point vectors.
44

5-
Casting is *not* safe in order to accommodate generic arrays and array-like
6-
objects.
7-
85
For best performance, provide 1-dimensional ndarrays whose underlying data
96
type is 'float64'.
107

@@ -22,6 +19,32 @@
2219
underlying data type is *not* 'float64', the value is cast to a
2320
1-dimensional ndarray whose data type is 'float64'.
2421

22+
options: Object (optional)
23+
Options. This parameter is only applicable when either `x` or `y` is not
24+
already an ndarray whose underlying data type is 'float64'.
25+
26+
options.codegen: boolean (optional)
27+
Boolean indicating whether to use code generation. Code generation can
28+
boost performance, but may be problematic in browser contexts enforcing
29+
a strict content security policy (CSP). This option is only applicable
30+
when either `x` or `y` is not already an ndarray whose underlying data
31+
type is 'float64'. Default: true.
32+
33+
options.casting: string (optional)
34+
Specifies the casting rule used to determine acceptable casts. The
35+
option may be one of the following values:
36+
37+
- 'none': only allow casting between identical types.
38+
- 'equiv': allow casting between identical and byte swapped types.
39+
- 'safe': only allow "safe" casts.
40+
- 'same-kind': allow "safe" casts and casts within the same kind (e.g.,
41+
between signed integers or between floats).
42+
- 'unsafe': allow casting between all types (including between integers
43+
and floats).
44+
45+
This option is only applicable when either `x` or `y` is not already an
46+
ndarray whose underlying data type is 'float64'. Default: 'safe'.
47+
2548
Returns
2649
-------
2750
dot: number
@@ -38,7 +61,7 @@
3861
// Using array-like objects...
3962
> x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
4063
> y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
41-
> {{alias}}( x, y )
64+
> {{alias}}( x, y, { 'casting': 'unsafe' } )
4265
-5.0
4366

4467
See Also

lib/node_modules/@stdlib/blas/ddot/docs/types/index.d.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,45 @@
2020

2121
/// <reference types="@stdlib/types"/>
2222

23-
import { NumericArray } from '@stdlib/types/array';
23+
// import { NumericArray } from '@stdlib/types/array'; // TODO: uncomment once `ndarray` type defs
24+
25+
// FIXME: add `ndarray` type for input arguments
26+
27+
/**
28+
* Interface describing options.
29+
*/
30+
interface Options {
31+
/**
32+
* Boolean indicating whether to use code generation.
33+
*/
34+
codegen?: boolean;
35+
36+
/**
37+
* Casting rule used to determine acceptable casts.
38+
*/
39+
casting?: 'none' | 'equiv' | 'safe' | 'same-kind' | 'unsafe';
40+
}
2441

2542
/**
2643
* Computes the dot product of `x` and `y`.
2744
*
2845
* ## Notes
2946
*
30-
* - Casting is **not** safe in order to accommodate generic arrays and array-like objects.
3147
* - For best performance, provide 1-dimensional `ndarrays` whose underlying data type is `float64`.
48+
* - Options are only applicable when either `x` or `y` is not already an `ndarray` whose underlying data type is `float64`.
3249
*
3350
* @param x - first input array
3451
* @param y - second input array
52+
* @param options - options
53+
* @param options.codegen - boolean indicating whether to use code generation (default: `true`)
54+
* @param options.casting - casting rule used to determine acceptable casts (default: 'safe')
3555
* @throws first argument must be either an array-like object or a 1-dimensional `ndarray`
3656
* @throws second argument must be either an array-like object or a 1-dimensional `ndarray`
3757
* @throws first argument must be either an array-like object or ndarray which can be cast to a 1-dimensional ndarray
3858
* @throws second argument must be either an array-like object or ndarray which can be cast to a 1-dimensional ndarray
3959
* @throws input arrays must be the same length
60+
* @throws casting not allowed
61+
* @throws must provide valid options
4062
* @returns dot product of `x` and `y`
4163
*
4264
* @example
@@ -53,10 +75,13 @@ import { NumericArray } from '@stdlib/types/array';
5375
* var x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
5476
* var y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
5577
*
56-
* var z = ddot( x, y );
78+
* var opts = {
79+
* 'casting': 'unsafe'
80+
* };
81+
* var z = ddot( x, y, opts );
5782
* // returns -5.0
5883
*/
59-
declare function ddot( x: NumericArray, y: NumericArray ): number; // FIXME: add `ndarray` type
84+
declare function ddot( x: any, y: any, options?: Options ): number; // tslint:disable-line:max-line-length
6085

6186

6287
// EXPORTS //

lib/node_modules/@stdlib/blas/ddot/docs/types/test.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ import ddot = require( './index' );
2323

2424
// The function returns a number...
2525
{
26+
// TODO: add ndarray arguments (?)
2627
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ] ); // $ExpectType number
28+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], {} ); // $ExpectType number
29+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': false } ); // $ExpectType number
30+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': 'unsafe' } ); // $ExpectType number
2731
}
2832

2933
// The compiler throws an error if the function is provided a first argument which is not an array-like object or ndarray...
@@ -52,10 +56,43 @@ import ddot = require( './index' );
5256
// ddot( x, ( x: number ): number => x ); // $ExpectError
5357
}
5458

59+
// The compiler throws an error if the function is provided an options argument which is not an object...
60+
{
61+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], 10 ); // $ExpectError
62+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], '10' ); // $ExpectError
63+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], true ); // $ExpectError
64+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], false ); // $ExpectError
65+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], null ); // $ExpectError
66+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], [] ); // $ExpectError
67+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], ( x: number ): number => x ); // $ExpectError
68+
}
69+
70+
// The compiler throws an error if the function is provided a `codegen` option which is not a boolean...
71+
{
72+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': 10 } ); // $ExpectError
73+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': '10' } ); // $ExpectError
74+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': null } ); // $ExpectError
75+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': [] } ); // $ExpectError
76+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': {} } ); // $ExpectError
77+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'codegen': ( x: number ): number => x } ); // $ExpectError
78+
}
79+
80+
// The compiler throws an error if the function is provided an unrecognized/unsupported `casting` option...
81+
{
82+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': 10 } ); // $ExpectError
83+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': '10' } ); // $ExpectError
84+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': true } ); // $ExpectError
85+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': false } ); // $ExpectError
86+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': null } ); // $ExpectError
87+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': [] } ); // $ExpectError
88+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': {} } ); // $ExpectError
89+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], { 'casting': ( x: number ): number => x } ); // $ExpectError
90+
}
91+
5592
// The compiler throws an error if the function is provided an unsupported number of arguments...
5693
{
5794
// FIXME: add ndarray arguments
5895
ddot(); // $ExpectError
5996
ddot( [ 1, 2, 3 ] ); // $ExpectError
60-
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], 1 ); // $ExpectError
97+
ddot( [ 1, 2, 3 ], [ 4, 5, 6 ], {}, 1 ); // $ExpectError
6198
}

lib/node_modules/@stdlib/blas/ddot/lib/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@
4040
* var x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
4141
* var y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
4242
*
43-
* var z = ddot( x, y );
43+
* var opts = {
44+
* 'casting': 'unsafe'
45+
* };
46+
* var z = ddot( x, y, opts );
4447
* // returns -5.0
4548
*/
4649

lib/node_modules/@stdlib/blas/ddot/lib/main.js

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
var isVectorLike = require( '@stdlib/assert/is-vector-like' );
2424
var isArrayLikeObject = require( '@stdlib/assert/is-array-like-object' );
2525
var isFloat64Array = require( '@stdlib/assert/is-float64array' );
26+
var isPlainObject = require( '@stdlib/assert/is-plain-object' );
27+
var hasOwnProp = require( '@stdlib/assert/has-own-property' );
2628
var array = require( '@stdlib/ndarray/array' );
2729
var dot = require( '@stdlib/blas/base/ddot' ).ndarray;
2830

@@ -39,11 +41,17 @@ var dot = require( '@stdlib/blas/base/ddot' ).ndarray;
3941
*
4042
* @param {(ArrayLike|VectorLike)} x - first input array
4143
* @param {(ArrayLike|VectorLike)} y - second input array
44+
* @param {Options} [options] - options
45+
* @param {boolean} [options.codegen=true] - boolean indicating whether to use code generation
46+
* @param {string} [options.casting='safe'] - casting rule used to determine acceptable casts
4247
* @throws {TypeError} first argument must be either an array-like object or a 1-dimensional ndarray
4348
* @throws {TypeError} second argument must be either an array-like object or a 1-dimensional ndarray
4449
* @throws {TypeError} first argument must be either an array-like object or ndarray which can be cast to a 1-dimensional ndarray
4550
* @throws {TypeError} second argument must be either an array-like object or ndarray which can be cast to a 1-dimensional ndarray
4651
* @throws {RangeError} input arrays must be the same length
52+
* @throws {Error} casting not allowed
53+
* @throws {TypeError} options argument must be an object
54+
* @throws {Error} must provide valid options
4755
* @returns {number} dot product of `x` and `y`
4856
*
4957
* @example
@@ -60,10 +68,13 @@ var dot = require( '@stdlib/blas/base/ddot' ).ndarray;
6068
* var x = [ 4.0, 2.0, -3.0, 5.0, -1.0 ];
6169
* var y = [ 2.0, 6.0, -1.0, -4.0, 8.0 ];
6270
*
63-
* var z = ddot( x, y );
71+
* var opts = {
72+
* 'casting': 'unsafe'
73+
* };
74+
* var z = ddot( x, y, opts );
6475
* // returns -5.0
6576
*/
66-
function ddot( x, y ) {
77+
function ddot( x, y, options ) {
6778
var opts;
6879
var bool;
6980

@@ -82,8 +93,22 @@ function ddot( x, y ) {
8293
}
8394
opts = {
8495
'dtype': 'float64',
85-
'casting': 'unsafe'
96+
'casting': 'safe',
97+
'codegen': true
8698
};
99+
if ( arguments.length > 2 ) {
100+
if ( !isPlainObject( options ) ) {
101+
throw new TypeError( 'invalid argument. Options argument must be an object. Value: `' + options + '`.' );
102+
}
103+
if ( hasOwnProp( options, 'codegen' ) ) {
104+
// Delegate option validation to `array` interface...
105+
opts.codegen = options.codegen;
106+
}
107+
if ( hasOwnProp( options, 'casting' ) ) {
108+
// Delegate option validation to `array` interface...
109+
opts.casting = options.casting;
110+
}
111+
}
87112
x = array( x, opts );
88113
y = array( y, opts );
89114
if ( x.shape.length !== 1 ) {

0 commit comments

Comments
 (0)