Skip to content

Commit

Permalink
Auto-generated commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stdlib-bot committed Mar 24, 2024
1 parent c8b54f2 commit 0cacf4c
Show file tree
Hide file tree
Showing 16 changed files with 1,857 additions and 58 deletions.
84 changes: 61 additions & 23 deletions base/tools/evalpoly-compile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,20 @@ limitations under the License.
var compile = require( '@stdlib/math/base/tools/evalpoly-compile' );
```

#### compile( c )
#### compile( c\[, options] )

Compiles a module `string` containing an exported function which evaluates a [polynomial][@stdlib/math/base/tools/evalpoly] having coefficients `c`.
Compiles a module string containing an exported function which evaluates a [polynomial][@stdlib/math/base/tools/evalpoly] having coefficients `c`.

```javascript
var str = compile( [ 3.0, 2.0, 1.0 ] );
// returns <string>
```

In the example above, the output `string` would correspond to the following module:
The function supports the following `options`:

- **dtype**: input argument floating-point data type (e.g., `float64` or `float32`). Default: `'float64'`.

In the example above, the output string would correspond to the following module:

<!-- eslint-disable no-unused-expressions -->

Expand All @@ -71,7 +75,7 @@ function evalpoly( x ) {
if ( x === 0.0 ) {
return 3.0;
}
return 3.0 + (x * (2.0 + (x * 1.0))); // eslint-disable-line max-len
return 3.0 + (x * (2.0 + (x * 1.0)));
}


Expand All @@ -82,6 +86,55 @@ module.exports = evalpoly;

The coefficients should be ordered in **ascending** degree, thus matching summation notation.

By default, the function assumes double-precision floating-point arithmetic. To emulate single-precision floating-point arithmetic, set the `dtype` option to `'float32'`.

```javascript
var str = compile( [ 3.0, 2.0, 1.0 ], {
'dtype': 'float32'
});
// returns <string>
```

In the previous example, the output string would correspond to the following module:

<!-- eslint-disable no-unused-expressions -->

```javascript
'use strict';

// MODULES //

var float64ToFloat32 = require( '@stdlib/number/float64/base/to-float32' );


// MAIN //

/**
* Evaluates a polynomial.
*
* ## Notes
*
* - The implementation uses [Horner's rule][horners-method] for efficient computation.
*
* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method
*
* @private
* @param {number} x - value at which to evaluate the polynomial
* @returns {number} evaluated polynomial
*/
function evalpoly( x ) {
if ( x === 0.0 ) {
return 3.0;
}
return float64ToFloat32(3.0 + float64ToFloat32(x * float64ToFloat32(2.0 + float64ToFloat32(x * 1.0)))); // eslint-disable-line max-len
}


// EXPORTS //

module.exports = evalpoly;
```

</section>

<!-- /.usage -->
Expand All @@ -103,29 +156,14 @@ The coefficients should be ordered in **ascending** degree, thus matching summat
<!-- eslint no-undef: "error" -->

```javascript
var randu = require( '@stdlib/random/base/randu' );
var round = require( '@stdlib/math/base/special/round' );
var Float64Array = require( '@stdlib/array/float64' );
var discreteUniform = require( '@stdlib/random/array/discrete-uniform' );
var compile = require( '@stdlib/math/base/tools/evalpoly-compile' );

var coef;
var sign;
var str;
var i;

// Create an array of random coefficients...
coef = new Float64Array( 10 );
for ( i = 0; i < coef.length; i++ ) {
if ( randu() < 0.5 ) {
sign = -1.0;
} else {
sign = 1.0;
}
coef[ i ] = sign * round( randu()*100.0 );
}
// Create an array of random coefficients:
var coef = discreteUniform( 10, -100, 100 );

// Compile a module for evaluating a polynomial:
str = compile( coef );
var str = compile( coef );
console.log( str );
```

Expand Down
13 changes: 12 additions & 1 deletion base/tools/evalpoly-compile/docs/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,28 @@

// TypeScript Version: 4.1

/**
* Interface describing function options.
*/
interface Options {
/**
* Input value floating-point data type (e.g., `float64` or `float32`). Default: `'float64'`.
*/
dtype?: 'float64' | 'float32';
}

/**
* Compiles a module string which exports a function for evaluating a polynomial.
*
* @param c - polynomial coefficients sorted in ascending degree
* @param options - function options
* @returns module string exporting a function for evaluating a polynomial
*
* @example
* var str = compile( [ 3.0, 2.0, 1.0 ] );
* // returns <string>
*/
declare function compile( c: Array<number> ): string;
declare function compile( c: Array<number>, options?: Options ): string;


// EXPORTS //
Expand Down
26 changes: 26 additions & 0 deletions base/tools/evalpoly-compile/docs/types/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import compile = require( './index' );
// The function returns a string...
{
compile( [ 3.0, 2.0, 1.0 ] ); // $ExpectType string
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': 'float32' } ); // $ExpectType string
}

// The compiler throws an error if the function is provided a first argument which is not an array of numbers...
Expand All @@ -34,6 +35,31 @@ import compile = require( './index' );
compile( 123 ); // $ExpectError
compile( {} ); // $ExpectError
compile( ( x: number ): number => x ); // $ExpectError

compile( true, {} ); // $ExpectError
compile( false, {} ); // $ExpectError
compile( 'abc', {} ); // $ExpectError
compile( 123, {} ); // $ExpectError
compile( {}, {} ); // $ExpectError
compile( ( x: number ): number => x, {} ); // $ExpectError
}

// The compiler throws an error if the function is provided a second argument which is not an object...
{
compile( [ 3.0, 2.0, 1.0 ], true ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], false ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], 'abc' ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], 123 ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], ( x: number ): number => x ); // $ExpectError
}

// The compiler throws an error if the function is provided an invalid `dtype` option...
{
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': true } ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': false } ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': [] } ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': 123 } ); // $ExpectError
compile( [ 3.0, 2.0, 1.0 ], { 'dtype': ( x: number ): number => x } ); // $ExpectError
}

// The compiler throws an error if the function is provided an insufficient number of arguments...
Expand Down
23 changes: 4 additions & 19 deletions base/tools/evalpoly-compile/examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@
'use strict';

var resolve = require( 'path' ).resolve;
var randu = require( '@stdlib/random/base/randu' );
var round = require( './../../../../base/special/round' );
var Float64Array = require( '@stdlib/array/float64' );
var discreteUniform = require( '@stdlib/random/array/discrete-uniform' );
var tryRequire = require( '@stdlib/utils/try-require' );

var compile = tryRequire( resolve( __dirname, '..', 'lib' ) );
Expand All @@ -32,23 +30,10 @@ if ( compile instanceof Error ) {
}

function main() {
var coef;
var sign;
var str;
var i;

// Create an array of random coefficients...
coef = new Float64Array( 10 );
for ( i = 0; i < coef.length; i++ ) {
if ( randu() < 0.5 ) {
sign = -1.0;
} else {
sign = 1.0;
}
coef[ i ] = sign * round( randu()*100.0 );
}
// Create an array of random coefficients:
var coef = discreteUniform( 10, -100, 100 );

// Compile a module for evaluating a polynomial:
str = compile( coef );
var str = compile( coef );
console.log( str );
}
60 changes: 53 additions & 7 deletions base/tools/evalpoly-compile/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var join = require( 'path' ).join;
var readFile = require( '@stdlib/fs/read-file' ).sync;
var replace = require( '@stdlib/string/replace' );
var isInteger = require( '@stdlib/assert/is-integer' ).isPrimitive;
var Float32Array = require( '@stdlib/array/float32' );


// VARIABLES //
Expand All @@ -35,9 +36,15 @@ var dir = join( __dirname, 'templates' );

// Templates:
var SINGLE_COEFFICIENT_TEMPLATE = readFile( join( dir, 'single_coefficient.js.txt' ), opts ); // eslint-disable-line id-length

var EVALPOLY_TEMPLATE = readFile( join( dir, 'evalpoly.js.txt' ), opts );
var EVALPOLY_FLOAT32_TEMPLATE = readFile( join( dir, 'evalpoly.float32.js.txt' ), opts );

var EMPTY_TEMPLATE = readFile( join( dir, 'empty.js.txt' ), opts );

var LOOP_TEMPLATE = readFile( join( dir, 'loop.js.txt' ), opts );
var LOOP_FLOAT32_TEMPLATE = readFile( join( dir, 'loop.float32.js.txt' ), opts );

var MAX_CHARS = 68; // max-len (80) - chars already in line ('tab': 4, 'return ': 7, ';': 1)


Expand All @@ -47,25 +54,39 @@ var MAX_CHARS = 68; // max-len (80) - chars already in line ('tab': 4, 'return '
* Compiles a module string which exports a function for evaluating a polynomial.
*
* @param {NumericArray} c - polynomial coefficients sorted in ascending degree
* @param {Options} [options] - function options
* @param {string} [options.dtype='float64'] - input value floating-point data type
* @returns {string} module string exporting a function for evaluating a polynomial
*
* @example
* var str = compile( [ 3.0, 2.0, 1.0 ] );
* // returns <string>
*/
function compile( c ) {
function compile( c, options ) {
var horner;
var opts;
var tmpl;
var str;
var n;
var m;
var i;

opts = {
'dtype': 'float64'
};
if ( arguments.length > 1 ) {
opts.dtype = options.dtype || opts.dtype;
}
n = c.length;

// If no coefficients, the function always returns 0...
if ( n === 0 ) {
return EMPTY_TEMPLATE;
}
if ( opts.dtype === 'float32' ) {
// Ensure that coefficients have been converted to single-precision:
c = new Float32Array( c );
}
// If only one coefficient, the function always returns that coefficient...
if ( n === 1 ) {
str = c[ 0 ].toString();
Expand All @@ -88,17 +109,34 @@ function compile( c ) {
str += ',\n';
}
}
return replace( LOOP_TEMPLATE, '{{coefficients}}', str );
if ( opts.dtype === 'float32' ) {
tmpl = LOOP_FLOAT32_TEMPLATE;
} else {
tmpl = LOOP_TEMPLATE;
}
return replace( tmpl, '{{coefficients}}', str );
}
// If more than one coefficient, apply Horner's method...
horner = c[ 0 ].toString();
if ( opts.dtype === 'float32' ) {
horner = 'float64ToFloat32(';
} else {
horner = '';
}
horner += c[ 0 ].toString();
if ( isInteger( c[ 0 ] ) ) {
horner += '.0';
}
for ( i = 1; i < n; i++ ) {
horner += ' + (x * ';
if ( i < m ) {
horner += '(';
if ( opts.dtype === 'float32' ) {
horner += ' + float64ToFloat32(x * ';
if ( i < m ) {
horner += 'float64ToFloat32(';
}
} else {
horner += ' + (x * ';
if ( i < m ) {
horner += '(';
}
}
horner += c[ i ].toString();
if ( isInteger( c[ i ] ) ) {
Expand All @@ -109,11 +147,19 @@ function compile( c ) {
for ( i = 0; i < (2*(n-1))-1; i++ ) {
horner += ')';
}
if ( opts.dtype === 'float32' ) {
horner += ')';
}
str = c[ 0 ].toString();
if ( isInteger( c[ 0 ] ) ) {
str += '.0';
}
str = replace( EVALPOLY_TEMPLATE, '{{coefficient}}', str );
if ( opts.dtype === 'float32' ) {
tmpl = EVALPOLY_FLOAT32_TEMPLATE;
} else {
tmpl = EVALPOLY_TEMPLATE;
}
str = replace( tmpl, '{{coefficient}}', str );
str = replace( str, '{{horner}}', horner );
return replace( str, '{{eslint}}', ( horner.length > MAX_CHARS ) ? ' // eslint-disable-line max-len' : '' );
}
Expand Down
33 changes: 33 additions & 0 deletions base/tools/evalpoly-compile/lib/templates/evalpoly.float32.js.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

// MODULES //

var float64ToFloat32 = require( '@stdlib/number/float64/base/to-float32' );


// MAIN //

/**
* Evaluates a polynomial.
*
* ## Notes
*
* - The implementation uses [Horner's rule][horners-method] for efficient computation.
*
* [horners-method]: https://en.wikipedia.org/wiki/Horner%27s_method
*
* @private
* @param {number} x - value at which to evaluate the polynomial
* @returns {number} evaluated polynomial
*/
function evalpoly( x ) {
if ( x === 0.0 ) {
return {{coefficient}};
}
return {{horner}};{{eslint}}
}


// EXPORTS //

module.exports = evalpoly;
Loading

0 comments on commit 0cacf4c

Please sign in to comment.