diff --git a/.gitmodules b/.gitmodules index 1bafac0..cb9a4b1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,5 +1,4 @@ - -[submodule "lightnumpy/_cpp_core/NumCpp"] - path = lightnumpy/_cpp_core/NumCpp +[submodule "third_party/NumCpp"] + path = third_party/NumCpp url = https://github.com/scikit-plots/NumCpp.git branch = gh_numcpp diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..9b7fe6c --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,6 @@ + + +Our Code of Conduct is at +https://scikit-plots.github.io/stable/project/code_of_conduct.html + +It is rendered from `doc/source/project/code_of_conduct.rst` \ No newline at end of file diff --git a/MANIFEST.in b/MANIFEST.in index b75fd74..2c1a288 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,7 +3,7 @@ ## Include all Python files (these are included by default, but it's good practice to be explicit) ## Include all files in the package source code -recursive-include scikitplot * +recursive-include lightnumpy * ## Include specific files with particular extensions in a subdirectory #recursive-include assets *.png *.jpg *.svg diff --git a/Makefile b/Makefile index 98b877f..f0dbd92 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,8 @@ ## Makefile for Python Packaging Library + +# Authors: The scikit-plots developers +# SPDX-License-Identifier: BSD-3-Clause + ## This Makefile contains various "targets" for project management tasks such as "compiling" the project, ## "cleaning" up build files, "running" tests, "building" Docker images, and more. diff --git a/README.md b/README.md index 864fb41..52e967f 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ pip install lightnumpy - **Scalable**: Ideal for IoT, embedded systems, and resource-limited devices. ## See Also -- https://scikit-plots.github.io/stable/api/scikitplot._numcpp_api.html - +- [1] https://scikit-plots.github.io/stable/api/scikitplot._numcpp_api.html +- [2] https://github.com/dpilger26/NumCpp --- ## LightNumPy Project Structure @@ -40,20 +40,14 @@ lightnumpy/ │ ├── __init__.py # Main package initializer │ ├── .clang-format # Code formatting rules for C/C++, code formatting rules like braces placement, and spacing. │ ├── .clang-tidy # Code linting rules for C/C++, code analysis, warnings, and bug detection. -│ ├── _c_core/ # Low-level C implementation sources -│ │ ├── include/ # C headers -│ │ │ ├── array.h # Array definitions -│ │ │ └── math_ops.h # Math operation headers -│ │ └── src/ # C source files -│ │ ├── array.c # Array operations -│ │ └── math_ops.c # Math implementations -│ ├── _cpp_core/ # Higher-level C++ implementation sources -│ │ ├── include/ # C++ headers -│ │ │ ├── tensor.hpp # Tensor operations -│ │ │ └── utilities.hpp # Helper utilities -│ │ └── src/ # C++ source files -│ │ ├── tensor.cpp # Tensor operation implementations -│ │ └── utilities.cpp # Utility function implementations +│ ├── _core/ # Low-level C and Higher-level C++ implementation sources +│ │ ├── include/ # C and C++ headers +│ │ │ ├── lightnumpy # lightnumpy core C and C++ headers +│ │ │ └── NumCpp # NumCpp Headers [2], Only available when packages installed +│ │ └── src/ # C and C++ source files +│ │ ├── dummymodule.c # Sample Module +│ │ ├── hello.c # Print and string operations +│ │ └── nc_version.cpp # NumCpp Headers versions │ ├── _gpu_core/ # GPU operations │ │ ├── include/ # GPU headers │ │ │ ├── gpu_ops.hpp # GPU operation definitions @@ -70,25 +64,18 @@ lightnumpy/ │ │ └── tpu_helpers.cpp # TPU utility functions │ ├── cy_bindings/ # Cython implementation, Cython bridging native libraries with Python APIs │ │ ├── __init__.py # Initialize the cython package -│ │ ├── include/ # Headers -│ │ └── src/ # TPU source files -│ │ ├── array_cy.pyx # Cython implementation of array module -│ │ ├── linalg_cy.pyx # Cython implementation of linalg operations -│ │ ├── utils_cy.pyx # Cython utilities -│ │ ├── gpu_cy.pyx # GPU-specific Cython bindings -│ │ ├── tpu_cy.pyx # TPU-specific Cython bindings +│ │ ├── include/ # Cython Headers +│ │ └── src/ # Cython Source files │ │ └── cython_helpers.pxd # Shared Cython declarations (optional) │ ├── py_bindings/ # Bindings for Python and native code, pybind11 bridging native libraries with Python APIs -│ │ ├── include/ # Headers -│ │ └── src/ # TPU source files -│ │ ├── c_bindings.c # C-Python bindings -│ │ ├── cpp_bindings.cpp # C++-Python bindings -│ │ ├── gpu_bindings.cu # CUDA-Python bindings -│ │ ├── tpu_bindings.cpp # TPU-Python bindings +│ │ ├── include/ # pybind11 Headers +│ │ └── src/ # pybind11 Source files +│ │ ├── py_math.cpp # Element-wise operations +│ │ ├── py_nc_random # Random array functionality pybind11 with NumCpp │ │ └── pybind_utils.cpp # Helper functions for bindings │ ├── python_api/ # Pure Python layer providing user-friendly interfaces for core functionality │ │ ├── __init__.py # API entry point for `python_api` -│ │ ├── _utils_impl.py # get_c_include, get_cpp_include, and get_include for lightnumpy library's C and C++ headers +│ │ ├── _utils_impl.py # get_include for lightnumpy library's C and C++ _core Headers with NumCpp Headers [2] │ │ ├── array.py # Array class implementation and basic methods │ │ ├── core.py # Contains core array functionality │ │ ├── linalg.py # Basic linear algebra operations (e.g., dot, transpose) diff --git a/lightnumpy/__init__.py b/lightnumpy/__init__.py index 87188c3..e6cf046 100644 --- a/lightnumpy/__init__.py +++ b/lightnumpy/__init__.py @@ -59,6 +59,9 @@ from .python_api import *; del python_api; +from . import ( + _core, +) # Remove symbols imported for internal use del ( diff --git a/lightnumpy/_build_utils/copyfiles.py b/lightnumpy/_build_utils/copyfiles.py new file mode 100644 index 0000000..c0a37f3 --- /dev/null +++ b/lightnumpy/_build_utils/copyfiles.py @@ -0,0 +1,21 @@ +""" +Platform independent file copier script +""" +#!/usr/bin/env python +import shutil +import argparse + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("infiles", nargs='+', + help="Paths to the input files") + parser.add_argument("outdir", + help="Path to the output directory") + args = parser.parse_args() + for infile in args.infiles: + shutil.copy2(infile, args.outdir) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lightnumpy/_build_utils/system_info.py b/lightnumpy/_build_utils/system_info.py new file mode 100644 index 0000000..a81a599 --- /dev/null +++ b/lightnumpy/_build_utils/system_info.py @@ -0,0 +1,37 @@ +def combine_dict(*dicts, **kw): + """ + Combine Numpy distutils style library configuration dictionaries. + + Parameters + ---------- + *dicts + Dictionaries of keys. List-valued keys will be concatenated. + Otherwise, duplicate keys with different values result to + an error. The input arguments are not modified. + **kw + Keyword arguments are treated as an additional dictionary + (the first one, i.e., prepended). + + Returns + ------- + combined + Dictionary with combined values. + """ + new_dict = {} + + for d in (kw,) + dicts: + for key, value in d.items(): + if new_dict.get(key, None) is not None: + old_value = new_dict[key] + if isinstance(value, (list, tuple)): + if isinstance(old_value, (list, tuple)): + new_dict[key] = list(old_value) + list(value) + continue + elif value == old_value: + continue + + raise ValueError(f"Conflicting configuration dicts: {new_dict!r} {d!r}") + else: + new_dict[key] = value + + return new_dict \ No newline at end of file diff --git a/lightnumpy/_build_utils/tempita.py b/lightnumpy/_build_utils/tempita.py new file mode 100644 index 0000000..91b5c47 --- /dev/null +++ b/lightnumpy/_build_utils/tempita.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +import os +import sys +import argparse + +# XXX: If this import ever fails (does it really?), vendor either +# cython.tempita or numpy/npy_tempita. +from Cython import Tempita as tempita + + +def process_tempita(fromfile, outfile=None): + """Process tempita templated file and write out the result. + + The template file is expected to end in `.c.in` or `.pyx.in`: + E.g. processing `template.c.in` generates `template.c`. + + """ + # template = tempita.Template.from_filename( + # fromfile, + # encoding=sys.getdefaultencoding() + # ) + with open(fromfile, "r", encoding="utf-8") as f: + template_content = f.read() + template = tempita.Template(template_content) + content = template.substitute() + + with open(outfile, "w", encoding="utf-8") as f: + f.write(content) + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "infile", + type=str, + help="Path to the input file" + ) + parser.add_argument( + "-o", + "--outfile", + type=str, + help="Path to the output file" + ) + parser.add_argument( + "-i", + "--ignore", + type=str, + help="An ignored input - may be useful to add a " + "dependency between custom targets", + ) + args = parser.parse_args() + + if not args.infile.endswith('.in'): + raise ValueError(f"Unexpected extension: {args.infile}") + + if not args.outfile: + raise ValueError("Missing `--outfile` argument to tempita.py") + + if os.path.isabs(args.outfile): + raise ValueError("`--outfile` must relative to the current directory") + + outdir_abs = os.path.join(os.getcwd(), args.outfile) + outfile = os.path.join( + outdir_abs, os.path.splitext(os.path.split(args.infile)[1])[0] + ) + + process_tempita(args.infile, outfile) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/lightnumpy/_c_core/include/array.h b/lightnumpy/_c_core/include/array.h deleted file mode 100644 index 3ce45c0..0000000 --- a/lightnumpy/_c_core/include/array.h +++ /dev/null @@ -1 +0,0 @@ -// Template: Define structures or function declarations related to arrays in C. \ No newline at end of file diff --git a/lightnumpy/_c_core/include/config_c_core.h b/lightnumpy/_c_core/include/config_c_core.h deleted file mode 100644 index 0cecfb2..0000000 --- a/lightnumpy/_c_core/include/config_c_core.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// Configuration settings for C core -#define USE_C_CORE 1 \ No newline at end of file diff --git a/lightnumpy/_c_core/include/hello.h b/lightnumpy/_c_core/include/hello.h deleted file mode 100644 index 874d988..0000000 --- a/lightnumpy/_c_core/include/hello.h +++ /dev/null @@ -1,41 +0,0 @@ -// include/hello.h -// C Header File for printing a customizable message -#ifndef HELLO_H // Include guard to prevent multiple inclusions, If not defined -#define HELLO_H - -// Standard C library header -#include // Standard I/O library for printf -#include // For string operations if needed - -// Default greeting message definition -#ifndef C_MESSAGE // 1. Check if C_MESSAGE is not defined -#define C_MESSAGE "Hello, from C!" // 2. If not, define it with the value "Hello, from C!" -// This block will be ignored if C_MESSAGE is already defined. -#endif // C_MESSAGE // 3. End the condition - -// Function declaration for printing a message -#ifdef __cplusplus -// Provide a C-compatible function for external use -// extern "C" disables name mangling, making the function callable from C -// and other languages that expect C-style linkage. -// Without extern "C", name mangling is enabled, -// and the function is only directly usable from C++. -// C++ function declaration with a default message. -// Ensures compatibility with C, Python, or other languages expecting C-style linkage. -extern "C" { -#endif - -// void print(const char* message = C_MESSAGE); -void printc(const char* message = C_MESSAGE) { - if (message == NULL || strlen(message) == 0) { - message = C_MESSAGE; // Use the default message if none is provided - } - // Print a message - printf("%s\n", message); -} - -#ifdef __cplusplus -} -#endif - -#endif // HELLO_H \ No newline at end of file diff --git a/lightnumpy/_c_core/include/math_ops.h b/lightnumpy/_c_core/include/math_ops.h deleted file mode 100644 index f991937..0000000 --- a/lightnumpy/_c_core/include/math_ops.h +++ /dev/null @@ -1 +0,0 @@ -// Template: Define mathematical operations (addition, multiplication, etc.) for the array module. \ No newline at end of file diff --git a/lightnumpy/_c_core/include/numpy_c.h b/lightnumpy/_c_core/include/numpy_c.h deleted file mode 100644 index 53fd0f8..0000000 --- a/lightnumpy/_c_core/include/numpy_c.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// NumPy C API headers -#include diff --git a/lightnumpy/_c_core/include/python_c.h b/lightnumpy/_c_core/include/python_c.h deleted file mode 100644 index 02ecf6e..0000000 --- a/lightnumpy/_c_core/include/python_c.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// Python C API header -#include diff --git a/lightnumpy/_c_core/include/std_lib_c.h b/lightnumpy/_c_core/include/std_lib_c.h deleted file mode 100644 index c507234..0000000 --- a/lightnumpy/_c_core/include/std_lib_c.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -// Standard C library header -#include -#include -#include diff --git a/lightnumpy/_c_core/meson.build b/lightnumpy/_c_core/meson.build deleted file mode 100644 index a159ded..0000000 --- a/lightnumpy/_c_core/meson.build +++ /dev/null @@ -1,90 +0,0 @@ -###################################################################### -## Include the Headers directories for _c_core -###################################################################### - -# list of include directories for Specific Subfolders -_c_core_inc_dir = [ - 'src', - 'include', -] - -###################################################################### -## Define include_directories for _c_core -###################################################################### - -# Use the include directory in your build setup -# Specify Include directories where your headers are located -# include_directories(header) -> static_library(mix), library(mix), declare_dependency(mix) -inc_dir_c_core = include_directories( - _c_core_inc_dir -) -# Optionally add a message to confirm the installation -message( - '\nC core Header compatibility files defined successfully: ' + - '@0@'.format('lightnumpy/_c_core/include') -) - -###################################################################### -## Define library for _c_core -###################################################################### - -# # Static library with C source file implementing bindings -# _st_lib_c_core = static_library('_st_lib_c_core', [], -# include_directories: inc_dir_c_core, -# dependencies: [], -# c_args: cython_c_flags, -# cpp_args: cython_cpp_flags, -# gnu_symbol_visibility: 'inlineshidden', -# link_with: [], -# link_args: [], -# # install: true, -# # install_dir: 'lightnumpy/_c_core', -# ) -# # Shared (dynamic) library with C source file implementing bindings -# _dyn_lib_c_core = library('_dyn_lib_c_core', [], -# include_directories: inc_dir_c_core, -# dependencies: [], -# c_args: cython_c_flags, -# cpp_args: cython_cpp_flags, -# gnu_symbol_visibility: 'hidden', -# gnu_symbol_visibility: 'inlineshidden', -# # link_with: [_st_lib_c_core], # Link with the static library -# # link_args: ['-shared'], # shared library that can be used by other programs at runtime. -# install: true, -# install_dir: 'lightnumpy/_c_core', -# ) - -###################################################################### -## Define Dependencies -###################################################################### - -# Get the Sources-Headers Dependencies -dep_c_core = declare_dependency( - compile_args: cython_c_flags, - dependencies: [], - include_directories: inc_dir_c_core, - # link_with: [_st_lib_c_core], # Link with the static/shared library - # link_args: ['-shared'], # shared library that can be used by other programs at runtime. -) -# Optionally add a message to confirm the installation -message( - '\nC core Header dependency defined successfully: ' + - '@0@'.format('dep_c_core') -) - -###################################################################### -## Next -###################################################################### - -###################################################################### -## Optional format, tidy -###################################################################### - -# # Custom targets (optional) -# custom_target('format', -# command: ['clang-format', '-i', '-style=file:.clang-format', '@INPUT@'], -# output: 'formatted', -# input: files('NumCpp.hpp'), # Adjust this pattern to match the actual header files -# ) -# custom_target('tidy', -# command: ['clang-tidy', '-p', meson.build_dir(), '-extra-arg=-std=c++17', '@INPUT@'], \ No newline at end of file diff --git a/lightnumpy/_c_core/src/array.c b/lightnumpy/_c_core/src/array.c deleted file mode 100644 index 43e19f4..0000000 --- a/lightnumpy/_c_core/src/array.c +++ /dev/null @@ -1 +0,0 @@ -// Template: Define C implementations for the operations declared in array.h. \ No newline at end of file diff --git a/lightnumpy/_c_core/src/hello.c b/lightnumpy/_c_core/src/hello.c deleted file mode 100644 index 79283be..0000000 --- a/lightnumpy/_c_core/src/hello.c +++ /dev/null @@ -1,41 +0,0 @@ -// src/hello.c -// C Header File for printing a customizable message -#ifndef HELLO_C // Include guard to prevent multiple inclusions, If not defined -#define HELLO_C - -// Standard C library header -#include // Standard I/O library for printf -#include // For string operations if needed - -// Default greeting message definition -#ifndef C_MESSAGE // 1. Check if C_MESSAGE is not defined -#define C_MESSAGE "Hello, from C!" // 2. If not, define it with the value "Hello, from C!" -// This block will be ignored if C_MESSAGE is already defined. -#endif // C_MESSAGE // 3. End the condition - -// Function declaration for printing a message -#ifdef __cplusplus -// Provide a C-compatible function for external use -// extern "C" disables name mangling, making the function callable from C -// and other languages that expect C-style linkage. -// Without extern "C", name mangling is enabled, -// and the function is only directly usable from C++. -// C++ function declaration with a default message. -// Ensures compatibility with C, Python, or other languages expecting C-style linkage. -extern "C" { -#endif - -// void print(const char* message = C_MESSAGE); -void printc(const char* message = C_MESSAGE) { - if (message == NULL || strlen(message) == 0) { - message = C_MESSAGE; // Use the default message if none is provided - } - // Print a message - printf("%s\n", message); -} - -#ifdef __cplusplus -} -#endif - -#endif // HELLO_C \ No newline at end of file diff --git a/lightnumpy/_c_core/src/math_ops.c b/lightnumpy/_c_core/src/math_ops.c deleted file mode 100644 index 9fe0a1b..0000000 --- a/lightnumpy/_c_core/src/math_ops.c +++ /dev/null @@ -1 +0,0 @@ -// Template: Implement math operations defined in math_ops.h. \ No newline at end of file diff --git a/lightnumpy/_c_core/.clang-format b/lightnumpy/_core/.clang-format similarity index 100% rename from lightnumpy/_c_core/.clang-format rename to lightnumpy/_core/.clang-format diff --git a/lightnumpy/_c_core/.clang-tidy b/lightnumpy/_core/.clang-tidy similarity index 100% rename from lightnumpy/_c_core/.clang-tidy rename to lightnumpy/_core/.clang-tidy diff --git a/lightnumpy/_core/__init__.py b/lightnumpy/_core/__init__.py new file mode 100644 index 0000000..8e0ad06 --- /dev/null +++ b/lightnumpy/_core/__init__.py @@ -0,0 +1,6 @@ + + +# NumCpp Call the function to get the version +# __version__ = py_numcpp_api.nc_version() +# __author__ = "David Pilger et al." +# __author_email__ = "dpilger26@gmail.com" \ No newline at end of file diff --git a/lightnumpy/_core/include/lightnumpy/boost_math.h b/lightnumpy/_core/include/lightnumpy/boost_math.h new file mode 100644 index 0000000..a868f19 --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/boost_math.h @@ -0,0 +1,17 @@ +#pragma once +// Notes: +// - Boost Math includes many advanced mathematical functions that are not available in the standard C++ library, such as Bessel functions (`boost::math::cyl_bessel_j()`), Gamma functions, and more. +// - To use Boost Math, make sure you've installed the Boost C++ libraries and included the relevant headers. +// - The functions are organized into namespaces like `boost::math` and are well-documented. For example, you can use `boost::math::pi` to get the value of π. +// - Boost provides high-precision and efficient implementations, especially for complex mathematical tasks such as statistical distributions and interpolation. + +// Optional Boost Math C++ Libraries +// Boost Math provides a wide range of advanced mathematical functions that are optimized for performance and precision. +#ifdef BOOST_MATH_INCLUDED // if defined(BOOST_MATH_INCLUDED) + #include + #include +#else + // ifndef BOOST_MATH_INCLUDED // if !defined(BOOST_MATH_INCLUDED) + // Boost Math is optional, so no error is raised. + // If you need Boost Math, install it and ensure it's available. +#endif diff --git a/lightnumpy/_c_core/include/.gitkeep b/lightnumpy/_core/include/lightnumpy/c/.gitkeep similarity index 100% rename from lightnumpy/_c_core/include/.gitkeep rename to lightnumpy/_core/include/lightnumpy/c/.gitkeep diff --git a/lightnumpy/_core/include/lightnumpy/config.h b/lightnumpy/_core/include/lightnumpy/config.h new file mode 100644 index 0000000..21f806f --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/config.h @@ -0,0 +1,41 @@ +// include/config.h +// Unified C and C++ Header File + +#pragma once // Ensures the file is included only once by the compiler + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +// Common configurations +#define APP_VERSION "1.0.0" +#define DEBUG_MODE 1 + +// Function declarations +// void initialize_app(); + +// const char* get_app_version(); +const char* get_app_version() { // config.c + return APP_VERSION; +} + +#ifdef __cplusplus +} // extern "C" + +// C++-specific configurations or features +#include +inline void print_version() { + std::cout << "App version: " << APP_VERSION << std::endl; +} +#endif + +#include +inline std::string get_app_version_cpp() { + return std::string(get_app_version()); +} +#endif + +#endif // CONFIG_H \ No newline at end of file diff --git a/lightnumpy/_c_core/src/.gitkeep b/lightnumpy/_core/include/lightnumpy/cpp/.gitkeep similarity index 100% rename from lightnumpy/_c_core/src/.gitkeep rename to lightnumpy/_core/include/lightnumpy/cpp/.gitkeep diff --git a/lightnumpy/_core/include/lightnumpy/hello.h b/lightnumpy/_core/include/lightnumpy/hello.h new file mode 100644 index 0000000..30d2ee5 --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/hello.h @@ -0,0 +1,206 @@ +// include/hello.h +// Unified C and C++ Header File for printing customizable messages and conversions + +#pragma once // Ensures the file is included only once by the compiler + +#ifndef HELLO_H // Traditional include guard for compatibility +#define HELLO_H + +#ifndef MIN_BUFFER_SIZE +#define MIN_BUFFER_SIZE 64 // Define minimum buffer size +#endif + +#ifndef MAX_BUFFER_SIZE +#define MAX_BUFFER_SIZE 1024 // Define maximum buffer size +#endif + +// Include standard headers +#ifdef __cplusplus + // C++ specific headers + #include // For std::string (C++ only) + #include + #include // For std::ostringstream (C++ only) + #include // For std::cout (C++ only) + #include // For math functions (C++ version of math.h) + #include // For std::vector (C++ only) +#else + // C specific headers + #include // For printf and sprintf (C only) + #include // For string operations (C only) + #include // For memory allocation and process control (C only) + #include // For math functions (C only) +#endif // End of standard headers inclusion + +// Default greeting message definition +#ifndef DEFAULT_MESSAGE +#ifdef __cplusplus +#define DEFAULT_MESSAGE "Hello, from C++!" +#else +#define DEFAULT_MESSAGE "Hello, from C!" +#endif +#endif // Default message + +#ifdef __cplusplus // C++ code begins here +// Provide C-Compatible Interface (explicitly defined for each type) +// extern "C" disables name mangling, making the function callable from C +// and other languages that expect C-style linkage. +// Without extern "C", name mangling is enabled, +// and the function is only directly usable from C++. +// C++ function declaration with a default message. +// Ensures compatibility with C, Python, or other languages expecting C-style linkage. +extern "C" { + +////////////////////////////////////////////////////////////////////// +// Begin of C-style Code (for C functions) +// C functions are automatically compatible with C and C++ +////////////////////////////////////////////////////////////////////// + +/** + * @brief Prints the given message to the console. For C, only C-style strings are supported. + * + * @param message A C-style string to print. Defaults to DEFAULT_MESSAGE if NULL or empty. + */ +// Function declaration for C (using const char* for C-style string) +// void to_print(const char* message = DEFAULT_MESSAGE); // Normally Header file function definition +void c_char_to_print(const char* message = DEFAULT_MESSAGE) { // We adding here hello.c + // if (message == NULL || message[0] == '\0') { + if (message == NULL || strlen(message) == 0) { + message = DEFAULT_MESSAGE; // Use the default message if none is provided + } + printf("%s\n", message); // Print the message +} + +/** + * @brief Converts an integer to a string in C. + * + * @param value The integer value to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold the result. + */ +// Function to convert integer to string +// void to_string_int(int value, char* buffer); +void c_int_to_string(int value, char** buffer) { + // Calculate required size for integer conversion + int size_needed = snprintf(NULL, 0, "%d", value) + 1; // +1 for null-termination + + // Ensure buffer size is at least the minimum size + int buffer_size = (size_needed < MIN_BUFFER_SIZE) ? MIN_BUFFER_SIZE : size_needed; + + // Allocate memory for the buffer + *buffer = (char*)malloc(buffer_size); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for integer conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + + // Format the integer into the buffer + snprintf(*buffer, buffer_size, "%d", value); +} + +/** + * @brief Converts a float to a string in C with a specified number of decimal places. + * Defaults to 2 decimal places if the user doesn't specify. + * + * @param value The float value to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold the result. + * @param decimal_places The number of decimal places to include. Defaults to 2. + */ +// Function to convert float to string with specified decimal places +// void to_string_float(float value, char* buffer, int decimal_places = 2); +void c_float_to_string(float value, char** buffer, int decimal_places = 2) { + if (decimal_places <= 0) { + decimal_places = 2; // Default to 2 decimal places if not provided + } + + // Calculate required size for float conversion + int size_needed = snprintf(NULL, 0, "%.*f", decimal_places, value) + 1; // +1 for null-termination + + // Ensure buffer size is within min/max range + int buffer_size = (size_needed < MIN_BUFFER_SIZE) ? MIN_BUFFER_SIZE : + (size_needed > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : size_needed); + + // Allocate memory for the buffer + *buffer = (char*)malloc(buffer_size); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for float conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + + // Format the float into the buffer + snprintf(*buffer, buffer_size, "%.*f", decimal_places, value); +} + +/** + * @brief Converts a C-style string to a string or DEFAULT_MESSAGE if null/empty. + * + * @param value The C-style string to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold DEFAULT_MESSAGE. + */ +// Function to convert C-style string to string +// void to_string_cstr(const char* value, char* buffer); +void c_char_to_string(const char* value, char** buffer) { + if (value == NULL || value[0] == '\0') { + // Allocate memory for default message + *buffer = (char*)malloc(strlen(DEFAULT_MESSAGE) + 1); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for default message.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + strcpy(*buffer, DEFAULT_MESSAGE); // Copy default message to buffer + } else { + // Allocate memory for the provided string + int size_needed = strlen(value) + 1; // +1 for null-termination + *buffer = (char*)malloc(size_needed); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for string conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + strcpy(*buffer, value); // Copy the string to the buffer + } +} + +////////////////////////////////////////////////////////////////////// +// Begin of C++-style Code (for C++ functions) +////////////////////////////////////////////////////////////////////// + +/** + * @brief Prints the given message to the console. Supports both C-style and C++ strings. + * + * @param message A string to print. Accepts `const char*` or `std::string`. + */ +// C++ version of to_print that accepts std::string (C++ only) +inline void cpp_str_to_print(const std::string& message = DEFAULT_MESSAGE) { + std::cout << (message.empty() ? DEFAULT_MESSAGE : message) << std::endl; // Output the message to the console +} +inline void cpp_char_to_print(const char* message = DEFAULT_MESSAGE) { + if (!message || strlen(message) == 0) { + std::cout << DEFAULT_MESSAGE << std::endl; // Output the message to the console + } else { + std::cout << message << std::endl; // Output the message to the console + } +} + +// Specialization for `std::string` +inline std::string cpp_str_to_string(const std::string& value) { + // Return the input string, but use DEFAULT_MESSAGE if it's empty + return value.empty() ? DEFAULT_MESSAGE : value; +} +// Specialization for `const char*` +inline std::string cpp_char_to_string(const char* value) { + // Return default message for null or empty C strings + // if (!value || strlen(value) == 0) {return DEFAULT_MESSAGE;} + // if (value == nullptr || strlen(value) == 0) {return DEFAULT_MESSAGE;} + // return std::string(value); // Return the input string as is + + // Return default message for null or empty C strings + return (value && strlen(value) > 0) ? value : DEFAULT_MESSAGE; +} + +} +#endif // End of C++-style Code +////////////////////////////////////////////////////////////////////// + +#endif // HELLO_H \ No newline at end of file diff --git a/lightnumpy/_core/include/lightnumpy/numpy.h b/lightnumpy/_core/include/lightnumpy/numpy.h new file mode 100644 index 0000000..dc3a0fe --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/numpy.h @@ -0,0 +1,14 @@ +#pragma once +// Notes: +// - NumPy arrays are represented as `PyArrayObject*` in the C API. +// - To work with NumPy arrays, you need to initialize the NumPy API by calling `import_array()` (usually done in the `main()` function). +// - NumPy provides a range of functions for array manipulation, such as `PyArray_Alloc()` (for creating arrays) and `PyArray_GetPtr()` (to access elements). +// - The NumPy C API allows for high-performance numerical operations, making it ideal for scientific computing. +// - Make sure to include `numpy/arrayobject.h` in your project and link the appropriate NumPy C library. + +// NumPy C API headers +// https://pythonextensionpatterns.readthedocs.io/en/latest/cpp_and_numpy.html +// This enables access to NumPy arrays and operations in C/C++ code. NumPy is widely used for numerical computations and large datasets in Python. +#include + +// #error "NumPy headers are missing. Ensure NumPy development headers are installed." \ No newline at end of file diff --git a/lightnumpy/_core/include/lightnumpy/pybind.h b/lightnumpy/_core/include/lightnumpy/pybind.h new file mode 100644 index 0000000..8871e67 --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/pybind.h @@ -0,0 +1,18 @@ +#pragma once +// Notes: +// - Pybind11 simplifies the process of creating Python extensions by eliminating the need for boilerplate code. With Pybind11, you can directly expose C++ classes and functions to Python. +// - Pybind11 supports both Python 2 and 3, and it works with modern C++ features, such as lambdas and smart pointers. +// - To expose a C++ class or function to Python, you only need to write a minimal wrapper, usually in a `.cpp` file, using `PYBIND11_MODULE()` to define the Python module. +// - Example: `PYBIND11_MODULE(my_module, m) { m.def("my_function", &my_function); }` binds the C++ function `my_function` to the Python module `my_module`. +// - Pybind11 handles the conversion between C++ types and Python types (e.g., `std::string` becomes `str`, `int` becomes `int`, etc.) automatically. + +// Optional Pybind11 header +// Pybind11 is a lightweight header-only library for creating Python bindings to C++ code. +// It allows C++ classes and functions to be directly exposed to Python. +#ifdef PYBIND11_H_INCLUDED // if defined(PYBIND11_H_INCLUDED) + #include +#else + // ifndef PYBIND11_H_INCLUDED // if !defined(PYBIND11_H_INCLUDED) + // Pybind11 is optional, so no error is raised. + // If you need Pybind11, install it and ensure it's available. +#endif diff --git a/lightnumpy/_core/include/lightnumpy/python.h b/lightnumpy/_core/include/lightnumpy/python.h new file mode 100644 index 0000000..6a6c051 --- /dev/null +++ b/lightnumpy/_core/include/lightnumpy/python.h @@ -0,0 +1,13 @@ +#pragma once +// Notes: +// - To use the Python C API, you must initialize the Python interpreter using `Py_Initialize()`. +// - After you're done with Python, call `Py_Finalize()` to clean up and shut down the interpreter. +// - Common Python C API functions include `PyRun_SimpleString()` (to execute Python code) and `PyImport_ImportModule()` (to import Python modules). +// - Python objects are handled using `PyObject*` types, and you can convert between C data types and Python objects using functions like `Py_BuildValue()` and `PyArg_ParseTuple()`. +// - Always manage reference counts properly using `Py_INCREF()` and `Py_DECREF()` to avoid memory leaks. + +// Python C API header +// This allows C/C++ code to interact with Python, enabling Python script execution and data manipulation within a C/C++ program. +#include + +// #error "Python headers are missing. Ensure you have Python development headers installed." \ No newline at end of file diff --git a/lightnumpy/_cpp_core/meson.build b/lightnumpy/_core/meson.build similarity index 60% rename from lightnumpy/_cpp_core/meson.build rename to lightnumpy/_core/meson.build index 401d1e6..845f9b2 100644 --- a/lightnumpy/_cpp_core/meson.build +++ b/lightnumpy/_core/meson.build @@ -1,32 +1,26 @@ ###################################################################### -## Submodule NumCpp -###################################################################### - -if get_option('numcpp').enabled() - if not fs.exists('NumCpp/README.md') - error('Missing the `NumCpp` submodule! ' + - 'Run `git submodule update --init` to fix this.') - endif -endif - -###################################################################### -## Define dependencies and Compiler Flags +## Define dependencies and Compiler Flags for NumCpp ###################################################################### +# Define args and dependencies for NumCpp _global_numcpp_args = [] - -# Define dependencies with NumCpp _dep_list_numcpp = [] -if get_option('numcpp').enabled() +if get_option('lnpy_use_numcpp').enabled() # Initialize an empty list for compiler flags _global_numcpp_args += [ + # The -D flag defines a macro that is globally available during compilation. + # The -U flag removes a macro definition during compilation, effectively ignoring it. + '-DLNPY_USE_NUMCPP', # Default disable all NumCpp features + '-DNUMCPP_INCLUDE_PYBIND_PYTHON_INTERFACE', # Include PyBind11 Python interface helper functions + # The -f option in compilers like gcc or g++ is used to enable + # or disable specific compiler features or behaviors. # to ensure that the generated code can be executed from any address in memory, # which is necessary for shared libraries. - # '-fPIC', - '-DNUMCPP_INCLUDE_PYBIND_PYTHON_INTERFACE', # Include PyBind11 Python interface helper functions + # '-fPIC', # Generate position-independent code + # -finline-functions # Enable function inlining + # -fno-inline-functions # Disable function inlining ] - # Optional Boost Dependency # dpkg -s libboost-dev | grep 'Version' if get_option('numcpp_no_use_boost') @@ -42,7 +36,6 @@ if get_option('numcpp').enabled() _dep_list_numcpp += [dep_boost] message('Dependency: Boost dependency added...') endif - # Optional TBB Dependency for Multithreading if get_option('numcpp_use_multithread') # Enable multithreading with STL parallel execution policies @@ -55,74 +48,45 @@ if get_option('numcpp').enabled() endif else _global_numcpp_args += [ - '-DNUMCPP_NO_INCLUDE', # Default disable all NumCpp features + '-U LNPY_USE_NUMCPP', # Default disable all NumCpp features ] endif cython_cpp_flags += _global_numcpp_args ###################################################################### -## Include the Headers directories for _cpp_core, NumCpp +## Include the Headers directories for _core, NumCpp ###################################################################### # include directories for Specific Subfolders _numcpp_inc_dir = [] -if get_option('numcpp').enabled() +if get_option('lnpy_use_numcpp').enabled() _numcpp_inc_dir = [ - 'NumCpp/include/NumCpp/Core/Internal', - 'NumCpp/include', - # 'NumCpp/include/NumCpp', - # 'NumCpp/include/NumCpp/Coordinates', - # 'NumCpp/include/NumCpp/Coordinates/ReferenceFrames', - # 'NumCpp/include/NumCpp/Coordinates/Transforms', - # 'NumCpp/include/NumCpp/Core', - # 'NumCpp/include/NumCpp/Core/Internal', - # 'NumCpp/include/NumCpp/DateTime', - # 'NumCpp/include/NumCpp/Filter', - # 'NumCpp/include/NumCpp/Filter/Boundaries', - # 'NumCpp/include/NumCpp/Filter/Boundaries/Boundaries1d', - # 'NumCpp/include/NumCpp/Filter/Boundaries/Boundaries2d', - # 'NumCpp/include/NumCpp/Filter/Filters', - # 'NumCpp/include/NumCpp/Filter/Filters/Filters1d', - # 'NumCpp/include/NumCpp/Filter/Filters/Filters2d', - # 'NumCpp/include/NumCpp/Functions', - # 'NumCpp/include/NumCpp/ImageProcessing', - # 'NumCpp/include/NumCpp/Integrate', - # 'NumCpp/include/NumCpp/Linalg', - # 'NumCpp/include/NumCpp/Linalg/svd', - # 'NumCpp/include/NumCpp/Logging', - # 'NumCpp/include/NumCpp/NdArray', - # 'NumCpp/include/NumCpp/Polynomial', - # 'NumCpp/include/NumCpp/PythonInterface', - # 'NumCpp/include/NumCpp/Random', - # 'NumCpp/include/NumCpp/Roots', - # 'NumCpp/include/NumCpp/Rotations', - # 'NumCpp/include/NumCpp/Special', - # 'NumCpp/include/NumCpp/Utils', - # 'NumCpp/include/NumCpp/Vector', + '../../third_party/NumCpp/include', + '../../third_party/NumCpp/include/NumCpp/Core/Internal', # version ] endif -_cpp_core_inc_dir = [ +_core_inc_dir = [ 'src', 'include', ] + _numcpp_inc_dir ###################################################################### -## Define include_directories for _c_core, NumCpp +## Define include_directories for _core, NumCpp ###################################################################### # Use the include directory in your build setup # Specify Include directories where your headers are located # include_directories(header) -> static_library(mix), library(mix), declare_dependency(mix) -inc_dir_cpp_core = include_directories( - _cpp_core_inc_dir +inc_dir_core = include_directories( + _core_inc_dir ) # Optionally add a message to confirm the installation message( '\nCpp Core Header compatibility files defined successfully: ' + - '@0@ '.format('lightnumpy/_cpp_core/include') + - 'with NumCpp: @0@'.format(get_option('numcpp').enabled()) + '@0@ '.format('lightnumpy/_core/include') + + 'with NumCpp: @0@'.format(get_option('lnpy_use_numcpp').enabled()) ) ###################################################################### @@ -131,8 +95,8 @@ message( ###################################################################### # # Static library with C++ source file implementing bindings -# _st_lib_cpp_core = static_library('_st_lib_cpp_core', [], -# include_directories: inc_dir_cpp_core, +# _st_lib_core = static_library('_st_lib_core', [], +# include_directories: inc_dir_core, # dependencies: [], # c_args: [], # cpp_args: [], @@ -140,20 +104,20 @@ message( # link_with: [], # link_args: [], # # install: true, -# # install_dir: 'lightnumpy/_cpp_core', +# # install_dir: 'lightnumpy/_core', # ) # # Shared (dynamic) library with C++ source file implementing bindings -# _dyn_lib_cpp_core = library('_dyn_lib_cpp_core', [], -# include_directories: inc_dir_cpp_core, +# _dyn_lib_core = library('_dyn_lib_core', [], +# include_directories: inc_dir_core, # dependencies: [], # c_args: [], # cpp_args: [], # gnu_symbol_visibility: 'hidden', # gnu_symbol_visibility: 'inlineshidden', -# # link_with: [_st_lib_cpp_core], # Link with the static library +# # link_with: [_st_lib_core], # Link with the static library # # link_args: ['-shared'], # shared library that can be used by other programs at runtime. # install: true, -# install_dir: 'lightnumpy/_cpp_core', +# install_dir: 'lightnumpy/_core', # ) ###################################################################### @@ -161,18 +125,18 @@ message( ###################################################################### # Get the NumCpp Dependencies with/without library -dep_cpp_core = declare_dependency( +dep_core = declare_dependency( compile_args: cython_cpp_flags, dependencies: _dep_list_numcpp, - include_directories: inc_dir_cpp_core, - # link_with: [_st_lib_cpp_core], # Link with the static/shared library - # link_args: ['-shared'], # shared library that can be used by other programs at runtime. + include_directories: inc_dir_core, + # link_with: [_st_lib_core], # Link with the static/shared library + # link_args: ['-shared'], # shared library that can be used by other programs at runtime. ) # Optionally add a message to confirm the installation message( '\nCpp Core Header dependency defined successfully: ' + - '@0@ '.format('dep_cpp_core') + - 'with NumCpp: @0@'.format(get_option('numcpp').enabled()) + '@0@ '.format('dep_core') + + 'with NumCpp: @0@'.format(get_option('lnpy_use_numcpp').enabled()) ) ###################################################################### diff --git a/lightnumpy/_cpp_core/include/.gitkeep b/lightnumpy/_core/src/.gitkeep similarity index 100% rename from lightnumpy/_cpp_core/include/.gitkeep rename to lightnumpy/_core/src/.gitkeep diff --git a/lightnumpy/_core/src/dummymodule.c b/lightnumpy/_core/src/dummymodule.c new file mode 100644 index 0000000..8b6b989 --- /dev/null +++ b/lightnumpy/_core/src/dummymodule.c @@ -0,0 +1,57 @@ +/* -*- c -*- */ + +/* + * This is a dummy module designed to ensure that distutils generates + * the necessary configuration files before building the libraries. + * + * The module doesn't provide any actual functionality but serves as a placeholder + * for the build process. + */ + +#define LNPY_NO_DEPRECATED_API LNPY_API_VERSION // Define API version for LNPY + +// #define NPY_NO_DEPRECATED_API NPY_API_VERSION // Define API version for NPY +// #define NO_IMPORT_ARRAY // Prevent NumPy from being imported here + +#define PY_SSIZE_T_CLEAN // Ensures that the Python API uses properly sized ssize_t for Python objects +#include // Python C API header + +// Define the methods for the module (empty in this case) +static struct PyMethodDef methods[] = { + {NULL, NULL, 0, NULL} // No methods provided +}; + +// Define the module structure +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, // Module definition structure + "dummy", // Module name + NULL, // Module documentation (none) + -1, // Size of per-interpreter state (none here) + methods, // Methods for the module (none here) + NULL, // Slot table (none here) + NULL, // Traverse function (none here) + NULL, // Clear function (none here) + NULL // Free function (none here) +}; + +/* + * Initialization function for the dummy module. + * This function is called by Python when the module is imported or initialized. + * + * @return PyObject* - The created module or NULL on error. + */ +PyMODINIT_FUNC PyInit__dummy(void) { + PyObject *m; + + // Create the module using the module definition + m = PyModule_Create(&moduledef); + + // Check for errors during module creation + if (!m) { + // Return NULL on failure to create the module + return NULL; + } + + // Return the created module + return m; +} \ No newline at end of file diff --git a/lightnumpy/_core/src/hello.c b/lightnumpy/_core/src/hello.c new file mode 100644 index 0000000..99d0de2 --- /dev/null +++ b/lightnumpy/_core/src/hello.c @@ -0,0 +1,206 @@ +// src/hello.c +// Unified C and C++ Header File for printing customizable messages and conversions + +#pragma once // Ensures the file is included only once by the compiler + +#ifndef HELLO_C // Traditional include guard for compatibility +#define HELLO_C + +#ifndef MIN_BUFFER_SIZE +#define MIN_BUFFER_SIZE 64 // Define minimum buffer size +#endif + +#ifndef MAX_BUFFER_SIZE +#define MAX_BUFFER_SIZE 1024 // Define maximum buffer size +#endif + +// Include standard headers +#ifdef __cplusplus + // C++ specific headers + #include // For std::string (C++ only) + #include + #include // For std::ostringstream (C++ only) + #include // For std::cout (C++ only) + #include // For math functions (C++ version of math.h) + #include // For std::vector (C++ only) +#else + // C specific headers + #include // For printf and sprintf (C only) + #include // For string operations (C only) + #include // For memory allocation and process control (C only) + #include // For math functions (C only) +#endif // End of standard headers inclusion + +// Default greeting message definition +#ifndef DEFAULT_MESSAGE +#ifdef __cplusplus +#define DEFAULT_MESSAGE "Hello, from C++!" +#else +#define DEFAULT_MESSAGE "Hello, from C!" +#endif +#endif // Default message + +#ifdef __cplusplus // C++ code begins here +// Provide C-Compatible Interface (explicitly defined for each type) +// extern "C" disables name mangling, making the function callable from C +// and other languages that expect C-style linkage. +// Without extern "C", name mangling is enabled, +// and the function is only directly usable from C++. +// C++ function declaration with a default message. +// Ensures compatibility with C, Python, or other languages expecting C-style linkage. +extern "C" { + +////////////////////////////////////////////////////////////////////// +// Begin of C-style Code (for C functions) +// C functions are automatically compatible with C and C++ +////////////////////////////////////////////////////////////////////// + +/** + * @brief Prints the given message to the console. For C, only C-style strings are supported. + * + * @param message A C-style string to print. Defaults to DEFAULT_MESSAGE if NULL or empty. + */ +// Function declaration for C (using const char* for C-style string) +// void to_print(const char* message = DEFAULT_MESSAGE); // Normally Header file function definition +void c_char_to_print(const char* message = DEFAULT_MESSAGE) { // We adding here hello.c + // if (message == NULL || message[0] == '\0') { + if (message == NULL || strlen(message) == 0) { + message = DEFAULT_MESSAGE; // Use the default message if none is provided + } + printf("%s\n", message); // Print the message +} + +/** + * @brief Converts an integer to a string in C. + * + * @param value The integer value to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold the result. + */ +// Function to convert integer to string +// void to_string_int(int value, char* buffer); +void c_int_to_string(int value, char** buffer) { + // Calculate required size for integer conversion + int size_needed = snprintf(NULL, 0, "%d", value) + 1; // +1 for null-termination + + // Ensure buffer size is at least the minimum size + int buffer_size = (size_needed < MIN_BUFFER_SIZE) ? MIN_BUFFER_SIZE : size_needed; + + // Allocate memory for the buffer + *buffer = (char*)malloc(buffer_size); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for integer conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + + // Format the integer into the buffer + snprintf(*buffer, buffer_size, "%d", value); +} + +/** + * @brief Converts a float to a string in C with a specified number of decimal places. + * Defaults to 2 decimal places if the user doesn't specify. + * + * @param value The float value to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold the result. + * @param decimal_places The number of decimal places to include. Defaults to 2. + */ +// Function to convert float to string with specified decimal places +// void to_string_float(float value, char* buffer, int decimal_places = 2); +void c_float_to_string(float value, char** buffer, int decimal_places = 2) { + if (decimal_places <= 0) { + decimal_places = 2; // Default to 2 decimal places if not provided + } + + // Calculate required size for float conversion + int size_needed = snprintf(NULL, 0, "%.*f", decimal_places, value) + 1; // +1 for null-termination + + // Ensure buffer size is within min/max range + int buffer_size = (size_needed < MIN_BUFFER_SIZE) ? MIN_BUFFER_SIZE : + (size_needed > MAX_BUFFER_SIZE ? MAX_BUFFER_SIZE : size_needed); + + // Allocate memory for the buffer + *buffer = (char*)malloc(buffer_size); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for float conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + + // Format the float into the buffer + snprintf(*buffer, buffer_size, "%.*f", decimal_places, value); +} + +/** + * @brief Converts a C-style string to a string or DEFAULT_MESSAGE if null/empty. + * + * @param value The C-style string to convert. + * @param buffer The buffer to store the resulting string. Must be large enough to hold DEFAULT_MESSAGE. + */ +// Function to convert C-style string to string +// void to_string_cstr(const char* value, char* buffer); +void c_char_to_string(const char* value, char** buffer) { + if (value == NULL || value[0] == '\0') { + // Allocate memory for default message + *buffer = (char*)malloc(strlen(DEFAULT_MESSAGE) + 1); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for default message.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + strcpy(*buffer, DEFAULT_MESSAGE); // Copy default message to buffer + } else { + // Allocate memory for the provided string + int size_needed = strlen(value) + 1; // +1 for null-termination + *buffer = (char*)malloc(size_needed); + if (*buffer == NULL) { + // Handle memory allocation failure + fprintf(stderr, "Memory allocation failed for string conversion.\n"); + exit(EXIT_FAILURE); // Exit the program with failure code + } + strcpy(*buffer, value); // Copy the string to the buffer + } +} + +////////////////////////////////////////////////////////////////////// +// Begin of C++-style Code (for C++ functions) +////////////////////////////////////////////////////////////////////// + +/** + * @brief Prints the given message to the console. Supports both C-style and C++ strings. + * + * @param message A string to print. Accepts `const char*` or `std::string`. + */ +// C++ version of to_print that accepts std::string (C++ only) +inline void cpp_str_to_print(const std::string& message = DEFAULT_MESSAGE) { + std::cout << (message.empty() ? DEFAULT_MESSAGE : message) << std::endl; // Output the message to the console +} +inline void cpp_char_to_print(const char* message = DEFAULT_MESSAGE) { + if (!message || strlen(message) == 0) { + std::cout << DEFAULT_MESSAGE << std::endl; // Output the message to the console + } else { + std::cout << message << std::endl; // Output the message to the console + } +} + +// Specialization for `std::string` +inline std::string cpp_str_to_string(const std::string& value) { + // Return the input string, but use DEFAULT_MESSAGE if it's empty + return value.empty() ? DEFAULT_MESSAGE : value; +} +// Specialization for `const char*` +inline std::string cpp_char_to_string(const char* value) { + // Return default message for null or empty C strings + // if (!value || strlen(value) == 0) {return DEFAULT_MESSAGE;} + // if (value == nullptr || strlen(value) == 0) {return DEFAULT_MESSAGE;} + // return std::string(value); // Return the input string as is + + // Return default message for null or empty C strings + return (value && strlen(value) > 0) ? value : DEFAULT_MESSAGE; +} + +} +#endif // End of C++-style Code +////////////////////////////////////////////////////////////////////// + +#endif // HELLO_C \ No newline at end of file diff --git a/lightnumpy/_core/src/nc_version.cpp b/lightnumpy/_core/src/nc_version.cpp new file mode 100644 index 0000000..ac91611 --- /dev/null +++ b/lightnumpy/_core/src/nc_version.cpp @@ -0,0 +1,66 @@ +// src/nc_version.cpp +// C++ Source File for retrieving the NumCpp version information + +#pragma once // Ensures the file is included only once by the compiler + +#ifndef NC_VERSION_CPP // Include guard to prevent multiple inclusions +#define NC_VERSION_CPP + +// Standard C++ library headers +#include // For std::string +#include // For std::ostringstream (optional, if needed for other operations) +#include // For std::cout (optional, if needed for debugging) + +////////////////////////////////////////////////////////////////////// +// NumCpp Header implemented functions by LNPY_USE_NUMCPP +////////////////////////////////////////////////////////////////////// + +// Check for the availability of NumCpp headers +#ifdef LNPY_USE_NUMCPP // If NumCpp is not included (controlled by a macro) + #include "Version.hpp" // NumCpp version header containing `nc::VERSION` + + // Define NC_VERSION with the actual version or fallback value + #ifndef NC_VERSION + #define NC_VERSION nc::VERSION // Use NumCpp version if available + #endif // NC_VERSION +#else + // Fallback: Define NC_VERSION as "Unavailable" if NumCpp is not available + #define NC_VERSION "Unavailable" +#endif // LNPY_USE_NUMCPP + +#ifdef __cplusplus +// Provide C-Compatible Interface (explicitly defined for each type) +// Ensures compatibility with C, Python, or other languages expecting C-style linkage. +extern "C" { +#endif + +/** + * Retrieves the NumCpp version string. + * This function is marked with `extern "C"` to ensure that it has C-style linkage, + * making it compatible with other languages like Python, C, and others that need C-style functions. + * + * @return const char* - The version string of NumCpp, or "Unavailable" if NumCpp headers are not included. + */ +const char* get_numcpp_version() { + if (std::string(NC_VERSION) == "Unavailable") { + std::cerr << "Warning: NumCpp version is unavailable. Make sure the NumCpp library is included." << std::endl; + } + return NC_VERSION; // Return the version string (either nc::VERSION or "Unavailable") +} + +/** + * Alias function for `get_numcpp_version`. + * This function provides an alternative name for retrieving the version. + * Useful for maintaining consistency in naming conventions across different parts of the code. + * + * @return const char* - The version string of NumCpp. + */ +const char* nc_version() { + return get_numcpp_version(); // Delegate to the original function `get_numcpp_version` +} + +#ifdef __cplusplus +} // End of `extern "C"` block +#endif + +#endif // NC_VERSION_CPP \ No newline at end of file diff --git a/lightnumpy/_core/src/np_test.c b/lightnumpy/_core/src/np_test.c new file mode 100644 index 0000000..f3aa049 --- /dev/null +++ b/lightnumpy/_core/src/np_test.c @@ -0,0 +1,50 @@ +// src/np_test.cpp +// C++ Source File for initializing Python and NumPy and running a simple test + +#pragma once // Ensures the file is included only once by the compiler + +#ifndef NP_TEST_CPP // Include guard to prevent multiple inclusions +#define NP_TEST_CPP + +// Standard C++ library headers +#include // For outputting to the console + +// Include necessary NumPy and Python headers +#include "numpy.h" // NumPy bindings +#include "python.h" // Python bindings + +// Python and NumPy initialization function +int np_test() { + try { + // Initialize the Python interpreter + Py_Initialize(); + + // Check if Python is initialized properly + if (!Py_IsInitialized()) { + throw std::runtime_error("Python initialization failed."); + } + + // Initialize the NumPy library (requires import_array from NumPy C-API) + import_array(); + + // Check if NumPy has been initialized properly + // This is a basic check, more advanced checks can be added if necessary + if (!PyArray_API) { + throw std::runtime_error("NumPy initialization failed."); + } + + // Output success message + std::cout << "NumPy Initialized Successfully." << std::endl; + + // Finalize the Python interpreter + Py_Finalize(); + } catch (const std::exception& e) { + // Print any errors that occur during initialization + std::cerr << "Error during NumPy initialization: " << e.what() << std::endl; + return -1; // Return a negative value to indicate failure + } + + return 0; // Return 0 to indicate success +} + +#endif // NP_TEST_CPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/.gitkeep b/lightnumpy/_core/tests/__init__.py similarity index 100% rename from lightnumpy/_cpp_core/src/.gitkeep rename to lightnumpy/_core/tests/__init__.py diff --git a/lightnumpy/_cpp_core/.clang-format b/lightnumpy/_cpp_core/.clang-format deleted file mode 100644 index 93cc3f1..0000000 --- a/lightnumpy/_cpp_core/.clang-format +++ /dev/null @@ -1,153 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: NumCpp -AccessModifierOffset: -4 -AlignAfterOpenBracket: Align -AlignArrayOfStructures: None -AlignConsecutiveMacros: true -AlignConsecutiveAssignments: true -AlignConsecutiveBitFields: None -AlignConsecutiveDeclarations: true -AlignEscapedNewlines: Left -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: false -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortEnumsOnASingleLine: true -AllowShortBlocksOnASingleLine: Empty -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: Empty -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: false -BinPackParameters: false -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: Always - AfterEnum: true - AfterFunction: true - AfterNamespace: false - AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - BeforeLambdaBody: false - BeforeWhile: true - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false - SplitEmptyNamespace: false -BreakBeforeBinaryOperators: None -BreakBeforeConceptDeclarations: true -BreakBeforeBraces: Allman -BreakBeforeInheritanceComma: false -BreakInheritanceList: AfterColon -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: AfterColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 120 -CommentPragmas: '^ NumCpp pragma:' -QualifierAlignment: Leave -CompactNamespaces: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: false -DeriveLineEnding: true -DerivePointerAlignment: true -DisableFormat: false -EmptyLineAfterAccessModifier: Never -EmptyLineBeforeAccessModifier: Always -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -PackConstructorInitializers: Never -IncludeBlocks: Regroup -IncludeCategories: - - Regex: '^"NumCpp/' - Priority: 4 - SortPriority: 0 - - Regex: '^"boost/' - Priority: 3 - SortPriority: 0 - - Regex: '^<' - Priority: 2 - SortPriority: 0 - - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '$' -IncludeIsMainSourceRegex: '' -IndentAccessModifiers: false -IndentCaseLabels: true -IndentCaseBlocks: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentExternBlock: AfterExternBlock -IndentRequires: true -IndentWidth: 4 -IndentWrappedFunctionNames: true -InsertTrailingCommas: None -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: false -LambdaBodyIndentation: Signature -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: All -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 4 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakOpenParenthesis: 0 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 60 -PenaltyIndentedWhitespace: 0 -PointerAlignment: Left -ReferenceAlignment: Pointer -ReflowComments: true -SeparateDefinitionBlocks: Always -SortIncludes: CaseSensitive -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCaseColon: false -SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceAroundPointerQualifiers: Default -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: true -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: Latest -TabWidth: 4 -Standard: c++17 -UseCRLF: false -UseTab: Never -... diff --git a/lightnumpy/_cpp_core/.clang-tidy b/lightnumpy/_cpp_core/.clang-tidy deleted file mode 100644 index 4ddc8e5..0000000 --- a/lightnumpy/_cpp_core/.clang-tidy +++ /dev/null @@ -1,37 +0,0 @@ -Checks: > - clang-analyzer-*, - # cppcoreguidelines-*, - # bugprone-*, - # -bugprone-easily-swappable-parameters, - google-readability-*, - modernize-*, - -modernize-use-trailing-return-type, - -# Turn all the warnings from the checks above into errors. -WarningsAsErrors: "*" - -CheckOptions: - - { key: readability-identifier-naming.NamespaceCase, value: lower_case } - - { key: readability-identifier-naming.ClassCase, value: CamelCase } - - { key: readability-identifier-naming.ClassMethodCase, value: camelBack } - - { key: readability-identifier-naming.StructCase, value: CamelCase } - - { - key: readability-identifier-naming.TemplateParameterCase, - value: CamelCase, - } - - { key: readability-identifier-naming.FunctionCase, value: camelBack } - - { key: readability-identifier-naming.VariableCase, value: camelBack } - - { key: readability-identifier-naming.PrivateMemberSuffix, value: _ } - - { key: readability-identifier-naming.ProtectedMemberSuffix, value: _ } - - { - key: readability-identifier-naming.MacroDefinitionCase, - value: UPPER_CASE, - } - - { key: readability-identifier-naming.EnumConstantCase, value: UPPER_CASE } - - { - key: readability-identifier-naming.ConstexprVariableCase, - value: UPPER_CASE, - } - - { key: readability-identifier-naming.GlobalConstantCase, value: UPPER_CASE } - - { key: readability-identifier-naming.MemberConstantCase, value: UPPER_CASE } - - { key: readability-identifier-naming.StaticConstantCase, value: UPPER_CASE } \ No newline at end of file diff --git a/lightnumpy/_cpp_core/include/config_cpp_core.hpp b/lightnumpy/_cpp_core/include/config_cpp_core.hpp deleted file mode 100644 index 0eae6b2..0000000 --- a/lightnumpy/_cpp_core/include/config_cpp_core.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// Configuration settings for C++ core -#define USE_CPP_CORE 1 diff --git a/lightnumpy/_cpp_core/include/hello.hpp b/lightnumpy/_cpp_core/include/hello.hpp deleted file mode 100644 index 7fe19fa..0000000 --- a/lightnumpy/_cpp_core/include/hello.hpp +++ /dev/null @@ -1,28 +0,0 @@ -// include/hello.hpp -// C++ Header File for printing a customizable message -#ifndef HELLO_HPP // Include guard to prevent multiple inclusions, If not defined -#define HELLO_HPP - -// Standard C++ library header -#include // For std::string -#include // For std::cout - -// Default greeting message definition -#ifndef CPP_MESSAGE // 1. Check if CPP_MESSAGE is not defined -#define CPP_MESSAGE "Hello, from C++!" // 2. If not, define it with the value "Hello, from C++!" -// This block will be ignored if CPP_MESSAGE is already defined. -#endif // CPP_MESSAGE // 3. End the condition - -// Provide a C-compatible function for external use -// extern "C" disables name mangling, making the function callable from C -// and other languages that expect C-style linkage. -// Without extern "C", name mangling is enabled, -// and the function is only directly usable from C++. -// C++ function declaration with a default message. -// Ensures compatibility with C, Python, or other languages expecting C-style linkage. -extern "C" void printcpp(const std::string& message = CPP_MESSAGE) { - // Output the message to the console - std::cout << message << std::endl; -} - -#endif // HELLO_HPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/include/numpy_cpp.hpp b/lightnumpy/_cpp_core/include/numpy_cpp.hpp deleted file mode 100644 index e8a6627..0000000 --- a/lightnumpy/_cpp_core/include/numpy_cpp.hpp +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -// https://pythonextensionpatterns.readthedocs.io/en/latest/cpp_and_numpy.html -// NumPy C API headers for C++ -#include diff --git a/lightnumpy/_cpp_core/include/python_cpp.hpp b/lightnumpy/_cpp_core/include/python_cpp.hpp deleted file mode 100644 index a7de914..0000000 --- a/lightnumpy/_cpp_core/include/python_cpp.hpp +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// Python C API header for C++ -#include diff --git a/lightnumpy/_cpp_core/include/std_lib_cpp.hpp b/lightnumpy/_cpp_core/include/std_lib_cpp.hpp deleted file mode 100644 index 7ac02ce..0000000 --- a/lightnumpy/_cpp_core/include/std_lib_cpp.hpp +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -// Standard C++ library headers -#include -#include -#include diff --git a/lightnumpy/_cpp_core/include/tensor.hpp b/lightnumpy/_cpp_core/include/tensor.hpp deleted file mode 100644 index f626097..0000000 --- a/lightnumpy/_cpp_core/include/tensor.hpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Declare C++ Tensor class and related operations. \ No newline at end of file diff --git a/lightnumpy/_cpp_core/include/utilities.hpp b/lightnumpy/_cpp_core/include/utilities.hpp deleted file mode 100644 index 33f61ae..0000000 --- a/lightnumpy/_cpp_core/include/utilities.hpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Declare helper functions for tensor operations. \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/array_ops.cpp b/lightnumpy/_cpp_core/src/array_ops.cpp deleted file mode 100644 index 54e9bc3..0000000 --- a/lightnumpy/_cpp_core/src/array_ops.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// #include -// #include - -// /* Adds two arrays element-wise using C++ vectors */ -// void add_arrays(const std::vector& a, const std::vector& b, std::vector& result) { -// size_t n = a.size(); -// result.resize(n); -// for (size_t i = 0; i < n; ++i) { -// result[i] = a[i] + b[i]; -// } -// } - -// /* Subtracts two arrays element-wise using C++ vectors */ -// void subtract_arrays(const std::vector& a, const std::vector& b, std::vector& result) { -// size_t n = a.size(); -// result.resize(n); -// for (size_t i = 0; i < n; ++i) { -// result[i] = a[i] - b[i]; -// } -// } \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/hello.cpp b/lightnumpy/_cpp_core/src/hello.cpp deleted file mode 100644 index 7033fe5..0000000 --- a/lightnumpy/_cpp_core/src/hello.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// src/hello.cpp -// C++ Source File for printing a customizable message -#ifndef HELLO_CPP // Include guard to prevent multiple inclusions, If not defined -#define HELLO_CPP - -// Standard C++ library header -#include // For std::string -#include // For std::cout - -// Default greeting message definition -#ifndef CPP_MESSAGE // 1. Check if CPP_MESSAGE is not defined -#define CPP_MESSAGE "Hello, from C++!" // 2. If not, define it with the value "Hello, from C++!" -// This block will be ignored if CPP_MESSAGE is already defined. -#endif // CPP_MESSAGE // 3. End the condition - -// Provide a C-compatible function for external use -// extern "C" disables name mangling, making the function callable from C -// and other languages that expect C-style linkage. -// Without extern "C", name mangling is enabled, -// and the function is only directly usable from C++. -// C++ function declaration with a default message. -// Ensures compatibility with C, Python, or other languages expecting C-style linkage. -extern "C" void printcpp(const std::string& message = CPP_MESSAGE) { - // Output the message to the console - std::cout << message << std::endl; -} - -#endif // HELLO_CPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/nc_version.cpp b/lightnumpy/_cpp_core/src/nc_version.cpp deleted file mode 100644 index 1a5308f..0000000 --- a/lightnumpy/_cpp_core/src/nc_version.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// src/nc_version.cpp -// C++ Source File for retrieving the NumCpp version information -#ifndef NC_VERSION_CPP // Include guard to prevent multiple inclusions, If not defined -#define NC_VERSION_CPP - -// Standard C++ library header -#include // For std::string -// #include - -#ifndef NUMCPP_NO_INCLUDE -// Include NumCpp if available -#include "Version.hpp" // NumCpp version header nc::VERSION - -// Ensure NUMCPP_VERSION is defined if not already specified -#ifndef NUMCPP_VERSION -#define NUMCPP_VERSION nc::VERSION -#endif // NUMCPP_VERSION - -#else // NUMCPP_NO_INCLUDE -// Fallback: Define NUMCPP_VERSION as "Unavailable" if NumCpp is not available -#ifndef NUMCPP_VERSION -#define NUMCPP_VERSION "Unavailable" -#endif // NUMCPP_VERSION -#endif // NUMCPP_NO_INCLUDE - -/** - * Get the version of NumCpp. - * Provides compatibility with other languages via extern "C". - * Ensures compatibility with C, Python, or other languages expecting C-style linkage. - * - * @return const char* - The version string of NumCpp. - */ -extern "C" const char* numcpp_version() { - // Print the version - // std::cout << nc::VERSION << std::endl; - - // Return the version string directly - // nc::VERSION is a const char[], safe to return directly - return NUMCPP_VERSION; -} - - -/** - * Alias function for numcpp_version. - * Useful for maintaining consistent naming conventions. - * - * @return const char* - The version string of NumCpp. - */ -extern "C" const char* nc_version() { - // Print the version - // std::cout << "Version: " << nc::VERSION << std::endl; - // std::cout << "Version: " << numcpp_version() << std::endl; - - // Delegate to the original function numcpp_version - return numcpp_version(); -} - -#endif // NC_VERSION_CPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/np_test.cpp b/lightnumpy/_cpp_core/src/np_test.cpp deleted file mode 100644 index d589ab5..0000000 --- a/lightnumpy/_cpp_core/src/np_test.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// #include "numpy_cpp.h" -// #include "python_cpp.h" -// #include "std_lib_cpp.h" - -// #include - -// int np_test() { -// Py_Initialize(); -// import_array(); -// std::cout << "NumPy Initialized." << std::endl; -// Py_Finalize(); -// return 0; -// } \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/py_math.cpp b/lightnumpy/_cpp_core/src/py_math.cpp deleted file mode 100644 index f69751a..0000000 --- a/lightnumpy/_cpp_core/src/py_math.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// src/py_math.cpp -// C++ Source File for Python bindings to perform mathematical operations -#ifndef PY_MATH_CPP // Include guard to prevent multiple inclusions, If not defined -#define PY_MATH_CPP - -// Standard C++ library header -#include // For runtime error handling - -// pybind11 library header -#include // For pybind11 support -#include // For handling NumPy arrays -namespace py = pybind11; - -// C++ Function to calculate the sum of squares of elements in a NumPy array -extern "C" double sum_of_squares(const py::array_t& input_array) { - // Obtain buffer information from the input NumPy array - py::buffer_info buf_info = input_array.request(); - double* data_ptr = static_cast(buf_info.ptr); // Pointer to the data - size_t array_size = buf_info.size; // Size of the array - - // Handle the case of an empty input array - if (array_size == 0) { - throw std::runtime_error("Input array is empty. Cannot compute sum of squares."); - } - - // Compute the sum of squares - double sum = 0.0; - for (size_t i = 0; i < array_size; ++i) { - sum += data_ptr[i] * data_ptr[i]; // Square each element and add to the sum - } - - return sum; // Return the computed sum -} - -#endif // PY_MATH_CPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/py_nc_random.cpp b/lightnumpy/_cpp_core/src/py_nc_random.cpp deleted file mode 100644 index fa5e461..0000000 --- a/lightnumpy/_cpp_core/src/py_nc_random.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// src/py_nc_random.cpp -// C++ Source File for generating random NumPy arrays using pybind11 and optionally NumCpp - -#ifndef PY_NC_RANDOM_CPP // Include guard to prevent multiple inclusions -#define PY_NC_RANDOM_CPP - -// Standard C++ library header -#include // For runtime error handling -#include // Part of the C++ Standard Template Library (STL) - -// pybind11 library header -#include // For pybind11 functionality -#include // For handling NumPy arrays -namespace py = pybind11; - -#ifndef NUMCPP_NO_INCLUDE -#include // Include NumCpp if available -#endif - -/** - * Generate a random NumPy array. - * If NumCpp is available, it uses NumCpp to generate the array. - * Otherwise, it falls back to a pybind11-based implementation. - * - * @param rows Number of rows in the array. - * @param cols Number of columns in the array. - * @return py::array_t A 2D NumPy array filled with random values. - */ -extern "C" py::array_t random_array(int rows, int cols) { - // Validate input dimensions - if (rows <= 0 || cols <= 0) { - throw std::invalid_argument("Rows and columns must be positive integers."); - } - -#ifdef NUMCPP_NO_INCLUDE - // Use NumCpp to generate a random array - auto array = nc::random::rand( - {static_cast(rows), static_cast(cols)} - ); - - // Prepare the buffer information for the NumPy array - py::buffer_info buf_info( - array.data(), // Pointer to data - sizeof(double), // Size of one element - py::format_descriptor::format(), // NumPy-compatible format - 2, // Number of dimensions - {static_cast(rows), static_cast(cols)}, // Shape - {static_cast(cols) * sizeof(double), sizeof(double)} // Strides - ); - - // Return the NumPy array - return py::array_t(buf_info); - -#else // NUMCPP_NO_INCLUDE - // Fallback implementation: generate random numbers using pybind11 - std::vector data(rows * cols); - for (auto& value : data) { - value = static_cast(rand()) / RAND_MAX; // Generate random double [0, 1) - } - - // Prepare the buffer information for the NumPy array - py::buffer_info buf_info( - data.data(), // Pointer to data - sizeof(double), // Size of one element - py::format_descriptor::format(), // NumPy-compatible format - 2, // Number of dimensions - {static_cast(rows), static_cast(cols)}, // Shape - {static_cast(cols) * sizeof(double), sizeof(double)} // Strides - ); - - // Return the NumPy array - return py::array_t(buf_info); -#endif // NUMCPP_NO_INCLUDE -} - -#endif // PY_NC_RANDOM_CPP \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/tensor.cpp b/lightnumpy/_cpp_core/src/tensor.cpp deleted file mode 100644 index a841201..0000000 --- a/lightnumpy/_cpp_core/src/tensor.cpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Implement C++ methods for Tensor class operations. \ No newline at end of file diff --git a/lightnumpy/_cpp_core/src/utilities.cpp b/lightnumpy/_cpp_core/src/utilities.cpp deleted file mode 100644 index deef85f..0000000 --- a/lightnumpy/_cpp_core/src/utilities.cpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Implement utility functions for tensor manipulations. \ No newline at end of file diff --git a/lightnumpy/_gpu_core/__init__.py b/lightnumpy/_gpu_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/_gpu_core/tests/__init__.py b/lightnumpy/_gpu_core/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/_tpu_core/__init__.py b/lightnumpy/_tpu_core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/_tpu_core/tests/__init__.py b/lightnumpy/_tpu_core/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/cy_bindings/__init__.py b/lightnumpy/cy_bindings/__init__.py index ee1356e..d65ddf8 100644 --- a/lightnumpy/cy_bindings/__init__.py +++ b/lightnumpy/cy_bindings/__init__.py @@ -5,9 +5,4 @@ from . import ( cy_numcpp_api, -) - -# NumCpp Call the function to get the version -# __version__ = cy_numcpp_api.nc_version() -# __author__ = "David Pilger et al." -# __author_email__ = "dpilger26@gmail.com" \ No newline at end of file +) \ No newline at end of file diff --git a/lightnumpy/cy_bindings/cy_numcpp_api.pxd b/lightnumpy/cy_bindings/cy_numcpp_api.pxd index 7502f5f..9ee1007 100644 --- a/lightnumpy/cy_bindings/cy_numcpp_api.pxd +++ b/lightnumpy/cy_bindings/cy_numcpp_api.pxd @@ -13,10 +13,18 @@ from libcpp.string cimport string # Import reusable code from the .pxi file, If Needed avoid duplicates # include "cy_numcpp_api.pxi" -# Declare a function from NumCpp header -cdef extern from "nc_version.cpp": - string numcpp_version() # Declaration of the get_version function +###################################################################### +## Standard headers implemented functions +###################################################################### # Declare external C++ functions -cdef extern from "hello.cpp": - void printcpp(const char* message) # Declaration of the print function \ No newline at end of file +cdef extern from "hello.c": + void cpp_char_to_print(const char* message) # Declaration of the print function + +###################################################################### +## NumCpp Header implemented functions by LNPY_USE_NUMCPP +###################################################################### + +# Declare a function from NumCpp header +cdef extern from "nc_version.cpp": + string get_numcpp_version() # Declaration of the get_version function \ No newline at end of file diff --git a/lightnumpy/cy_bindings/cy_numcpp_api.pxi b/lightnumpy/cy_bindings/cy_numcpp_api.pxi index ad83a7d..06c23dc 100644 --- a/lightnumpy/cy_bindings/cy_numcpp_api.pxi +++ b/lightnumpy/cy_bindings/cy_numcpp_api.pxi @@ -16,10 +16,14 @@ # Import the necessary C++ standard library components from libcpp.string cimport string +###################################################################### +## Standard headers implemented functions +###################################################################### + # We use inline to reduce function call overhead # and improve performance by embedding the function directly at the call site. # Declare the inline function with the correct C++ string handling -cdef inline void say_hello_inline(const char* message = b"Hello, from Cython .pxi file!"): +cdef inline void cy_char_to_print(const char* message = b"Hello, from Cython .pxi file!"): # Convert the char* to a C++ string cdef string cpp_message = string(message) diff --git a/lightnumpy/cy_bindings/cy_numcpp_api.pyi b/lightnumpy/cy_bindings/cy_numcpp_api.pyi index d6d4439..979128a 100644 --- a/lightnumpy/cy_bindings/cy_numcpp_api.pyi +++ b/lightnumpy/cy_bindings/cy_numcpp_api.pyi @@ -8,8 +8,4 @@ # or IDEs to understand the types and signatures of the functions # and classes in the corresponding .pyx files. -# cdef void printcpp(const std::string& message = "Hello, from C++!") # Stub for print_message function -# cdef double sum_of_squares(const double* arr, long size) # Stub for sum_of_squares function - -# def py_sum_of_squares(arr: np.ndarray) -> float: # Stub for Python-exposed function -# pass # Implementation not included in .pyi +# cdef inline void cy_char_to_print(const char* message = b"Hello, from Cython .pxi file!") # Stub for print function diff --git a/lightnumpy/cy_bindings/cy_numcpp_api.pyx b/lightnumpy/cy_bindings/cy_numcpp_api.pyx index 0e71e6e..0f1086f 100644 --- a/lightnumpy/cy_bindings/cy_numcpp_api.pyx +++ b/lightnumpy/cy_bindings/cy_numcpp_api.pyx @@ -11,51 +11,39 @@ Created by Cython. # that is still very readable and can easily interface with Python. When compiled, # .pyx files yield C/C++ extensions that can be imported and used in Python. +###################################################################### +## Numpy implemented functions +###################################################################### + import numpy as np # Import Cython's NumPy support cimport numpy as cnp # Cython's NumPy support # Ensure NumPy is properly initialized for Cython cnp.import_array() +###################################################################### +## Import implemented functions +###################################################################### + from .cy_numcpp_api cimport * # Import declarations from .pxd -include "cy_numcpp_api.pxi" # Include the .pxi file, If Needed avoid duplicates +include "cy_numcpp_api.pxi" # Include the .pxi file, If Needed avoid duplicates ## Define __all__ to specify the public interface of the module, # not required default all above func __all__ = [ - 'nc_version', 'py_print', - 'py_say_hello_inline', + 'py_byte_print', + 'nc_version', 'py_random_array', 'py_sum_of_squares', ] - # Expose the C++ print_message function to Python -def nc_version(): - """ - Get the NumCpp header library version. - - Returns - ------- - str - NumCpp header library version. - - Examples - -------- - .. jupyter-execute:: - - >>> from lightnumpy.cy_bindings import cy_numcpp_api as lp - >>> lp.nc_version() - """ - # Call the C++ function and return the version (utf-8 decoded bytes) - return numcpp_version().decode('utf-8') - - -# Expose the C++ print_message function to Python -def py_print(message="Hello, from Cython C++!"): - """ +def py_print( + message="Hello, from Cython C++!", +) -> None: + """\ Prints a Unicode message. Parameters @@ -75,12 +63,13 @@ def py_print(message="Hello, from Cython C++!"): >>> from lightnumpy.cy_bindings import cy_numcpp_api as lp >>> lp.py_print() """ - printcpp(message.encode('utf-8')) # Call the C++ function with the message - + cpp_char_to_print(message.encode('utf-8')) # Call the C++ function with the message # Expose the C++ inline function to Python -def py_say_hello_inline(message="Hello, from Cython .pxi file!"): - """ +def py_byte_print( + message="Hello, from Cython .pxi file!", +) -> None: + """\ Prints a unicode message as byte. Parameters @@ -98,24 +87,43 @@ def py_say_hello_inline(message="Hello, from Cython .pxi file!"): .. jupyter-execute:: >>> from lightnumpy.cy_bindings import cy_numcpp_api as lp - >>> lp.py_say_hello_inline() + >>> lp.py_byte_print() """ # Call the C++ inline function, ensuring the Python string is converted to char* (utf-8 encoded bytes) - say_hello_inline(message.encode('utf-8'))#.decode('utf-8') + cy_char_to_print(message.encode('utf-8')) #.decode('utf-8') +# Overriding cdef method with def method. +def nc_version() -> str: + """\ + Get the NumCpp header library version. + + Returns + ------- + str + NumCpp header library version. + + Examples + -------- + .. jupyter-execute:: + + >>> from lightnumpy.cy_bindings import cy_numcpp_api as lp + >>> lp.nc_version() + """ + # Call the C++ function and return the version (utf-8 decoded bytes) + return get_numcpp_version().decode('utf-8') # Cython function interfacing with C++ # Python-exposed function to calculate the sum of squares of a NumPy array def py_sum_of_squares( - cnp.ndarray arr, - axis=None, - dtype=None, - out=None, - keepdims=np._NoValue, - initial=np._NoValue, - where=np._NoValue -): - """ + cnp.ndarray arr, + axis=None, + dtype=None, + out=None, + keepdims=np._NoValue, + initial=np._NoValue, + where=np._NoValue +) -> float: + """\ Calculate the sum of squares of a NumPy array along a specified axis. Parameters @@ -169,10 +177,11 @@ def py_sum_of_squares( # Calculate and return the sum of squares along the specified axis return np.sum(arr ** 2, axis=axis, dtype=dtype, out=out, keepdims=keepdims, initial=initial, where=where) - # Python-exposed function to get random_array of a NumPy array -def py_random_array(*shape): - """ +def py_random_array( + *shape, +) -> np.ndarray[np.float64]: + """\ Generate a random NumPy array of the given shape with random values in the range [0, 1). Parameters diff --git a/lightnumpy/cy_bindings/meson.build b/lightnumpy/cy_bindings/meson.build index ffb4f9d..721d6dd 100644 --- a/lightnumpy/cy_bindings/meson.build +++ b/lightnumpy/cy_bindings/meson.build @@ -17,7 +17,7 @@ cy_bindings_cython_tree = [ ###################################################################### # Define dependencies with NumCpp -dep_list = [dep_py, dep_pybind11, dep_np, dep_cpp_core] +dep_list = [dep_py, dep_pybind11, dep_np, dep_core] ###################################################################### ## extension metadata @@ -32,7 +32,7 @@ cy_bindings_extension_metadata = { 'cy_numcpp_api.pyx' ], 'include_directories': [ # Include dirs for compilation - inc_dir_cpp_core, + inc_dir_core, ], 'dependencies': dep_list, # External libraries and dependencies 'link_with': [], # Link with the created static library @@ -48,6 +48,7 @@ cy_bindings_extension_metadata = { }, } +# https://mesonbuild.com/Syntax.html#foreach-with-a-dictionary # Loop over each defined extension and create the corresponding module foreach ext_name, ext_dict : cy_bindings_extension_metadata pyext_module = py.extension_module( diff --git a/lightnumpy/cy_bindings/src/array_cy.pyx b/lightnumpy/cy_bindings/src/array_cy.pyx deleted file mode 100644 index 2a0c889..0000000 --- a/lightnumpy/cy_bindings/src/array_cy.pyx +++ /dev/null @@ -1,7 +0,0 @@ -# Template: Implement array-related operations in Cython. - -# Example Cython code using external C++ function -cimport cython_helpers - -def print_message(message: str): - cython_helpers.printcpp(message.encode('utf-8')) \ No newline at end of file diff --git a/lightnumpy/cy_bindings/src/cython_helpers.pxd b/lightnumpy/cy_bindings/src/cython_helpers.pxd deleted file mode 100644 index ce41897..0000000 --- a/lightnumpy/cy_bindings/src/cython_helpers.pxd +++ /dev/null @@ -1,5 +0,0 @@ -# Template: Declare Cython-exposed C/C++ functions for use in .pyx files. - -# Declare external C++ functions -cdef extern from "hello.cpp": - void printcpp(const char* message) diff --git a/lightnumpy/cy_bindings/src/gpu_cy.pyx b/lightnumpy/cy_bindings/src/gpu_cy.pyx deleted file mode 100644 index 2f32c11..0000000 --- a/lightnumpy/cy_bindings/src/gpu_cy.pyx +++ /dev/null @@ -1 +0,0 @@ -# Template: Implement GPU-specific operations in Cython. \ No newline at end of file diff --git a/lightnumpy/cy_bindings/src/linalg_cy.pyx b/lightnumpy/cy_bindings/src/linalg_cy.pyx deleted file mode 100644 index efdf3df..0000000 --- a/lightnumpy/cy_bindings/src/linalg_cy.pyx +++ /dev/null @@ -1 +0,0 @@ -# Template: Implement linear algebra functions in Cython. \ No newline at end of file diff --git a/lightnumpy/cy_bindings/src/tpu_cy.pyx b/lightnumpy/cy_bindings/src/tpu_cy.pyx deleted file mode 100644 index 766e235..0000000 --- a/lightnumpy/cy_bindings/src/tpu_cy.pyx +++ /dev/null @@ -1 +0,0 @@ -# Template: Implement TPU-specific operations in Cython. \ No newline at end of file diff --git a/lightnumpy/cy_bindings/src/utils_cy.pyx b/lightnumpy/cy_bindings/src/utils_cy.pyx deleted file mode 100644 index 2f0680f..0000000 --- a/lightnumpy/cy_bindings/src/utils_cy.pyx +++ /dev/null @@ -1 +0,0 @@ -# Template: Implement utility functions in Cython. \ No newline at end of file diff --git a/lightnumpy/cy_bindings/tests/__init__.py b/lightnumpy/cy_bindings/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/meson.build b/lightnumpy/meson.build index ccc38ae..c4f28a6 100644 --- a/lightnumpy/meson.build +++ b/lightnumpy/meson.build @@ -190,10 +190,7 @@ _cython_tree = [ # belows can be needs to be to be before ... since ... cimport *.pxd # Subdirectories for different cores -# subdir('_c_core') -subdir('_cpp_core') -# subdir('_gpu_core') -# subdir('_tpu_core') +subdir('_core') # Subdirectories for python module subdir('cy_bindings') diff --git a/lightnumpy/py_bindings/__init__.py b/lightnumpy/py_bindings/__init__.py index a1a1df6..7b20650 100644 --- a/lightnumpy/py_bindings/__init__.py +++ b/lightnumpy/py_bindings/__init__.py @@ -3,9 +3,4 @@ from . import ( py_numcpp_api, -) - -# NumCpp Call the function to get the version -# __version__ = py_numcpp_api.nc_version() -# __author__ = "David Pilger et al." -# __author_email__ = "dpilger26@gmail.com" \ No newline at end of file +) \ No newline at end of file diff --git a/lightnumpy/py_bindings/meson.build b/lightnumpy/py_bindings/meson.build index e1691ef..f238e76 100644 --- a/lightnumpy/py_bindings/meson.build +++ b/lightnumpy/py_bindings/meson.build @@ -35,7 +35,7 @@ inc_dir_py_bindings = include_directories( message( '\npy_bindings module compatibility files defined successfully: ' + '@0@ '.format('lightnumpy/py_bindings/include') + - 'with NumCpp: @0@'.format(get_option('numcpp').enabled()) + 'with NumCpp: @0@'.format(get_option('lnpy_use_numcpp').enabled()) ) ###################################################################### @@ -43,7 +43,7 @@ message( ###################################################################### # Define dependencies with NumCpp -dep_list = [dep_py, dep_pybind11, dep_np, dep_cpp_core] +dep_list = [dep_py, dep_pybind11, dep_np, dep_core] ###################################################################### ## extension metadata @@ -58,7 +58,7 @@ py_bindings_extension_metadata = { 'src/py_numcpp_api.cpp', ], 'include_directories': [ # Include dirs for compilation - inc_dir_cpp_core, inc_dir_py_bindings + inc_dir_py_bindings, inc_dir_core ], 'dependencies': dep_list, # External libraries and dependencies 'link_with': [], # Link with the created static library @@ -73,7 +73,7 @@ py_bindings_extension_metadata = { }, } - +# https://mesonbuild.com/Syntax.html#foreach-with-a-dictionary # Loop over each defined extension and create the corresponding module foreach ext_name, ext_dict : py_bindings_extension_metadata pyext_module = py.extension_module( diff --git a/lightnumpy/py_bindings/src/c_bindings.c b/lightnumpy/py_bindings/src/c_bindings.c deleted file mode 100644 index 98273b3..0000000 --- a/lightnumpy/py_bindings/src/c_bindings.c +++ /dev/null @@ -1 +0,0 @@ -// Template: Provide C bindings to the library using Python.h. \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/cpp_bindings.cpp b/lightnumpy/py_bindings/src/cpp_bindings.cpp deleted file mode 100644 index 4f4d359..0000000 --- a/lightnumpy/py_bindings/src/cpp_bindings.cpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Provide C++ bindings to the library using pybind11. \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/gpu_bindings.cu b/lightnumpy/py_bindings/src/gpu_bindings.cu deleted file mode 100644 index 8e6e852..0000000 --- a/lightnumpy/py_bindings/src/gpu_bindings.cu +++ /dev/null @@ -1 +0,0 @@ -// Template: Provide GPU bindings using CUDA and pybind11. \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/py_math.cpp b/lightnumpy/py_bindings/src/py_math.cpp new file mode 100644 index 0000000..a8776fc --- /dev/null +++ b/lightnumpy/py_bindings/src/py_math.cpp @@ -0,0 +1,64 @@ +// src/py_math.cpp +// C++ Source File for Python bindings to perform mathematical operations + +#ifndef PY_MATH_CPP // Include guard to prevent multiple inclusions +#define PY_MATH_CPP + +// Standard C++ library headers +#include // For runtime error handling + +////////////////////////////////////////////////////////////////////// +// pybind11 Header implemented functions +////////////////////////////////////////////////////////////////////// + +// pybind11 library headers +#include // For pybind11 support +#include // For handling NumPy arrays + +namespace py = pybind11; + +#ifdef __cplusplus +// Ensures compatibility with C, Python, or other languages expecting C-style linkage. +extern "C" { +#endif + +/** + * @brief Computes the sum of squares of elements in a NumPy array. + * + * This function calculates the sum of squares of the elements in the provided + * NumPy array (input_array). It handles cases where the array is empty and + * throws an exception with a detailed message if an error occurs. + * + * @param input_array The NumPy array (array_t) containing the elements. + * @return double The sum of squares of the elements in the input array. + * @throws std::invalid_argument if the input array is empty. + */ +double sum_of_squares(const py::array_t& input_array) { + try { + // Obtain buffer information from the input NumPy array + py::buffer_info buf_info = input_array.request(); + double* data_ptr = static_cast(buf_info.ptr); // Pointer to the data + size_t array_size = buf_info.size; // Size of the array + + // Handle the case of an empty input array + if (array_size == 0) { + throw std::invalid_argument("Input array is empty. Cannot compute sum of squares."); + } + + // Compute the sum of squares + double sum = 0.0; + for (size_t i = 0; i < array_size; ++i) { + sum += data_ptr[i] * data_ptr[i]; // Square each element and add to the sum + } + + return sum; // Return the computed sum + } catch (const std::exception& e) { + throw std::runtime_error("Error in sum_of_squares: " + std::string(e.what())); + } +} + +#ifdef __cplusplus +} // End of `extern "C"` block +#endif + +#endif // PY_MATH_CPP \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/py_nc_random.cpp b/lightnumpy/py_bindings/src/py_nc_random.cpp new file mode 100644 index 0000000..13a7724 --- /dev/null +++ b/lightnumpy/py_bindings/src/py_nc_random.cpp @@ -0,0 +1,138 @@ +// src/py_nc_random.cpp +// C++ Source File for generating random NumPy arrays using pybind11 and optionally NumCpp + +#ifndef PY_NC_RANDOM_CPP // Include guard to prevent multiple inclusions +#define PY_NC_RANDOM_CPP + +// Standard C++ library headers +#include // For runtime error handling +#include // For STL vector + +////////////////////////////////////////////////////////////////////// +// pybind11 Header implemented functions by LNPY_USE_NUMCPP +////////////////////////////////////////////////////////////////////// + +// pybind11 library headers +#include // For pybind11 functionality +#include // For handling NumPy arrays +namespace py = pybind11; + +////////////////////////////////////////////////////////////////////// +// NumCpp Header implemented functions by LNPY_USE_NUMCPP +////////////////////////////////////////////////////////////////////// + +#ifdef LNPY_USE_NUMCPP +#include // Include NumCpp if available +#endif + +#ifdef __cplusplus +// Ensures compatibility with C, Python, or other languages expecting C-style linkage. +extern "C" { +#endif + +#ifdef LNPY_USE_NUMCPP +/** + * @brief Helper function to generate random array using NumCpp. + * + * @param rows Number of rows in the array. + * @param cols Number of columns in the array. + * @return py::array_t A 2D NumPy array filled with random values. + * @throws std::runtime_error if NumCpp generation fails. + */ +py::array_t generate_random_array_with_numcpp(int rows, int cols) { + try { + // Use NumCpp to generate a random array + auto array = nc::random::rand({static_cast(rows), static_cast(cols)}); + + // Prepare the buffer information for the NumPy array + py::buffer_info buf_info( + array.data(), // Pointer to data + sizeof(double), // Size of one element + py::format_descriptor::format(), // NumPy-compatible format + 2, // Number of dimensions + {static_cast(rows), static_cast(cols)}, // Shape + {static_cast(cols) * sizeof(double), sizeof(double)} // Strides + ); + + // Return the NumPy array + return py::array_t(buf_info); + } catch (const std::exception& e) { + throw std::runtime_error("Error in NumCpp array generation: " + std::string(e.what())); + } +} +#endif + +/** + * @brief Helper function to generate random array using pybind11 (fallback). + * + * @param rows Number of rows in the array. + * @param cols Number of columns in the array. + * @return py::array_t A 2D NumPy array filled with random values. + * @throws std::runtime_error if pybind11 generation fails. + */ +py::array_t generate_random_array_with_pybind11(int rows, int cols) { + try { + // Fallback: generate random numbers using pybind11 and C++ standard library + std::vector array(rows * cols); + for (auto& value : array) { + value = static_cast(rand()) / RAND_MAX; // Generate random double [0, 1) + } + + // Prepare the buffer information for the NumPy array + py::buffer_info buf_info( + array.data(), // Pointer to data + sizeof(double), // Size of one element + py::format_descriptor::format(), // NumPy-compatible format + 2, // Number of dimensions + {static_cast(rows), static_cast(cols)}, // Shape + {static_cast(cols) * sizeof(double), sizeof(double)} // Strides + ); + + // Return the NumPy array + return py::array_t(buf_info); + } catch (const std::exception& e) { + throw std::runtime_error("Error in pybind11 random array generation: " + std::string(e.what())); + } +} + +/** + * @brief Generate a random NumPy array. + * + * This function generates a 2D NumPy array with random values. It first checks if + * NumCpp is available. If it is, it uses NumCpp to generate the array. Otherwise, + * it falls back to a pybind11-based implementation that uses the C++ Standard Library. + * + * @param rows Number of rows in the array (must be positive). + * @param cols Number of columns in the array (must be positive). + * @return py::array_t A 2D NumPy array filled with random values. + * @throws std::invalid_argument if rows or columns are non-positive. + * @throws std::runtime_error if NumCpp is unavailable and pybind11-based fallback fails. + */ +py::array_t random_array(int rows, int cols) { + // Validate input dimensions + if (rows <= 0 || cols <= 0) { + throw std::invalid_argument("Rows and columns must be positive integers."); + } + // Check if NumCpp is available and use it if possible + #ifdef LNPY_USE_NUMCPP + // NumCpp is available, use it to generate the random array + try { + return generate_random_array_with_numcpp(rows, cols); + } catch (const std::exception& e) { + throw std::runtime_error("NumCpp random array generation failed: " + std::string(e.what())); + } + #else + // Fallback implementation: generate random numbers using pybind11 + try { + return generate_random_array_with_pybind11(rows, cols); + } catch (const std::exception& e) { + throw std::runtime_error("Fallback pybind11 random array generation failed: " + std::string(e.what())); + } + #endif +} + +#ifdef __cplusplus +} // End of extern "C" block +#endif + +#endif // PY_NC_RANDOM_CPP \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/py_numcpp_api.cpp b/lightnumpy/py_bindings/src/py_numcpp_api.cpp index fe358ac..a0ab8f5 100644 --- a/lightnumpy/py_bindings/src/py_numcpp_api.cpp +++ b/lightnumpy/py_bindings/src/py_numcpp_api.cpp @@ -5,25 +5,34 @@ // You write your binding code directly in C++ using the Pybind11 API // to expose C++ functions and classes to Python. +// Standard C++ library headers +#include "hello.c" // Include header or function prototypes if needed + +////////////////////////////////////////////////////////////////////// +// pybind11 Header implemented functions +////////////////////////////////////////////////////////////////////// + #include -#include // For numpy array bindings -#include // For STL bindings +#include // For numpy array bindings +#include // For STL bindings namespace py = pybind11; -#include "hello.cpp" // Include header or function prototypes if needed -#include "nc_version.cpp" // Include for version -#include "py_math.cpp" // Include header or function prototypes if needed +#include "py_math.cpp" // Include header or function prototypes if needed -#ifndef NUMCPP_NO_INCLUDE -#include "py_nc_random.cpp" // Include header or function prototypes if needed +////////////////////////////////////////////////////////////////////// +// NumCpp Header implemented functions by LNPY_USE_NUMCPP +////////////////////////////////////////////////////////////////////// -void numcpp_function(pybind11::module_ &m) { - // Add bindings here - // AdD More numcpp feature - // Define module functions using a Function Pointer and a docstring - m.def("py_random_array", +#include "nc_version.cpp" // Include for version +#include "py_nc_random.cpp" // Include header or function prototypes if needed + +void numcpp_function(pybind11::module_ &m) { +// Add bindings here +// Add More NumCpp feature +// Define module functions using a Function Pointer and a docstring +m.def("py_random_array", &random_array, - R"(\ + R"( Create a random NumCpp array. Parameters @@ -50,26 +59,29 @@ Examples )" ); } -#endif // NUMCPP_NO_INCLUDE +////////////////////////////////////////////////////////////////////// +// PYBIND11_MODULE "py_numcpp_api" +////////////////////////////////////////////////////////////////////// // Expose the functions to Python Module using Pybind11 // In practice, implementation and binding code will generally be located in separate files. // https://pybind11.readthedocs.io/en/stable/reference.html#c.PYBIND11_MODULE PYBIND11_MODULE(py_numcpp_api, m) { - m.doc() = - R"(\ +m.doc() = + R"( NumCpp API Python module that uses Pybind11 C/C++ for numerical computations. Created by Pybind11. )"; - // optional module docstring - // Add bindings here - // Define module functions using a Lambda Function and a docstring - m.def("py_print", - [](std::string message = - "Hello, from Pybind11 C++!") { printcpp(message); }, - py::arg("message") = "Hello, from Pybind11 C++!", - R"(\ + +// optional module docstring +// Add bindings here +// Define module functions using a Lambda Function and a docstring +m.def("py_print", + [](std::string message = + "Hello, from Pybind11 C++!") { cpp_str_to_print(message); }, + py::arg("message") = "Hello, from Pybind11 C++!", + R"(\ Prints a Unicode message. Parameters @@ -91,13 +103,13 @@ Examples )" ); - // Expose the VERSION constant to Python as a function that returns it - // Return the version string defined in Version.hpp - m.def("nc_version", []() { +// Expose the VERSION constant to Python as a function that returns it +// Return the version string defined in Version.hpp +m.def("nc_version", []() { // Example: Return a NumPy-like array or another complex object - return numcpp_version(); + return nc_version(); }, - R"(\ + R"( Get the NumCpp header library version. Returns @@ -114,10 +126,10 @@ Examples )" ); - // Define module functions using a Function Pointer and a docstring - m.def("py_sum_of_squares", - &sum_of_squares, - R"(\ +// Define module functions using a Function Pointer and a docstring +m.def("py_sum_of_squares", + &sum_of_squares, + R"( Calculate the sum of squares. Parameters @@ -140,8 +152,6 @@ Examples )" ); - // Conditionally add function or feature based on NUMCPP_NO_INCLUDE -#ifndef NUMCPP_NO_INCLUDE - numcpp_function(m); // This will add the function when numcpp is enabled -#endif +// Conditionally add function or feature based on LNPY_USE_NUMCPP +numcpp_function(m); // This will add the function when numcpp is enabled } \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/pybind_module.cpp b/lightnumpy/py_bindings/src/pybind_module.cpp deleted file mode 100644 index e4f2cd7..0000000 --- a/lightnumpy/py_bindings/src/pybind_module.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// #include -// #include // For numpy array bindings -// #include // For STL bindings -// namespace py = pybind11; - -// PYBIND11_MODULE(lightnumpy, m) { -// m.def("nc_version", &nc_version, "Get NumCpp version"); -// m.def("hello", &print, "Print a hello message"); -// } diff --git a/lightnumpy/py_bindings/src/pybind_utils.cpp b/lightnumpy/py_bindings/src/pybind_utils.cpp deleted file mode 100644 index 428c38a..0000000 --- a/lightnumpy/py_bindings/src/pybind_utils.cpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Define helper functions for Pybind11-based bindings. \ No newline at end of file diff --git a/lightnumpy/py_bindings/src/tpu_bindings.cpp b/lightnumpy/py_bindings/src/tpu_bindings.cpp deleted file mode 100644 index 1172ba6..0000000 --- a/lightnumpy/py_bindings/src/tpu_bindings.cpp +++ /dev/null @@ -1 +0,0 @@ -// Template: Provide TPU bindings using C++ and XLA. \ No newline at end of file diff --git a/lightnumpy/py_bindings/tests/__init__.py b/lightnumpy/py_bindings/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lightnumpy/python_api/_utils_impl.py b/lightnumpy/python_api/_utils_impl.py index 44ac57c..6ee60ca 100644 --- a/lightnumpy/python_api/_utils_impl.py +++ b/lightnumpy/python_api/_utils_impl.py @@ -1,56 +1,13 @@ import os from typing import List, Tuple - -# @set_module('lightnumpy') -def get_c_include() -> str: - """ - Return the directory containing the C headers for the lightnumpy library. - - This function is intended for extension modules that need to compile - against lightnumpy's C API. - - Notes - ----- - When using ``setuptools``, for example in ``setup.py``:: - - import lightnumpy as ln - ... - Extension('extension_name', ... - include_dirs=[ln.get_c_include()]) - ... - - Returns - ------- - str - Path to the directory containing C header files. - - Examples - -------- - >>> import lightnumpy as ln - >>> ln.get_c_include() - '/path/to/lightnumpy/_c_core/include' # may vary - """ - import lightnumpy - if lightnumpy.show_config is None: - # running from lightnumpy source directory - d = os.path.join(os.path.dirname(lightnumpy.__file__), "_c_core", "include") - else: - # using installed lightnumpy core headers - import lightnumpy._c_core as _core - d = os.path.join(os.path.dirname(_core.__file__), 'include') - - if not os.path.isdir(d): - raise FileNotFoundError(f"LightNumpy C headers directory not found: {d}") - return d - # @set_module('lightnumpy') -def get_cpp_include() -> str: +def get_include() -> str: """ - Return the directory containing the C++ headers for the lightnumpy library. + Return the directory containing the C and C++ headers for the lightnumpy library. This function is intended for extension modules that need to compile - against lightnumpy's C++ API. + against lightnumpy's C and C++ API. Notes ----- @@ -59,60 +16,30 @@ def get_cpp_include() -> str: import lightnumpy as ln ... Extension('extension_name', ... - include_dirs=[ln.get_cpp_include()]) + include_dirs=ln.[get_include()]) ... Returns ------- str - Path to the directory containing C++ header files. + Path to the directory containing C and C++ header files. Examples -------- >>> import lightnumpy as ln - >>> ln.get_cpp_include() - '/path/to/lightnumpy/_cpp_core/include' # may vary + >>> ln.get_include() + '/path/to/lightnumpy/_core/include' # may vary """ import lightnumpy if lightnumpy.show_config is None: # running from lightnumpy source directory - d = os.path.join(os.path.dirname(lightnumpy.__file__), "_cpp_core", "include") + d = os.path.join(os.path.dirname(lightnumpy.__file__), "_core", "include") else: # using installed lightnumpy core headers - import lightnumpy._cpp_core as _core - d = os.path.join(os.path.dirname(_core.__file__), 'include') + import lightnumpy._core as core + # dirname = core.__path__ + d = os.path.join(os.path.dirname(core.__file__), 'include') if not os.path.isdir(d): - raise FileNotFoundError(f"LightNumpy C++ headers directory not found: {d}") - return d - -# @set_module('lightnumpy') -def get_include() -> Tuple[str]: - """ - Return a tuple of directories containing the C and C++ headers for the lightnumpy library. - - Extension modules that need to compile against lightnumpy may use this - function to locate the appropriate include directories. - - Notes - ----- - When using ``setuptools``, for example in ``setup.py``:: - - import lightnumpy as ln - ... - Extension('extension_name', ... - include_dirs=ln.get_include()) - ... - - Returns - ------- - tuple of str - Paths to the C and C++ headers. - - Examples - -------- - >>> import lightnumpy as ln - >>> ln.get_include() - ('/path/to/lightnumpy/_c_core/include', '/path/to/lightnumpy/_cpp_core/include') # may vary - """ - return get_c_include(), get_cpp_include() \ No newline at end of file + raise FileNotFoundError(f"LightNumpy C and C++ headers directory not found: {d}") + return d \ No newline at end of file diff --git a/lightnumpy/python_api/tests/__init__.py b/lightnumpy/python_api/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/meson.build b/meson.build index 62a1332..94286cd 100644 --- a/meson.build +++ b/meson.build @@ -1,14 +1,17 @@ ## scikit-plots/meson.build +# Authors: The scikit-plots developers +# SPDX-License-Identifier: BSD-3-Clause + ###################################################################### ## Project +## https://mesonbuild.com/Syntax.html#syntax ###################################################################### # Project configuration project( - 'lightnumpy', + 'lightnumpy', # The name of the project 'c', 'cpp', 'cython', #'python', - # version: '0.1.0', # Note that the git commit hash cannot be added dynamically here # That only happens when importing from a git repository. # See `lightnumpy/__init__.py` @@ -18,7 +21,6 @@ project( ['python', 'lightnumpy/_build_utils/version.py'], check: true, ).stdout().strip(), - license: 'BSD-3 Clause', meson_version: '>= 1.5.0', license: 'BSD-3-Clause', # license_files: [], @@ -29,8 +31,8 @@ project( 'c_std=c17', # Set C standard to C17 'cpp_std=c++17', # Set C++ standard to C++17 'fortran_std=legacy', - # 'blas=openblas', - # 'lapack=openblas', + # 'blas=openblas', # 'scipy-openblas' + # 'lapack=openblas', # 'scipy-openblas' # https://mesonbuild.com/Builtin-options.html#details-for-warning_level # 'warning_level=3', # You can specify warning levels here if needed # 'werror=true', # Treat warnings as errors globally @@ -47,7 +49,6 @@ release_version = meson.project_version() # Get the directory relative to the build directory # build_dir = meson.current_build_dir() - ###################################################################### ## BLAS/LAPACK dependency ###################################################################### @@ -1016,6 +1017,27 @@ dep_np = declare_dependency( include_directories: inc_dir_np, ) +###################################################################### +## py copier os independent +###################################################################### + +cli_copier = find_program(['cp', 'lightnumpy/_build_utils/copyfiles.py']) + +###################################################################### +## py tempita +###################################################################### + +# Usage: custom_target(command: [py, cli_tempita, '@INPUT@', '-o', '@OUTDIR@'], +# Usage: custom_target(command: [cli_tempita, '@INPUT@', '-o', '@OUTPUT@'], +cli_tempita = find_program('lightnumpy/_build_utils/tempita.py') + +# Usage: tempita_gen.process('__config__.py.in') +# Used for templated py/C/Cpp/pyx/pxd code +gen_tempita = generator(cli_tempita, + arguments : ['@INPUT@', '-o', '@OUTPUT@'], + output : '@BASENAME@', +) + ###################################################################### ## Installation tags ## https://mesonbuild.com/Installing.html#installing @@ -1047,9 +1069,8 @@ install_subdir( 'lightnumpy', install_dir: py.get_install_dir(), # Folder relative to site-packages to install to install_tag: 'python-runtime', # Tag to help categorize the install - exclude_directories: [ # Directories to exclude from installation - 'tests', # Excludes the 'tests' directory - 'NumCpp', # Excludes the 'NumCpp' directory Submodule + exclude_directories: [ # Exclude from installation, but it doesn't work as expected + '*tests', # Excludes the 'tests' directory ], ) # Optionally add a message to confirm the installation @@ -1062,4 +1083,5 @@ message( ## Next ###################################################################### +subdir('third_party') subdir('lightnumpy') \ No newline at end of file diff --git a/meson.options b/meson.options index 7de06f6..03afcfe 100644 --- a/meson.options +++ b/meson.options @@ -57,7 +57,7 @@ option('pythran', type: 'feature', value: 'auto', 'the implementation). ' + 'A feature option has three states: "enabled", "disabled" or "auto".') # numcpp -option('numcpp', type: 'feature', value: 'enabled', +option('lnpy_use_numcpp', type: 'feature', value: 'enabled', description: 'If set to "disabled", disables using numcpp (it falls back ' + 'to either pure Python code or Cython code, depending on ' + 'the implementation).' + diff --git a/pyproject.toml b/pyproject.toml index d0b79b8..0397555 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,32 +1,349 @@ +# This file is the modern replacement for setup.py, used to configure how your Python package is built. +# +# https://packaging.python.org/en/latest/discussions/setup-py-deprecated/#setup-py-deprecated +# https://packaging.python.org/en/latest/guides/writing-pyproject-toml/#a-full-example +# +# The [build-system] section specifies the build system requirements. +# "setuptools.build_meta" is the default backend used by setuptools for building projects. +# You can add other build dependencies as needed. +# +# https://packaging.python.org/en/latest/specifications/pyproject-toml/ [build-system] +# +# "build-backend" specifies the Python backend to use for building the package. build-backend = "mesonpy" requires = [ + # building an env isolated one + "meson-python>=0.16.0", # A PEP 517 backend for building Python packages with Meson. "meson>=1.5.0", # The Meson build system itself to coordinate the compilation of code. "ninja>=1.11.0", # The ninja build system used to compile code - "meson-python>=0.16.0", # A PEP 517 backend for building Python packages with Meson. - "Cython>=3.0.10", - "pybind11>=2.13.2", + "Cython>=3.0.8", + "pybind11>=2.13.0", # numpy requirement for wheel builds for distribution on PyPI - building # against 2.x yields wheels that are also compatible with numpy 1.x at # runtime. # Note that building against numpy 1.x works fine too - users and # redistributors can do this by installing the numpy version they like and # disabling build isolation. - "numpy>=2.1.0", + "numpy>=2.0.0", # Add other dependencies here if needed + # "scipy>=1.6.0", "pythran>=0.14.0", - "scipy>=1.6.0", ] +# The [project] section contains metadata about your project. [project] name = "lightnumpy" dynamic = ["version"] # The version is determined dynamically, inside meson.build description = "A lightweight library for array operations with CPU, GPU, and TPU support." + +# [project.readme] +# content-type = "text/x-rst" +# The readme file is specified here. This is what users will see on your project's PyPI page. readme = "README.md" + +# [project.license] +# License information is critical. It's recommended to specify the license file. +# license = {text = "BSD-3 Clause License"} # TODO: add `license-files` once PEP 639 is accepted (see meson-python#88) # at that point, no longer include them in `py3.install_sources()` license = {file = "LICENSE"} + +# [[project.authors]] +# List the authors of the project authors = [ - # {name = "Your Name", email = "your.email@example.com"} + # {name = "scikit-plots developers", email=""}, +] +# [[project.maintainers]] +# Project maintainers +maintainers = [ + {name = "scikit-plots developers", email=""}, +] + +# Keywords to describe your project, useful for searchability +keywords = [ + "data science", + "machine learning", + "numpy", + "lightnumpy", ] + +# Classifiers help users understand the maturity, audience, and compatible environments for your project. +# https://pypi.org/pypi?%3Aaction=list_classifiers +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + 'License :: OSI Approved :: BSD License', + 'License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)', + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + 'Programming Language :: C', + 'Programming Language :: C++', + 'Programming Language :: Cython', + 'Programming Language :: Fortran', + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Software Development :: Libraries", + "Topic :: Software Development :: Libraries :: Python Modules" +] + +# Specify the minimum Python version required requires-python = ">=3.9" + +# Replace these with the actual dependencies from requirements.txt +dependencies = [ + # Core dependencies required for the project to run + "numpy>=1.19.5", + "scipy>=1.6.0", +] + +[project.optional-dependencies] +# Development dependencies (for linting, type checking, and general dev tools) +dev = [ + "numpydoc>=1.2.0", # Numpy-style docstrings + "mypy>=1.9.0", # Type checking + "pycodestyle", # PEP-8 compliance + "ruff>=0.5.1", # Linting + "cython-lint>=0.12.2", # Linting for Cython + "black>=24.3.0", # Code formatting + "doit>=0.36.0", # Task automation + "typing_extensions", # Backports for older Python versions + "pydevtool", # Development tools + "types-psutil", # Type stubs for psutil + "rich-click", # Enhanced CLI +] +# Build dependencies (for packaging and building extensions) +build = [ + "meson-python>=0.16.0", # A PEP 517 backend for building Python packages with Meson. + "meson>=1.5.0", # The Meson build system itself to coordinate the compilation of code. + "ninja>=1.11.0", # The ninja build system used to compile code + "Cython>=3.0.8", # Cython bindings for extensions + "pybind11>=2.13.2", # Python bindings + "numpy>=1.23.5", + # "scipy>=1.6.0", + "pythran>=0.14.0", # Static Python compiler + "pandas>=1.5.1", + "matplotlib>=3.5", + "build", # Standard Python build tool + "twine", # Upload to PyPI +] +# Testing dependencies +test = [ + "pytest>=7.1.2", # Core testing framework + "pytest-cov>=2.9.0", # Coverage reports + "pytest-mpl", # Matplotlib testing + "hypothesis>=6.30", # Property-based testing + "matplotlib>=3.5", # Plotting for tests + "pandas>=1.5.1", # Data analysis for tests + "pyarrow>=12.0.0", # Arrow format + "polars>=0.20.30", # DataFrame library + "pyamg>=4.0.0", # Algebraic multigrid solvers + "pooch>=1.6.0", # Data downloading + "scikit-learn>=1.1", # Machine learning + "scikit-image>=0.17.2", # Image processing + "catboost", # Gradient boosting + "tensorflow", # Deep learning +] +# Documentation dependencies +doc = [ + "pooch>=1.6.0", # Data management + "packaging>=21", # Package utilities + "numpydoc>=1.2.0", # Numpy-style docstrings + "jinja2", # Templating engine + "sphinx>=5.0.0,<8.0.0", # Documentation generator + "sphinx-rtd-theme", # ReadTheDocs theme + "pydata-sphinx-theme", # PyData theme + "sphinx-gallery", # Gallery examples + "sphinx-prompt", # Shell prompts + "sphinxext-opengraph", # Social media metadata + "sphinx-copybutton", # Copy button for code blocks + "sphinxcontrib-sass", # SASS support + "sphinx-design", # Modern design elements + "sphinx-remove-toctrees", # Customize toctrees + "myst-parser", # Markdown support + "myst-nb", # Jupyter Notebook integration + "jupytext", # Text-based Notebook formats + "jupyter-sphinx", # Jupyter integration + "jupyterlite-sphinx", # JupyterLite integration + "jupyterlite-pyodide-kernel", # Pyodide support + "intersphinx_registry", # Intersphinx management + "colorspacious", # Color management + "sphinxcontrib-svg2pdfconverter", # SVG to PDF conversion + "sphinxcontrib-inlinesyntaxhighlight", # Inline syntax highlighting + "sphinx-tabs", # Tabbed content + "sphinx-tags", # Tagging support + "matplotlib>=3.5", # Visualization + "plotly>=5.10", # Interactive plotting + "seaborn>=0.11", # Statistical plotting + "pandas>=1.5", # Data analysis + "polars>=0.20.30", # DataFrame library + "pyarrow>=12.0.0", # Arrow format + "Pillow>=9.1", # Image processing + "scikit-image>=0.17.2", # Image processing + "scikit-learn>=1.1", # Machine learning + "tensorflow>=2.10", # Deep learning +] +# Maintenance tools +maintenance = [ + "conda-lock==2.5.6", # Dependency lock files for Conda +] +# Specialized dependencies for specific hardware +cpu = [ + "numpy", # CPU-based numerical computing + "jax", # import jax.numpy as jnp + # "jaxlib", # import jax.numpy as jnp +] +gpu = [ + # https://jax.readthedocs.io/en/latest/installation.html#installation + # "jax[cuda] -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html", # import jax.numpy as jnp + # "jax[cuda11_cudnn805] -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html", # import jax.numpy as jnp + # "jax[cuda12]", # import jax.numpy as jnp + "cupy", # GPU-based numerical computing + "torch", # PyTorch +] +tpu = [ + "tensorflow", # TPU-accelerated machine learning + # JAXlib is a library by DeepMind that provides the low-level bindings for JAX and allows you to perform tensor computations on TPU, GPU, and CPU. + # https://jax.readthedocs.io/en/latest/installation.html#installation + # "jax[tpu] -f https://storage.googleapis.com/jax-releases/libtpu_releases.html" + "jax[tpu]", # TPU-accelerated machine learning + # "dm-haiku", # neural network library built on top of JAX by Google Research + # "flax", # Flax is another JAX-based library but with a more comprehensive set of tools for defining neural networks. +] + +# https://packaging.python.org/en/latest/specifications/well-known-project-urls/#well-known-labels +# Links to important pages related to the project +[project.urls] +# homepage (Homepage) +homepage = "https://scikit-plots.github.io" +# source (Source Code), repository, sourcecode, github +repository = "https://github.com/scikit-plots/lightnumpy" +# download (Download), equivalent to Download-URL +download = "https://github.com/scikit-plots/lightnumpy" +# changelog (Changelog), changes, whatsnew, history +# The changelog, really useful for ongoing users of your project +# changelog = "https://scikit-plots.github.io/dev/whats_new/index.html" +# releasenotes (Release Notes) +# documentation (Documentation), docs +documentation = "https://scikit-plots.github.io" +# issues (Issue Tracker), "Bug Tracker" +# bugs, issue, tracker, issuetracker, bugtracker +issues = "https://github.com/scikit-plots/lightnumpy/issues" +# funding (Funding), sponsor, donate, donation +# Donate = "https://github.com/scikit-plots/lightnumpy#donate" +# Forum = "https://github.com/scikit-plots/lightnumpy/issues" + +# Configuration for the pytest testing framework +[tool.pytest.ini_options] +minversion = "6.0" # Specify the minimum version of pytest +addopts = "-ra -q" # Add command-line options +testpaths = [ + "lightnumpy", +] # Directories where tests are located +# filterwarnings = [ +# "error", +# 'default:.*pyamg, which cannot \(yet\) be imported with NumPy >=2:RuntimeWarning' +# ] + +# Black is a code formatter; this section configures its behavior. +[tool.black] +line-length = 100 # Maximum line length 88 +target-version = ['py35', 'py310', 'py314'] # Python versions to target +preview = true # Enable Black's preview features +exclude = ''' +/( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.mypy_cache + | \.vscode + | builddir + | build + | dist + | doc/build + | doc/_build + | doc/auto_examples + | lightnumpy/externals + | asv_benchmarks/env + | auto_building_tools/ +)/ +''' + +[tool.ruff] +# max line length for black +line-length = 88 +target-version = "py38" +exclude=[ + ".git", + "__pycache__", + "dist", + "doc/build", + "build", +] + +[tool.ruff.lint] +# This enables us to use CPY001: copyright header check +preview = true +# This enables us to use the explicit preview rules that we want only +explicit-preview-rules = true +# all rules can be found here: https://beta.ruff.rs/docs/rules/ +select = ["E", "F", "W", "I", "CPY001"] +ignore=[ + # space before : (needed for how black formats slicing) + "E203", + # do not assign a lambda expression, use a def + "E731", + # do not use variables named 'l', 'O', or 'I' + "E741", + # E721 is in preview (july 2024) and gives many false positives. + # Use `is` and `is not` for type comparisons, or `isinstance()` for + # isinstance checks + "E721", + # F841 is in preview (july 2024), and we don't care much about it. + # Local variable ... is assigned to but never used + "F841", +] + +[tool.ruff.lint.flake8-copyright] +notice-rgx = "\\#\\ Authors:\\ The\\ scikit\\-plots\\ developers\\\r?\\\n\\#\\ SPDX\\-License\\-Identifier:\\ BSD\\-3\\-Clause" + +[tool.ruff.lint.per-file-ignores] +# It's fine not to put the import at the top of the file in the examples +# folder. +"galleries/*"=["E402"] +"docs/conf.py"=["E402"] +"docs/*"=["CPY001"] +"**/tests/*"=["CPY001"] +"tools/*"=["CPY001"] +".spin/*"=["CPY001"] +".github/*"=["CPY001"] +# __doc__ is too long (>4096 chars) and therefore false positive on copyright check +# "examples/model_selection/plot_precision_recall.py"=["CPY001"] +# __all__ has un-imported names +# "lightnumpy/__init__.py"=["F822"] + +[tool.cython-lint] +# Ignore the same error codes as ruff +# + E501 (line too long) because keeping it < 88 in cython +# often makes code less readable. +ignore = [ + # multiple spaces/tab after comma + 'E24', + # space before : (needed for how black formats slicing) + 'E203', + # line too long + 'E501', + # do not assign a lambda expression, use a def + 'E731', + # do not use variables named 'l', 'O', or 'I' + 'E741', + # line break before binary operator + 'W503', + # line break after binary operator + 'W504', +] \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..f307013 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,61 @@ +## pytest.ini + +## Pytest Writing and running tests quickly. +[pytest] +## Directories to be ignored during test discovery +norecursedirs = + .ipynb_checkpoints + auto_building_tools + docs + galleries examples + +## Additional command-line options for pytest +## https://docs.pytest.org/en/stable/how-to/output.html#modifying-python-traceback-printing +addopts = + ## show local variables (shortcut) + -l + ## shorter traceback format for easier reading + --tb=short + # Disable warnings for cleaner output + --disable-warnings + # Stop testing after the first failure + --maxfail=1 + # Enable verbose output + -v + +## Use JUnit XML format for test results +junit_family = xunit2 + +## Configure test run settings +filterwarnings = + # Treat these warnings as errors + error + # Always show this specific warning from scipy + always::scipy._lib._testutils.FPUModeChangeWarning + # Ignore deprecation warnings from IPython + ignore:.*deprecated and ignored since IPython.*:DeprecationWarning + # Show LAPACK bug warning only once + once:.*LAPACK bug 0038.*:RuntimeWarning + # Ignore import warnings related to module spec + ignore:can't resolve package from __spec__ or __package__, falling back on __name__ and __path__:ImportWarning + # Ignore specific pytest configuration warnings + ignore:assertions not in test modules or plugins:pytest.PytestConfigWarning + ignore:'environmentfilter' is renamed to 'pass_environment' + ignore:'contextfunction' is renamed to 'pass_context' + # Ignore deprecation warnings related to distutils + ignore:.*The distutils.* is deprecated.*:DeprecationWarning + ignore:\s*.*numpy.distutils.*:DeprecationWarning + ignore:.*`numpy.core` has been made officially private.*:DeprecationWarning + ignore:.*In the future `np.long` will be defined as.*:FutureWarning + # Ignore specific warnings from CuPy + ignore:.*JAX is multithreaded.*:RuntimeWarning + ignore:.*The 2023.12 version of the array API specification is still preliminary.*:UserWarning + ignore:^Using the slower implmentation::cupy + ignore:Using the slower implementation::cupy + ignore:Jitify is performing a one-time only warm-up::cupy + # Ignore specific deprecation warnings from scikitplot + ignore:.*deprecated.*:DeprecationWarning + ignore:.*deprecated.*:UserWarning + ignore::FutureWarning + # Ignore convergence warnings from sklearn + ignore::sklearn.exceptions.ConvergenceWarning \ No newline at end of file diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..a6b115e --- /dev/null +++ b/setup.cfg @@ -0,0 +1,43 @@ +# Inside of setup.cfg +# See https://setuptools.pypa.io/en/latest/userguide/declarative_config.html for details. + +[metadata] +license = BSD-3-Clause +license_files = LICENSES/* +description_file = README.md + +[options] +packages = find: + +[options.packages.find] +include = lightnumpy* +exclude = + auto_building_tools* + docs* + galleries* + +[options.extras_require] +testing = + pytest + +[aliases] +test = pytest + +[tool:pytest] +# disable-pytest-warnings should be removed once we rewrite tests +# using yield with parametrize +doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS +testpaths = lightnumpy +addopts = + --doctest-modules + --disable-pytest-warnings + --color=yes + +[mypy] +ignore_missing_imports = True +allow_redefinition = True +exclude= + lightnumpy/externals + +[mypy-joblib.*] +follow_imports = skip \ No newline at end of file diff --git a/subprojects/.gitignore b/subprojects/.gitignore new file mode 100644 index 0000000..3b39074 --- /dev/null +++ b/subprojects/.gitignore @@ -0,0 +1,2 @@ +/*/ +!packagefiles/ \ No newline at end of file diff --git a/subprojects/packagefiles/.gitkeep b/subprojects/packagefiles/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/subprojects/template.wrap b/subprojects/template.wrap new file mode 100644 index 0000000..7541438 --- /dev/null +++ b/subprojects/template.wrap @@ -0,0 +1,17 @@ +[wrap-git] +# Meson subprojects are primarily for compile-time dependency management. +# https://mesonbuild.com/Wrap-dependency-system-manual.html +# https://github.com/mesonbuild/wrapdb/tree/master/subprojects + +# template +# directory = lightnumpy +# patch_filename = lightnumpy +# patch_directory = lightnumpy + +# url = https://github.com/scikit-plots/lightnumpy.git +# revision = gh_lightnumpy +# source_filename = lightnumpy.tar.gz +# sha256 = + +# [provide] +# project = dep_ \ No newline at end of file diff --git a/lightnumpy/_cpp_core/NumCpp b/third_party/NumCpp similarity index 100% rename from lightnumpy/_cpp_core/NumCpp rename to third_party/NumCpp diff --git a/third_party/meson.build b/third_party/meson.build new file mode 100644 index 0000000..186e1a3 --- /dev/null +++ b/third_party/meson.build @@ -0,0 +1,106 @@ +###################################################################### +## Submodule NumCpp +###################################################################### + +if not fs.exists('NumCpp/README.md') + error( + 'Missing the `NumCpp` submodule! ' + + 'Run `git submodule update --init` to fix this.') +endif + +###################################################################### +## Copy Include Headers directories for to _cpp_core/include/NumCpp +###################################################################### + +# _numcpp_inc_dir = [ +# 'NumCpp/include/NumCpp/Core/Internal', # version +# 'NumCpp/include', +# # 'NumCpp/include/NumCpp', +# # 'NumCpp/include/NumCpp/Coordinates', +# # 'NumCpp/include/NumCpp/Coordinates/ReferenceFrames', +# # 'NumCpp/include/NumCpp/Coordinates/Transforms', +# # 'NumCpp/include/NumCpp/Core', +# # 'NumCpp/include/NumCpp/Core/Internal', +# # 'NumCpp/include/NumCpp/DateTime', +# # 'NumCpp/include/NumCpp/Filter', +# # 'NumCpp/include/NumCpp/Filter/Boundaries', +# # 'NumCpp/include/NumCpp/Filter/Boundaries/Boundaries1d', +# # 'NumCpp/include/NumCpp/Filter/Boundaries/Boundaries2d', +# # 'NumCpp/include/NumCpp/Filter/Filters', +# # 'NumCpp/include/NumCpp/Filter/Filters/Filters1d', +# # 'NumCpp/include/NumCpp/Filter/Filters/Filters2d', +# # 'NumCpp/include/NumCpp/Functions', +# # 'NumCpp/include/NumCpp/ImageProcessing', +# # 'NumCpp/include/NumCpp/Integrate', +# # 'NumCpp/include/NumCpp/Linalg', +# # 'NumCpp/include/NumCpp/Linalg/svd', +# # 'NumCpp/include/NumCpp/Logging', +# # 'NumCpp/include/NumCpp/NdArray', +# # 'NumCpp/include/NumCpp/Polynomial', +# # 'NumCpp/include/NumCpp/PythonInterface', +# # 'NumCpp/include/NumCpp/Random', +# # 'NumCpp/include/NumCpp/Roots', +# # 'NumCpp/include/NumCpp/Rotations', +# # 'NumCpp/include/NumCpp/Special', +# # 'NumCpp/include/NumCpp/Utils', +# # 'NumCpp/include/NumCpp/Vector', +# ] + +# `NumCpp` install to simplify import path for public Headers; +# should be updated whenever new files are added to `NumCpp` +# Copy all the .hpp files to the install dir, rather than using +# py.install_sources and needing to list them explicitely one by one +# ls '/opt/conda/lib/python3.11/site-packages/lightnumpy/_cpp_core/include/NumCpp/include' +install_subdir( + 'NumCpp/include', + install_dir: py.get_install_dir()/'lightnumpy/_core/include/NumCpp', + install_tag: 'python-runtime', +) +# Optionally add a message to confirm the installation +message( + '\nNumCpp Header compatibility files installed successfully: ' + + '@0@'.format(py.get_install_dir()/'lightnumpy/_core/include/NumCpp') +) + +###################################################################### +## Submodule boost-math +###################################################################### + +# if not fs.exists('math/README.md') +# error('Missing the `math` submodule! Run `git submodule update --init` to fix this.') +# endif +# # Optionally add a message to confirm the installation +# message( +# '\nmath compatibility files installed successfully: ' + +# '@0@'.format('third_party/xla') +# ) + +###################################################################### +## Submodule boost +###################################################################### + +# if not fs.exists('boost/README.md') +# error('Missing the `boost` submodule! Run `git submodule update --init` to fix this.') +# endif +# # Optionally add a message to confirm the installation +# message( +# '\nboost compatibility files installed successfully: ' + +# '@0@'.format('third_party/xla') +# ) + +###################################################################### +## Submodule xla +###################################################################### + +# if not fs.exists('xla/README.md') +# error('Missing the `xla` submodule! Run `git submodule update --init` to fix this.') +# endif +# # Optionally add a message to confirm the installation +# message( +# '\nXLA compatibility files installed successfully: ' + +# '@0@'.format('third_party/xla') +# ) + +###################################################################### +## +###################################################################### \ No newline at end of file