Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC]: add support for boolean arrays in stdlib #65

Closed
6 tasks done
soumajit23 opened this issue Mar 28, 2024 · 3 comments
Closed
6 tasks done

[RFC]: add support for boolean arrays in stdlib #65

soumajit23 opened this issue Mar 28, 2024 · 3 comments
Labels
2024 2024 GSoC proposal. rfc Project proposal.

Comments

@soumajit23
Copy link

soumajit23 commented Mar 28, 2024

Full name

Soumajit Chatterjee

University status

Yes

University name

Institute of Engineering and Management, Kolkata

University program

B.Tech in Electronics and Communications Engineering

Expected graduation

2026

Short biography

I am a 2nd year student pursuing a B.Tech in Electronics and Communications Engineering, from Institute of Engineering and Management, Kolkata, where I completed various relevant courses on Statistics, Calculus, Data Structures, and Algorithms. I am highly passionate about software development, especially web development, and have taken courses on Python and web development.

Apart from software, my interest also lies in hardware. I have worked on several Arduino/microcontroller-based projects and other electronics projects.

Timezone

IST (UTC+05:30)

Contact details

email:[email protected], github:soumajit23, IRC nick:soumajit23

Platform

Windows

Editor

I use VSCode since it's less cpu draining and the extensive extension options provide the ability to customize the editor according to requirements. The integrated terminal allows me to run commands and scripts within the editor, increasing productivity.

Programming experience

I have an extensive skill set in various programming languages. I am proficient in HTML, CSS, JavaScript, and C. I also have experience coding in MATLAB, Java, and Python languages.

Furthermore, I am familiar with several technologies such as Bootstrap, Node.js, Express.js, PostgreSQL, EJS, jQuery and REST APIs, and I am well-versed in their usage. I also have a good understanding of CLI usage.

Some projects I have worked on:

JavaScript experience

I am proficient in JavaScript, having built projects, which use JavaScript for both frontend and backend development.

A thing I like about JavaScript is its vast ecosystem of libraries and frameworks, that simplify development for various tasks like user interface creation, data manipulation, and more. Also, JavaScript has a large and active community of developers who contribute to its growth and improvement. This means there are plenty of resources, tutorials, and open-source projects available to help developers like me, learn and solve problems.

Node.js experience

Experience with Node.js for backend development has given me a robust foundation in building efficient server-side applications. Working on projects with Node.js has allowed me to harness its extensive ecosystem of libraries and frameworks, enabling rapid development and deployment of features. I have implemented RESTful APIs, used frameworks such as Express.js to build efficient server applications, and built projects that have the usage of Node.js.

C/Fortran experience

My familiarity with the C language, gained through university coursework spanning the second and third semesters, has given me a solid understanding of fundamental programming concepts and principles. I've explored various data structures like arrays, linked lists, stacks, queues, trees, and graphs, understanding their implementations, operations, and applications.

Interest in stdlib

Everything, from the source code to the pull requests is well organized, properly named, and easy to follow and refer to. This makes contributing to stdlib much easier and more convenient. The community is also very welcoming to people like me who are new to open-source contributions.

Furthermore, since I am passionate about mathematics and always get intrigued to learn new ways to implement mathematical and scientific computations to coding, stdlib seems like the perfect place to do so.

Version control

Yes

Contributions to stdlib

I have 3 open PRs as of now:

Goals

The primary goal of this project is to enhance stdlib for JavaScript by introducing support for boolean arrays (BooleanArray). Currently, stdlib provides extensive support for numeric arrays but lacks dedicated support for boolean data types. The introduction of BooleanArray aims to address this and provide support for boolean values. This project will refer to previously added custom-typed arrays, namely Complex64Array and Complex128Array.

@stdlib/array/bool Package Creation:

The key objective is to create a new @stdlib/array/bool package that exposes a BooleanArray constructor, enabling developers to create and manipulate boolean arrays efficiently. This involves implementing standard array methods, such as indexing, iteration, and manipulation while adhering to the conventions established by existing typed arrays in stdlib.

  • Package will have separate directories for benchmarks, docs, examples, libs, and tests along with a README.md file to document the package and a package.json file to expose the directories and dependencies.
  • The BooleanArray will be a typed array, backed by a Uint8Array and will not simply wrap a generic array.

For example,

 // Create a boolean array from a Uint8Array:
 var arr = new Uint8Array([1, 0, 1, 1, 0]);
 var boolArray = new BooleanArray(arr);

 console.log(boolArray); // => [true, false, true, true, false]
  • Benchmark files for BooleanArray will encompass a range of operations such as modification, iteration, filtering, mapping, reducing, and other relevant functionalities. For example, a benchmark.js file for BooleanArray can be:
'use strict';

// MODULES
var bench = require('@stdlib/bench');
var ArrayBuffer = require('@stdlib/array/buffer');
var Uint8Array = require('@stdlib/array/uint8');
var isArrayBuffer = require('@stdlib/assert/is-arraybuffer');
var isNonNegativeInteger = require('@stdlib/assert/is-nonnegative-integer').isPrimitive;
var ITERATOR_SYMBOL = require('@stdlib/symbol/iterator');
var pkg = require('./../package.json').name;
var BooleanArray = require('./../lib');

// VARIABLES
var opts = {
    'skip': (ITERATOR_SYMBOL === null)
};

// MAIN

// Instantiation Benchmarks

bench(pkg + '::instantiation,new', function benchmark(b) {
    var arr;
    var i;
    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray();
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,no_new', function benchmark(b) {
    var ctor;
    var arr;
    var i;

    ctor = BooleanArray;

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = ctor();
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,length', function benchmark(b) {
    var arr;
    var i;
    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(0);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,typed_array', function benchmark(b) {
    var buf;
    var arr;
    var i;

    buf = new Uint8Array(0);

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(buf);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,array', function benchmark(b) {
    var buf;
    var arr;
    var i;

    buf = [];

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(buf);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,iterable', opts, function benchmark(b) {
    var arr;
    var i;

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(createIterable());
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();

    function createIterable() {
        var out = {};
        out[ITERATOR_SYMBOL] = iterator;
        return out;

        function iterator() {
            return {
                'next': next
            };
        }

        function next() {
            return {
                'done': true
            };
        }
    }
});

bench(pkg + '::instantiation,arraybuffer', function benchmark(b) {
    var buf;
    var arr;
    var i;

    buf = new ArrayBuffer(0);

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(buf);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,arraybuffer,byte_offset', function benchmark(b) {
    var buf;
    var arr;
    var i;

    buf = new ArrayBuffer(8);

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(buf, 8);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::instantiation,arraybuffer,byte_offset,length', function benchmark(b) {
    var buf;
    var arr;
    var i;

    buf = new ArrayBuffer(8);

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        arr = new BooleanArray(buf, 8, 0);
        if (arr.length !== 0) {
            b.fail('should have length 0');
        }
    }
    b.toc();
    if (!(arr instanceof BooleanArray)) {
        b.fail('should return an instance');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::get:buffer', function benchmark(b) {
    var arr;
    var v;
    var i;

    arr = new BooleanArray();

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        v = arr.buffer;
        if (typeof v !== 'object') {
            b.fail('should return an object');
        }
    }
    b.toc();
    if (!isArrayBuffer(v)) {
        b.fail('should return an ArrayBuffer');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::get:byteLength', function benchmark(b) {
    var arr;
    var v;
    var i;

    arr = new BooleanArray();

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        v = arr.byteLength;
        if (v !== v) {
            b.fail('should not return NaN');
        }
    }
    b.toc();
    if (!isNonNegativeInteger(v)) {
        b.fail('should return a nonnegative integer');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::get:byteOffset', function benchmark(b) {
    var arr;
    var v;
    var i;

    arr = new BooleanArray();

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        v = arr.byteOffset;
        if (v !== v) {
            b.fail('should not return NaN');
        }
    }
    b.toc();
    if (!isNonNegativeInteger(v)) {
        b.fail('should return a nonnegative integer');
    }
    b.pass('benchmark finished');
    b.end();
});

bench(pkg + '::get:length', function benchmark(b) {
    var arr;
    var v;
    var i;

    arr = new BooleanArray();

    b.tic();
    for (i = 0; i < b.iterations; i++) {
        v = arr.length;
        if (v !== v) {
            b.fail('should not return NaN');
        }
    }
    b.toc();
    if (!isNonNegativeInteger(v)) {
        b.fail('should return a nonnegative integer');
    }
    b.pass('benchmark finished');
    b.end();
});

Other files like benchmark.fill.js, benchmark.filter.js, benchmark.map.js, benchmark.to_string.js, etc. will be added to run benchmarks for a vast set of operations.

  • An index.js file will be added to the examples directory to run examples like:
'use strict';

// MODULES
var Uint8Array = require('@stdlib/array/uint8');
var logEach = require('@stdlib/console/log-each');
var BooleanArray = require('./../lib');

// Create a boolean array from a Uint8Array buffer view:
var arr = new Uint8Array([1, 0, 1, 1, 0, 0]);
var boolArray = new BooleanArray(arr.buffer, 0, 6);

// Log each boolean value:
logEach('%s', boolArray);
  • Files in the lib directory will be responsible for exporting modules. For instance, a from-array.js might look like this:
'use strict';

// MAIN //

/**
* Returns a strided array of boolean values.
*
* @private
* @param {Uint8Array} buf - output array
* @param {Array} arr - array containing boolean values
* @returns {(Uint8Array|null)} output array or null
*/
function fromArray( buf, arr ) {
    var len = arr.length;
    for (var i = 0; i < len; i++) {
        if (typeof arr[i] !== 'boolean') {
            return null;
        }
        buf[i] = arr[i] ? 1 : 0;
    }
    return buf;
}

// EXPORTS //

module.exports = fromArray;

This file exports a fromArray function to provide functionality to convert an array of boolean values into a strided array. Similarly other files like from_iterator.js, main.js will be added.

  • Test files will provide tests for most of the operations and will be implemented similarly. A test.ts file will be implemented for test cases in TypeScript language.

Tests, benchmarks and examples will be run thoroughly to address any issue or bug in the code. To run tests,

$ make TESTS_FILTER=".*/array/bool/.*" test

will be run. Similarly, for benchmarks and examples,

$ make BENCHMARKS_FILTER=".*/array/bool/.*" benchmark
$ make EXAMPLES_FILTER=".*/array/bool/.*" examples

will be run.

Integration of BooleanArray Throughout stdlib:

The project aims to integrate BooleanArray seamlessly throughout stdlib, ensuring compatibility with existing modules and functions wherever arrays are utilized. This integration effort includes updating documentation, writing tests, refining the implementation based on feedback, etc. This work will probably make up the majority of this project and will require most of the time invested in making sure of proper integration throughout stdlib.

  • Addition of BooleanArray as a supported array data type should be done in the @stdlib/array/dtypes namespace.
var indexOf = require( '@stdlib/utils/index-of' );
var dtypes = require( '@stdlib/array/dtypes' );

var DTYPES = dtypes();

function isdtype( str ) {
    if ( indexOf( DTYPES, str ) === -1 ) {
        return false;
    }
    return true;
}

var bool = isdtype( 'bool' );
//returns true

Here, bool should return true after integration of boolean array in the namespace.

  • The function filledarray() should recognize the data type bool and should be able to return a boolean array. This requires the addition of boolean array support to the @stdlib/array/filled namespace.
var dtypes = require( '@stdlib/array/typed-real-dtypes' );
var filledarray = require( '@stdlib/array/filled' );

var arr = filledarray( 1, 3, 'bool' );
// returns <BooleanArray>[ true, true, true ]

These are some of the integration work of boolean array in @stdlib/array/*. Further work will be done to add support of boolean arrays.
Namespaces like @stdlib/array/to-fancy, @stdlib/array/typed, etc. will be worked upon and updated accordingly.

  • @stdlib/strided namespace will be updated to support a boolean array data type.
var indexOf = require( '@stdlib/utils/index-of' );
var dtypes = require( '@stdlib/strided/dtypes' );

var DTYPES = dtypes();
var bool;

function isdtype( str ) {
    return ( indexOf( DTYPES, str ) >= 0 );
}

bool = isdtype( 'bool' );
// returns true

@stdlib/strided/dtypes will be updated to support boolean array data type.

  • Similarly, @stdlib/ndarray will be updated to support a boolean array data type.

  • Addition of a package @stdlib/assert/is-booleanarray will be done for assertion utilities.

var BooleanArray = require( '@stdlib/array/bool' );
var Float32Array = require( '@stdlib/array/float32' );
var isBooleanArray = require( '@stdlib/assert/is-booleanarray' );

var bool = isBooleanArray( new BooleanArray( 10 ) );
// returns true

bool = isBooleanArray( new Float32Array( 10 ) );
// returns false

isBooleanArray tests if a value is a BooleanArray.

Support for Boolean Arrays in ndarray and strided array APIs

The project will also support BooleanArray instances as backing for ndarrays and strided arrays. This entails working with C APIs and potentially modifying existing ndarrays and strided arrays functionality to accommodate boolean arrays effectively.

  • Implementation of APIs will be done throughout @stdlib/strided/base/*. Boolean will be provided with a character code p. For instance,
#include "stdlib/strided/base/binary/pp_p.h"
#include "stdlib/strided/base/binary/macros.h"
#include <stdint.h>

/**
* Applies a binary callback to strided input array elements and assigns results to elements in a strided output array.
*
* @param arrays   array whose first two elements are pointers to strided input arrays and whose last element is a pointer to a strided output array
* @param shape    array whose only element is the number of elements over which to iterate
* @param strides  array containing strides (in bytes) for each strided array
* @param fcn      callback
*
* @example
* #include "stdlib/strided/base/binary/pp_p.h"
* #include <stdint.h>
*
* // Create underlying byte arrays:
* uint8_t x[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
* uint8_t y[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
* uint8_t out[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
*
* // Define a pointer to an array containing pointers to strided arrays:
* uint8_t *arrays[] = { x, y, out };
*
* // Define the strides:
* int64_t strides[] = { 1, 1, 1 };
*
* // Define the number of elements over which to iterate:
* int64_t shape[] = { 3 };
*
* // Define a callback:
* static bool add_bool( bool x, bool y ) {
*     return x + y; // Addition operation on boolean values
* }
*
* // Apply the callback:
* stdlib_strided_pp_p( arrays, shape, strides, (void *)add_bool );
*/
void stdlib_strided_pp_p( uint8_t *arrays[], const int64_t *shape, const int64_t *strides, void *fcn ) {
    typedef bool func_type( const bool x, const bool y );
    func_type *f = (func_type *)fcn;
    STDLIB_STRIDED_BINARY_LOOP_CLBK( bool, bool, bool )
}

Function void stdlib_strided_pp_p(...), can be implemented in the @stdlib/strided/base/binary namespace. The function takes two boolean array inputs, their shapes and strides, a callback function, and performs element-wise binary operations on the input arrays, storing the results in the boolean array output.

  • Similarly,
#ifndef STDLIB_STRIDED_BASE_BINARY_P_AS_K_H
#define STDLIB_STRIDED_BASE_BINARY_P_AS_K_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
* Applies a nullary callback to strided input array elements and assigns results to elements in a strided output array.
*/
void stdlib_strided_p_as_k( uint8_t *arrays[], const int64_t *shape, const int64_t *strides, void *fcn );

#ifdef __cplusplus
}
#endif

#endif // !STDLIB_STRIDED_BASE_BINARY_P_AS_K_H

Implemented in @stdlib/strided/base/nullary. To apply the nullary callback,

#include <stdint.h>

// Create underlying byte arrays:
uint8_t out[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };

// Define a pointer to an array containing pointers to strided arrays:
uint8_t *arrays[] = { out };

// Define the strides:
int64_t strides[] = { 8 };

// Define the number of elements over which to iterate:
int64_t shape[] = { 3 };

// Define a callback:
static int16_t fcn( void ) {
    return 3;
}

// Apply the callback:
stdlib_strided_p_as_k( arrays, shape, strides, (void *)fcn );

These are some of the APIs to be implemented for strided arrays. Further careful addition of APIs would be done.

  • API implementation will also be done in the @stdlib/ndarray/* namespace. For instance an implementation can be,
#ifndef STDLIB_NDARRAY_BASE_UNARY_P_P_AS_K_K_H
#define STDLIB_NDARRAY_BASE_UNARY_P_P_AS_K_K_H

#include "stdlib/ndarray/ctor.h"
#include <stdint.h>

/*
* If C++, prevent name mangling so that the compiler emits a binary file having undecorated names, thus mirroring the behavior of a C compiler.
*/
#ifdef __cplusplus
extern "C" {
#endif

/**
* Applies a unary callback to an input ndarray and assigns results to elements in an output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a zero-dimensional input ndarray and assigns results to elements in a zero-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_0d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a one-dimensional input ndarray and assigns results to elements in a one-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_1d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a two-dimensional input ndarray and assigns results to elements in a two-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_2d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a two-dimensional input ndarray and assigns results to elements in a two-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_2d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a three-dimensional input ndarray and assigns results to elements in a three-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_3d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a three-dimensional input ndarray and assigns results to elements in a three-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_3d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a four-dimensional input ndarray and assigns results to elements in a four-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_4d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a four-dimensional input ndarray and assigns results to elements in a four-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_4d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a five-dimensional input ndarray and assigns results to elements in a five-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_5d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a five-dimensional input ndarray and assigns results to elements in a five-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_5d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a six-dimensional input ndarray and assigns results to elements in a six-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_6d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a six-dimensional input ndarray and assigns results to elements in a six-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_6d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a seven-dimensional input ndarray and assigns results to elements in a seven-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_7d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a seven-dimensional input ndarray and assigns results to elements in a seven-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_7d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to an eight-dimensional input ndarray and assigns results to elements in an eight-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_8d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to an eight-dimensional input ndarray and assigns results to elements in an eight-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_8d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a nine-dimensional input ndarray and assigns results to elements in a nine-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_9d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a nine-dimensional input ndarray and assigns results to elements in a nine-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_9d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a ten-dimensional input ndarray and assigns results to elements in a ten-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_10d( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to a ten-dimensional input ndarray and assigns results to elements in a ten-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_10d_blocked( struct ndarray *arrays[], void *fcn );

/**
* Applies a unary callback to an n-dimensional input ndarray and assigns results to elements in an n-dimensional output ndarray.
*/
int8_t stdlib_ndarray_p_p_as_k_k_nd( struct ndarray *arrays[], void *fcn );

#ifdef __cplusplus
}
#endif

#endif // !STDLIB_NDARRAY_BASE_UNARY_P_P_AS_K_K_H

Implemented in @stdlib/ndarray/base/unary. To apply callback,

#include "stdlib/ndarray/dtypes.h"
#include "stdlib/ndarray/index_modes.h"
#include "stdlib/ndarray/orders.h"
#include "stdlib/ndarray/ctor.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

// Define the ndarray data types:
enum STDLIB_NDARRAY_DTYPE xdtype = STDLIB_NDARRAY_UINT8;
enum STDLIB_NDARRAY_DTYPE ydtype = STDLIB_NDARRAY_INT16;

// Create underlying byte arrays:
uint8_t xbuf[] = { 0, 0, 0, 0 };
uint8_t ybuf[] = { 0, 0, 0, 0, 0, 0, 0, 0 };

// Define the number of dimensions:
int64_t ndims = 2;

// Define the array shapes:
int64_t shape[] = { 2, 2 };

// Define the strides:
int64_t sx[] = { 2, 1 };
int64_t sy[] = { 4, 2 };

// Define the offsets:
int64_t ox = 0;
int64_t oy = 0;

// Define the array order:
enum STDLIB_NDARRAY_ORDER order = STDLIB_NDARRAY_ROW_MAJOR;

// Specify the index mode:
enum STDLIB_NDARRAY_INDEX_MODE imode = STDLIB_NDARRAY_INDEX_ERROR;

// Specify the subscript index modes:
int8_t submodes[] = { imode };
int64_t nsubmodes = 1;

// Create an input ndarray:
struct ndarray *x = stdlib_ndarray_allocate( xdtype, xbuf, ndims, shape, sx, ox, order, imode, nsubmodes, submodes );
if ( x == NULL ) {
    fprintf( stderr, "Error allocating memory.\n" );
    exit( EXIT_FAILURE );
}

// Create an output ndarray:
struct ndarray *y = stdlib_ndarray_allocate( ydtype, ybuf, ndims, shape, sy, oy, order, imode, nsubmodes, submodes );
if ( y == NULL ) {
    fprintf( stderr, "Error allocating memory.\n" );
    exit( EXIT_FAILURE );
}

// Create an array containing the ndarrays:
struct ndarray *arrays[] = { x, y };

// Define a callback:
static int16_t fcn( const int16_t x ) {
    return x;
}

// Apply the callback:
int8_t status = stdlib_ndarray_p_p_as_k_k( arrays, (void *)fcn );
if ( status != 0 ) {
    fprintf( stderr, "Error during computation.\n" );
    exit( EXIT_FAILURE );
}

// ...

// Free allocated memory:
stdlib_ndarray_free( x );
stdlib_ndarray_free( y );

Further careful addition and implementation of APIs will be done for ndarrays to support boolean arrays.

Throughout development, attention will be paid to performance optimizations, ensuring that BooleanArray operations are efficient and scalable. Moreover, comprehensive documentation will guide developers in utilizing BooleanArray effectively within their projects.

This project aims to enrich the stdlib ecosystem with a dedicated boolean array data type, empowering JavaScript developers with enhanced data manipulation and analysis capabilities, particularly in scenarios requiring boolean-based indexing and filtering operations.

Why this project?

The addition of BooleanArray support expands the capabilities of stdlib by providing developers with a dedicated data type for boolean arrays. This enhances its versatility, allowing for more efficient and expressive manipulation of boolean data within JavaScript applications. By addressing the need for boolean arrays within stdlib, the project demonstrates responsiveness to the needs of the community. Providing features that align with developers' requirements enhances satisfaction and fosters continued adoption and support for stdlib.

I would like to mention that contributing to this project would not only help in achieving the project's goals but also aid in my personal and professional growth. It would provide me with an opportunity to work on a complex project, collaborate with others, and contribute positively to the community. Moreover, this project would enable me to enhance my JavaScript programming skills, especially in the areas of array manipulation and API design.

Qualifications

Working on this project requires knowledge of JavaScript, C, Node,js, and Native Addons. Whether through University coursework or by building projects, I feel like I have the necessary knowledge of these technologies and would be able to implement these in a major project.

I have also gone through the source code and realized the needs of stdlib and the necessity of this project.

Prior art

Implementation of custom-typed arrays similar to the proposed BooleanArray in other programming languages and libraries:

  • In Python, NumPy provides support for boolean arrays through its ndarray data structure. NumPy arrays can hold boolean values and are commonly used for boolean indexing and masking operations, similar to what BooleanArray should do.
  • In Java's standard library, there is support for boolean arrays as one of its primitive array types.
  • R provides support for boolean arrays through its vector data structures.

Studying these implementations could prove helpful when working on @stdlib/array/bool.

Additionally, since there exists prior art for adding custom-typed arrays to stdlib; namely, Complex64Array and Complex128Array, these should serve as the appropriate approach to work on @stdlib/array/bool.

Commitment

I do not have any other professional commitment for the entire summer, and my academic schedule does not clash with the coding period. Therefore, I plan on dedicating 30 hours per week to this project for the entire 12-week program duration.

Schedule

Assuming a 12 week schedule,

Community Bonding Period:

  • Familiarize with the existing stdlib codebase and documentation.
  • Review the project requirements, objectives, and proposed implementation and break down the project into smaller tasks.
  • Discuss project goals and requirements with mentors.
  • Study prior implementation of boolean array support in various programming languages.
  • Begin working on the initial implementation of the BooleanArray constructor and basic functionality.

Week 1-2: BooleanArray Implementation

  • Continue working on the @stdlib/array/bool package exposing a new typed array constructor.
  • Perform tests to ensure the correctness of the BooleanArray implementation.
  • Address issues in BooleanArray functionality in isolation to identify and fix any bugs.

Week 3-5: Integration with stdlib Modules

  • Start integrating BooleanArray support into existing stdlib modules, starting with basic array manipulation functions.
  • Update documentation to reflect the addition of BooleanArray support and provide examples for users.
  • Write integration tests to verify the compatibility of BooleanArray with other stdlib modules.
  • Address any compatibility issues or conflicts that arise during integration.

Week 6-7: Support for ndarrays (midterm)

  • Take feedback from mentors and address issues if any.
  • Begin working on integrating BooleanArray support with ndarrays.
  • Familiarize with the relevant C APIs and tools for working with native addons in Node.js.
  • Modify ndarrays to support BooleanArray as backing arrays and ensure efficient operability between them.

Week 8: Optimizations to improve the integration with ndarrays

  • Test BooleanArray-backed ndarrays to ensure correct behavior and performance.
  • Address any issues or optimizations to improve the integration with ndarrays.

Week 9-10: Documentation and Testing

  • Complete the documentation for BooleanArray, including API reference documentation and usage guides.
  • Write comprehensive unit tests and integration tests to thoroughly test BooleanArray functionality.
  • Try to conduct testing across different environments and platforms to ensure compatibility and reliability.

Week 11-12: Refinement and Finalization

  • Address any outstanding issues or optimizations to improve the performance and usability.
  • Finalize the project documentation, including updating README files.
  • Take feedback from mentors for any last-minute tweaks.

Final Week: Submission

  • Submit the project and document all the goals achieved.

Note:

Integration of BooleanArray throughout stdlib and adding support for boolean arrays in ndarrays could be challenging and might take longer than mentioned in the schedule. This might become evident when working on the project and the schedule could be updated accordingly.

Related issues

#43

Checklist

  • I have read and understood the Code of Conduct.
  • I have read and understood the application materials found in this repository.
  • I understand that plagiarism will not be tolerated, and I have authored this application in my own words.
  • I have read and understood the patch requirement which is necessary for my application to be considered for acceptance.
  • The issue name begins with [RFC]: and succinctly describes your proposal.
  • I understand that, in order to apply to be a GSoC contributor, I must submit my final application to https://summerofcode.withgoogle.com/ before the submission deadline.
@soumajit23 soumajit23 added 2024 2024 GSoC proposal. rfc Project proposal. labels Mar 28, 2024
@Planeshifter
Copy link
Member

You show a good understanding of the required technologies and have provided examples of previous projects. However, keep in mind the proverb "show, don't tell": When mentioning prior projects from your portfolio, it's always more effective if you can also link to them.

Your proposal itself is comprehensive, but it would be good to include more details on what APIs would have to be implemented and the potential challenges you may run into and how they might be addressed.

@kgryte
Copy link
Member

kgryte commented Apr 1, 2024

@soumajit23 Thank you for sharing a draft of your proposal. Building on Philipp's comments, I have a few of my own:

  • In addition to @stdlib/array and @stdlib/ndarray, we'd also need to update @stdlib/strided to support a boolean array data type.
  • There is no need for isBooleanLike. You seemed to have copied from array/complex128 or similar. In those packages, we needed to verify that input values were complex-like. No such validation is necessary for boolean arrays.
  • For assertion utilities, we'd need something like @stdlib/assert/is-booleanarray, similar to @stdlib/assert/is-complex128array. Note that this is distinct from the existing package @stdlib/assert/is-boolean-array, which checks for an any array-like object containing boolean values.
  • Can you comment a bit on what changes we'd need to make to the C implementations in both ndarray and strided? We leverage scaffolding a fair amount, and I'd be curious to know how well our current scaffolding is suited for adding bool dtype support and what changes we'd likely need to make.

@soumajit23
Copy link
Author

@kgryte Thank you for reviewing the proposal!
I have made the changes you suggested. Is there anything else you would like me to implement?

@kgryte kgryte closed this as completed Apr 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2024 2024 GSoC proposal. rfc Project proposal.
Projects
None yet
Development

No branches or pull requests

3 participants