Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DRAFT: Python implementation of cobyla #37

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
68 changes: 68 additions & 0 deletions .github/workflows/test_python.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Test Python

on:
# Trigger the workflow on push or pull request
#push:
pull_request: # DANGEROUS! MUST be disabled for self-hosted runners!
# Trigger the workflow by cron. The default time zone of GitHub Actions is UTC.
schedule:
- cron: '0 16 4-31/4 * *'
# Trigger the workflow manually
workflow_dispatch:


jobs:

test:
name: Run Python tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
solver: [cobyla]
testdim: [small]

steps:
- name: Checkout repository
uses: actions/[email protected]
with:
submodules: recursive
# ssh-key: ${{ secrets.SSH_PRIVATE_KEY_ACT }} # This forces checkout to use SSH, not HTTPS
# As of 230425, checkout with ssh fails frequently on Windows runners.

# TODO: See if this is necessary for Python
# - name: Make tools such as grep, make, and git available on Windows
# if: runner.os == 'Windows'
# run: $env:Path += ";C:\Program Files\Git\usr\bin;C:\Program Files\Git\bin;C:\ProgramData\Chocolatey\bin"

# - name: Miscellaneous setup
# shell: bash # Important; otherwise, the following statements do not work on Windows.
# run: bash .github/scripts/misc_setup
- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: "3.11"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install numpy pytest

- name: Conduct the test
# shell: bash # Important; otherwise, `<` will not work on Windows.
run: |
cd "$ROOT_DIR"/python && pytest --cov=src --cov-report=html test

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error test

cov is not a recognized word. (unrecognized-spelling)

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error test

cov is not a recognized word. (unrecognized-spelling)


- name: Store artifacts
uses: actions/[email protected]
if: always() # Always run even if the workflow is canceled manually or due to overtime.
# Note that `$TEST_DIR` does not work on Windows, where its equivalent is `$env:TEST_DIR`.
# In the following, we enquire `$TEST_DIR` by using the `env` context, which is platform independent.
with:
path: ${{ env.TEST_DIR }}/prima/python/htmlcov/*

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error test

htmlcov is not a recognized word. (unrecognized-spelling)

- name: Remove the test data
shell: bash # Important; otherwise, `rm -rf` will not work on Windows.
run: rm -rf ${{ env.TEST_DIR }}
74 changes: 74 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
To develop, `cd` into the `src` directory and run

```pip install --editable .```

This will install prima locally in an editable fashion. From there you can run the examples/cobyla/cobyla_example.py (from any directory) and go from there.

## Style notes

- In cases where there are Python or numpy functions that can achieve the same aim (i.e. sum vs np.sum) we prefer the numpy functions.
- Rationale:
- In some cases we must use the numpy function because it has functionality the Python function doesn't, i.e. np.sum has an axis argument, whereas sum does not.
- In light of this, for the sake of consistency we prefer to use the numpy functions everywhere.
- Most of the comments are copied from Fortran verbatim, except in cases where they need to modified due to specifics of the Python language. In these cases a note will be made of the difference between Fortran and Python
- Rationale:
- The main purpose of this is to keep the Python and Fortran codebases as similar as possible.

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

codebases is not a recognized word. (unrecognized-spelling)
- For determining the dimensions of an array, we exclusively use `np.size` instead of `np.shape` or `some_array.shape` or `len`
- Rationale:
- Fortran uses `SIZE` so this helps us to be as consistent with the Fortran code as possible.

## A note on Fortran's `max` and `maxval` and their Python equivalents

| Fortran | Python |
|---------|--------|
| `max` | `np.maximum` |
| `maxval` | `np.max` or `max` |

Fortran's `max` and numpy's `maximum` accept two arguments, either of which can be a scalar or an array,
and returns an elementwise maximum of the two arguments. In the case of a scalar and an array argument it
returns an elementwise maximum of the scalar and each element of the array.

Fortran's `maxval` takes a single argument and returns the largest item in the list, similar to numpy's `max`.
Python's built-in `max` can either take a single argument and return the largest element, or it can take a
variable number of arguments and return the largest of all of them.

Per the style notes, prefer `np.max` over the built-in `max`.

For the larger of two numbers Fortran uses `max`, and we prefer `np.maximum` over the Python `max` for consistenchy in the translation.

Check failure

Code scanning / check-spelling

Unrecognized Spelling Error

consistenchy is not a recognized word. (unrecognized-spelling)

This note applies to `min` and `minval` as well.


## A note on indices

Consider the following Fortran code

```
do i=0:5
print *, *
end do
```

It can be easily and automatically translated to Python as

```
for i in range(0, 6):
print(i)
```

Now consider the following similar loop

```
do i=1:5
print *, some_array(i)
end do
```

This can be translated to Python as

```
for i in range(1, 6):
print(some_array[i-1])
```

This leads to awkward Python code, since the more pythonic code would range from 0 to 5, and the indexing would be `some_array[i]`. In order to make the Python code more usable, we will attempt to write more "pythonic" code, even though that makes the translation a little bit more difficult.
10 changes: 10 additions & 0 deletions python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "prima"
version = "0.0.1"
dependencies = [
"numpy"
]

[tool.setuptools.packages.find]
where = ["src"] # ["."] by default
exclude = ["prima.examples*"] # empty by default
Empty file added python/src/prima/__init__.py
Empty file.
Empty file.
Loading