Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .mkdocs/theme/breadcrumbs.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,17 @@
<li class="breadcrumb-item active">{{ page.title }}</li>
{%- endif %}
<li class="wy-breadcrumbs-aside">
<a
href="https://colab.research.google.com/github/PyNumLab/prik/blob/main/examples/notebooks/quickstart.ipynb"
class="prik-notebook-link"
target="_blank"
rel="noopener noreferrer"
title="Run the PRIK quickstart notebook in Google Colab"
aria-label="Run the PRIK quickstart notebook in Google Colab in a new tab"
>
<span aria-hidden="true">&#9654;</span>
<span>Run it in Colab</span>
</a>
<a
href="{{ config.repo_url }}"
class="prik-repository-link"
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ release tags add a leading `v` to the package version.

## Unreleased

- The `jupyter` extra now accepts IPython 7.0 and newer instead of requiring
8.0. The cell magics use only long-stable IPython APIs, and the higher floor
made `pip install prik[jupyter]` upgrade the IPython that hosted notebook
environments ship, which forced a runtime restart for no benefit. The `qa`
extra installs `prik[jupyter]` rather than repeating that requirement, so
the supported IPython range is stated once.

- Added a runnable `examples/notebooks/quickstart.ipynb` and its guided
tutorial, covering a Fortran cell, a C cell, and reshaping the generated API
by editing its semantic contract in the same session. The home page, Getting
Started, the tutorial, and the README offer it as a Colab run or a direct
download, so the documented workflow can be tried before installing anything.

- Generated contracts now represent a one-level primitive C pointer as
runtime-rank `T[...]` NumPy storage instead of choosing a scalar temporary.
It accepts ranks 0 through 15 with any strides, so a Fortran-ordered array
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ Fortran and C code.
[![codecov](https://codecov.io/gh/PyNumLab/prik/graph/badge.svg?token=QZRRCS5YO6)](https://codecov.io/gh/PyNumLab/prik)
[![DOI](https://zenodo.org/badge/1241799694.svg)](https://doi.org/10.5281/zenodo.21881987)

**Try it without installing anything.** The quickstart notebook compiles a
Fortran cell and a C cell, then reshapes the generated API by editing its
`.pyi` contract.

[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/PyNumLab/prik/blob/main/examples/notebooks/quickstart.ipynb)
[Download the notebook](https://pynumlab.github.io/prik/examples/notebooks/quickstart.ipynb)

It preserves modules, derived types, arrays, callbacks, and native behavior
while letting you reshape the resulting Python API through editable `.pyi`
contracts instead of writing low-level binding code.
Expand Down Expand Up @@ -455,7 +462,9 @@ python3 -m pip install "prik[jupyter]"

Use `%%fortran` or `%%c` to compile native source in a cell. Add `--pyi` to
review and edit the generated contract before compilation, or use `%%pyi` with
existing native source files. See [IPython and Jupyter
existing native source files. See [Run PRIK in a
Notebook](https://pynumlab.github.io/prik/user/tutorials/notebook-quickstart/)
for the guided version, or [IPython and Jupyter
Notebooks](https://pynumlab.github.io/prik/user/guide/notebooks/) for the
complete workflow.

Expand Down
9 changes: 9 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,15 @@ print(item.norm_squared()) # 20.0

Same Fortran source, but a more natural Python API: module procedures become methods.

**Want to run that loop yourself?** The quickstart notebook does exactly this —
compiles a Fortran cell and a C cell, then reshapes the generated API by editing
its `.pyi` contract. It needs no installation.

<p class="prik-notebook-actions">
<a class="prik-primary-cta" href="https://colab.research.google.com/github/PyNumLab/prik/blob/main/examples/notebooks/quickstart.ipynb">▶&nbsp; Run it in Colab</a>
<a class="prik-secondary-cta" href="examples/notebooks/quickstart.ipynb" download="quickstart.ipynb">⬇&nbsp; Download the notebook</a>
</p>

## Why PRIK

- **Natural Python APIs:** Fortran modules become namespaces and derived types
Expand Down
89 changes: 88 additions & 1 deletion docs/stylesheets/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,49 @@
display: none;
}

.wy-breadcrumbs-aside {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}

.prik-notebook-link {
display: inline-flex;
align-items: center;
gap: 0.4rem;
min-height: 2.15rem;
padding: 0.4rem 0.8rem;
border: 1px solid var(--prik-primary);
border-radius: 0.35rem;
background: #fff;
color: var(--prik-primary);
font-size: 0.82rem;
font-weight: 600;
line-height: 1;
text-decoration: none;
white-space: nowrap;
transition:
background-color 120ms ease,
border-color 120ms ease,
color 120ms ease;
}

.prik-notebook-link:visited {
color: var(--prik-primary);
}

.prik-notebook-link:hover,
.prik-notebook-link:focus {
background: var(--prik-primary-bg);
border-color: var(--prik-primary-dark);
color: var(--prik-primary-dark);
}

.prik-notebook-link:focus-visible {
outline: 2px solid #f5b041;
outline-offset: 2px;
}

.prik-repository-link {
display: inline-flex;
align-items: center;
Expand Down Expand Up @@ -170,6 +213,49 @@
outline-offset: 2px;
}

.prik-notebook-actions {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin: 1.25rem 0 1.5rem;
}

.prik-secondary-cta {
display: inline-flex;
align-items: center;
min-height: 2.6rem;
padding: 0.65rem 1rem;
border: 1px solid var(--prik-primary);
border-radius: 0.35rem;
background: #fff;
color: var(--prik-primary);
font-weight: 700;
text-decoration: none;
transition:
background-color 120ms ease,
border-color 120ms ease,
box-shadow 120ms ease,
transform 120ms ease;
}

.prik-secondary-cta:visited {
color: var(--prik-primary);
}

.prik-secondary-cta:hover,
.prik-secondary-cta:focus {
background: var(--prik-primary-bg);
border-color: var(--prik-primary-dark);
box-shadow: 0 4px 9px rgb(0 0 0 / 12%);
color: var(--prik-primary-dark);
transform: translateY(-1px);
}

.prik-secondary-cta:focus-visible {
outline: 2px solid #f5b041;
outline-offset: 2px;
}

.prik-faq-item {
max-width: 56rem;
margin: 0.8rem 0;
Expand Down Expand Up @@ -442,7 +528,8 @@

@media screen and (max-width: 768px) {
.wy-breadcrumbs-aside {
display: block;
display: flex;
flex-wrap: wrap;
float: none;
margin-top: 0.75rem;
}
Expand Down
3 changes: 3 additions & 0 deletions docs/user/getting-started/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ Follow these pages in order:
3. **[Your First Function](first-wrapped-function.md)** — Build the same scalar function from Fortran or C.
4. **[Development Workflow](beginner-workflow.md)** — Repeat the edit → review → build → test loop.

The [quickstart notebook](https://colab.research.google.com/github/PyNumLab/prik/blob/main/examples/notebooks/quickstart.ipynb)
runs this same loop in Colab, with nothing to install.

---

## What You Will Build
Expand Down
156 changes: 156 additions & 0 deletions docs/user/tutorials/notebook-quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
---
title: Run PRIK in a Notebook
description: Compile Fortran and C cells and reshape the generated API without leaving the notebook
audience: users
prerequisites: installation, IPython and Jupyter notebooks
related: ../guide/notebooks.md, ../guide/c/pointers-arrays-and-strings.md, pythonic-blas.md
status: maintained
publication: reviewed
---

# Run PRIK in a Notebook

This tutorial compiles Fortran and C in notebook cells, calls them from Python,
and then reshapes the generated API by editing its semantic contract — all in
one session.

<p class="prik-notebook-actions">
<a class="prik-primary-cta" href="https://colab.research.google.com/github/PyNumLab/prik/blob/main/examples/notebooks/quickstart.ipynb">▶&nbsp; Run it in Colab</a>
<a class="prik-secondary-cta" href="../../../examples/notebooks/quickstart.ipynb" download="quickstart.ipynb">⬇&nbsp; Download the notebook</a>
</p>

The notebook runs top to bottom and builds real extension modules, so it needs a
compiler. In Colab the first cell installs one.

## 1. Load the extension

```ipython
%load_ext prik.jupyter
```

## 2. Compile a Fortran cell

`%%fortran` compiles the cell and publishes what it declares. A Fortran module
becomes a notebook name:

```ipython
%%fortran
module geometry
contains
real(8) function circle_area(radius)
real(8), intent(in) :: radius
circle_area = 3.141592653589793d0 * radius**2
end function
end module
```

```python
area = geometry.circle_area(np.float64(2.0))
assert np.isclose(area, np.pi * 4)
print(f"✅ circle_area(2.0) = {area} (expected {np.pi * 4})")
```

```text
✅ circle_area(2.0) = 12.566370614359172 (expected 12.566370614359172)
```

Every result the notebook claims is asserted, so a ✅ means the cell really did
that rather than the page saying so.

## 3. Compile a C cell

`%%c` publishes C functions directly. This one doubles an array in place and
takes the element count the way C usually does:

```ipython
%%c
#include <stddef.h>

void scale(size_t count, double *values) {
for (size_t index = 0; index < count; ++index) {
values[index] *= 2.0;
}
}
```

`double *values` becomes runtime-rank storage, so it accepts a NumPy array of
any rank and writes through it. The count still has to be passed by hand,
though NumPy already knows it:

```python
values = np.array([1.0, 2.0, 3.0])
scale(np.uintp(values.size), values)
assert np.allclose(values, [2.0, 4.0, 6.0])
print(f"✅ scale(count, values) doubled in place: {values} (expected [2. 4. 6.])")
```

```text
✅ scale(count, values) doubled in place: [2. 4. 6.] (expected [2. 4. 6.])
```

## 4. Reshape the API with a contract

`--pyi` compiles nothing. It keeps the source and hands back the semantic
contract it derived, as an editable cell:

```ipython
%%c --pyi
#include <stddef.h>

void scale(size_t count, double *values) {
for (size_t index = 0; index < count; ++index) {
values[index] *= 2.0;
}
}
```

Jupyter and Colab insert the contract below the cell you just ran:

```ipython
%%pyi

# prik: source-sha256=<generated digest>

from prik.contracts import Float64, UInt64

def scale(
count: UInt64,
values: Float64[...]
) -> None: ...
```

Edit it so the count comes from the array. `Arg(0).size` supplies it, and
`Float64[:]` pins the rank to one. Keep the `# prik:` line, then run the cell:

```ipython
%%pyi

# prik: source-sha256=<generated digest>

from prik.contracts import Arg, Float64, native_call

@native_call([Arg(0).size, Arg(0)])
def scale(values: Float64[:]) -> None: ...
```

Same C code, same compiler; only the Python API changed — `count` is gone:

```python
values = np.array([1.0, 2.0, 3.0])
scale(values)
assert np.allclose(values, [2.0, 4.0, 6.0])
print(f"✅ scale(values) doubled in place: {values} (expected [2. 4. 6.])")
```

```text
✅ scale(values) doubled in place: [2. 4. 6.] (expected [2. 4. 6.])
```

## Where to go next

- [IPython and Jupyter Notebooks](../guide/notebooks.md) covers every magic,
its options, and the cell cache.
- [C Pointers, Arrays, and Strings](../guide/c/pointers-arrays-and-strings.md)
explains what `Float64[...]` accepts and how to narrow it.
- [Design a Pythonic BLAS API](pythonic-blas.md) applies the same contract
editing to a real library.
Loading
Loading