Skip to main content

UML Energy & Combustion Research Laboratory

ECabc: optimization algorithm for tuning user-defined parametric functions

GitHub version PyPI version GitHub license CI DOI

ECabc is an open source Python package used to tune parameters for user-supplied functions based on the Artificial Bee Colony by D. Karaboğa. ECabc optimizes user supplied functions, or fitness functions, using a set of variables that exist within a search space. The bee colony consists of three types of bees: employers, onlookers and scouts. An employer bee exploits a solution comprised of a permutation of the variables in the search space, and evaluates the viability of the solution. An onlooker bee chooses an employer bee with an optimal solution and searches for new solutions near them. The scout bee, a variant of the employer bee, will search for a new solution if it has stayed too long at its current solution.

Research applications

While it has several applications, ECabc has been successfully used by the Energy and Combustion Research Laboratory (ECRL) at the University of Massachusetts Lowell to tune the hyperparameters of ECNet, an open source Python package tailored to predicting fuel properties. ECNet provides scientists an open source tool for predicting key fuel properties of potential next-generation biofuels, reducing the need for costly fuel synthesis and experimentation. By increasing the accuracy of ECNet and similar models efficiently, ECabc helps to provide a higher degree of confidence in discovering new, optimal fuels. A single run of ECabc on ECNet yielded a lower average root mean square error (RMSE) for cetane number (CN) and yield sooting index (YSI) when compared to the RMSE generated by a year of manual tuning. While the manual tuning generated an RMSE of 10.13, the ECabc was able to yield an RMSE of 8.06 in one run of 500 iterations.

Installation

Requires Python 3.10 or newer. ECabc has no runtime third-party dependencies (stdlib only). A virtual environment is recommended.

Method 1: pip

pip install ecabc

To upgrade to the latest release:

pip install --upgrade ecabc

Method 2: From source

Clone or download this repository, then from the repository root:

pip install .

Usage

API stability for the public surface is documented in API_STABILITY.md (also the Sphinx API stability policy page under docs/source/stability.rst).

To start using ECabc, you need a couple items:

  • a fitness function (cost function) to optimize
  • parameters used by the fitness function

For example, let's define a fitness function to minimize the sum of three integers:

def minimize_integers(integers):

    return sum(integers)

Your fitness function must accept a list from ECabc. The list values represent the current "food source", i.e. parameter values, being exploited by a given bee.

Now that we have our fitness function, let's import the ABC object from ECabc, initialize the artificial bee colony, and add our parameters:

from ecabc import ABC

def minimize_integers(integers):

    return sum(integers)

abc = ABC(10, minimize_integers)
abc.add_param(0, 10, name='Int_1')
abc.add_param(0, 10, name='Int_2')
abc.add_param(0, 10, name='Int_3')

Here we initialize the colony with 10 employer bees, supply our fitness function, and add our parameters. Parameters are added with minimum/maximum values for its search space and optionally a name. By default, parameter mutations (searching a neighboring food source) will not exceed the specified parameter bounds [min_val, max_val]; if this limitation is not desired, supply the "restrict=False" argument:

abc.add_param(0, 10, restrict=False, name='Int_1')

Once we have created our colony and added our parameters, we then need to "initialize" the colony's bees:

from ecabc import ABC

def minimize_integers(integers):

    return sum(integers)

abc = ABC(10, minimize_integers)
abc.add_param(0, 10, name='Int_1')
abc.add_param(0, 10, name='Int_2')
abc.add_param(0, 10, name='Int_3')
abc.initialize()

Initializing the colony's bees deploys employer bees (in this example, 10 bees) to random food sources (random parameter values are generated), their fitness is evaluated (in this example, lowest sum is better), and onlooker bees (equal to the number of employers) are deployed proportionally to neighboring food sources of well-performing bees.

We then send the colony through a predetermined of "search cycles":

from ecabc import ABC

def minimize_integers(integers):

    return sum(integers)

abc = ABC(10, minimize_integers)
abc.add_param(0, 10, name='Int_1')
abc.add_param(0, 10, name='Int_2')
abc.add_param(0, 10, name='Int_3')
abc.initialize()
for _ in range(10):
    abc.search()

A search cycle consists of:

  • each bee searches a neighboring food source (performs a mutation on one parameter)
  • if the food source produces a better fitness than the bee's current food source, move there
  • otherwise, the bee stays at its current food source
    • if the bee has stayed for (NE * D) cycles (NE = number of employers, D = dimension of the function, 3 in our example), abandon the food source
      • if the bee is an employer, go to a new random food source
      • if the bee is an onlooker, go to a food source neighboring a well-performing bee

We can access the colony's average fitness score, average fitness function return value, best fitness score, best fitness function return value and best parameters at any time:

print(abc.average_fitness)
print(abc.average_ret_val)
print(abc.best_fitness)
print(abc.best_ret_val)
print(abc.best_params)

ECabc can utilize multiple CPU cores for concurrent processing:

abc = ABC(10, minimize_integers, num_processes=8)

Tying everything together, we have:

from ecabc import ABC

def minimize_integers(integers):

    return sum(integers)

abc = ABC(10, minimize_integers)
abc.add_param(0, 10, name='Int_1')
abc.add_param(0, 10, name='Int_2')
abc.add_param(0, 10, name='Int_3')
abc.initialize()
for _ in range(10):
    abc.search()
    print('Average fitness: {}'.format(abc.average_fitness))
    print('Average obj. fn. return value: {}'.format(abc.average_ret_val))
    print('Best fitness score: {}'.format(abc.best_fitness))
    print('Best obj. fn. return value: {}'.format(abc.best_ret_val))
    print('Best parameters: {}\n'.format(abc.best_params))

Running this script produces:

Average fitness: 0.08244866244866243
Average obj. fn. return value: 11.65
Best fitness score: 0.125
Best obj. fn. return value: 7
Best parameters: {'Int_1': 4, 'Int_2': 3, 'Int_3': 0}

Average fitness: 0.0885855117105117
Average obj. fn. return value: 10.8
Best fitness score: 0.125
Best obj. fn. return value: 7
Best parameters: {'Int_1': 4, 'Int_2': 3, 'Int_3': 0}

Average fitness: 0.10361832611832611
Average obj. fn. return value: 9.4
Best fitness score: 0.16666666666666666
Best obj. fn. return value: 5
Best parameters: {'Int_1': 2, 'Int_2': 3, 'Int_3': 0}

Average fitness: 0.11173502151443326
Average obj. fn. return value: 8.8
Best fitness score: 0.2
Best obj. fn. return value: 4
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 4}

Average fitness: 0.12448879551820731
Average obj. fn. return value: 7.95
Best fitness score: 0.2
Best obj. fn. return value: 4
Best parameters: {'Int_1': 1, 'Int_2': 3, 'Int_3': 0}

Average fitness: 0.1767694805194805
Average obj. fn. return value: 6.7
Best fitness score: 1.0
Best obj. fn. return value: 0
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 0}

Average fitness: 0.183255772005772
Average obj. fn. return value: 6.3
Best fitness score: 1.0
Best obj. fn. return value: 0
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 0}

Average fitness: 0.20172799422799423
Average obj. fn. return value: 5.65
Best fitness score: 1.0
Best obj. fn. return value: 0
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 0}

Average fitness: 0.23827561327561328
Average obj. fn. return value: 4.95
Best fitness score: 1.0
Best obj. fn. return value: 0
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 0}

Average fitness: 0.28456349206349213
Average obj. fn. return value: 4.35
Best fitness score: 1.0
Best obj. fn. return value: 0
Best parameters: {'Int_1': 0, 'Int_2': 0, 'Int_3': 0}

To run this script yourself, head over to our examples directory.

Contributing, Reporting Issues and Other Support:

To contribute to ECabc, make a pull request. Contributions should include tests for new features added, as well as extensive documentation.

To report problems with the software or feature requests, file an issue. When reporting problems, include information such as error messages, your OS/environment and Python version.

For additional support/questions, contact Sanskriti Sharma (Sanskriti_Sharma@student.uml.edu), Hernan Gelaf-Romer (Hernan_Gelafromer@student.uml.edu), or Travis Kessler (Travis_Kessler@student.uml.edu).

Metadata

Release files for ecabc 3.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ecabc 3.0.2
File Size Uploaded Provenance Actions
ecabc-3.0.2.tar.gz 17.7 kB Without provenance Details for ecabc-3.0.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ecabc 3.0.2
File Interpreter ABI Platform Actions
ecabc-3.0.2-py3-none-any.whl Python 3 none any Details for ecabc-3.0.2-py3-none-any.whl

Total release size: 29.9 kB

Release files / ecabc-3.0.2.tar.gz

Download URL ecabc-3.0.2.tar.gz
Size 17.7 kB
Tags Source
SHA-256 checksum
How to use checksums
f85be4a66e5ec9f0d74228137b188953f45cf9f77bb027f2ddfe304d57b0040d
BLAKE2b-256 checksum
How to use checksums
b7b3983216db31b82431481988061bb844330247b0ec1d5646e1a017b27a75c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / ecabc-3.0.2-py3-none-any.whl

Download URL ecabc-3.0.2-py3-none-any.whl
Size 12.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c81f79f31bd114b3197a48b1df51f4fb6f5fc1f64dd0ff09bdffd4054afccc3d
BLAKE2b-256 checksum
How to use checksums
b81be66116af1ab20068af63167b417e0bd32135247935dfda8d8974a0e69538
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Security for ecabc 3.0.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page