Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,126 @@ console.log( ndarray2array( v ) );

<!-- /.examples -->

<!-- C interface documentation. -->

* * *

<section class="c">

## C APIs

<section class="usage">

### Usage

```c
#include "stdlib/blas/ext/base/ndarray/dcartesian_product.h"
```

#### stdlib_blas_ext_dcartesian_product( arrays )

Computes the Cartesian product for two double-precision floating-point ndarrays and stores each pair in a row of a two-dimensional output ndarray.

The function accepts the following arguments:

- **arrays**: `[in] struct ndarray**` list containing two one-dimensional input ndarrays and a two-dimensional output ndarray.

```c
void stdlib_blas_ext_dcartesian_product( const struct ndarray *arrays[] );
```

</section>

<!-- /.usage -->

<section class="notes">

### Notes

- For inputs of lengths `M` and `N`, the output ndarray should have shape `[M*N, 2]`.
- The first column contains elements from the first input and the second column contains elements from the second input.
- If `M <= 0` or `N <= 0`, the output ndarray is unchanged.
- C ndarray strides and offsets are specified in bytes. The function supports independently strided input and output views.

</section>

<!-- /.notes -->

<section class="examples">

### Examples

```c
#include "stdlib/blas/ext/base/ndarray/dcartesian_product.h"
#include "stdlib/ndarray/ctor.h"
#include "stdlib/ndarray/dtypes.h"
#include "stdlib/ndarray/index_modes.h"
#include "stdlib/ndarray/orders.h"
#include "stdlib/ndarray/base/bytes_per_element.h"
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>

int main( void ) {
// Create data buffers:
const double dataX[] = { 1.0, 2.0 };
const double dataY[] = { 3.0, 4.0, 5.0 };
double dataOut[ 12 ];

// Specify input and output shapes:
int64_t shapeX[] = { 2 };
int64_t shapeY[] = { 3 };
int64_t shapeOut[] = { 6, 2 };

// Specify byte strides:
int64_t strides[] = { STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT };
int64_t stridesOut[] = {
2 * STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT,
STDLIB_NDARRAY_FLOAT64_BYTES_PER_ELEMENT
};

const enum STDLIB_NDARRAY_ORDER order = STDLIB_NDARRAY_ROW_MAJOR;
const enum STDLIB_NDARRAY_INDEX_MODE imode = STDLIB_NDARRAY_INDEX_ERROR;
int8_t submodes[] = { STDLIB_NDARRAY_INDEX_ERROR };

// Create input and output ndarrays:
// cppcheck-suppress invalidPointerCast
struct ndarray *x = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)dataX, 1, shapeX, strides, 0, order, imode, 1, submodes );

// cppcheck-suppress invalidPointerCast
struct ndarray *y = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)dataY, 1, shapeY, strides, 0, order, imode, 1, submodes );

// cppcheck-suppress invalidPointerCast
struct ndarray *out = stdlib_ndarray_allocate( STDLIB_NDARRAY_FLOAT64, (uint8_t *)dataOut, 2, shapeOut, stridesOut, 0, order, imode, 1, submodes );
if ( x == NULL || y == NULL || out == NULL ) {
stdlib_ndarray_free( x );
stdlib_ndarray_free( y );
stdlib_ndarray_free( out );
fprintf( stderr, "Error allocating memory.\n" );
exit( 1 );
}

const struct ndarray *arrays[] = { x, y, out };
stdlib_blas_ext_dcartesian_product( arrays );

// Print the resulting pairs:
for ( int i = 0; i < 6; i++ ) {
printf( "out[ %i ] = ( %lf, %lf )\n", i, dataOut[ i*2 ], dataOut[ (i*2)+1 ] );
}
stdlib_ndarray_free( x );
stdlib_ndarray_free( y );
stdlib_ndarray_free( out );
}
```

</section>

<!-- /.examples -->

</section>

<!-- /.c -->

<!-- Section for related `stdlib` packages. Do not manually edit this section, as it is automatically populated. -->

<section class="related">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* @license Apache-2.0
*
* Copyright (c) 2026 The Stdlib Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

'use strict';

// MODULES //

var resolve = require( 'path' ).resolve;
var bench = require( '@stdlib/bench' );
var uniform = require( '@stdlib/random/uniform' );
var zeros = require( '@stdlib/ndarray/zeros' );
var isnan = require( '@stdlib/math/base/assert/is-nan' );
var pow = require( '@stdlib/math/base/special/pow' );
var format = require( '@stdlib/string/format' );
var tryRequire = require( '@stdlib/utils/try-require' );
var pkg = require( './../package.json' ).name;


// VARIABLES //

var dcartesianProduct = tryRequire( resolve( __dirname, './../lib/native.js' ) );
var opts = {
'skip': ( dcartesianProduct instanceof Error )
};
var options = {
'dtype': 'float64'
};


// FUNCTIONS //

/**
* Creates a benchmark function.
*
* @private
* @param {PositiveInteger} len - array length
* @returns {Function} benchmark function
*/
function createBenchmark( len ) {
var out;
var x;
var y;

x = uniform( [ len ], -100.0, 100.0, options );
y = uniform( [ len ], -100.0, 100.0, options );
out = zeros( [ len*len, 2 ], options );

return benchmark;

/**
* Benchmark function.
*
* @private
* @param {Benchmark} b - benchmark instance
*/
function benchmark( b ) {
var v;
var i;

b.tic();
for ( i = 0; i < b.iterations; i++ ) {
v = dcartesianProduct( [ x, y, out ] );
if ( typeof v !== 'object' ) {
b.fail( 'should return an ndarray' );
}
}
b.toc();
if ( isnan( v.get( i%(len*len), i%2 ) ) ) {
b.fail( 'should not return NaN' );
}
b.pass( 'benchmark finished' );
b.end();
}
}


// MAIN //

/**
* Main execution sequence.
*
* @private
*/
function main() {
var len;
var min;
var max;
var f;
var i;

min = 1; // 10^min
max = 3; // 10^max

for ( i = min; i <= max; i++ ) {
len = pow( 10, i );
f = createBenchmark( len );
bench( format( '%s::native:len=%d', pkg, len ), opts, f );
}
}

main();
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
#/
# @license Apache-2.0
#
# Copyright (c) 2026 The Stdlib Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#/

# VARIABLES #

ifndef VERBOSE
QUIET := @
else
QUIET :=
endif

# Determine the OS ([1][1], [2][2]).
#
# [1]: https://en.wikipedia.org/wiki/Uname#Examples
# [2]: http://stackoverflow.com/a/27776822/2225624
OS ?= $(shell uname)
ifneq (, $(findstring MINGW,$(OS)))
OS := WINNT
else
ifneq (, $(findstring MSYS,$(OS)))
OS := WINNT
else
ifneq (, $(findstring CYGWIN,$(OS)))
OS := WINNT
else
ifneq (, $(findstring Windows_NT,$(OS)))
OS := WINNT
endif
endif
endif
endif

# Define the program used for compiling C source files:
ifdef C_COMPILER
CC := $(C_COMPILER)
else
CC := gcc
endif

# Define the command-line options when compiling C files:
CFLAGS ?= \
-std=c99 \
-O3 \
-Wall \
-pedantic

# Determine whether to generate position independent code ([1][1], [2][2]).
#
# [1]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#Code-Gen-Options
# [2]: http://stackoverflow.com/questions/5311515/gcc-fpic-option
ifeq ($(OS), WINNT)
fPIC ?=
else
fPIC ?= -fPIC
endif

# List of includes (e.g., `-I /foo/bar -I /beep/boop/include`):
INCLUDE ?=

# List of source files:
SOURCE_FILES ?=

# List of libraries (e.g., `-lopenblas -lpthread`):
LIBRARIES ?=

# List of library paths (e.g., `-L /foo/bar -L /beep/boop`):
LIBPATH ?=

# List of C targets:
c_targets := benchmark.length.out


# RULES #

#/
# Compiles source files.
#
# @param {string} [C_COMPILER] - C compiler (e.g., `gcc`)
# @param {string} [CFLAGS] - C compiler options
# @param {(string|void)} [fPIC] - compiler flag determining whether to generate position independent code (e.g., `-fPIC`)
# @param {string} [INCLUDE] - list of includes (e.g., `-I /foo/bar -I /beep/boop/include`)
# @param {string} [SOURCE_FILES] - list of source files
# @param {string} [LIBPATH] - list of library paths (e.g., `-L /foo/bar -L /beep/boop`)
# @param {string} [LIBRARIES] - list of libraries (e.g., `-lopenblas -lpthread`)
#
# @example
# make
#
# @example
# make all
#/
all: $(c_targets)

.PHONY: all

#/
# Compiles C source files.
#
# @private
# @param {string} CC - C compiler (e.g., `gcc`)
# @param {string} CFLAGS - C compiler options
# @param {(string|void)} fPIC - compiler flag determining whether to generate position independent code (e.g., `-fPIC`)
# @param {string} INCLUDE - list of includes (e.g., `-I /foo/bar`)
# @param {string} SOURCE_FILES - list of source files
# @param {string} LIBPATH - list of library paths (e.g., `-L /foo/bar`)
# @param {string} LIBRARIES - list of libraries (e.g., `-lopenblas`)
#/
$(c_targets): %.out: %.c
$(QUIET) $(CC) $(CFLAGS) $(fPIC) $(INCLUDE) -o $@ $(SOURCE_FILES) $< $(LIBPATH) -lm $(LIBRARIES)

#/
# Runs compiled benchmarks.
#
# @example
# make run
#/
run: $(c_targets)
$(QUIET) ./$<

.PHONY: run

#/
# Removes generated files.
#
# @example
# make clean
#/
clean:
$(QUIET) -rm -f *.o *.out

.PHONY: clean
Loading
Loading