Skip to content

Commit

Permalink
SA old core (#71)
Browse files Browse the repository at this point in the history
* add SA from old core

* add pypi action

* add SA tutorial

* add tests

* Update README.rst

* add nips bibtex, fix installation guide
  • Loading branch information
MangaBoba committed Dec 25, 2023
1 parent c36d5af commit a91c4ef
Show file tree
Hide file tree
Showing 23 changed files with 317 additions and 257 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/pyblish_pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Build and publish package to PyPi

on:
workflow_dispatch:

jobs:
build_and_publish:

runs-on: ubuntu-latest
strategy:
matrix:
python-version: [ 3.9 ]

steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Build package
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade setuptools wheel
python setup.py sdist bdist_wheel
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_PASSWORD }}
repository_url: https://upload.pypi.org/legacy/
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ celerybeat.pid
# Environments
.env
.venv
.venv*
env/
venv/
ENV/
Expand Down
44 changes: 39 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,18 @@
.. list-table::
:stub-columns: 1

* - tests
- | |build|
* - docs
- |docs|
* - license
- | |license|
* - support
- | |tg|
* - gitlab
- | |gitlab|
* - funding
- | |ITMO| |NCCR|

.. end-badges
Expand Down Expand Up @@ -41,8 +47,9 @@ The dynamics of the optimisation can be visualized as (breakwaters optimisation
How to use
==========

All details about first steps with GEFEST might be found in the `quick start guide <https://gefest.readthedocs.io/en/latest/gefest/quickstart.html>`__
and in the `tutorial for novices </docs/tutorials/sample.rst>`__
All details about first steps with GEFEST might be found in the `quick start guide <https://gefest.readthedocs.io/en/latest/gefest/quickstart.html>`__.

Tutorals for more spicific use cases can be found `tutorial section of docs <https://gefest.readthedocs.io/en/latest/tutorials/index.html>`__.

Project Structure
=================
Expand All @@ -58,21 +65,25 @@ The repository includes the following directories:

Cases and examples
==================
**Note**: To run the examples below, the old kernel gefest version, which can be installed on python 3.7 with:

.. code:: bash
pip install git+https://github.com/aimclub/GEFEST.git@4f9c34c449c0eb65d264476e5145f09b4839cd70
- `Experiments <https://github.com/ITMO-NSS-team/GEFEST-paper-experiments>`__ with various real and synthetic cases
- `Case <https://github.com/ITMO-NSS-team/rbc-traps-generative-design>`__ devoted to the red blood cell traps design.

Migrated examples can be found in cases folder of the main branch.

Current R&D and future plans
============================

Currently, we are working on integration of new types of physical objects with consideration of their internal structure.\n

The major ongoing tasks:

* to make the use of GEFEST more accessible and simple for users
* to integrate three dimensional physical objects
* to implement gradient based approaches for optimization of physical objects
* to improve efficiency of GEFEST's standard sampler

Documentation
=============
Expand Down Expand Up @@ -116,6 +127,17 @@ Citation
publisher={Elsevier}
}

@inproceedings{solovev2023ai,
title={AI Framework for Generative Design of Computational Experiments with Structures in Physical Environment},
author={Solovev, Gleb Vitalevich and Kalyuzhnaya, Anna and Hvatov, Alexander and Starodubcev, Nikita and Petrov, Oleg and Nikitin, Nikolay},
booktitle={NeurIPS 2023 AI for Science Workshop},
year={2023}
}

.. |build| image:: https://github.com/aimclub/GEFEST/workflows/unit%20tests/badge.svg?branch=main
:alt: Build Status
:target: https://github.com/aimclub/GEFEST/actions

.. |docs| image:: https://readthedocs.org/projects/gefest/badge/?version=latest
:target: https://gefest.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
Expand All @@ -126,4 +148,16 @@ Citation

.. |tg| image:: https://img.shields.io/badge/Telegram-Group-blue.svg
:target: https://t.me/gefest_helpdesk
:alt: Telegram Chat
:alt: Telegram Chat

.. |ITMO| image:: https://github.com/ITMO-NSS-team/open-source-ops/blob/add_badge/badges/ITMO_badge_rus.svg
:alt: Acknowledgement to ITMO
:target: https://itmo.ru

.. |NCCR| image:: https://github.com/ITMO-NSS-team/open-source-ops/blob/add_badge/badges/NCCR_badge.svg
:alt: Acknowledgement to NCCR
:target: https://actcognitive.org/

.. |gitlab| image:: https://camo.githubusercontent.com/9bd7b8c5b418f1364e72110a83629772729b29e8f3393b6c86bff237a6b784f6/68747470733a2f2f62616467656e2e6e65742f62616467652f6769746c61622f6d6972726f722f6f72616e67653f69636f6e3d6769746c6162
:alt: GitLab mirror for this repository
:target: https://gitlab.actcognitive.org/itmo-nss-team/GEFEST
8 changes: 4 additions & 4 deletions cases/sound_waves/configuration/config_parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ def _evaluate(self, ind: Structure):

tuner_cfg = TunerParams(
tuner_type='sequential',
n_steps_tune=10,
hyperopt_dist='normal',
n_steps_tune=50,
hyperopt_dist='uniform',
verbose=True,
variacne_generator=partial(percent_edge_variance, percent=0.2),
variacne_generator=partial(percent_edge_variance, percent=0.5),
timeout_minutes=30,
)

Expand Down Expand Up @@ -121,7 +121,7 @@ def _evaluate(self, ind: Structure):
],
extra=5,
estimation_n_jobs=-1,
n_jobs=11,
n_jobs=-1,
log_dir='logs/tuners_exp',
run_name='roulette_1_obj',
golem_keep_histoy=True,
Expand Down
10 changes: 5 additions & 5 deletions cases/synthetic/circle/single_objective.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ def __init__(self, domain: Domain, estimator: Estimator = None) -> None:

def _evaluate(self, ind: Structure) -> float:

num = 3
num_polys = len(ind.polygons)
loss = 0
for poly in ind.polygons:
area = self.domain.geometry.get_square(poly)
length = self.domain.geometry.get_length(poly)
if area == 0:
ratio = None
ratio = float('inf')
else:
ratio = 1 - 4 * np.pi * area / length ** 2

loss += ratio

loss = loss + 20 * abs(num_polys - num)
if num_polys > 1:
loss += 20 * abs(num_polys - 1)
return loss


Expand Down Expand Up @@ -61,7 +60,7 @@ def _evaluate(self, ind: Structure) -> float:

tuner_cfg = TunerParams(
tuner_type='optuna',
n_steps_tune=10,
n_steps_tune=25,
hyperopt_dist='uniform',
verbose=True,
timeout_minutes=60,
Expand Down Expand Up @@ -101,6 +100,7 @@ def _evaluate(self, ind: Structure) -> float:
'not_too_close_points',
],
extra=5,
estimation_n_jobs=-1,
n_jobs=-1,
log_dir='logs',
run_name='run_name',
Expand Down
10 changes: 0 additions & 10 deletions docs/source/gefest/installation.rst

This file was deleted.

10 changes: 5 additions & 5 deletions docs/source/gefest/quickstart.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Tested on python 3.9-3.10

.. code::
pip install https://github.com/ITMO-NSS-team/GEFEST/archive/master.zip
pip install gefest
How to run
----------
Expand Down Expand Up @@ -62,7 +62,7 @@ Let's take a step-by-step look at how to do this.
from gefest.core.opt.objective.objective import Objective
from gefest.tools.estimators.estimator import Estimator
- **Step 1**. Define objectives using loss function and simulator of the physical process if required.
- **Step 1**. Define objectives using fitness function and simulator of the physical process if required.

Objective for finding a polygon that seems like circle showed below.

Expand Down Expand Up @@ -127,7 +127,7 @@ Domain describes geometric constraints for individuals.

By default, the standard sampler is used.
You can select another sampler or define custom for spicific task.
How to define your own samler described in the tutorials section of the documentation.
How to define your own sampler described in the tutorials section of the documentation.

- **Step 4**. Define tuner configuraton.

Expand Down Expand Up @@ -197,7 +197,7 @@ To know more about configuration options see :ref:`configuration` section of API
- **Step 5**. Run generative design and results visualisation.

Now you can run the optimization as it was described above in *How to run* section of this tutorial.
Let's look at how it works inside.
Let's take a look at code in `run_experiments.py` script.

.. code:: python
Expand All @@ -221,7 +221,7 @@ Let's look at how it works inside.
# Optimized pop visualization
logger.info('Collecting plots of optimized structures...')
# GIFMaker object creates mp4 series of optimized structures plots
# GIFMaker object creates mp4 from optimized structures plots
gm = GIFMaker(domain=opt_params.domain)
for st in tqdm(optimized_pop):
gm.create_frame(st, {'Optimized': st.fitness})
Expand Down
1 change: 1 addition & 0 deletions docs/source/tutorials/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ Tutorials

optimisation
tuning
sa
10 changes: 5 additions & 5 deletions docs/source/tutorials/optimisation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Optimisation
Optimisers summary
------------------

To solve the optimisation problem, 4 optimisers are available in GEFEST - 1 native and 2 based on GOLEM.
To solve the optimisation problems 4 optimisers are available in GEFEST - 1 native and 2 based on GOLEM.
All of them have a single interface and can be imported from ``gefest.tools.optimizers``.

.. list-table:: Optimizers comparation
Expand Down Expand Up @@ -39,13 +39,13 @@ All of them have a single interface and can be imported from ``gefest.tools.opti
- :raw-html-m2r:`<code style="background:green;color:white;font-weight:bold">Yes</code>`


``BaseGA`` implements the base genetic algorithm, that performs generation of the initial population,
``BaseGA`` implements the base genetic algorithm, that performs sampling of the initial population,
crossover and mutation operations, fitness estimation and selection.
Each of the steps is encapsulated in a separate executor, which allows you to change the logic of individual steps.
Thus, BaseGA essentially only implements the sequence of their call.

``StandardOptimizer`` is a wrapper for GOLEM`s ``EvoGraphOptimizer`` optimiser.
It allows to select different evolutionary schemes, adaptive mutation strategies and some other features.
``StandardOptimizer`` is a wrapper for GOLEM`s ``EvoGraphOptimizer``.
It allows to use different evolutionary schemes, adaptive mutation strategies and some other features.
To use multiobjective optimisation set `golem_selection_type` in ``OptimizationParams`` config to 'spea2'.

``SurrogateOptimizer`` is the extension of ``StandardOptimizer`` with the ability
Expand All @@ -64,7 +64,7 @@ How to optimise

Easiest way to run optimiser described in :ref:`quickstart`.

If you want to get some more control you can do it in code by import corresponding classes:
If you want to get some more control you can do it in your code:

.. code-block:: python
Expand Down
39 changes: 39 additions & 0 deletions docs/source/tutorials/sa.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Sensitivity analysis
====================

SA
--

Use SA to run local search near an optimized structure.


.. code-block:: python
from gefest.core.configs.optimization_params import OptimizationParams
from gefest.core.geometry.datastructs.structure import Structure
from gefest.tools.tuners.sa import SensitivityAnalysis, report_viz
from matplotlib import pyplot as plt
structure: list[Structure] | Structure = ...
opt_params: OptimizationParams = ...
sa = SensitivityAnalysis([optimized_struct], opt_params)
res = sa.analysis()
# plot analysis history
report_viz(res)
# plot initial and best structure
sv = StructVizualizer()
sv.plot_structure(res[1][0])
sv.plot_structure(res[1][1])
plt.show(block=True)
# animated history of structures during SA
gm = GIFMaker()
for st in tqdm(res[1]):
gm.create_frame(st, {'sa': st.fitness})
gm.make_gif('sa individuals', 500)
3 changes: 2 additions & 1 deletion docs/source/tutorials/tuning.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ Here we will take a closer look at several ``TunerParams`` attributes which may

*
``hyperopt_dist`` is the type of distribution from which random values will be taken during tuning. Available values are names of `hpyeropt hp module finctions <https://github.com/hyperopt/hyperopt/blob/master/hyperopt/hp.py>`_.
**Note**: in GOLEM 0.4.0 part of tuners does not converts bounds into mu and sigma. Use 'uniform' to avoid invalid intervals.

*
``variance_generator`` is function that generates bounds of intervals from which random values should pe picked for all components of all point in structure. If normal distribution set they will be automatically converted into means and varicances.

``verage_edge_variance`` function setes variance to 50% of average edge length for each polygon. This solution can be much more "greedy" than necessary, which can lead to many invalid intermediate variants during tuning. To improve fitness in fewer tuning steps, it is worth creating variance generation functions for selecting smaller intervals based on the conditions of a specific task.
``percent_edge_variance`` function setes variance to spicific percent of average edge length for each polygon. This solution can be much more "greedy" than necessary, which can lead to many invalid intermediate variants during tuning. To improve fitness in fewer tuning steps, it is worth creating variance generation functions for selecting smaller intervals based on the conditions of a specific task.

Now that the ``OptimizationParams`` have been defined and some structures have been created, we can run tuning with couple lines of code:

Expand Down
4 changes: 2 additions & 2 deletions gefest/core/opt/adapters/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


class StructureFactory(RandomGraphFactory):
"""Simple GEFEST sampler wrap for GOLEM RandomGraphFactory compatibility."""
"""GOLEM RandomGraphFactory version of GEFEST sampler."""

def __init__(
self,
Expand All @@ -19,4 +19,4 @@ def __init__(
def __call__(self, *args, **kwargs) -> OptGraph:
"""Generates ranom GOLEM graph."""
samples = self.sampler(1)
return self.adapter(samples[0])
return self.adapter.adapt(samples[0])
8 changes: 7 additions & 1 deletion gefest/core/opt/objective/objective_eval.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from typing import Union

from golem.utilities.data_structures import ensure_wrapped_in_sequence

from gefest.core.geometry.datastructs.structure import Structure
from gefest.core.opt.objective.objective import Objective
from gefest.core.utils import where
Expand All @@ -20,10 +24,12 @@ def __init__(

def __call__(
self,
pop: list[Structure],
pop: Union[list[Structure], Structure],
**kwargs,
) -> list[Structure]:
"""Calls objectives evaluation."""
pop = ensure_wrapped_in_sequence(pop)

return self.set_pop_objectives(pop=pop)

def set_pop_objectives(
Expand Down

0 comments on commit a91c4ef

Please sign in to comment.