mixed#

t01_square_int#

# cython: language_level=3
"""
t01_square_int — typed integer function (minimal).

What it demonstrates:

- Declaring C-typed arguments in a Python-visible function.
- Returning Python integers from C-typed arithmetic.

How to run:

>>> from scikitplot.cython import compile_template
>>> m = compile_template("t01_square_int")
>>> m.f(10)
100
"""


def f(int n):
    # A C-typed local variable is faster than Python ints for arithmetic.
    cdef int x = n
    return x * x

t02_fib_cpdef#

# cython: language_level=3
"""
t02_fib_cpdef — cpdef Fibonacci (iterative).

What it demonstrates:

- ``cpdef``: a function that is callable efficiently from both Cython and Python.
- Strict input validation (no heuristics).

How to run:

>>> from scikitplot.cython import compile_template
>>> m = compile_template("t02_fib_cpdef")
>>> m.fib(10)
55
"""

cpdef long fib(int n):
    # Strict validation: negative inputs are rejected deterministically.
    if n < 0:
        raise ValueError("n must be >= 0")

    cdef long a = 0
    cdef long b = 1
    cdef int i

    for i in range(n):
        a, b = b, a + b
    return a

t03_cdef_class_counter#

# cython: language_level=3
"""
t03_cdef_class_counter — cdef class with typed fields.

What it demonstrates:

- ``cdef class`` for C-accelerated classes.
- Typed attribute storage and methods.

How to run:

>>> from scikitplot.cython import compile_template
>>> m = compile_template("t03_cdef_class_counter")
>>> c = m.Counter(3)
>>> c.inc()
4
"""

cdef class Counter:
    cdef long _value

    def __cinit__(self, long start=0):
        self._value = start

    cpdef long value(self):
        return self._value

    cpdef long inc(self, long step=1):
        self._value += step
        return self._value

t04_memoryview_sum#

# cython: language_level=3
"""
t04_memoryview_sum — sum a 1D typed memoryview.

What it demonstrates:

- Using typed memoryviews (buffer protocol) without importing NumPy.
- Strict typing for predictable performance.

How to run:

>>> from scikitplot.cython import compile_template
>>> m = compile_template("t04_memoryview_sum")
>>> m.sum_double([1.0, 2.0, 3.0])
6.0

Notes
-----
Python lists do not expose a buffer, so pass an ``array('d')`` or ``memoryview``
of a suitable buffer for best results:

>>> import array
>>> a = array.array('d', [1.0, 2.0, 3.0])
>>> m.sum_double(a)
6.0
"""


def sum_double(double[:] x):

    cdef Py_ssize_t i, n = x.shape[0]
    cdef double s = 0.0

    for i in range(n):
        s += x[i]
    return s

t05_numpy_ndarray_sum#

# cython: language_level=3
"""
t05_numpy_ndarray_sum — typed NumPy ndarray loop.

What it demonstrates:

- ``cimport numpy`` and typed ndarrays for fast loops.
- Enforcing dtype/ndim at call time.

How to run:

>>> from scikitplot.cython import compile_template
>>> import numpy as np
>>> m = compile_template("t05_numpy_ndarray_sum")
>>> m.sum_int32(np.array([1, 2, 3], dtype=np.int32))
6
"""

cimport numpy as cnp
import numpy as np


def sum_int32(np.ndarray[cnp.int32_t, ndim=1] x):
    cdef Py_ssize_t i, n = x.shape[0]
    cdef long s = 0
    for i in range(n):
        s += x[i]
    return s

t06_directives_boundscheck#

# cython: language_level=3
"""
t06_directives_boundscheck — directives for speed.

What it demonstrates
--------------------
- ``cython.boundscheck(False)`` and ``cython.wraparound(False)``.
- Local, explicit performance directives (no global magic).

How to run
----------
>>> from scikitplot.cython import compile_template
>>> import numpy as np
>>> m = compile_template("t06_directives_boundscheck")
>>> m.prefix_sum(np.array([1, 2, 3], dtype=np.int64)).tolist()
[1, 3, 6]
"""

import cython
cimport numpy as cnp
import numpy as np


@cython.boundscheck(False)
@cython.wraparound(False)
def prefix_sum(np.ndarray[cnp.int64_t, ndim=1] x):
    cdef Py_ssize_t i, n = x.shape[0]
    cdef np.ndarray[cnp.int64_t, ndim=1] out = np.empty(n, dtype=np.int64)
    cdef long long acc = 0
    for i in range(n):
        acc += x[i]
        out[i] = acc
    return out

t07_libc_math#

# cython: language_level=3
"""
t07_libc_math — libc math usage.

What it demonstrates:

- ``cimport`` from ``libc.math`` for fast math operations.
- A pure C-style loop over a memoryview.

How to run:

>>> from scikitplot.cython import compile_template
>>> import array
>>> m = compile_template("t07_libc_math")
>>> a = array.array('d', [0.0, 1.0, 4.0])
>>> m.sqrt_sum(a)
3.0
"""

from libc.math cimport sqrt


def sqrt_sum(double[:] x):
    cdef Py_ssize_t i, n = x.shape[0]
    cdef double s = 0.0
    for i in range(n):
        s += sqrt(x[i])
    return s

t08_struct_point#

# cython: language_level=3
"""
t08_struct_point — cdef struct.

What it demonstrates
--------------------
- Defining a ``cdef struct`` and using it for computation.
- Returning Python floats from C math.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t08_struct_point")
>>> m.dist2(0.0, 0.0, 3.0, 4.0)
25.0
"""


cdef struct Point:
    double x
    double y


def dist2(double x1, double y1, double x2, double y2):
    cdef Point a
    cdef Point b

    a.x = x1
    a.y = y1
    b.x = x2
    b.y = y2

    cdef double dx = a.x - b.x
    cdef double dy = a.y - b.y
    return dx*dx + dy*dy

t09_enum_state#

# cython: language_level=3
"""
t09_enum_state — cdef enum.

What it demonstrates
--------------------
- Defining an enum and exposing stable integer codes to Python.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t09_enum_state")
>>> m.state_code("ok")
0
"""


cdef enum State:
    OK = 0
    WARN = 1
    ERROR = 2


def state_code(str s):
    if s == "ok":
        return OK
    if s == "warn":
        return WARN
    if s == "error":
        return ERROR
    raise ValueError("unknown state")

t10_safe_div_except#

# cython: language_level=3
"""
t10_safe_div_except — exception-aware cpdef.

What it demonstrates
--------------------
- ``cpdef`` with an explicit exception behavior.
- Strict error handling (division by zero).

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t10_safe_div_except")
>>> m.safe_div(10, 2)
5
"""

cpdef int safe_div(int a, int b) except? -1:
    if b == 0:
        raise ZeroDivisionError("b must be non-zero")
    return a // b

t11_fused_types_dot#

# cython: language_level=3
"""
t11_fused_types_dot — fused types dot product.

What it demonstrates
--------------------
- Fused types to generate specialized versions for multiple numeric types.
- Typed memoryviews for flexible inputs.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> import array
>>> m = compile_template("t11_fused_types_dot")
>>> a = array.array('d', [1.0, 2.0, 3.0])
>>> b = array.array('d', [4.0, 5.0, 6.0])
>>> m.dot(a, b)
32.0
"""

ctypedef fused floating:
    float
    double


def dot(floating[:] a, floating[:] b):
    cdef Py_ssize_t i, n = a.shape[0]
    if b.shape[0] != n:
        raise ValueError("shapes must match")
    cdef double s = 0.0
    for i in range(n):
        s += a[i] * b[i]
    return s

t12_inline_clamp#

# cython: language_level=3
"""
t12_inline_clamp — cdef inline helper.

What it demonstrates
--------------------
- ``cdef inline`` helper to avoid repetition and keep hot loops tight.
- Clean separation of helper vs public function.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> import array
>>> m = compile_template("t12_inline_clamp")
>>> x = array.array('d', [-1.0, 0.5, 2.0])
>>> m.clamp01(x).tolist()
[0.0, 0.5, 1.0]
"""


cdef inline double clamp01_scalar(double x):
    if x < 0.0:
        return 0.0
    if x > 1.0:
        return 1.0
    return x


def clamp01(double[:] x):
    cdef Py_ssize_t i, n = x.shape[0]
    # We return a Python list to keep this template dependency-free.
    out = [0.0] * n
    for i in range(n):
        out[i] = clamp01_scalar(x[i])
    return out

t13_bytes_xor#

# cython: language_level=3
"""
t13_bytes_xor — bytes processing with memoryviews.

What it demonstrates:

- Using ``unsigned char[:]`` memoryviews.
- Creating output as ``bytes`` deterministically.

How to run:

>>> from scikitplot.cython import compile_template
>>> m = compile_template("t13_bytes_xor")
>>> m.xor_bytes(b"abc", 1)
b'`cb'
"""


def xor_bytes(bytes data, unsigned char key):
    cdef unsigned char[:] src = data
    cdef Py_ssize_t i, n = src.shape[0]
    out = bytearray(n)
    cdef unsigned char[:] dst = out
    for i in range(n):
        dst[i] = src[i] ^ key
    return bytes(out)

t14_string_reverse#

# cython: language_level=3
"""
t14_string_reverse — Python string manipulation.

What it demonstrates
--------------------
- Not everything needs to be C-typed; Cython can still help structure code.
- Deterministic behavior with Unicode strings.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t14_string_reverse")
>>> m.reverse("héllo")
'olléh'
"""


def reverse(str s):
    # Python-level reversal is correct for Unicode code points.
    return s[::-1]

t15_lcg_rng#

# cython: language_level=3
"""
t15_lcg_rng — deterministic RNG (LCG) as cdef class.

What it demonstrates
--------------------
- A tiny reproducible PRNG implemented with 32-bit arithmetic.
- cdef class encapsulation for state and speed.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t15_lcg_rng")
>>> r = m.LCG(123)
>>> [r.next_u32() for _ in range(3)]
[... deterministic ...]
"""

cdef class LCG:
    cdef unsigned int _state

    def __cinit__(self, unsigned int seed=1):
        if seed == 0:
            seed = 1
        self._state = seed

    cpdef unsigned int next_u32(self):
        # Numerical Recipes LCG constants (deterministic).
        self._state = self._state * 1664525u + 1013904223u
        return self._state

    cpdef double next_float01(self):
        # Convert to [0, 1) using 32-bit scaling.
        return self.next_u32() / 4294967296.0

t16_insertion_sort#

# cython: language_level=3
"""
t16_insertion_sort — insertion sort on a typed memoryview.

What it demonstrates:

- In-place algorithms on typed memoryviews.
- Strict algorithm with deterministic output.

How to run:

>>> from scikitplot.cython import compile_template
>>> import array
>>> m = compile_template("t16_insertion_sort")
>>> a = array.array('d', [3.0, 1.0, 2.0])
>>> m.insertion_sort(a)
>>> list(a)
[1.0, 2.0, 3.0]
"""


def insertion_sort(double[:] x):
    cdef Py_ssize_t i, j, n = x.shape[0]
    cdef double key
    for i in range(1, n):
        key = x[i]
        j = i - 1
        while j >= 0 and x[j] > key:
            x[j + 1] = x[j]
            j -= 1
        x[j + 1] = key

t17_kahan_sum#

# cython: language_level=3
"""
t17_kahan_sum — Kahan summation.

What it demonstrates
--------------------
- Numerically stable summation using compensation.
- Useful in ML metrics aggregation.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> import array
>>> m = compile_template("t17_kahan_sum")
>>> a = array.array('d', [1e100, 1.0, -1e100])
>>> m.kahan_sum(a)
1.0
"""


def kahan_sum(double[:] x):
    cdef Py_ssize_t i, n = x.shape[0]
    cdef double s = 0.0
    cdef double c = 0.0  # compensation
    cdef double y, t
    for i in range(n):
        y = x[i] - c
        t = s + y
        c = (t - s) - y
        s = t
    return s

t18_histogram_int#

# cython: language_level=3
"""
t18_histogram_int — histogram counting (NumPy int32).

What it demonstrates
--------------------
- Counting histogram bins with typed ndarrays.
- Strict bounds checks on bin range.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> import numpy as np
>>> m = compile_template("t18_histogram_int")
>>> x = np.array([0, 1, 1, 2], dtype=np.int32)
>>> m.hist_counts(x, 3).tolist()
[1, 2, 1]
"""

cimport numpy as cnp
import numpy as np


def hist_counts(np.ndarray[cnp.int32_t, ndim=1] x, int n_bins):
    if n_bins <= 0:
        raise ValueError("n_bins must be > 0")
    cdef np.ndarray[cnp.int64_t, ndim=1] out = np.zeros(n_bins, dtype=np.int64)
    cdef Py_ssize_t i, n = x.shape[0]
    cdef int v
    for i in range(n):
        v = x[i]
        if v < 0 or v >= n_bins:
            raise ValueError("value out of range")
        out[v] += 1
    return out

t19_popcount#

# cython: language_level=3
"""
t19_popcount — portable bit population count.

What it demonstrates
--------------------
- Bitwise operations on unsigned ints.
- Portability: no compiler-specific builtins.

How to run
----------
>>> from scikitplot.cython import compile_template
>>> m = compile_template("t19_popcount")
>>> m.popcount32(0b1011)
3
"""

cpdef int popcount32(unsigned int x):
    cdef int count = 0
    while x:
        x &= x - 1  # clear lowest set bit
        count += 1
    return count

t20_matmul_small#

# cython: language_level=3
"""
t20_matmul_small — naive 2D matrix multiplication (memoryviews).

What it demonstrates:

- 2D typed memoryviews and triple loops.
- Strict dimension checks.

How to run:

>>> from scikitplot.cython import compile_template
>>> import numpy as np
>>> m = compile_template("t20_matmul_small")
>>> A = np.array([[1., 2.],[3., 4.]], dtype=np.float64)
>>> B = np.array([[5., 6.],[7., 8.]], dtype=np.float64)
>>> m.matmul(A, B)
array([[19., 22.],
       [43., 50.]])
"""

cimport numpy as cnp
import numpy as np


def matmul(np.ndarray[cnp.float64_t, ndim=2] A, np.ndarray[cnp.float64_t, ndim=2] B):
    cdef Py_ssize_t i, j, k
    cdef Py_ssize_t m = A.shape[0]
    cdef Py_ssize_t n = A.shape[1]
    if B.shape[0] != n:
        raise ValueError("shape mismatch")
    cdef Py_ssize_t p = B.shape[1]
    cdef np.ndarray[cnp.float64_t, ndim=2] C = np.zeros((m, p), dtype=np.float64)
    for i in range(m):
        for k in range(n):
            for j in range(p):
                C[i, j] += A[i, k] * B[k, j]
    return C