Overview
Add full F-order (Fortran/column-major) memory layout support to NumSharp, enabling proper interoperability with Fortran-based libraries and matching NumPy 2.x behavior for order-sensitive operations.
Problem
NumSharp currently only supports C-order (row-major) memory layout:
Shape.layout is hardcoded as const char layout = 'C' (Shape.cs:120)
Shape.ChangeTensorLayout() is a no-op stub that returns immediately (Shape.cs:802-808)
- APIs like
reshape(order='F'), ravel(order='F'), np.copy(order='F') accept the parameter but silently ignore it
This prevents:
- Proper interoperability with Fortran-based libraries (LAPACK, BLAS)
- Loading/saving F-order
.npy files created by Python NumPy
- Matching NumPy behavior for
reshape(order='F'), ravel(order='F'), etc.
- Correct
np.asfortranarray() and np.ascontiguousarray() implementations
NumPy Order Modes
NumPy has 2 memory layouts and 4 order modes:
| Mode |
Character |
Type |
Meaning |
| C-order |
'C' |
Layout |
Row-major (last axis varies fastest) |
| F-order |
'F' |
Layout |
Column-major (first axis varies fastest) |
| Any-order |
'A' |
Selector |
Use F if input is F-contiguous, else C |
| Keep-order |
'K' |
Selector |
Preserve input's order as closely as possible |
Proposal
Implement full F-order support matching NumPy 2.x behavior exactly, including all 4 order modes.
Phase 1: Core Infrastructure (Shape.cs)
Phase 2: Array Creation APIs
Phase 3: Iteration Order Support
Phase 4: Reshape/Ravel/Flatten
Phase 5: Broadcasting and Slicing
Phase 6: NDIterator
Phase 7: I/O
Evidence
NumPy Reference (v2.4.2 source)
Order Enum (ndarraytypes.h:224-234):
| Value |
Name |
Meaning |
| -1 |
NPY_ANYORDER |
Fortran if all inputs Fortran, C otherwise |
| 0 |
NPY_CORDER |
C order (row-major, last index varies fastest) |
| 1 |
NPY_FORTRANORDER |
Fortran order (column-major, first index varies fastest) |
| 2 |
NPY_KEEPORDER |
As close to input order as possible |
Stride Computation (ctors.c:4150-4206):
// F-order: Loop left-to-right
for (i = 0; i < nd; i++) {
strides[i] = itemsize;
itemsize *= dims[i];
}
// C-order: Loop right-to-left
for (i = nd - 1; i >= 0; i--) {
strides[i] = itemsize;
itemsize *= dims[i];
}
Example: Shape (2, 3, 4), itemsize=1 element
| Axis |
Dim |
C-stride |
F-stride |
| 0 |
2 |
12 |
1 |
| 1 |
3 |
4 |
2 |
| 2 |
4 |
1 |
6 |
Order Resolution (for 'A' and 'K' modes):
char effectiveOrder = order switch {
'K' => input.Shape.Order, // Keep same as input
'A' => input.Shape.IsFContiguous ? 'F' : 'C', // F if F-contiguous, else C
_ => order // 'C' or 'F' used directly
};
Scope / Non-goals
In scope:
- C-order and F-order memory layouts
- All 4 order modes: C, F, A, K
- Order parameter on creation/manipulation APIs
- .npy file interop with correct fortran_order
Not in scope:
- Performance optimizations for F-order SIMD (future)
- F-order specific BLAS/LAPACK bindings (separate issue)
Breaking Changes
| Change |
Impact |
Migration |
Shape.layout becomes mutable field |
Internal only |
None required |
Shape struct size increases slightly |
Memory |
Negligible |
ChangeTensorLayout actually works |
Code relying on no-op may break |
Review usages |
Related Issues
- Enables proper LAPACK/BLAS interop for future
np.linalg work
- Required for loading F-order .npy files from Python scientific libraries
Overview
Add full F-order (Fortran/column-major) memory layout support to NumSharp, enabling proper interoperability with Fortran-based libraries and matching NumPy 2.x behavior for order-sensitive operations.
Problem
NumSharp currently only supports C-order (row-major) memory layout:
Shape.layoutis hardcoded asconst char layout = 'C'(Shape.cs:120)Shape.ChangeTensorLayout()is a no-op stub that returns immediately (Shape.cs:802-808)reshape(order='F'),ravel(order='F'),np.copy(order='F')accept the parameter but silently ignore itThis prevents:
.npyfiles created by Python NumPyreshape(order='F'),ravel(order='F'), etc.np.asfortranarray()andnp.ascontiguousarray()implementationsNumPy Order Modes
NumPy has 2 memory layouts and 4 order modes:
'C''F''A''K'Proposal
Implement full F-order support matching NumPy 2.x behavior exactly, including all 4 order modes.
Phase 1: Core Infrastructure (Shape.cs)
layouta mutable field instead of const_computeStridesForOrder(char order)method (F: left-to-right, C: right-to-left)char order = 'C'parameter toShape(int[] dims)constructorIsFContiguousproperty (mirror ofIsContiguousfor F-order)ChangeTensorLayout(char order)(currently no-op)ComputeHashcode()to include layoutPhase 2: Array Creation APIs
char order = 'C'parameter tonp.empty(),np.zeros(),np.ones(),np.full()char order = 'C'parameter to*_like()variantsnp.copy(order)with all 4 modes: C, F, A, K (has TODO comment)np.asfortranarray()andnp.ascontiguousarray()Phase 3: Iteration Order Support
ValueCoordinatesIncrementorfor order-aware iterationShape.GetCoordinates(offset)for F-order factor computationPhase 4: Reshape/Ravel/Flatten
np.ravel(order)with all 4 modes: C, F, A, Knp.reshape(order)with all 4 modes: C, F, A, KNDArray.flatten(order)with all 4 modes (currently ignored)Phase 5: Broadcasting and Slicing
Phase 6: NDIterator
orderparameter to NDIteratorPhase 7: I/O
np.save()to write correctfortran_orderin .npy headernp.load()to create shapes with correct order from headerEvidence
NumPy Reference (v2.4.2 source)
Order Enum (
ndarraytypes.h:224-234):Stride Computation (
ctors.c:4150-4206):Example: Shape (2, 3, 4), itemsize=1 element
Order Resolution (for 'A' and 'K' modes):
Scope / Non-goals
In scope:
Not in scope:
Breaking Changes
Shape.layoutbecomes mutable fieldShapestruct size increases slightlyChangeTensorLayoutactually worksRelated Issues
np.linalgwork