TOC »
numchi
A mathematical library inspired by NumPy
Introduction
NumChi attempts to provide a subset of a similar API to Python's NumPy based on SRFI-179's arrays. All of SRFI-179's procedures are reexported. Because this library defines many procedures, some of which have the same names as scheme procedures, it's strongly recommended to prefix the module: (import (prefix numchi nc)) or similar.
Disclaimers
This egg is not yet released, but you can find the sources at the following link:
https://code.dieggsy.com/numchi.
This library should still be considered alpha software. There may be breaking changes in the future. Help and advice are very welcome at (string-append "dieggsy" "@" "pm" "." "me") or dieggsy on the #chicken IRC channel.
Currently, the code is written for correct results rather than performance, and tested against NumPy itself using the pyffi egg. It's possible that the library could be made faster in the future by specializing for lower dimensions (like SRFI-179 does) and/or dropping into the Chicken C interface. Ideas for performance can be found in the bits/matrix-multiply.scm file (blas/Eigen integration) as well as in the fast-math branch (fast generic math routines with dispatching in C/C++)
Most optional arguments are implemented as keyword arguments (except in certain cases like round) as these convey the purpose of the argument more clearly than optional arguments, and can also be used similarly to python's optional arguments (in any order).
The library procedures should work on arrays with domains with non-zero lower bounds, but this is currently not well-tested.
Mode of operation
This library sets (specialize-array-default-safe? #t). It's possible that setting this to #f might give you a small performance benefit.
There are two basic modes of operation, determined by the value of the array-default-copy parameter. If its value is #t (the default), the library behaves more like NumPy in that array operations return specialized arrays. This is referred to as NumPy-like.
If its value is #f, the library behaves more like SRFI-179 in that the results of array operations are not specialized arrays (meaning the resulting arrays behave more like functions defined on the input arrays). This is refered to as SRFI-like. This may be sort of unfamiliar since e.g. the array returned by (array-sum a #:axis 0) will later change if a changes. To avoid unexpected behavior, setting (array-default-copy #f) also sets (specialized-array-default-mutable? #f), which can of course be unset manually if you don't want this behavior.
Procedures that behave in the same way regardless of the "mode" should be documented as such.
Dtypes and storage-class aliases
For the purposes of this library, a "dtype" is simply an SRFI-179 storage-class. The following aliases are provided for convenience.
Dtype aliases
- genconstant
- c128constant
- c64constant
- f64constant
- f32constant
- s64constant
- u64constant
- s32constant
- u32constant
- s16constant
- u16constant
- s8constant
- u8constant
- u1constant
Fairly self-explanatory aliases for SRFI-179 storage classes. gen is generic-storage-class, the remaining are the same as [dtype]-storage-class, where [dtype] is one of the idetifiers above.
Dtype conversion table
For generic operations on multiple arrays like add, multiply, etc., the resulting dtype is determined according to the following table, which is based on numpy's default type conversion rules:
gen c128 c64 f64 f32 s64 u64 s32 u32 s16 u16 s8 u8 gen gen gen gen gen gen gen gen gen gen gen gen gen gen c128 gen c128 c128 c128 c128 c128 c128 c128 c128 c128 c128 c128 c128 c64 gen c128 c64 c128 c64 c128 c128 c128 c128 c64 c64 c64 c64 f64 gen c128 c128 f64 f64 f64 f64 f64 f64 f64 f64 f64 f64 f32 gen c128 c64 f64 f32 f64 f64 f64 f64 f32 f32 f32 f32 s64 gen c128 c128 f64 f64 s64 f64 s64 s64 s64 s64 s64 s64 u64 gen c128 c128 f64 f64 f64 u64 f64 u64 f64 u64 f64 u64 s32 gen c128 c128 f64 f64 s64 f64 s32 s64 s32 s32 s32 s32 u32 gen c128 c128 f64 f64 s64 u64 s64 u32 s64 u32 s64 u32 s16 gen c128 c64 f64 f32 s64 f64 s32 s64 s16 s32 s16 s16 u16 gen c128 c64 f64 f32 s64 u64 s32 u32 s32 u16 s32 u16 s8 gen c128 c64 f64 f32 s64 f64 s32 s64 s16 s32 s8 s16 u8 gen c128 c64 f64 f32 s64 u64 s32 u32 s16 u16 s16 u8
Basic array operations
Mode of operation
- array-default-copyparameter
Unless otherwise specified by procedure documentation, if set to #t, the library is NumPy-like (returned arrays are specialized). If set to #f, the library is SRFI-like (returned arrays are functional).
- (without-copy body ...)syntax
Allows you to temporarily change the mode of operation for body ... to SRFI-like.
- (with-copy body ...)syntax
Allows you to temporarily change the mode of operation for body ... to NumPy-like.
Constructors
There are a few ways to create arrays with numchi:
;; Using the array procedure (array '((1 2) ;; dtype inferred (3 4))) (array '((1 2) ;; explicit dtype (3 4)) dtype: s64) ;; Using the special read syntax '#!a((1 2) ;; dtype inferred (3 4)) '#!s64a((1 2) ;; explicit dtype (3 4))
You may also prefer srfi-179's list->array:
;; You don't have to import srfi-179 since numchi reexports it. (list->array '(1 2 3 4) (domain #(2 2)) s64)
- list->array* lst #!key dtypeprocedure
Converts an array-like nested list to an array. See array.
- array lst #!key dtypeprocedure
Main array creation procedure. Currently synonymous to list->array*.
Similar: numpy.array
- domain arg1 #!optional arg2procedure
Like SRFI-179's make-interval, but interval bounds can be specified as vectors, lists, or pairs.
Array attributes
- array-shape aprocedure
Return the shape of a as a vector. This equivalent to the upper bounds of the array domain if the domain is normalized to 0 lower bounds.
Similar: ndarray.shape
- array-ndim aprocedure
Return the number of array dimensions, synonymous to SRFI-179's array-dimension.
Similar: ndarray.ndim
- array-data aprocedure
The same as SRFI-179's array-body.
Similar: ndarray.data
- array-size aprocedure
Returns the total number of elements in the array.
Similar: ndarray.size
- array-dtype aprocedure
Returns the dtype of the array or #f if a is not a specialized array.
Similar: ndarray.dtype
Array procedures
- array->list* aprocedure
Converts an array to an array-like nested list.
Similar: ndarray.tolist
- array-T a #!key axesprocedure
Returns a transposed shared array. Equivalent to SRFI-179's array-permute but with an optional permutation argument with a default value.
Similar: ndarray.T
- axes
- Reverses the order of a's axes if not given. Otherwise, a vector of integers: i in the j-th place in the tuple means a’s i-th axis becomes (array-transpose a)’s j-th axis.
- array-real aprocedure
Returns the real part of a.
Similar: ndarray.real
- array-imag aprocedure
Returns the imaginary part of a.
Similar: ndarray.imag
- array-astype a dtypeprocedure
Copy the array, cast to the specified dtype.
Similar: ndarray.astype
- dtype
- A storage class
- array-copy* a #!optional dtype new-domain mutable? safe?procedure
Like SRFI-179's array-copy, new-domain can be specified as for the domain procedure.
Similar: ndarray.copy
- array-map* f a #!rest asprocedure
Like SRFI-179's array-map, but behaves differently on (array-default-copy #t): namely, it returns a copy of the map with the first argument's storage class.
- array-map! f a #!rest asprocedure
Like SRFI-179's array-map, but stores the results in a, the first passed array.
- array-fill! a valueprocedure
Fill a with value.
Similar: ndarray.fill
- array-reshape a shapeprocedure
Returns an array containing the same data with new shape. Unaffected by array-default-copy.
Similar: ndarray.reshape
- a
- A specialized array
- shape
- A domain in the same format as specified by domain
- array-transpose a #!key axesprocedure
Synonymous to array-T.
Similar: ndarray.transpose
- array-flatten arrayprocedure
Returns a copy of the array collapsed into one dimension. Unaffected by array-default-copy.
Similar: ndarray.flatten
- array-diagonal a #!key (offset 0) (axis1 0) (axis2 1)procedure
Return diagonals of a as a shared array. Unaffected by array-default-copy. Currently only works on specialized arrays.
NOTE: Part of the implementation of this procedure is based on NumPy's C sources (translated to scheme), and is pretty gross if not inefficient.
Similar: ndarray.diagonal
DIFF: Offsets must be within a's bounds, since SRFI-179 does not support zero sized arrays/dimensions.
- array-max a #!key axis (initial -inf.0)procedure
Return the maximum of the array or the maximum along the given axis.
Similar: ndarray.max
- initial
- Minimum value of an input element.
- array-min a #!key axis (initial +inf.0)procedure
Return the minimum of the array or the minimum along the given axis.
Similar: ndarray.min
- initial
- Maximum value of an input element.
- array-clip a #!key min maxprocedure
Return an array whose minimum values are min and maximum values are max.
Similar: ndarray.clip
- array-clip! a #!key min maxprocedure
Like array-clip, but modifies the original array.
- array-conj aprocedure
Complex conjugate all elements of a.
Similar: ndarray.conj
- array-round a #!optional nprocedure
Round all elements of a.
Similar: ndarray.round
- n
- Decimal places to round to, can be negative to round the tens, hundreds, etc. place.
- array-trace a #!key (offset 0) (axis1 0) (axis2 1) (dtype generic-storage-class)procedure
Return the sum along the diagonals of the array.
DIFF: See array-diagonal
Similar: ndarray.trace
- array-sum a #!key axis (dtype generic-storage-class)procedure
Return the sum of the array elements over the given axis.
DIFF: Because the result may overflow, on (array-default-copy #t) the returned array has the generic storage class by default.
Similar: ndarray.sum
- array-mean a #!key axis (dtype generic-storage-class)procedure
Returns the average of the array elements along given axis.
DIFF: This procedure will return averages as exact numbers where possible, so on (array-default-copy #t) the returned array has the generic storage class by default.
Similar: mean
- array-var a #!key axis (dtype generic-storage-class)procedure
Returns the variance of the array elements, along given axis.
DIFF: This procedure will return variance as exact numbers where possible, so on (array-default-copy #t) the returned array has the generic storage class by default.
Similar: ndarray.var
- array-std a #!key axis (dtype generic-storage-class)procedure
Returns the standard deviation of the array elements along given axis.
Similar: ndarray.std
- array-prod a #!key axis (dtype generic-storage-class)procedure
Return the product of the array elements over the given axis
DIFF: Because the result may overflow, on (array-default-copy #t) the returned array has the generic storage class by default.
Similar: ndarray.prod
- array-all a #!key axis (dtype generic-storage-class)procedure
Returns #t if all elements are not #f.
DIFF: This will return slightly different results than numpy's array-all because while scheme and python both have "truthiness" (non #t or True objects evaluate as true for boolean operations), scheme does not have Python's "falsiness" for values like 0, [], "", etc.
Similar: ndarray.all
- array-any* a #!key axis (dtype generic-storage-class)procedure
Returns #t if any of the elements is not #f. Note the * in the name to avoid shadowing srfi-179's array-any.
DIFF: This will return slightly different results than numpy's array-all because while scheme and python both have "truthiness" (objects that are not #t or True evaluate as true for boolean operations), scheme does not have Python's "falsiness" for values like 0, [], "", etc.
Similar: ndarray.any
Array I/O
Read/write syntax
The special read syntax '#!a(...) is an alias for (array '(...)). You can also specify a dtype, like so: '#![dtype]a(...) (e.g. '#!f64a(...)). Arrays are by default printed in the dtype syntax, with non-specialized arrays printed as '#!*a(...), which currently does not have an equivalent read syntax.
Procedures
- (write-array a #!optional (port (current-output-port)) #!key mode summarize)procedure
Writes an array to port. If #:summarize is #t, prints a summary of the array according to the array-summary-* parameters. The keyword argument #:mode is currently a no-op, but there are plans to use it for writing arrays in e.g. binary or ascii format.
Parameters
- array-summary-maxsizeconstant
Sets the maximum size that an array can be beyond which its printed form is summarized.
- array-summary-num-edgesconstant
Sets the number of edges to display for a summarized array.
- array-summary-flonum-precisionconstant
Sets the array flounm print precision for a summarized array.
Constants
- infconstant
An alias for +inf.0
- ninfconstant
An alias for -inf.0
- nanconstant
An alias for +nan.0
- nzeroconstant
An alias for -0.0
- econstant
Euler's number
- euler-gammaconstant
Euler-Mascheroni constant
- piconstant
Mathematical functions
- conj aprocedure
Returns the complex conjugate of a number or element-wise complex conjugate of an array.
Similar: numpy.conj
- round a #!optional bprocedure
Evenly rounds the number (or array, element-wise) to n decimals. If n is negative, rounds to nearest tens, hundreds, etc.
Similar: numpy.around
- around a #!optional nprocedure
The same as round.
- add a b #!key dtypeprocedure
Adds arguments element-wise. Arguments can be arrays or numbers. A resulting array's dtype is determined by the dtype conversion table if dtype is not given.
Repository
https://code.dieggsy.com/numchi
Author
Diego A. Mundo
License
BSD
Copyright (c) 2021 Diego A. Mundo All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted (subject to the limitations in the disclaimer below) provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.