Skip to content

Commit d3f0f23

Browse files
authored
Merge pull request #221 from nbelakovski/pyprima
Include Python implementation of COBYLA and associated CI test. Thank @nbelakovski for this great contribution to PRIMA! -Zaikun
2 parents ecb6c48 + c18f93b commit d3f0f23

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+10818
-0
lines changed

.github/actions/spelling/allow.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2261,3 +2261,40 @@ TESTQUAD
22612261
WAITALL
22622262
xcodebuild
22632263
ICX
2264+
Belakovski
2265+
allclose
2266+
argmin
2267+
biggs
2268+
CHEC
2269+
checkbreak
2270+
chisti
2271+
codebases
2272+
cov
2273+
cqai
2274+
cqi
2275+
degenlpb
2276+
errinbar
2277+
fhisti
2278+
hstack
2279+
isneginf
2280+
isposinf
2281+
joptcandidate
2282+
jth
2283+
Kbreak
2284+
mgh
2285+
mmm
2286+
nanargmax
2287+
tenbars
2288+
tfi
2289+
pyprima
2290+
primasum
2291+
primapow
2292+
autouse
2293+
SYNTHES
2294+
pytestmark
2295+
misra
2296+
polak
2297+
loadgroup
2298+
rosen
2299+
newx
2300+
COBYQA

.github/workflows/test_pyprima.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Test PyPRIMA
2+
3+
on:
4+
# Trigger the workflow on push or pull request
5+
#push:
6+
pull_request: # DANGEROUS! MUST be disabled for self-hosted runners!
7+
# Trigger the workflow by cron. The default time zone of GitHub Actions is UTC.
8+
schedule:
9+
- cron: '0 16 4-31/4 * *'
10+
# Trigger the workflow manually
11+
workflow_dispatch:
12+
13+
14+
jobs:
15+
16+
test:
17+
name: Run PyPRIMA tests
18+
runs-on: ${{ matrix.os }}
19+
strategy:
20+
fail-fast: false
21+
matrix:
22+
os: [ubuntu-latest, windows-latest, macos-latest]
23+
24+
steps:
25+
- name: Checkout repository
26+
uses: actions/[email protected]
27+
28+
- name: Setup Python
29+
uses: actions/setup-python@v3
30+
with:
31+
python-version: "3.12"
32+
33+
- name: Install dependencies
34+
run: |
35+
python -m pip install --upgrade pip
36+
pip install -r pyprima/tests/requirements.txt
37+
38+
- name: Conduct the test
39+
shell: bash
40+
run: |
41+
cd pyprima
42+
# Need editable mode for coverage to work correctly
43+
python -m pip install --editable .
44+
pytest --cov=src --cov-report=html tests/
45+
46+
47+
- name: Store artifacts
48+
uses: actions/upload-artifact@v4
49+
id: artifact-coverage
50+
with:
51+
name: coverage-html-${{ matrix.os }}
52+
path: pyprima/htmlcov/*
53+
54+
- name: Output artifact URL
55+
run: echo 'Artifact URL is https://github.com/nbelakovski/prima/actions/runs/${{ github.run_id }}/artifacts/${{ steps.artifact-coverage.outputs.artifact-id }}'

pyprima/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pycutest_cache_holder
2+
out

pyprima/README.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
To develop, `cd` into the `src` directory and run
2+
3+
```pip install --editable .```
4+
5+
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.
6+
7+
## Style notes
8+
9+
- 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
10+
- Rationale:
11+
- The main purpose of this is to keep the Python and Fortran codebases as similar as possible.
12+
- For determining the dimensions of an array, we exclusively use `np.size` instead of `np.shape` or `some_array.shape` or `len`
13+
- Rationale:
14+
- Fortran uses `SIZE` so this helps us to be as consistent with the Fortran code as possible.
15+
16+
## A note on Fortran's `maxval`, `maximum`, and `maxval` and their Python equivalents
17+
18+
| Fortran | Python | Return value |
19+
|-----------|--------------|--------------|
20+
| `maxval` | `max` | scalar |
21+
| `maximum` | `np.max` | scalar |
22+
| `max` | `np.maximum` | vector |
23+
24+
The difference between `maxval` and `maximum` is that `maximum` will return NaN if the input contains NaN. Python's `max`
25+
and numpy's `np.max` have a similar distinction.
26+
27+
Fortran's `max` and numpy's `mp.maximum` accept two arguments, either of which can be a scalar or an array,
28+
and returns an elementwise maximum of the two arguments. In the case of a scalar and an array argument it
29+
returns an elementwise maximum of the scalar and each element of the array.
30+
31+
This note applies to `minval`, `minimum`, and `min` as well.
32+
33+
34+
## A note on indices
35+
36+
Consider the following Fortran code
37+
38+
```
39+
do i=0:5
40+
print *, *
41+
end do
42+
```
43+
44+
It can be easily and automatically translated to Python as
45+
46+
```
47+
for i in range(0, 6):
48+
print(i)
49+
```
50+
51+
Now consider the following similar loop
52+
53+
```
54+
do i=1:5
55+
print *, some_array(i)
56+
end do
57+
```
58+
59+
This can be translated to Python as
60+
61+
```
62+
for i in range(1, 6):
63+
print(some_array[i-1])
64+
```
65+
66+
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.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pycutest_cache_holder
2+
out
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This folder contains scripts and utilities to run performance profiles of the PRIMA Python bindings against the PRIMA MATLAB bindings.
2+
3+
In general we expect the performance profiles to show a straight line for both the output based and history based profiles since the underlying code is the same. However since there are bound to be some differences in how MATLAB and Python handle floating point arithmetic we expect to see a few cases where one might perform slightly "better" than the other.
4+
5+
In order to use this you will need Python and MATLAB and in the MATLAB GUI you should have run setup.m from the root of the repo. If that has been completed you should be able to run the profiles with simply `python profiles.py`. By default no profiles will be run, so you need to specify which algorithm you'd like to run profiles for using any combination of `-b` for BOBYQA, `-c` for COBYLA, `-l` for LINCOA, `-n` for NEWUOA, and `-u` for UOBYQA. You can also use `-j#` to change the number of jobs used to run the problems. For example to run both UOBYQA and NEWUOA with 4 jobs, you would run `python profiles.py -nuj4`.
6+
7+
It is not necessary to have a MATLAB window open to run the profiles. Each job will create an instance of the MATLAB engine for Python. Please note that this instance takes up about 500MB of memory so you may want to limit the number of jobs accordingly.

0 commit comments

Comments
 (0)