Merge pull request 'develop' (#5) from develop into main
Gitea Actions For Fabelous-Math / Explore-Gitea-Actions (push) Successful in 18s Details
Run VectorLoader Script / Explore-Gitea-Actions (push) Failing after 10s Details

Reviewed-on: #5
This commit is contained in:
Falko Victor Habel 2025-02-11 20:02:55 +00:00
commit efa67dfc3f
20 changed files with 544 additions and 2 deletions

View File

@ -0,0 +1,37 @@
name: Run VectorLoader Script
on:
push:
branches:
- main
jobs:
Explore-Gitea-Actions:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.11.7'
- name: Clone additional repository
run: |
git config --global credential.helper cache
git clone https://fabel:${{ secrets.CICD }}@gitea.fabelous.app/fabel/VectorLoader.git
- name: Install dependencies
run: |
cd VectorLoader
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run vectorizing
env:
VECTORDB_TOKEN: ${{ secrets.VECTORDB_TOKEN }}
run: |
cd VectorLoader
python -m src.run --full

View File

@ -0,0 +1,36 @@
name: Gitea Actions For Fabelous-Math
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [push]
jobs:
Explore-Gitea-Actions:
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11.7'
- name: Cache pip and model
uses: actions/cache@v3
with:
path: |
~/.cache/pip
./fabel
key: ${{ runner.os }}-pip-model-${{ hashFiles('requirements-dev.txt')}}
restore-keys: |
${{ runner.os }}-pip-model-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
- name: Run tests
run: |
pip install -e .
pytest tests

19
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,19 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"C:/Users/Falko/AppData/Local/Programs/Python/Python311/include",
"C:/Users/Falko/AppData/Local/Programs/Python/Python311/Lib/site-packages/pybind11/include"
],
"defines": [],
"windowsSdkVersion": "10.0.19041.0",
"compilerPath": "cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64"
}
],
"version": 4
}

75
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,75 @@
{
"files.associations": {
"*.py": "python",
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"exception": "cpp",
"filesystem": "cpp",
"format": "cpp",
"forward_list": "cpp",
"functional": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"iterator": "cpp",
"limits": "cpp",
"list": "cpp",
"locale": "cpp",
"memory": "cpp",
"mutex": "cpp",
"new": "cpp",
"optional": "cpp",
"ostream": "cpp",
"ratio": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"string": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"utility": "cpp",
"vector": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xutility": "cpp",
"fstream": "cpp",
"iostream": "cpp",
"codecvt": "cpp"
}
}

View File

@ -1,3 +1,72 @@
# fabelous-math
# Fabelous Math
Python addtional math libary
Fabelous Math is a simple library designed to provide basic mathematical functions, saving you the trouble of writing these common utilities repeatedly. This library includes essential functions like checking if a number is even or odd.
## Installation
You can easily install `fabelous-math` using pip:
```sh
pip install https://gitea.fabelous.app/Fabel/fabelous-math.git
```
## Usage
### Python
To use the functions provided by Fabelous Math in your Python code, you can import them as follows:
```python
from fabelous_math import is_even, is_odd
# Example usage:
number = 42
print(f"Is {number} even? {is_even(number)}")
print(f"Is {number} odd? {is_odd(number)}")
```
## Functions
### `is_even`
Checks if a given number is even.
- **Python:**
```python
def is_even(number: int) -> bool:
pass
```
- **C++:**
```cpp
namespace simple_functions {
bool is_even(long long number);
}
```
### `is_odd`
Checks if a given number is odd.
- **Python:**
```python
def is_odd(number: int) -> bool:
pass
```
- **C++:**
```cpp
namespace simple_functions {
bool is_odd(long long number);
}
```
## Performance Comparison
To understand the performance of `fabelous-math` functions, I conducted a series of tests comparing my methods with traditional modulo operations. Below are the results:
### Low Numbers Performance:
![Low Numbers Performance](docs/low_numbers_comparison.png)
### High Numbers Performance:
![High Numbers Performance](docs/high_numbers_comparison.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

4
example.py Normal file
View File

@ -0,0 +1,4 @@
from fabelous_math import is_even, is_odd
print(is_even(5))
print(is_odd(19))

12
pyproject.toml Normal file
View File

@ -0,0 +1,12 @@
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "fabelous_math"
version = "0.0.1"
description = "Math functions written in C++ for faster code"
authors = [
{name = "Falko Habel", email = "falko.habel@fabelous.app"}
]
requires-python = ">=3.7"

2
pytest.ini Normal file
View File

@ -0,0 +1,2 @@
[pytest]
testpaths = tests

2
requirements-dev.txt Normal file
View File

@ -0,0 +1,2 @@
pytest
pytest-cpp

138
result.py Normal file
View File

@ -0,0 +1,138 @@
import timeit
import random
import statistics
import matplotlib.pyplot as plt
import numpy as np
from fabelous_math import is_even, is_odd
def generate_test_numbers(count: int, min_val: int, max_val: int):
return random.sample(range(min_val, max_val), count)
def run_benchmark(numbers, func, iterations=100):
times = []
for _ in range(iterations):
start_time = timeit.default_timer()
for num in numbers:
func(num)
end_time = timeit.default_timer()
times.append(end_time - start_time)
return times
def create_visualization(results, title):
# Prepare data
methods = list(results.keys())
means = [statistics.mean(times) * 1000 for times in results.values()] # Convert to milliseconds
stds = [statistics.stdev(times) * 1000 for times in results.values()] # Convert to milliseconds
# Create figure with two subplots
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10), height_ratios=[2, 1])
fig.suptitle(title, fontsize=14)
plt.subplots_adjust(top=0.9) # Adjust spacing for title
# Bar plot
x = np.arange(len(methods))
width = 0.35
bars = ax1.bar(x, means, width, yerr=stds, capsize=5)
# Customize bar plot
ax1.set_ylabel('Time (milliseconds)')
ax1.set_xticks(x)
ax1.set_xticklabels(methods, rotation=0)
ax1.grid(True, axis='y', linestyle='--', alpha=0.7)
# Add value labels on bars
for bar in bars:
height = bar.get_height()
ax1.text(bar.get_x() + bar.get_width()/2., height,
f'{height:.3f}ms',
ha='center', va='bottom')
# Create table
cell_text = []
for method, times in results.items():
mean_time = statistics.mean(times) * 1000
std_dev = statistics.stdev(times) * 1000
min_time = min(times) * 1000
max_time = max(times) * 1000
cell_text.append([
method,
f"{mean_time:.3f}",
f"{std_dev:.3f}",
f"{min_time:.3f}",
f"{max_time:.3f}"
])
# Add table
ax2.axis('tight')
ax2.axis('off')
columns = ['Method', 'Mean (ms)', 'Std Dev (ms)', 'Min (ms)', 'Max (ms)']
table = ax2.table(cellText=cell_text,
colLabels=columns,
loc='center',
cellLoc='center')
# Adjust table appearance
table.auto_set_font_size(False)
table.set_fontsize(9)
table.scale(1.2, 1.5)
plt.tight_layout()
return plt
def main():
# Test parameters
SAMPLE_SIZE = 5000
LOW_RANGE = (1, 10000000)
HIGH_RANGE = (1000000000000, 1000000010000000)
ITERATIONS = 100
print(f"Running benchmarks with {SAMPLE_SIZE} numbers, {ITERATIONS} iterations each...")
# Generate test numbers
low_numbers = generate_test_numbers(SAMPLE_SIZE, *LOW_RANGE)
high_numbers = generate_test_numbers(SAMPLE_SIZE, *HIGH_RANGE)
# Run benchmarks for low numbers
print("\nTesting low numbers...")
low_results = {
'Fabelous Even': run_benchmark(low_numbers, is_even, ITERATIONS),
'Fabelous Odd': run_benchmark(low_numbers, is_odd, ITERATIONS),
'Modulo Even': run_benchmark(low_numbers, lambda x: x % 2 == 0, ITERATIONS),
'Modulo Odd': run_benchmark(low_numbers, lambda x: x % 2 == 1, ITERATIONS)
}
# Run benchmarks for high numbers
print("Testing high numbers...")
high_results = {
'Fabelous Even': run_benchmark(high_numbers, is_even, ITERATIONS),
'Fabelous Odd': run_benchmark(high_numbers, is_odd, ITERATIONS),
'Modulo Even': run_benchmark(high_numbers, lambda x: x % 2 == 0, ITERATIONS),
'Modulo Odd': run_benchmark(high_numbers, lambda x: x % 2 == 1, ITERATIONS)
}
# Create and save visualizations
print("\nGenerating visualizations...")
plt_low = create_visualization(low_results, 'Performance Comparison - Low Numbers')
plt_low.savefig('low_numbers_comparison.png')
plt_low.show()
plt_high = create_visualization(high_results, 'Performance Comparison - High Numbers')
plt_high.savefig('high_numbers_comparison.png')
plt_high.show()
# Print summary
print("\nSummary of Findings:")
print("-------------------")
print("1. Low Numbers Performance:")
for method, times in low_results.items():
mean_time = statistics.mean(times) * 1000
print(f" - {method}: {mean_time:.3f}ms average")
print("\n2. High Numbers Performance:")
for method, times in high_results.items():
mean_time = statistics.mean(times) * 1000
print(f" - {method}: {mean_time:.3f}ms average")
if __name__ == "__main__":
main()

30
setup.py Normal file
View File

@ -0,0 +1,30 @@
from setuptools import setup, Extension
import platform
extra_compile_args = []
extra_link_args = []
# Set C++17 flag based on the compiler
if platform.system() == "Windows":
extra_compile_args.append('/std:c++17')
else:
extra_compile_args.append('-std=c++17')
module = Extension(
'fabelous_math.simple_functions',
sources=[
'src/fabelous_math/cpp/functions/simple_functions.cpp',
'src/fabelous_math/cpp/functions/bindings.cpp'
],
include_dirs=['src/fabelous_math/include'],
extra_compile_args=extra_compile_args,
extra_link_args=extra_link_args,
)
setup(
name='fabelous_math',
description='Math functions written in C++ for faster code',
ext_modules=[module],
author="Falko Habel",
author_email="falko.habel@fabelous.app"
)

View File

@ -0,0 +1,3 @@
from fabelous_math.simple_functions import is_even, is_odd
__all__ = ["is_even", "is_odd"]

View File

@ -0,0 +1,36 @@
#include <Python.h>
#include "simple_functions.hpp"
static PyObject* is_even_wrapper(PyObject* self, PyObject* args) {
long long number;
if (!PyArg_ParseTuple(args, "L", &number)) {
return NULL;
}
return PyBool_FromLong(simple_functions::is_even(number));
}
static PyObject* is_odd_wrapper(PyObject* self, PyObject* args) {
long long number;
if (!PyArg_ParseTuple(args, "L", &number)) {
return NULL;
}
return PyBool_FromLong(simple_functions::is_odd(number));
}
static PyMethodDef NumberUtilsMethods[] = {
{"is_even", is_even_wrapper, METH_VARARGS, "Check if a number is even"},
{"is_odd", is_odd_wrapper, METH_VARARGS, "Check if a number is odd"},
{NULL, NULL, 0, NULL}
};
static struct PyModuleDef number_utils_module = {
PyModuleDef_HEAD_INIT,
"simple_functions",
"Module for checking if numbers are even or odd",
-1,
NumberUtilsMethods
};
PyMODINIT_FUNC PyInit_simple_functions(void) {
return PyModule_Create(&number_utils_module);
}

View File

@ -0,0 +1,11 @@
#include "simple_functions.hpp"
namespace simple_functions {
bool is_even(long long number) {
return (number & 1) == 0;
}
bool is_odd(long long number) {
return (number & 1);
}
}

View File

@ -0,0 +1,6 @@
#pragma once
namespace simple_functions {
bool is_even(long long number);
bool is_odd(long long number);
}

0
tests/__init__.py Normal file
View File

View File

View File

@ -0,0 +1,62 @@
import pytest
from fabelous_math import is_even, is_odd
def test_is_even():
# Test positive even numbers
assert is_even(0) == True
assert is_even(2) == True
assert is_even(4) == True
assert is_even(100) == True
# Test positive odd numbers
assert is_even(1) == False
assert is_even(3) == False
assert is_even(99) == False
# Test negative even numbers
assert is_even(-2) == True
assert is_even(-4) == True
assert is_even(-100) == True
# Test negative odd numbers
assert is_even(-1) == False
assert is_even(-3) == False
assert is_even(-99) == False
# Test large numbers
assert is_even(1000000) == True
assert is_even(-1000001) == False
def test_is_odd():
# Test positive odd numbers
assert is_odd(1) == True
assert is_odd(3) == True
assert is_odd(99) == True
# Test positive even numbers
assert is_odd(0) == False
assert is_odd(2) == False
assert is_odd(4) == False
assert is_odd(100) == False
# Test negative odd numbers
assert is_odd(-1) == True
assert is_odd(-3) == True
assert is_odd(-99) == True
# Test negative even numbers
assert is_odd(-2) == False
assert is_odd(-4) == False
assert is_odd(-100) == False
# Test large numbers
assert is_odd(1000001) == True
assert is_odd(-1000000) == False
def test_is_even_is_odd_complementary():
# Ensure is_even and is_odd are complementary for various numbers
test_numbers = [0, 1, -1, 2, -2, 99, -99, 1000000, -1000001]
for num in test_numbers:
assert is_even(num) != is_odd(num), \
f"Failed for number {num}: is_even and is_odd should be opposite"