Objective-C++ (a .mm file) calls the library’s C++ API directly, on MLX
arrays as below; the library is itself written in Objective-C++. Code that
holds its matrices in its own memory can skip MLX and use the C API instead,
from .m or .mm files: see Without MLX. A complete program is examples/objc_quickstart.mm,
built and run with the other examples by ctest.
#import <Foundation/Foundation.h>
#include <metal_linalg/metal_linalg.h>
#include <mlx/mlx.h>
namespace mx = mlx::core;
// floats: an app's own buffer of `batch` symmetric n x n matrices, row-major
mx::array A(floats.begin(), {batch, n, n}, mx::float32); // copies the buffer
auto [w, V] = metal_linalg::eigh_accelerated(A); // w ascending
mx::array values = mx::contiguous(w);
mx::eval({values, V});
const float* eigenvalues = values.data<float>(); // batch x n
Arrays are MLX’s (mlx::core::array): build one from a buffer as above, and
read results with eval, then data<float>() on a contiguous array. The
functions are written for, and tested with, the GPU as the default MLX device.
With CMake, as for C++ (see the README), with Objective-C++ enabled:
project(my_app LANGUAGES CXX OBJCXX)
find_package(MetalLinalg REQUIRED)
add_executable(my_app main.mm)
target_link_libraries(my_app PRIVATE metal_linalg::metal_linalg "-framework Foundation")
In Xcode, with metal-linalg and MLX installed by Homebrew, in the target’s build settings:
| setting | value |
|---|---|
| C++ Language Dialect | C++20 |
| Header Search Paths | /opt/homebrew/include |
| Library Search Paths | /opt/homebrew/lib |
| Other Linker Flags | -lmetal_linalg -lmlx |
| Runpath Search Paths | /opt/homebrew/lib |
and name the files that call the library .mm. An app that ships to other
Macs embeds libmetal_linalg.dylib and libmlx.dylib in its bundle
(Frameworks, Libraries and Embedded Content) and sets the runpath to
@executable_path/../Frameworks instead.
An app that has its matrices in its own memory need not involve MLX at all:
the C API (plain C, so usable from .m files too) and the C++ buffer API
<metal_linalg/core.h> take float buffers directly, with no copies in and
out of MLX arrays. Build with -DMETAL_LINALG_WITH_MLX=OFF to leave MLX out
of the library as well.
#import <Foundation/Foundation.h>
#include <metal_linalg/c_api.h>
// `matrices`: `batch` symmetric n x n matrices, row-major, one after another.
NSData* eigenvalues(NSData* matrices, uint32_t batch, uint32_t n, NSError** error) {
NSMutableData* w = [NSMutableData dataWithLength:(NSUInteger)batch * n * sizeof(float)];
metal_linalg_status st = metal_linalg_eigh(matrices.bytes, batch, n, 1, w.mutableBytes, NULL, NULL);
if (st != METAL_LINALG_OK) {
if (error) *error = [NSError errorWithDomain:@"metal_linalg" code:st
userInfo:@{NSLocalizedDescriptionKey: @(metal_linalg_last_error())}];
return nil;
}
return w;
}
See docs/c-api.md for the conventions.
Use the Swift package, on [Float] or on mlx-swift’s MLXArray:
docs/swift.md.