Skip to content

Commit 5d42dee

Browse files
committed
Merge branch 'dev' into main
2 parents b0ec0d7 + 0a8709e commit 5d42dee

13 files changed

+744
-9
lines changed

README.md

+16
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@ Ruck aims to fill the following criteria:
4040
2. Be easily **extensible** and **debuggable**.
4141
3. Performant while maintaining its simplicity.
4242

43+
## Features
44+
45+
Ruck has various features that will be expanded upon in time
46+
- 📦 Modular evolutionary systems inspired by pytorch lightning
47+
+ Helps organise code & arguably looks clean
48+
49+
- ➕ Multi-Objective optimisation support
50+
+ Optionally optimised version of NSGA-II if `numba` is installed, over 65x faster
51+
52+
- 🏎 Optional multithreading support with `ray`, including helper functions
53+
54+
- 🏭 Factory methods for simple evolutionary algorithms
55+
56+
- 🧪 Various helper functions for selection, mutation and mating
57+
58+
4359
## Citing Ruck
4460

4561
Please use the following citation if you use Ruck in your research:

examples/multiobjective.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from matplotlib import pyplot as plt
2626

2727
from ruck import *
28-
from ruck.external.deap import select_nsga2
28+
from ruck.functional import select_nsga2
2929

3030

3131
class MultiObjectiveMinimalModule(EaModule):

requirements-all.txt

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ pip>=21.0
22
numpy>=1.19
33
tqdm>=4
44

5+
# optional for performance improvements
6+
numba>=0.40.0
7+
58
# requirements needed for examples too
69
ray>=1.6.0
710
deap>=1.3

ruck/external/_numba.py

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
2+
# MIT License
3+
#
4+
# Copyright (c) 2021 Nathan Juraj Michlo
5+
#
6+
# Permission is hereby granted, free of charge, to any person obtaining a copy
7+
# of this software and associated documentation files (the "Software"), to deal
8+
# in the Software without restriction, including without limitation the rights
9+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
# copies of the Software, and to permit persons to whom the Software is
11+
# furnished to do so, subject to the following conditions:
12+
#
13+
# The above copyright notice and this permission notice shall be included in
14+
# all copies or substantial portions of the Software.
15+
#
16+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
# SOFTWARE.
23+
# ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
24+
25+
26+
# ========================================================================= #
27+
# Timer #
28+
# ========================================================================= #
29+
30+
31+
def optional_njit(*args, cache=True, **kwargs):
32+
"""
33+
Optionally apply the numba JIT to a function if numba is installed.
34+
- Additionally by default sets the cache=True value on
35+
the JIT functions so that startup times are faster!
36+
"""
37+
38+
def _decorator(fn):
39+
# try import numba
40+
try:
41+
import numba
42+
except ImportError:
43+
import warnings
44+
warnings.warn(f'Performance of {fn.__name__} will be slow. Skipping JIT compilation because numba is not installed!')
45+
numba = None
46+
# handle cases
47+
if numba is not None:
48+
fn = numba.njit(*args, cache=cache, **kwargs)(fn)
49+
# done!
50+
return fn
51+
# return decorator
52+
return _decorator
53+
54+
55+
# ========================================================================= #
56+
# lists #
57+
# ========================================================================= #

ruck/external/deap.py

+18-3
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,44 @@
2222
# SOFTWARE.
2323
# ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
2424

25+
import warnings
2526
from typing import Optional
26-
from typing import Tuple
27+
from typing import Sequence
28+
2729
from ruck.functional import check_selection
2830

2931

3032
try:
3133
import deap
3234
except ImportError as e:
33-
import warnings
3435
warnings.warn('failed to import deap, please install it: $ pip install deap')
3536
raise e
3637

38+
3739
# ========================================================================= #
3840
# deap helper #
3941
# ========================================================================= #
4042

4143

44+
# CONFIG: | JIT: | PYTHON:
45+
# (in=0008 out=0004) | [OLD: 0.000176 NEW: 0.000156s SPEEDUP: 1.126655x] | [OLD: 0.000139 NEW: 0.000198s SPEEDUP: 0.699888x]
46+
# (in=0064 out=0032) | [OLD: 0.002818 NEW: 0.000316s SPEEDUP: 8.913371x] | [OLD: 0.002732 NEW: 0.003151s SPEEDUP: 0.867194x]
47+
# (in=0256 out=0128) | [OLD: 0.040459 NEW: 0.001258s SPEEDUP: 32.161621x] | [OLD: 0.038630 NEW: 0.045156s SPEEDUP: 0.855490x]
48+
# (in=1024 out=0512) | [OLD: 0.672029 NEW: 0.010862s SPEEDUP: 61.872225x] | [OLD: 0.644428 NEW: 0.768074s SPEEDUP: 0.839018x]
49+
# (in=4096 out=2048) | [OLD: 10.511867 NEW: 0.158704s SPEEDUP: 66.235660x] | [OLD: 10.326754 NEW: 12.973584s SPEEDUP: 0.795983x]
50+
51+
4252
@check_selection
43-
def select_nsga2(population, num_offspring: int, weights: Optional[Tuple[float, ...]] = None):
53+
def select_nsga2(population, num_offspring: int, weights: Optional[Sequence[float]] = None):
4454
"""
4555
This is hacky... ruck doesn't yet have NSGA2
4656
support, but we will add it in future!
4757
"""
58+
# this function has been deprecated
59+
warnings.warn('`ruck.external.deap.select_nsga2` has been deprecated in favour of `ruck.functional.select_nsga2`. `ruck.external.deap` will be removed in version v0.3.0')
60+
# checks
61+
if num_offspring == 0:
62+
return []
4863
# get a fitness value to perform checks
4964
f = population[0].fitness
5065
# check fitness

ruck/functional/__init__.py

+17-3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,23 @@
2222
# SOFTWARE.
2323
# ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~
2424

25-
from ruck.functional._mate import *
26-
from ruck.functional._mutate import *
27-
from ruck.functional._select import *
25+
from ruck.functional._mate import check_mating
26+
from ruck.functional._mate import mate_crossover_1d
27+
from ruck.functional._mate import mate_crossover_nd
28+
29+
from ruck.functional._mutate import check_mutation
30+
from ruck.functional._mutate import mutate_flip_bits
31+
from ruck.functional._mutate import mutate_flip_bit_groups
32+
33+
from ruck.functional._select import check_selection
34+
from ruck.functional._select import select_best
35+
from ruck.functional._select import select_worst
36+
from ruck.functional._select import select_random
37+
from ruck.functional._select import select_tournament
38+
39+
from ruck.functional._select_nsga import select_nsga2
40+
from ruck.functional._select_nsga import argsort_non_dominated
41+
from ruck.functional._select_nsga import compute_crowding_distances
2842

2943
# helper -- should be replaced
3044
from ruck.functional._algorithm import *

ruck/functional/_algorithm.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
from ruck._member import Member
3333
from ruck._member import Population
34-
from ruck.functional import SelectFnHint
34+
from ruck.functional._select import SelectFnHint
3535
from ruck.functional._mate import MateFnHint
3636
from ruck.functional._mutate import MutateFnHint
3737
from ruck.util._iter import chained

0 commit comments

Comments
 (0)