├── .gitignore ├── LICENSE.txt ├── MANIFEST ├── README.md ├── doc ├── reference │ ├── Makefile │ ├── README │ └── source │ │ ├── .templates │ │ ├── index.html │ │ ├── indexsidebar.html │ │ └── layout.html │ │ ├── api.rst │ │ ├── conf.py │ │ ├── contents.rst │ │ ├── installation.rst │ │ ├── opal.rst │ │ ├── sphinxext │ │ ├── inheritance_diagram.py │ │ ├── ipython_console_highlighting.py │ │ └── mathjax.py │ │ └── tutorial.rst └── technical-report │ ├── analysis-design.pdf │ └── analysis-design.tex ├── examples ├── coopsort │ ├── benchmark_algorithms.py │ ├── cleanup │ ├── coopsort.py │ ├── coopsort_declaration.py │ ├── coopsort_optimize.py │ ├── coopsort_optimize_surrogate.py │ ├── coopsort_run.py │ ├── generate_performance_profiles.py │ ├── sort.py │ ├── test.py │ ├── test_coopsort.py │ ├── test_generate_list.py │ ├── test_sort.py │ └── transform_iteration_log.py ├── dfo │ ├── dfo_declaration.py │ ├── dfo_optimize.py │ └── dfo_run.py ├── fd │ ├── README.rst │ ├── fd.py │ ├── fd_declaration.py │ ├── fd_optimize.py │ ├── fd_run.py │ └── test_fd.py ├── ipopt │ ├── ipopt_composite_measures.py │ ├── ipopt_declaration.py │ ├── ipopt_optimize.py │ ├── ipopt_run.py │ └── ipopt_test_problems.py ├── test_examples.py └── trunk │ ├── test_trunk.py │ ├── trunk_declaration.py │ ├── trunk_optimize.py │ ├── trunk_optimize_lsf.py │ ├── trunk_optimize_mpi.py │ ├── trunk_optimize_opalmpi.py │ ├── trunk_optimize_opalsmp_nomadmpi.py │ ├── trunk_optimize_surrogate.py │ └── trunk_run.py ├── nosetests.py ├── opal ├── Platforms │ ├── __init__.py │ ├── linux.py │ ├── lsf.py │ ├── mpi.py │ ├── smp.py │ ├── sungrid.py │ └── test_platforms.py ├── Solvers │ ├── __init__.py │ └── nomad.py ├── TestProblemCollections │ ├── CUTEr.data │ ├── CUTEr.py │ ├── __init__.py │ └── cuterfactory.py ├── __init__.py ├── config.py ├── core │ ├── __init__.py │ ├── algorithm.py │ ├── data.py │ ├── datagenerator.py │ ├── datamanager.py │ ├── experimentmanager.py │ ├── io.py │ ├── log.py │ ├── mafrw.py │ ├── measure.py │ ├── model.py │ ├── modeldata.py │ ├── modelevaluator.py │ ├── modelstructure.py │ ├── opalproblem.py │ ├── parameter.py │ ├── platform.py │ ├── savablefunction.py │ ├── set.py │ ├── solver.py │ ├── statsmeasure.py │ ├── structureevaluator.py │ ├── test_core.py │ ├── testproblem.py │ └── tools.py └── test_opal.py ├── setup.py └── test.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.py~ 3 | *~ 4 | build 5 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | README 2 | setup.py 3 | paropt/__init__.py 4 | paropt/Algorithms/DFO.py 5 | paropt/Algorithms/__init__.py 6 | paropt/Drivers/DFO.py 7 | paropt/Drivers/__init__.py 8 | paropt/Measures/__init__.py 9 | paropt/Measures/basics.py 10 | paropt/Platforms/LINUX.py 11 | paropt/Platforms/LSF.py 12 | paropt/Platforms/__init__.py 13 | paropt/Solvers/NOMAD.py 14 | paropt/Solvers/__init__.py 15 | paropt/TestProblemCollections/CUTEr.py 16 | paropt/TestProblemCollections/__init__.py 17 | paropt/core/__init__.py 18 | paropt/core/algorithm.py 19 | paropt/core/blackbox.py 20 | paropt/core/driver.py 21 | paropt/core/measure.py 22 | paropt/core/optmodel.py 23 | paropt/core/parameter.py 24 | paropt/core/paramopt.py 25 | paropt/core/platform.py 26 | paropt/core/poproblem.py 27 | paropt/core/popsolver.py 28 | paropt/core/posolver.py 29 | paropt/core/solver.py 30 | paropt/core/test.py 31 | paropt/core/testproblem.py 32 | paropt/core/utility.py 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OPAL—A Framework for Optimization of Algorithms 2 | 3 | ## What is OPAL? 4 | 5 | OPAL is a Python modeling language for algorithmic optimization. Most 6 | algorithms depend on parameters. Although changing the values of those 7 | parameters doesn't affect the correctness of the algorithm, it typically 8 | affects its performance, where *performance* is understood broadly. How can we 9 | best choose those parameter values so as to maximize a certain measure of 10 | performance? 11 | 12 | OPAL is a framework that allows to easily declare algorithms and the parameters 13 | on which they depend along with representative test cases. It provides a 14 | convenient syntax to formulate the optimization problem to be solved. A 15 | black-box optimization solver takes care of the rest. 16 | 17 | ## Requirements 18 | 19 | + Python version 2.6 or 2.7 (not tested with 3.x) 20 | + [NOMAD](http://www.gerad.ca/NOMAD) 21 | 22 | ## Install 23 | 24 | + Unzip the package or clone the git repository 25 | + Go to the source directory 26 | + Run `python setup.py install` 27 | 28 | ## Testing 29 | 30 | To run the following test, [Numpy](http://www.numpy.org) is required. Install 31 | it with `pip install numpy`. 32 | 33 | Assuming your `PYTHONPATH` is set correctly, you should be able to do: 34 | 35 | cd examples/fd 36 | python fd_optimize.py 37 | 38 | ## References 39 | 40 | + [Optimization of Algorithms with OPAL](http://dx.doi.org/10.1007/s12532-014-0067-x) 41 | + [Templating and Automatic Code Generation for Performance with Python](https://gerad.ca/en/papers/G-2011-30/view) 42 | + [Taking Advantage of Parallelism in Algorithmic Parameter Optimization](http://dx.doi.org/10.1007/s11590-011-0428-6) 43 | + [Algorithmic Parameter Optimization of the DFO Method with the OPAL Framework](http://dx.doi.org/10.1007/978-1-4419-6935-4_15) 44 | 45 | ## Licensing 46 | 47 | [![LGPL-3.0](http://www.gnu.org/graphics/lgplv3-88x31.png)](http://www.gnu.org/licenses/lgpl-3.0.html) 48 | -------------------------------------------------------------------------------- /doc/reference/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " singlehtml to make a single large HTML file" 22 | @echo " pickle to make pickle files" 23 | @echo " json to make JSON files" 24 | @echo " htmlhelp to make HTML files and a HTML help project" 25 | @echo " qthelp to make HTML files and a qthelp project" 26 | @echo " devhelp to make HTML files and a Devhelp project" 27 | @echo " epub to make an epub" 28 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 29 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 30 | @echo " text to make text files" 31 | @echo " man to make manual pages" 32 | @echo " changes to make an overview of all changed/added/deprecated items" 33 | @echo " linkcheck to check all external links for integrity" 34 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 35 | 36 | clean: 37 | -rm -rf $(BUILDDIR)/* 38 | 39 | html: 40 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 41 | @echo 42 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 43 | 44 | dirhtml: 45 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 48 | 49 | singlehtml: 50 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 51 | @echo 52 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 53 | 54 | pickle: 55 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 56 | @echo 57 | @echo "Build finished; now you can process the pickle files." 58 | 59 | json: 60 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 61 | @echo 62 | @echo "Build finished; now you can process the JSON files." 63 | 64 | htmlhelp: 65 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 66 | @echo 67 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 68 | ".hhp project file in $(BUILDDIR)/htmlhelp." 69 | 70 | qthelp: 71 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 72 | @echo 73 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 74 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 75 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bla.qhcp" 76 | @echo "To view the help file:" 77 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bla.qhc" 78 | 79 | devhelp: 80 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 81 | @echo 82 | @echo "Build finished." 83 | @echo "To view the help file:" 84 | @echo "# mkdir -p $$HOME/.local/share/devhelp/bla" 85 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bla" 86 | @echo "# devhelp" 87 | 88 | epub: 89 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 90 | @echo 91 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 92 | 93 | latex: 94 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 95 | @echo 96 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 97 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 98 | "(use \`make latexpdf' here to do that automatically)." 99 | 100 | latexpdf: 101 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 102 | @echo "Running LaTeX files through pdflatex..." 103 | make -C $(BUILDDIR)/latex all-pdf 104 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 105 | 106 | text: 107 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 108 | @echo 109 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 110 | 111 | man: 112 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 113 | @echo 114 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 115 | 116 | changes: 117 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 118 | @echo 119 | @echo "The overview file is in $(BUILDDIR)/changes." 120 | 121 | linkcheck: 122 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 123 | @echo 124 | @echo "Link check complete; look for any errors in the above output " \ 125 | "or in $(BUILDDIR)/linkcheck/output.txt." 126 | 127 | doctest: 128 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 129 | @echo "Testing of doctests in the sources finished, look at the " \ 130 | "results in $(BUILDDIR)/doctest/output.txt." 131 | -------------------------------------------------------------------------------- /doc/reference/README: -------------------------------------------------------------------------------- 1 | To build documentation in html format, use 'make html'. The entry point is in 2 | ./build/html/index.html. 3 | 4 | To build documentation in PDF format, use 'make latex'. Change directory to 5 | ./build/latex and use 'make all-pdf'. The documentation file is ParOpt.pdf. 6 | -------------------------------------------------------------------------------- /doc/reference/source/.templates/index.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% set title = 'Overview' %} 3 | {% block body %} 4 | 5 |

Welcome

6 | 7 |
8 |

What authors say:

9 |

“Enjoy trying a tool that optimizes an algorithm in a snap!”

10 |
11 | 12 |

13 | OPAL stands for Optimization of Algorithm. OPAL provides a framework in 14 | which algorithmic parameter optimization problems can be defined and solved 15 | in a programmatic way. 16 |

17 | 28 | 38 |

39 | OPAL is written in Python and uses Python as the language in which the parameter 40 | optimization problem is described. The procedure consists in three main steps: 41 | declare the target algorithm, define an optimization problem and choose a 42 | suitable solver. 43 |

44 | 45 |

Documentation

46 | 47 | 48 | 59 |
49 | 51 | 53 | 54 | 56 | 58 |
60 | 61 | 62 |

Examples

63 |

Links to some examples can be found in the 64 | Tutorial section. 65 |

66 | 67 |

Get OPAL

68 |

69 | OPAL is available 70 | here. 71 |

72 | 73 | {% endblock %} 74 | 75 | -------------------------------------------------------------------------------- /doc/reference/source/.templates/indexsidebar.html: -------------------------------------------------------------------------------- 1 | 5 | 6 |

Download

7 | {% if version.endswith('(hg)') %} 8 |

This documentation is for version {{ version }}, which is 9 | not released yet.

10 |

You can use it from the 11 | Mercurial repo or look for 12 | released versions in the Python 13 | Package Index.

14 | {% else %} 15 |

Current version: {{ version }}

16 |

Get OPAL's stable version 17 | , or browse the repository

18 |

Latest development version docs 19 | are also available.

20 | {% endif %} 21 | 22 |

Questions? Suggestions?

23 |
24 | 25 | 26 | 27 |

28 | 29 |

30 | 31 | 32 |

33 | 34 |

35 | 36 | 37 |

38 | 39 |
40 | 41 | 42 |
43 |
44 |

or write to us. 45 | -------------------------------------------------------------------------------- /doc/reference/source/.templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block extrahead %} 4 | {{ super() }} 5 | {%- if not embedded %} 6 | 10 | {%- endif %} 11 | {% endblock %} 12 | 13 | {% block rootrellink %} 14 |

  • OPAL home | 
  • 15 |
  • Documentation 16 | »
  • 17 | {% endblock %} 18 | 19 | {% block header %} 20 |
    21 | 22 |

    OPAL—Optimization of Algorithms

    23 | 24 |
    25 | {% endblock %} 26 | 27 | -------------------------------------------------------------------------------- /doc/reference/source/api.rst: -------------------------------------------------------------------------------- 1 | .. API Documentation 2 | 3 | ================= 4 | API Documentation 5 | ================= 6 | 7 | 8 | .. automodule:: opal 9 | 10 | -------------------------------------------------------------------------------- /doc/reference/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # opal documentation build configuration file, created by 4 | # sphinx-quickstart on Thu May 21 22:41:01 2009. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # The contents of this file are pickled, so don't put values in the namespace 9 | # that aren't pickleable (module imports are okay, they're removed automatically). 10 | # 11 | # Note that not all possible configuration values are present in this 12 | # autogenerated file. 13 | # 14 | # All configuration values have a default; values that are commented out 15 | # serve to show the default. 16 | 17 | import sys, os 18 | 19 | # If your extensions are in another directory, add it here. If the directory 20 | # is relative to the documentation root, use os.path.abspath to make it 21 | # absolute, like shown here. 22 | here=os.path.abspath('.') 23 | sys.path.append(here) 24 | sys.path.append('sphinxext') 25 | 26 | # Import support for ipython console session syntax highlighting (lives 27 | # in the sphinxext directory defined above) 28 | import ipython_console_highlighting 29 | import inheritance_diagram 30 | import mathjax 31 | 32 | # General configuration 33 | # --------------------- 34 | 35 | # Add any Sphinx extension module names here, as strings. They can be extensions 36 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 37 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest'] 38 | extensions += ['sphinx.ext.todo'] 39 | extensions += ['ipython_console_highlighting'] 40 | extensions += ['inheritance_diagram'] 41 | extensions += ['mathjax'] 42 | mathjax_path = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' 43 | 44 | todo_include_todos = True 45 | 46 | # Add any paths that contain templates here, relative to this directory. 47 | templates_path = ['.templates'] 48 | 49 | # The suffix of source filenames. 50 | source_suffix = '.rst' 51 | 52 | # The encoding of source files. 53 | source_encoding = 'utf-8' 54 | 55 | # The master toctree document. 56 | master_doc = 'contents' 57 | html_index = 'index.html' 58 | 59 | # General information about the project. 60 | project = u'opal' 61 | copyright = u'2009-2011, C. Audet, K. C. Dang, D. Orban' 62 | 63 | # The version info for the project you're documenting, acts as replacement for 64 | # |version| and |release|, also used in various other places throughout the 65 | # built documents. 66 | # 67 | # The short X.Y version. 68 | version = '1.3' 69 | # The full version, including alpha/beta/rc tags. 70 | release = '1.3' 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | #language = None 75 | 76 | # There are two options for replacing |today|: either, you set today to some 77 | # non-false value, then it is used: 78 | #today = '' 79 | # Else, today_fmt is used as the format for a strftime call. 80 | #today_fmt = '%B %d, %Y' 81 | 82 | # List of documents that shouldn't be included in the build. 83 | #unused_docs = [] 84 | 85 | # List of directories, relative to source directory, that shouldn't be searched 86 | # for source files. 87 | exclude_trees = [] 88 | 89 | # The reST default role (used for this markup: `text`) to use for all documents. 90 | #default_role = None 91 | 92 | # If true, '()' will be appended to :func: etc. cross-reference text. 93 | #add_function_parentheses = True 94 | 95 | # If true, the current module name will be prepended to all description 96 | # unit titles (such as .. function::). 97 | #add_module_names = True 98 | 99 | # If true, sectionauthor and moduleauthor directives will be shown in the 100 | # output. They are ignored by default. 101 | #show_authors = False 102 | 103 | # The name of the Pygments (syntax highlighting) style to use. 104 | pygments_style = 'sphinx' 105 | 106 | 107 | # Options for HTML output 108 | # ----------------------- 109 | 110 | html_theme = "sphinxdoc" 111 | 112 | # The style sheet to use for HTML and HTML Help pages. A file of that name 113 | # must exist either in Sphinx' static/ path, or in one of the custom paths 114 | # given in html_static_path. 115 | #html_style = 'default.css' 116 | #html_style = 'sphinxdoc.css' 117 | 118 | # The name for this set of Sphinx documents. If None, it defaults to 119 | # " v documentation". 120 | #html_title = None 121 | 122 | # A shorter title for the navigation bar. Default is the same as html_title. 123 | #html_short_title = None 124 | 125 | # The name of an image file (relative to this directory) to place at the top 126 | # of the sidebar. 127 | #html_logo = None 128 | 129 | # The name of an image file (within the static path) to use as favicon of the 130 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 131 | # pixels large. 132 | #html_favicon = None 133 | 134 | # Add any paths that contain custom static files (such as style sheets) here, 135 | # relative to this directory. They are copied after the builtin static files, 136 | # so a file named "default.css" will overwrite the builtin "default.css". 137 | #html_static_path = ['_static'] 138 | 139 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 140 | # using the given strftime format. 141 | #html_last_updated_fmt = '%b %d, %Y' 142 | 143 | # If true, SmartyPants will be used to convert quotes and dashes to 144 | # typographically correct entities. 145 | #html_use_smartypants = True 146 | 147 | # Custom sidebar templates, maps document names to template names. 148 | html_sidebars = { 149 | 'index' : ['indexsidebar.html', 150 | 'searchbox.html'] 151 | } 152 | 153 | # Additional templates that should be rendered to pages, maps page names to 154 | # template names. 155 | html_additional_pages = {'index': 'index.html'} 156 | 157 | # If false, no module index is generated. 158 | #html_use_modindex = True 159 | 160 | # If false, no index is generated. 161 | #html_use_index = True 162 | 163 | # If true, the index is split into individual pages for each letter. 164 | #html_split_index = False 165 | 166 | # If true, links to the reST sources are added to the pages. 167 | #html_show_sourcelink = True 168 | 169 | # If true, an OpenSearch description file will be output, and all pages will 170 | # contain a tag referring to it. The value of this option must be the 171 | # base URL from which the finished HTML is served. 172 | #html_use_opensearch = '' 173 | 174 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 175 | #html_file_suffix = '' 176 | 177 | # Output file base name for HTML help builder. 178 | htmlhelp_basename = 'opaldoc' 179 | 180 | 181 | # Options for LaTeX output 182 | # ------------------------ 183 | 184 | # The paper size ('letter' or 'a4'). 185 | latex_paper_size = 'letter' 186 | 187 | # The font size ('10pt', '11pt' or '12pt'). 188 | #latex_font_size = '10pt' 189 | 190 | # Grouping the document tree into LaTeX files. List of tuples 191 | # (source start file, target name, title, author, document class [howto/manual]). 192 | latex_documents = [ 193 | ('index', 'opal.tex', ur'OPAL Documentation', 194 | ur'C. Audet, K. C. Dang, D. Orban', 'manual'), 195 | ] 196 | 197 | # The name of an image file (relative to this directory) to place at the top of 198 | # the title page. 199 | #latex_logo = None 200 | 201 | # For "manual" documents, if this is true, then toplevel headings are parts, 202 | # not chapters. 203 | #latex_use_parts = False 204 | 205 | # Additional stuff for the LaTeX preamble. 206 | #latex_preamble = '' 207 | 208 | # Documents to append as an appendix to all manuals. 209 | #latex_appendices = [] 210 | 211 | # If false, no module index is generated. 212 | #latex_use_modindex = True 213 | -------------------------------------------------------------------------------- /doc/reference/source/contents.rst: -------------------------------------------------------------------------------- 1 | .. OPAL documentation master file, created by sphinx-quickstart on Thu May 21 22:41:01 2009. 2 | You can adapt this file completely to your liking, but it should at least 3 | contain the root `toctree` directive. 4 | 5 | .. _contents: 6 | 7 | ========================== 8 | OPAL General Documentation 9 | ========================== 10 | 11 | :Release: |version| 12 | :Date: |today| 13 | 14 | .. module:: opal 15 | 16 | This is the general documentation for OPAL, a pure Python package for 17 | the optimization of algorithmic parameters. 18 | 19 | Contents: 20 | 21 | .. toctree:: 22 | :numbered: 23 | :maxdepth: 2 24 | 25 | Installation 26 | Tutorial 27 | OPAL components description 28 | API 29 | 30 | .. TODO List 31 | ========= 32 | 33 | .. Add todo items in the sections of the documentation and they will appear 34 | .. here. 35 | 36 | .. 37 | .. todolist:: 38 | 39 | 40 | Indices and tables 41 | ================== 42 | 43 | * :ref:`genindex` 44 | * :ref:`modindex` 45 | * :ref:`search` 46 | 47 | -------------------------------------------------------------------------------- /doc/reference/source/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | OPAL is a Python package and can be easily installed with 6 | `distutils`. 7 | 8 | Requirements 9 | ============ 10 | 11 | Python version 2.6 or later is required. Previous versions may result in errors 12 | relating to the `import` statement. OPAL was not tested with Python 3k. 13 | 14 | OPAL uses NOMAD as default solver. A working NOMAD installation is not needed to 15 | install OPAL but is needed to run the simplest examples provided in the 16 | package. NOMAD can be downloaded from ``_. 17 | 18 | `Sphinx `_ if you intend to rebuild the documentation. 19 | 20 | Download and installation 21 | ========================= 22 | 23 | After downloading the OPAL source code, simply type:: 24 | 25 | shell$ python setup.py install 26 | 27 | If you do not have write permissions to the system-wide ``site-packages`` 28 | directory, a local ``site-packages`` should be provided when installing, e.g.:: 29 | 30 | shell$ python setup.py install --prefix=$LOCAL_PYTHON_DIR 31 | 32 | and the package will be installed in 33 | ``$LOCAL_PYTHON_DIR/lib/python-2.6/site-packages`` (assuming you are using 34 | Python 2.6) 35 | 36 | Documentation 37 | ============= 38 | 39 | The documentation can be rebuilt from source using Sphinx:: 40 | 41 | shell$ cd doc/reference 42 | shell$ make html 43 | 44 | The documentation is in `build/html`. 45 | -------------------------------------------------------------------------------- /doc/reference/source/opal.rst: -------------------------------------------------------------------------------- 1 | .. Description of objects. 2 | 3 | =========================== 4 | OPAL components description 5 | =========================== 6 | 7 | 8 | Core objects 9 | ============ 10 | 11 | .. automodule:: opal.core.data 12 | 13 | Data 14 | ---- 15 | 16 | .. autoclass:: Data 17 | :show-inheritance: 18 | :members: 19 | :inherited-members: 20 | :undoc-members: 21 | 22 | DataSet 23 | ------- 24 | 25 | .. autoclass:: DataSet 26 | :show-inheritance: 27 | :members: 28 | :inherited-members: 29 | :undoc-members: 30 | 31 | 32 | Basic objects 33 | ============= 34 | 35 | Parameter 36 | --------- 37 | 38 | .. inheritance-diagram:: opal.core.parameter 39 | 40 | .. automodule:: opal.core.parameter 41 | 42 | .. autoclass:: Parameter 43 | :show-inheritance: 44 | :members: 45 | :inherited-members: 46 | :undoc-members: 47 | 48 | .. autoclass:: ParameterSet 49 | :show-inheritance: 50 | :members: 51 | :inherited-members: 52 | :undoc-members: 53 | 54 | .. autoclass:: ParameterConstraint 55 | :show-inheritance: 56 | :members: 57 | :inherited-members: 58 | :undoc-members: 59 | 60 | 61 | 62 | Measure 63 | ------- 64 | 65 | .. inheritance-diagram:: opal.core.measure 66 | 67 | .. automodule:: opal.core.measure 68 | 69 | .. autoclass:: Measure 70 | :show-inheritance: 71 | :members: 72 | :inherited-members: 73 | :undoc-members: 74 | 75 | MeasureTable 76 | ------------ 77 | 78 | .. autoclass:: MeasureValueTable 79 | :show-inheritance: 80 | :members: 81 | :inherited-members: 82 | :undoc-members: 83 | 84 | Problem 85 | ------- 86 | 87 | .. inheritance-diagram:: opal.core.testproblem 88 | 89 | .. automodule:: opal.core.testproblem 90 | 91 | .. autoclass:: TestProblem 92 | :show-inheritance: 93 | :members: 94 | :inherited-members: 95 | :undoc-members: 96 | 97 | .. autoclass:: OptimizationTestProblem 98 | :show-inheritance: 99 | :members: 100 | :inherited-members: 101 | :undoc-members: 102 | 103 | .. Algorithm experiment description object 104 | .. ======================================= 105 | 106 | 107 | 108 | Parameter Optimization Problem Definition 109 | ========================================= 110 | 111 | In the OPAL framework, a parameter optimization model (shortly OPAL model) has 112 | the following components: 113 | 114 | #. A structure, which is a sort of optimization problem template, disconnected 115 | from any specifics such as the particular algorithm being tuned or the particular 116 | test set used to tune the parameters. An example of problem structure may 117 | be as simple as "minimize the total CPU time" or "maximize the throughput 118 | subject to network constraints." 119 | 120 | #. Data, which fills in the blanks and brings the model to life. Data, in a 121 | sense, instantiates the problem structure by populating it with the 122 | particular algorithm being tuned, the parameters being fine-tuned, the test 123 | set, etc. 124 | 125 | Instead of ``problem``, we will often use the term ``model`` and we will refer 126 | to its components as the ``model structure`` and ``model data``. 127 | 128 | Once the model structure and model data have been defined, we can put them 129 | together into a single composite object representing the parameter optimization 130 | problem. It is then referred to as a ``model``. 131 | 132 | 133 | Algorithm experiment 134 | -------------------- 135 | 136 | .. automodule:: opal.core.algorithm 137 | 138 | .. autoclass:: Algorithm 139 | :show-inheritance: 140 | :members: 141 | :inherited-members: 142 | :undoc-members: 143 | 144 | The most important ingredients of an algorithmic parameter optimization problem 145 | are: 146 | 147 | #. The algorithm to be fine tuned, 148 | #. The parameters to fine tune, 149 | #. The measures defining the performance criterion. 150 | 151 | In this section, we examine the basic ingredients in detail. 152 | 153 | ModelStructure 154 | -------------- 155 | 156 | .. automodule:: opal.core.modelstructure 157 | 158 | .. autoclass:: ModelStructure 159 | :show-inheritance: 160 | :members: 161 | :inherited-members: 162 | :undoc-members: 163 | 164 | ModelData 165 | --------- 166 | 167 | .. automodule:: opal.core.modeldata 168 | 169 | .. autoclass:: ModelData 170 | :show-inheritance: 171 | :members: 172 | :inherited-members: 173 | :undoc-members: 174 | 175 | Model 176 | ----- 177 | 178 | .. automodule:: opal.core.blackbox 179 | 180 | .. autoclass:: BlackBoxModel 181 | :show-inheritance: 182 | :members: 183 | :inherited-members: 184 | :undoc-members: 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /doc/reference/source/sphinxext/ipython_console_highlighting.py: -------------------------------------------------------------------------------- 1 | from pygments.lexer import Lexer, do_insertions 2 | from pygments.lexers.agile import PythonConsoleLexer, PythonLexer, \ 3 | PythonTracebackLexer 4 | from pygments.token import Comment, Generic 5 | from sphinx import highlighting 6 | import re 7 | 8 | line_re = re.compile('.*?\n') 9 | 10 | class IPythonConsoleLexer(Lexer): 11 | """ 12 | For IPython console output or doctests, such as: 13 | 14 | Tracebacks are not currently supported. 15 | 16 | .. sourcecode:: ipython 17 | 18 | In [1]: a = 'foo' 19 | 20 | In [2]: a 21 | Out[2]: 'foo' 22 | 23 | In [3]: print a 24 | foo 25 | 26 | In [4]: 1 / 0 27 | """ 28 | name = 'IPython console session' 29 | aliases = ['ipython'] 30 | mimetypes = ['text/x-ipython-console'] 31 | input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)") 32 | output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)") 33 | continue_prompt = re.compile(" \.\.\.+:") 34 | tb_start = re.compile("\-+") 35 | 36 | def get_tokens_unprocessed(self, text): 37 | pylexer = PythonLexer(**self.options) 38 | tblexer = PythonTracebackLexer(**self.options) 39 | 40 | curcode = '' 41 | insertions = [] 42 | for match in line_re.finditer(text): 43 | line = match.group() 44 | input_prompt = self.input_prompt.match(line) 45 | continue_prompt = self.continue_prompt.match(line.rstrip()) 46 | output_prompt = self.output_prompt.match(line) 47 | if line.startswith("#"): 48 | insertions.append((len(curcode), 49 | [(0, Comment, line)])) 50 | elif input_prompt is not None: 51 | insertions.append((len(curcode), 52 | [(0, Generic.Prompt, input_prompt.group())])) 53 | curcode += line[input_prompt.end():] 54 | elif continue_prompt is not None: 55 | insertions.append((len(curcode), 56 | [(0, Generic.Prompt, continue_prompt.group())])) 57 | curcode += line[continue_prompt.end():] 58 | elif output_prompt is not None: 59 | insertions.append((len(curcode), 60 | [(0, Generic.Output, output_prompt.group())])) 61 | curcode += line[output_prompt.end():] 62 | else: 63 | if curcode: 64 | for item in do_insertions(insertions, 65 | pylexer.get_tokens_unprocessed(curcode)): 66 | yield item 67 | curcode = '' 68 | insertions = [] 69 | yield match.start(), Generic.Output, line 70 | if curcode: 71 | for item in do_insertions(insertions, 72 | pylexer.get_tokens_unprocessed(curcode)): 73 | yield item 74 | 75 | highlighting.lexers['ipython'] = IPythonConsoleLexer() 76 | -------------------------------------------------------------------------------- /doc/reference/source/sphinxext/mathjax.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | sphinx.ext.mathjax 4 | ~~~~~~~~~~~~~~~~~~ 5 | 6 | Allow `MathJax `_ to be used to display math 7 | in Sphinx's HTML writer - requires the MathJax JavaScript library 8 | on your webserver/computer. 9 | 10 | Kevin Dunn, kgdunn@gmail.com, 3-clause BSD license. 11 | 12 | 13 | For background, installation details and support: 14 | 15 | https://bitbucket.org/kevindunn/sphinx-extension-mathjax 16 | 17 | """ 18 | from docutils import nodes 19 | from sphinx.application import ExtensionError 20 | from sphinx.ext.mathbase import setup_math as mathbase_setup 21 | 22 | def html_visit_math(self, node): 23 | self.body.append(self.starttag(node, 'span', '', CLASS='math')) 24 | self.body.append(self.builder.config.mathjax_inline[0] + \ 25 | self.encode(node['latex']) +\ 26 | self.builder.config.mathjax_inline[1] + '') 27 | raise nodes.SkipNode 28 | 29 | def html_visit_displaymath(self, node): 30 | self.body.append(self.starttag(node, 'div', CLASS='math')) 31 | if node['nowrap']: 32 | self.body.append(self.builder.config.mathjax_display[0] + \ 33 | node['latex'] +\ 34 | self.builder.config.mathjax_display[1]) 35 | self.body.append('') 36 | raise nodes.SkipNode 37 | 38 | parts = [prt for prt in node['latex'].split('\n\n') if prt.strip() != ''] 39 | for i, part in enumerate(parts): 40 | part = self.encode(part) 41 | if i == 0: 42 | # necessary to e.g. set the id property correctly 43 | if node['number']: 44 | self.body.append('(%s)' % 45 | node['number']) 46 | if '&' in part or '\\\\' in part: 47 | self.body.append(self.builder.config.mathjax_display[0] + \ 48 | '\\begin{split}' + part + '\\end{split}' + \ 49 | self.builder.config.mathjax_display[1]) 50 | else: 51 | self.body.append(self.builder.config.mathjax_display[0] + part + \ 52 | self.builder.config.mathjax_display[1]) 53 | self.body.append('\n') 54 | raise nodes.SkipNode 55 | 56 | def builder_inited(app): 57 | if not app.config.mathjax_path: 58 | raise ExtensionError('mathjax_path config value must be set for the ' 59 | 'mathjax extension to work') 60 | app.add_javascript(app.config.mathjax_path) 61 | 62 | def setup(app): 63 | mathbase_setup(app, (html_visit_math, None), (html_visit_displaymath, None)) 64 | app.add_config_value('mathjax_path', '', False) 65 | app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html') 66 | app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html') 67 | app.connect('builder-inited', builder_inited) 68 | 69 | -------------------------------------------------------------------------------- /doc/technical-report/analysis-design.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythonOptimizers/opal/b6e12bafe7210910a6df2a9b59829cde584153cb/doc/technical-report/analysis-design.pdf -------------------------------------------------------------------------------- /examples/coopsort/benchmark_algorithms.py: -------------------------------------------------------------------------------- 1 | from coopsort import CooperationTreeFactory, coopsort 2 | from coopsort import create_test_list, verify_sorted_list, benchmarkTime 3 | import sort 4 | import sys 5 | from inspect import isfunction 6 | 7 | coopTreeFactory = CooperationTreeFactory(name="test factory") 8 | 9 | coopTrees = {} 10 | 11 | coopTrees["quick sort"] = sort.quicksort 12 | coopTrees["quick sort mixed"] = sort.quicksort6 13 | coopTrees["quick sort non-recursive"] = sort.quicksort0 14 | coopTrees["merge sort"] = sort.mergesort 15 | coopTrees['heap sort'] = sort.heapsort 16 | #coopTrees["tim sort"] = sort.timsort 17 | 18 | benchmarkSpec = {'algorithms': {'coopsort 522': [5, 2, 2], 19 | 'coopsort 5522522': [5, 5, 2, 2, 5, 2, 2], 20 | 'coopsort 411': [4, 1, 1] 21 | }, 22 | 'lists': {'specs': [(8, 0.0125)], 23 | 'unit length': 20, 24 | 'number of list': 200 25 | }, 26 | 'testing': {'repeats': 100 27 | } 28 | } 29 | 30 | if len(sys.argv) > 1: 31 | f = open(sys.argv) 32 | benchmarkSpec = eval(f.read()) 33 | f.close() 34 | 35 | algorithms = benchmarkSpec['algorithms'] 36 | createAlgo = coopTreeFactory.createTree 37 | for algoName in algorithms: 38 | coopTrees[algoName] = createAlgo(name='coopsort', 39 | methodSequence=algorithms[algoName]) 40 | 41 | cpuTime = {} 42 | 43 | listSpecs = benchmarkSpec['lists']['specs'] 44 | listLenghUnit = benchmarkSpec['lists']['unit length'] 45 | numberOfList = benchmarkSpec['lists']['number of list'] 46 | numberOfRepeat = benchmarkSpec['testing']['repeats'] 47 | 48 | for listSpec in listSpecs: 49 | listType = str(listSpec) 50 | cpuTime[listType] = {} 51 | for name, coopTree in coopTrees.iteritems(): 52 | cpuTime[listType][name] = {} 53 | for k in range(numberOfList): 54 | n = listLengthUnit * (k + 1) 55 | l = create_test_list(listSpec, n, 0) 56 | for name, coopTree in coopTrees.iteritems(): 57 | meanTime = 0.0 58 | for r in range(numberOfRepeat): 59 | l1 = list(l) 60 | if isfunction(coopTree): 61 | tb = benchmarkTime() 62 | l1 = coopTree(l1) 63 | else: 64 | tb = benchmarkTime() 65 | l1 = coopsort(l1, coopTree.getRoot()) 66 | te = benchmarkTime() 67 | listIsSorted = verify_sorted_list(l1) 68 | if listIsSorted: 69 | meanTime = meanTime + (te - tb) 70 | else: 71 | raise Exception("There is a problem with " + name) 72 | del l1[:] 73 | del l1 74 | cpuTime[listType][name][n] = meanTime / numberOfRepeat 75 | print cpuTime 76 | -------------------------------------------------------------------------------- /examples/coopsort/cleanup: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm *.log 2> /dev/null 4 | rm *.dat* 2> /dev/null 5 | rm nomad*.txt 2> /dev/null 6 | rm blackbox.py 2> /dev/null 7 | rm neighbors.py 2> /dev/null 8 | rm surrogate.py 2> /dev/null 9 | 10 | if [[ $# > 0 && $1 == '-a' ]] 11 | then 12 | rm *.pyc 2> /dev/null 13 | rm iterations*.txt 2> /dev/null 14 | fi 15 | -------------------------------------------------------------------------------- /examples/coopsort/coopsort_declaration.py: -------------------------------------------------------------------------------- 1 | from opal.core.algorithm import Algorithm 2 | from opal.core.parameter import Parameter 3 | from opal.core.measure import Measure 4 | 5 | # Define new algorithm. 6 | coopsort = Algorithm(name='CoopSort', description='Sort Algorithm') 7 | 8 | # Register executable. 9 | coopsort.set_executable_command('python coopsort_run.py') 10 | 11 | # Define parameters. 12 | 13 | # The following coop tree amounts to 5522522 (in base 6.) 14 | coopsort.add_param(Parameter(name='coopTree', 15 | kind='categorical', 16 | default=275378, 17 | #default=284354431, 18 | description='Encoded cooperation tree')) 19 | 20 | # This dummy parameter is just there to circumvent a bug in NOMAD 21 | # that occurs when the problem has a single parameter and this parameter 22 | # is categorical. 23 | coopsort.add_param(Parameter(name='nothing', 24 | kind='integer', 25 | default=0, 26 | description='To avoid a bug in NOMAD')) 27 | 28 | coopsort.add_measure(Measure(name='TIME', 29 | kind='real', 30 | description='Computing time')) 31 | -------------------------------------------------------------------------------- /examples/coopsort/coopsort_optimize.py: -------------------------------------------------------------------------------- 1 | from coopsort_declaration import coopsort 2 | 3 | from opal import ModelStructure, ModelData, Model, MeasureFunction, TestProblem 4 | from opal.Solvers import NOMAD 5 | 6 | 7 | def sum_time(parameters, measures): 8 | val = sum(measures['TIME']) 9 | return val 10 | 11 | 12 | def get_neighbors(parameters): 13 | tmpStr = parameters[0] 14 | encodedNumber = tmpStr[0:tmpStr.find('.')] 15 | 16 | # Set of names for the leaf node 17 | s_s = ['0', '1', '2', '3'] 18 | # Set of names for the internal node 19 | s_d = ['4', '5'] 20 | # Neighborhood relation for a single node name 21 | n_s = {'0': ['2', '3'], 22 | '1': ['2', '3'], 23 | '2': ['0', '3'], 24 | '3': ['1', '2'], 25 | '4': ['5'], 26 | '5': ['4'] 27 | } 28 | # Initialize an empty list of neighbors 29 | neighbors = [] 30 | for i in range(len(encodedNumber)): 31 | c = encodedNumber[i] 32 | for n in n_s[c]: 33 | tmpStr = encodedNumber[0:i] + n + encodedNumber[i + 1:] 34 | 35 | # A neighbor is a parameter point 36 | neighbor = list(parameters) 37 | 38 | # Change value of the first coordinate of the parameter point 39 | neighbor[0] = int(float(tmpStr)) 40 | 41 | # Add the neighbor to the neighbor list 42 | neighbors.append(neighbor) 43 | 44 | if c in s_s: # Is is a leaf node 45 | for d in s_d: 46 | tmpStr = encodedNumber[0:i] + \ 47 | d + n_s[c][0] + n_s[c][1] + \ 48 | encodedNumber[i + 1:] 49 | neighbor = list(parameters) 50 | 51 | # Change value of the first coordinate of the parameter point 52 | neighbor[0] = int(float(tmpStr)) 53 | 54 | # Add the neighbor to the neighbor list 55 | neighbors.append(neighbor) 56 | 57 | elif i < len(encodedNumber) - 2: 58 | s_1 = encodedNumber[i + 1] 59 | s_2 = encodedNumber[i + 2] 60 | if (s_1 in s_s) and (s_2 in s_s): 61 | tmpStr = encodedNumber[0:i] + s_1 + encodedNumber[i + 3:] 62 | neighbor = list(parameters) 63 | neighbor[0] = int(float(tmpStr)) 64 | neighbors.append(neighbor) 65 | tmpStr = encodedNumber[0:i] + s_2 + encodedNumber[i + 3:] 66 | neighbor = list(parameters) 67 | neighbor[0] = int(float(tmpStr)) 68 | neighbors.append(neighbor) 69 | return neighbors 70 | 71 | problems = [] 72 | listTypes = [0, 5, 6, 7] 73 | numberOfList = 16 74 | listLengthStep = 25 75 | for listType in listTypes: 76 | for k in range(numberOfList): 77 | n = listLengthStep * (k + 1) 78 | probName = str(listType) + '-' + str(n) + '-50' 79 | problems.append(TestProblem(name=probName)) 80 | 81 | #SMP.set_parameter(name='MAX_PROC', value=5); 82 | 83 | # Define parameter optimization problem. 84 | data = ModelData(algorithm=coopsort, problems=problems) 85 | 86 | struct = ModelStructure(objective=MeasureFunction(sum_time), 87 | constraints=[], # Unconstrained 88 | neighborhood=get_neighbors) 89 | 90 | prob = Model(modelData=data, modelStructure=struct) 91 | 92 | # Solve parameter optimization problem. 93 | 94 | if __name__ == '__main__': 95 | from opal.Solvers import NOMAD 96 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=100) 97 | NOMAD.set_parameter(name='DISPLAY_DEGREE', value=4) 98 | NOMAD.set_parameter(name='EXTENDED_POLL_TRIGGER', value='r0.1') 99 | NOMAD.set_parameter(name='MAX_MESH_INDEX', value='2') 100 | NOMAD.set_parameter(name='MODEL_SEARCH_OPTIMISTIC', value='no') 101 | NOMAD.solve(blackbox=prob) 102 | -------------------------------------------------------------------------------- /examples/coopsort/coopsort_optimize_surrogate.py: -------------------------------------------------------------------------------- 1 | from coopsort_declaration import coopsort 2 | 3 | from opal import ModelStructure, ModelData, Model, MeasureFunction, TestProblem 4 | from opal.Solvers import NOMAD 5 | 6 | 7 | def sum_time(parameters, measures): 8 | val = sum(measures['TIME']) 9 | return val 10 | 11 | 12 | def get_neighbors(parameters): 13 | def encode(number, base=6): 14 | numberStr = '' 15 | if number == 0: 16 | return '0' 17 | while number > 0: 18 | (number, r) = divmod(number, base) 19 | numberStr = str(r) + numberStr 20 | return numberStr 21 | 22 | def decode(numberStr, base=6): 23 | invertedStr = numberStr[::-1] 24 | number = 0 25 | quotient = 1 26 | for c in invertedStr: 27 | number = number + int(c) * quotient 28 | quotient = quotient * base 29 | return number 30 | 31 | import logging 32 | logger = logging.getLogger(__name__) 33 | fh = logging.FileHandler('neighborhood.log') 34 | logger.setLevel(logging.INFO) 35 | fh.setLevel(logging.INFO) 36 | logger.addHandler(fh) 37 | encodedNumber = encode(int(float(parameters[0])), 6) 38 | logMessage = parameters[0] + ', ' + \ 39 | str(int(float(parameters[0]))) + ', ' + \ 40 | encodedNumber + ': ' 41 | # Set of names for the leaf node 42 | s_s = ['0', '1', '2', '3'] 43 | # Set of names for the internal node 44 | s_d = ['4', '5'] 45 | # Neighborhood relation for a single node name 46 | n_s = {'0': ['2', '3'], 47 | '1': ['2', '3'], 48 | '2': ['1', '3'], 49 | '3': ['1', '2'], 50 | '4': ['5'], 51 | '5': ['4'] 52 | } 53 | # Initialize an empty list of neighbors 54 | neighbors = [] 55 | for i in range(len(encodedNumber)): 56 | c = encodedNumber[i] 57 | for n in n_s[c]: 58 | tmpStr = encodedNumber[0:i] + n + encodedNumber[i + 1:] 59 | 60 | # A neighbor is a parameter point 61 | neighbor = list(parameters) 62 | 63 | # Change value of the first coordinate of the parameter point 64 | neighbor[0] = decode(tmpStr) 65 | logMessage = logMessage + tmpStr + ' -> ' + \ 66 | str(neighbor[0]) + ', ' 67 | 68 | # Add the neighbor to the neighbor list 69 | neighbors.append(neighbor) 70 | 71 | if c in s_s: # It is a leaf node 72 | for d in s_d: 73 | tmpStr = encodedNumber[0:i] + \ 74 | d + n_s[c][0] + n_s[c][1] + \ 75 | encodedNumber[i + 1:] 76 | neighbor = list(parameters) 77 | 78 | # Change value of the first coordinate of the parameter point 79 | neighbor[0] = decode(tmpStr) 80 | logMessage = logMessage + tmpStr + ' -> ' + \ 81 | str(neighbor[0]) + ', ' 82 | 83 | # Add the neighbor to the neighbor list 84 | neighbors.append(neighbor) 85 | 86 | elif i < len(encodedNumber) - 2: 87 | s_1 = encodedNumber[i + 1] 88 | s_2 = encodedNumber[i + 2] 89 | if (s_1 in s_s) and (s_2 in s_s): 90 | tmpStr = encodedNumber[0:i] + s_1 + encodedNumber[i + 3:] 91 | neighbor = list(parameters) 92 | neighbor[0] = decode(tmpStr) 93 | logMessage = logMessage + tmpStr + ' -> ' + \ 94 | str(neighbor[0]) + ', ' 95 | neighbors.append(neighbor) 96 | tmpStr = encodedNumber[0:i] + s_2 + encodedNumber[i + 3:] 97 | neighbor = list(parameters) 98 | neighbor[0] = decode(tmpStr) 99 | logMessage = logMessage + tmpStr + ' -> ' + \ 100 | str(neighbor[0]) + ', ' 101 | neighbors.append(neighbor) 102 | logger.info(logMessage + '\n') 103 | return neighbors 104 | 105 | problems = [] 106 | listSpecIndices = [1] 107 | numberOfList = 1 108 | listLengthStep = 4000 109 | numberOfRepetition = 100 110 | for listSpecIndex in listSpecIndices: 111 | for k in range(numberOfList): 112 | n = listLengthStep * (k + 1) 113 | probName = str(listSpecIndex) + \ 114 | '-' + str(n) + '-' + str(numberOfRepetition) 115 | problems.append(TestProblem(name=probName)) 116 | 117 | surrogate_problems = [] 118 | for listSpecIndex in listSpecIndices: 119 | for k in range(numberOfList): 120 | n = listLengthStep * (k + 1) 121 | probName = str(listSpecIndex) + \ 122 | '-' + str(n) + '-10' 123 | surrogate_problems.append(TestProblem(name=probName)) 124 | 125 | #SMP.set_parameter(name='MAX_PROC', value=5); 126 | 127 | # Define parameter optimization problem. 128 | data = ModelData(algorithm=coopsort, problems=problems) 129 | 130 | surrogate_data = ModelData(algorithm=coopsort, problems=surrogate_problems) 131 | 132 | struct = ModelStructure(objective=MeasureFunction(sum_time), 133 | constraints=[], # Unconstrained 134 | neighborhood=get_neighbors) 135 | 136 | prob = Model(modelData=data, modelStructure=struct) 137 | surrogate_prob = Model(modelData=surrogate_data, modelStructure=struct) 138 | 139 | # Solve parameter optimization problem. 140 | 141 | if __name__ == '__main__': 142 | from opal.Solvers import NOMAD 143 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=100) 144 | NOMAD.set_parameter(name='DISPLAY_DEGREE', value=1) 145 | NOMAD.set_parameter(name="DISPLAY_STATS", 146 | value="%3dEVAL %3dBBE %4dSGTE [ %15lSOL, ] %8.2eBBO %4.2fTIME") 147 | NOMAD.set_parameter(name="STATS_FILE", 148 | value="iterations.txt %3dEVAL %3dBBE %4dSGTE [ %15lSOL, ] %8.2eBBO %4.2fTIME") 149 | #NOMAD.set_parameter(name='EXTENDED_POLL_TRIGGER', value='r0.1') 150 | NOMAD.set_parameter(name='MAX_MESH_INDEX', value='2') 151 | NOMAD.solve(blackbox=prob, surrogate=surrogate_prob) 152 | -------------------------------------------------------------------------------- /examples/coopsort/coopsort_run.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | from opal.core.io import * 5 | from opal.core.tools import * 6 | 7 | from coopsort import CooperationTreeFactory, coopsort 8 | from coopsort import create_test_list, benchmarkTime 9 | import sort 10 | import random 11 | import time 12 | 13 | 14 | listSpecs = [(8, 1), (8, 0.0125)] 15 | 16 | 17 | def run(param_file, problem): 18 | probInfos = problem.split('-') 19 | listSpecIndex = int(probInfos[0]) 20 | if len(probInfos) > 1: 21 | listLength = int(probInfos[1]) 22 | else: 23 | listLength = 4000 24 | if len(probInfos) > 2: 25 | numberOfRepeat = int(probInfos[2]) 26 | else: 27 | numberOfRepeat = 1 28 | if len(probInfos) > 3: 29 | groupSize = int(probInfos[3]) 30 | else: 31 | groupSize = 1 32 | params = read_params_from_file(param_file) 33 | if int(params['nothing']) != 0: 34 | return {'TIME': float("inf")} 35 | 36 | coopTreeFactory = CooperationTreeFactory(name="test factory") 37 | try: 38 | treeEncodedNumber = int(params['coopTree']) 39 | except: 40 | treeEncodedNumber = int(float(params['coopTree'])) 41 | createTree = coopTreeFactory.createTreeFromEncodedNumber 42 | coopTree = createTree(name='coop tree', 43 | encodedNumber=treeEncodedNumber, 44 | radix=6) 45 | l = [] 46 | for g in range(groupSize): 47 | l.append(create_test_list(listSpecs[listSpecIndex], listLength, 0)) 48 | meanTime = 0.0 49 | for r in range(numberOfRepeat): 50 | sortingTime = 0.0 51 | for i in range(groupSize): 52 | l1 = list(l[i]) 53 | tb = benchmarkTime() 54 | try: 55 | l1 = coopsort(l1, coopTree.getRoot()) 56 | except: 57 | return {'TIME': float("inf")} 58 | te = benchmarkTime() 59 | sortingTime = sortingTime + (te - tb) 60 | del l1[:] 61 | del l1 62 | meanTime = meanTime + sortingTime 63 | 64 | measures = {'TIME': meanTime / numberOfRepeat} 65 | return measures 66 | 67 | 68 | if __name__ == '__main__': 69 | param_file = sys.argv[1] 70 | problem = sys.argv[2] 71 | output_file = sys.argv[3] 72 | 73 | # Solve, gather measures and write to file. 74 | param_file = os.path.abspath(param_file) 75 | measures = run(param_file, problem) 76 | write_measures_to_file(output_file, measures) 77 | -------------------------------------------------------------------------------- /examples/coopsort/generate_performance_profiles.py: -------------------------------------------------------------------------------- 1 | from coopsort import CooperationTreeFactory, coopsort 2 | from coopsort import create_test_list, benchmarkTime 3 | import sort 4 | import sys 5 | 6 | from inspect import isfunction 7 | 8 | coopTreeFactory = CooperationTreeFactory(name="test factory") 9 | 10 | coopTrees = {} 11 | coopTrees["quick sort"] = sort.quicksort6 12 | coopTrees["merge sort"] = sort.mergesort 13 | coopTrees["radix sort"] = sort.radixsort 14 | 15 | 16 | benchmarkSpec = {'algorithms': {'coopsort 522': [5, 2, 2], 17 | 'coopsort 5522522': [5, 5, 2, 2, 5, 2, 2], 18 | 'coopsort 411': [4, 1, 1] 19 | }, 20 | 'lists': {'specs': [(8, 0.0125)], 21 | 'unit length': 4000, 22 | 'number of list': 1000 23 | }, 24 | 'testing': {'repeats': 100 25 | } 26 | } 27 | 28 | if len(sys.argv) > 1: 29 | f = open(sys.argv) 30 | benchmarkSpec = eval(f.read()) 31 | f.close() 32 | 33 | algorithms = benchmarkSpec['algorithms'] 34 | createAlgo = coopTreeFactory.createTree 35 | for algoName in algorithms: 36 | coopTrees[algoName] = createAlgo(name='coopsort', 37 | methodSequence=algorithms[algoName]) 38 | 39 | listSpec = benchmarkSpec['lists']['specs'][0] 40 | listLengh = benchmarkSpec['lists']['unit length'] 41 | numberOfList = benchmarkSpec['lists']['number of list'] 42 | numberOfRepeat = benchmarkSpec['testing']['repeats'] 43 | 44 | cpuTime = {} 45 | profiles = {} 46 | for name, coopTree in coopTrees.iteritems(): 47 | profiles[name] = [] 48 | 49 | for i in range(numberOfList): 50 | l = create_test_list(listSpec, listLength, 0) 51 | minTime = float('inf') 52 | cpuTime = {} 53 | for name, coopTree in coopTrees.iteritems(): 54 | meanTime = 0.0 55 | for r in range(numberOfRepeat): 56 | l1 = list(l) 57 | if isfunction(coopTree): 58 | tb = benchmarkTime() 59 | l1 = coopTree(l1) 60 | else: 61 | tb = benchmarkTime() 62 | l1 = coopsort(l1, coopTree.getRoot()) 63 | te = benchmarkTime() 64 | del l1[:] 65 | del l1 66 | meanTime = meanTime + (te - tb) 67 | meanTime = meanTime / numberOfRepeat 68 | cpuTime[name] = meanTime 69 | if (meanTime < minTime): 70 | minTime = meanTime 71 | 72 | for name, t in cpuTime.iteritems(): 73 | profiles[name].append(t / minTime) 74 | 75 | percentage = [float(i + 1) / numberOfList for i in range(numberOfList)] 76 | 77 | for name, x in profiles.iteritems(): 78 | profiles[name] = (sorted(x), percentage) 79 | 80 | print profiles 81 | -------------------------------------------------------------------------------- /examples/coopsort/test.py: -------------------------------------------------------------------------------- 1 | from inspect import isfunction 2 | import sort 3 | import random 4 | import time 5 | 6 | N = 100000 7 | 8 | # Extract all functions from sort module. 9 | fcns = [val for key, val in sort.__dict__.iteritems() if isfunction(val)] 10 | 11 | # Time. 12 | for fcn in fcns: 13 | l = [int(N * random.random()) for i in xrange(N)] 14 | args = () 15 | if fcn.__name__ == 'bubblesort': 16 | continue 17 | if fcn.__name__ == 'countsort': 18 | args = (1+max(l),) 19 | t = time.clock() 20 | fcn(l, *args) 21 | t = time.clock() - t 22 | print '%15s %6.2f' % (fcn.__name__, t) 23 | -------------------------------------------------------------------------------- /examples/coopsort/test_coopsort.py: -------------------------------------------------------------------------------- 1 | from coopsort import CooperationTreeFactory, coopsort 2 | import sort 3 | import random 4 | import time 5 | 6 | N = 20 7 | 8 | # Extract all functions from sort module. 9 | #fcns = [val for key, val in sort.__dict__.iteritems() if isfunction(val)] 10 | 11 | # Time. 12 | #for fcn in fcns: 13 | 14 | coopTreeFactory = CooperationTreeFactory(name="test factory") 15 | 16 | coopTrees = {} 17 | coopTrees["quick sort"] = coopTreeFactory.createTree(name="quick sort", 18 | methodSequence=[2]) 19 | coopTrees["merge sort"] = coopTreeFactory.createTreeFromEncodedNumber(name="merge sort", 20 | encodedNumber=1) 21 | coopTrees["insertion sort"] = coopTreeFactory.createTree(name="insertion sort", 22 | methodSequence=[0]) 23 | coopTrees["radix sort"] = coopTreeFactory.createTree(name="radix sort", 24 | methodSequence=[3]) 25 | coopTrees['coop sort 1'] = coopTreeFactory.createTree(name='test tree 1', 26 | methodSequence=[4,2,3]) 27 | coopTrees['coop sort 2'] = coopTreeFactory.createTree(name='test tree 2', 28 | methodSequence=[4,4,2,3,3]) 29 | coopTrees['coop sort 3'] = coopTreeFactory.createTreeFromEncodedNumber(name='test tree 3', 30 | encodedNumber=45203) 31 | 32 | for name, coopTree in coopTrees.iteritems(): 33 | l = [int(N * random.random()) for i in xrange(N)] 34 | print "CoopSort with the tree:", coopTree._name 35 | t = time.clock() 36 | l = coopsort(l, coopTree.getRoot()) 37 | t = time.clock() - t 38 | #print "after sorting", l 39 | print 'Computing time: %6.2f second \n' % (t) 40 | -------------------------------------------------------------------------------- /examples/coopsort/test_generate_list.py: -------------------------------------------------------------------------------- 1 | from coopsort import create_test_list 2 | import sys 3 | 4 | if len(sys.argv) > 1: 5 | listSpecs = eval(sys.argv[1]) 6 | else: 7 | listSpecs = [[8, 0.0125]] 8 | if len(sys.argv) > 2: 9 | numberOfList = int(sys.argv[2]) 10 | else: 11 | numberOfList = 200 12 | if len(sys.argv) > 3: 13 | listLengthUnit = int(sys.argv[3]) 14 | else: 15 | listLengthUnit = 20 16 | 17 | generatedLists = {} 18 | for listSpec in listSpecs: 19 | listType = listSpec[0] 20 | for k in range(numberOfList): 21 | n = listLengthUnit * (k + 1) 22 | #for n in [250, 500, 750, 1000, 1250, 1500, 1750, 2000]: 23 | listName = str(listSpec) + 'l' + str(n) 24 | generatedLists[listName] = create_test_list(listSpec, n, 0) 25 | print generatedLists 26 | -------------------------------------------------------------------------------- /examples/coopsort/test_sort.py: -------------------------------------------------------------------------------- 1 | from inspect import isfunction 2 | import sort 3 | import random 4 | import time 5 | 6 | N = 10000 7 | 8 | # Extract all functions from sort module. 9 | fcns = [val for key, val in sort.__dict__.iteritems() if isfunction(val)] 10 | 11 | # Time. 12 | for fcn in fcns: 13 | #l = [int(N * random.random()) for i in xrange(N)] 14 | l = [i for i in xrange(N)] 15 | #l = [N - i for i in xrange(N)] 16 | args = () 17 | ignoredAlgorithms = ['bubblesort', 'insertionsort', 'selectionsort', 18 | 'quicksort2', 'quicksort3', 'quicksort4', 19 | 'quicksort5', 'quicksort'] 20 | if fcn.__name__ in ignoredAlgorithms: 21 | continue 22 | if fcn.__name__ == 'countsort': 23 | args = (1 + max(l),) 24 | t = time.time() 25 | fcn(l, *args) 26 | t = time.time() - t 27 | print '%15s %9.5f' % (fcn.__name__, t) 28 | -------------------------------------------------------------------------------- /examples/coopsort/transform_iteration_log.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import re 3 | 4 | import coopsort 5 | 6 | if __name__ == '__main__': 7 | regExp = r'(.+\[\s*)(\d+)\.?\d*( , 0\s+\].*)' 8 | f = open(sys.argv[1]) 9 | lines = f.readlines() 10 | f.close() 11 | for line in lines: 12 | beginPart = (re.sub(regExp, r'\1', line)).strip() 13 | midPart = (re.sub(regExp, r'\2', line)).strip() 14 | endPart = (re.sub(regExp, r'\3', line)).strip() 15 | #print midPart 16 | treeCode10 = int(re.sub(regExp, r'\2', line).strip()) 17 | treeCode6 = coopsort.encode(treeCode10, 6) 18 | print beginPart, treeCode6, endPart 19 | -------------------------------------------------------------------------------- /examples/dfo/dfo_declaration.py: -------------------------------------------------------------------------------- 1 | from opal.core.algorithm import Algorithm 2 | from opal.core.parameter import Parameter 3 | from opal.core.measure import Measure 4 | 5 | # Define new algorithm. 6 | DFO = Algorithm(name='DFO', description='Derivative-free Optimization') 7 | 8 | # Register executable for DFO. 9 | DFO.set_executable_command('python dfo_run.py') 10 | 11 | # Define parameters. 12 | nx = Parameter(kind='integer', default=1, name='NX') 13 | maxit = Parameter(kind='integer', default=5000, name='MAXIT') 14 | maxef = Parameter(kind='integer', default=9500, name='MAXNF') 15 | stpcrtr = Parameter(kind='integer', default=2, name='STPCRTR') 16 | delmin = Parameter(default=1.0e-4, name='DELMIN',bound=(1.0e-8,1.0e-3)) 17 | stpthr = Parameter(default=1.0e-3, name='STPTHR',bound=(0,None)) 18 | cnstol = Parameter(default=1.0e-5, name='CNSTOL',bound=(0,0.1)) 19 | delta = Parameter(default=1.0e0, name='DELTA',bound=(1.0e-8,None)) 20 | pp = Parameter(default=1.0e0, name='PP',bound=(1,None)) 21 | scale = Parameter(kind='integer', default=0, name='SCALE') 22 | iprint = Parameter(kind='integer', default=1, name='IPRINT') 23 | 24 | # Register parameters with algorithm. 25 | DFO.add_param(nx) 26 | DFO.add_param(maxit) 27 | DFO.add_param(maxef) 28 | DFO.add_param(stpcrtr) 29 | DFO.add_param(delmin) 30 | DFO.add_param(stpthr) 31 | DFO.add_param(cnstol) 32 | DFO.add_param(delta) 33 | DFO.add_param(pp) 34 | DFO.add_param(scale) 35 | DFO.add_param(iprint) 36 | 37 | # Define the feasible region. 38 | DFO.add_parameter_constraint('DELTA >= DELMIN') 39 | 40 | # Define and register measures. 41 | exitcode = Measure(kind='integer', name='EXITCODE', description='Exit code') 42 | fval = Measure(kind='real', name='FVAL', description='Function value') 43 | cpu = Measure(kind='real', name='CPU', description='CPU time usage') 44 | feval = Measure(kind='real', name='FEVAL', 45 | description='Number of function evaluations') 46 | 47 | DFO.add_measure(exitcode) 48 | DFO.add_measure(fval) 49 | DFO.add_measure(cpu) 50 | DFO.add_measure(feval) 51 | -------------------------------------------------------------------------------- /examples/dfo/dfo_optimize.py: -------------------------------------------------------------------------------- 1 | # Simple demo: tune DFO parameters for CPU time on simple HS problems. 2 | from opal import ModelStructure, ModelData, Model 3 | from opal.TestProblemCollections import CUTEr 4 | from dfo_declaration import DFO 5 | 6 | 7 | from opal.Solvers import NOMAD 8 | 9 | def avg_time(parameters,measures): 10 | n = len(measures['CPU']) 11 | if n == 0: 12 | return 0.0 13 | return (sum(measures["CPU"]) + 0.0)/(n + 0.0) 14 | 15 | # Select real parameters from DFO. 16 | params = [par for par in DFO.parameters if par.is_real] 17 | 18 | # Select tiny unconstrained HS problems. 19 | problems = [prb for prb in CUTEr.HS if prb.nvar <= 5 and prb.ncon == 0] 20 | 21 | print 'Working with parameters ', [par.name for par in params] 22 | print 'Testing on problems ', [prb.name for prb in problems] 23 | 24 | data = ModelData(DFO, problems, params) 25 | structure = ModelStructure(objective=avg_time, constraints=[]) # Unconstrained 26 | 27 | # Instantiate black-box solver. 28 | model = Model(modelData=data, modelStructure=structure) 29 | 30 | # Solve parameter optimization problem. 31 | NOMAD.solve(blackbox=model) 32 | -------------------------------------------------------------------------------- /examples/dfo/dfo_run.py: -------------------------------------------------------------------------------- 1 | # A sample gateway to DFO to be used by OPAL. 2 | 3 | import os 4 | import sys 5 | import pickle 6 | from string import atof 7 | from string import atoi 8 | from opal.core.io import * 9 | 10 | def write_specfile(parameter_file, loc='.', name='DFO.SPC'): 11 | "Write a valid DFO.SPC given a parameter file." 12 | # Read parameters into a dictionary 13 | parms = read_params_from_file(parameter_file) 14 | 15 | # Write out DFO.SPC. Parameters must be in order. 16 | f = open(os.path.join(loc, name), 'w') 17 | f.write('%10i\n' % parms['NX']) 18 | f.write('%10i\n' % parms['MAXIT']) 19 | f.write('%10i\n' % parms['MAXNF']) 20 | f.write('%10i\n' % parms['STPCRTR']) 21 | f.write('%10.3e\n' % float(parms['DELMIN'])) 22 | f.write('%10.3e\n' % float(parms['STPTHR'])) 23 | f.write('%10.3e\n' % float(parms['CNSTOL'])) 24 | f.write('%10.3e\n' % float(parms['DELTA'])) 25 | f.write('%10.3e\n' % float(parms['PP'])) 26 | f.write('%10i\n' % parms['SCALE']) 27 | f.write('%10i\n' % parms['IPRINT']) 28 | f.close() 29 | return 30 | 31 | 32 | def solve(problem_name): 33 | os.chdir(problem_name) 34 | os.system('./dfomin > run.log') 35 | 36 | ctime = 0.0 37 | f = open('cuter.log', 'r') 38 | for line in f.xreadlines(): 39 | line = line.strip('\n') 40 | if len(line) <= 0: 41 | continue 42 | stats = line.split(':') 43 | stat = stats[1] 44 | stat = stat.lstrip() 45 | stat = stat.rstrip() 46 | if stat == 'PTIME': 47 | ctime = ctime + atof(stats[-1]) 48 | if stat == 'STIME': 49 | ctime = ctime + atof(stats[-1]) 50 | if stat == 'FVAL': 51 | fval = atof(stats[-1]) 52 | if stat == 'NFEVAL': 53 | nfeval = atoi(stats[-1]) 54 | if stat == 'EXITCODE': 55 | exitcode = atoi(stats[-1]) 56 | if stat == 'FZERO': 57 | fzero = atof(stats[-1]) 58 | if stat == 'NCON': 59 | ncon = atof(stats[-1]) 60 | 61 | f.close() 62 | os.chdir('..') 63 | return {'EXITCODE' : exitcode, 64 | 'FVAL' : fval, 65 | 'CPU' : ctime, 66 | 'FEVAL' : nfeval*(ncon + 1), 67 | 'DESCENT' : fzero-fval} 68 | 69 | 70 | def compile_driver(problem_name, log_file='compile.log'): 71 | if not os.path.exists(problem_name): 72 | os.system('mkdir %s' % problem) 73 | os.chdir(problem_name) 74 | os.system('sifdecode %s > %s 2>&1' % (problem_name, log_file)) 75 | os.system('runcuter --package dfo --keep --blas none --lapack none ' +\ 76 | '> /dev/null') 77 | os.chdir('..') 78 | 79 | 80 | if __name__ == '__main__': 81 | param_file = sys.argv[1] 82 | problem = sys.argv[2] 83 | output_file = sys.argv[3] 84 | 85 | # Ensure executable is present for current problem. 86 | executable = os.path.join(problem, 'dfomin') 87 | if not os.path.exists(executable): 88 | compile_driver(problem) 89 | 90 | # Ensure spec file is in place and solve. 91 | write_specfile(param_file, loc=problem) 92 | measure_values = solve(problem) 93 | write_measures_to_file(output_file, measure_values) 94 | 95 | -------------------------------------------------------------------------------- /examples/fd/README.rst: -------------------------------------------------------------------------------- 1 | Example of algorithmic tuning 2 | ============================= 3 | 4 | This simple example demonstrates OPAL usage on the simple problem of adjusting 5 | the finite-difference parameter for the computation of an approximation to the 6 | first-order derivative of a noise-free function. 7 | 8 | The example uses the function f(x) = sin(x) and approximates the derivative 9 | using the formula:: 10 | 11 | f(x) ≠ (f(x+h) - f(x))/h 12 | 13 | where h > 0 is the finite-difference parameter. It is known that if f is 14 | continuously differentiable and noise free, an optimal value of h---i.e., 15 | minimizing the approximation and roundoff errors---is located around the square 16 | root of the machine epsilon. On platforms using IEEE double precision 17 | arithmetic, this value is around 1.0e-8. 18 | 19 | Below is the output of a run on a i386 Intel Core2 Duo running OSX 10.5.8:: 20 | 21 | MADS run{ 22 | 23 | EVAL BBE [ SOL, ] OBJ TIME \\ 24 | 25 | 1 1 [ 0.5 ] 0.2022210836 0 \\ 26 | 2 2 [ 0.4 ] 0.1582516709 0 \\ 27 | 3 3 [ 0.1 ] 0.03650380828 1 \\ 28 | 11 6 [ 0.075 ] 0.0271668032 2 \\ 29 | 15 8 [ 0.05 ] 0.01796857799 3 \\ 30 | 19 10 [ 0.025 ] 0.008912029073 3 \\ 31 | 27 12 [ 0.01875 ] 0.006670363173 4 \\ 32 | 31 14 [ 0.0125 ] 0.004437773933 5 \\ 33 | 35 16 [ 0.00625 ] 0.002214305049 6 \\ 34 | 43 18 [ 0.00380859375 ] 0.001348249081 7 \\ 35 | 47 20 [ 0.0013671875 ] 0.0004835939884 8 \\ 36 | 55 23 [ 0.0006286621094 ] 0.0002223121897 9 \\ 37 | 61 25 [ 0.0002380371094 ] 8.416550444e-05 9 \\ 38 | 67 27 [ 5.340576172e-05 ] 1.88821243e-05 10 \\ 39 | 75 30 [ 5.125999451e-06 ] 1.812326825e-06 11 \\ 40 | 87 35 [ 2.074893564e-06 ] 7.335931301e-07 13 \\ 41 | 93 37 [ 5.490146577e-07 ] 1.940868919e-07 14 \\ 42 | 101 40 [ 1.675449312e-07 ] 5.898094313e-08 15 \\ 43 | 109 43 [ 7.217749951e-08 ] 2.629330675e-08 16 \\ 44 | 115 45 [ 2.450397003e-08 ] 9.569121828e-09 17 \\ 45 | 123 49 [ 1.258558766e-08 ] 2.656297737e-09 19 \\ 46 | 134 57 [ 1.407570378e-08 ] 8.138155705e-10 22 \\ 47 | 157 78 [ 1.407861414e-08 ] 3.433888729e-10 30 \\ 48 | 170 87 [ 1.407861414e-08 ] 3.433888729e-10 33 \\ 49 | 50 | }end of run (mesh size reached NOMAD precision) 51 | 52 | The outcome of the run is that the final value of the stepsize found is 53 | h=1.407861414e-08 and the error value is 3.433888729e-10. The error is computed 54 | as the absolute value of the difference between the "exact" derivative and 55 | the approximation computed by finite differences. 56 | -------------------------------------------------------------------------------- /examples/fd/fd.py: -------------------------------------------------------------------------------- 1 | # Simple forward finite-difference approximation. 2 | 3 | def fd(f, x, h): 4 | # Return the forward finite-difference approximation to df(x). 5 | if h == 0.0: return float("infinity") 6 | return (f(x+h) - f(x))/h 7 | 8 | -------------------------------------------------------------------------------- /examples/fd/fd_declaration.py: -------------------------------------------------------------------------------- 1 | # Description of the forward finite-difference "algorithm". 2 | from opal.core.algorithm import Algorithm 3 | from opal.core.parameter import Parameter 4 | from opal.core.measure import Measure 5 | 6 | # Define Algorithm object. 7 | FD = Algorithm(name='FD', description='Forward Finite Differences') 8 | 9 | # Register executable for FD. 10 | FD.set_executable_command('python fd_run.py') 11 | 12 | # Register parameter file used by black-box solver to communicate with FD. 13 | #FD.set_parameter_file('fd.param') # Should be chosen automatically and hidden. 14 | 15 | # Define parameter and register it with algorithm. 16 | h = Parameter(kind='real', default=0.5, bound=(0, None), 17 | name='h', description='Step size') 18 | FD.add_param(h) 19 | 20 | # Define relevant measure and register with algorithm. 21 | error = Measure(kind='real', name='ERROR', description='Error in derivative') 22 | FD.add_measure(error) 23 | -------------------------------------------------------------------------------- /examples/fd/fd_optimize.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the 2 | # FD algorithm. 3 | from fd_declaration import FD 4 | 5 | from opal import ModelStructure, ModelData, Model 6 | 7 | from opal.Solvers import NOMAD 8 | 9 | # Return the error measure. 10 | def get_error(parameters, measures): 11 | return sum(measures["ERROR"]) 12 | 13 | # Define parameter optimization problem. 14 | data = ModelData(FD) 15 | struct = ModelStructure(objective=get_error) # Unconstrained 16 | model = Model(modelData=data, modelStructure=struct) 17 | 18 | # Solve parameter optimization problem. 19 | #NOMAD.set_parameter(name='DISPLAY_STATS', 20 | # value='%3dBBE %7.1eSOL %8.3eOBJ %5.2fTIME') 21 | NOMAD.solve(blackbox=model) 22 | 23 | # Inform user of expected optimal value for information. 24 | try: 25 | import numpy as np 26 | eps = np.finfo(np.double).eps 27 | except: 28 | # Approximate machine epsilon. 29 | eps = 1.0 30 | while 1+eps > 1: eps /= 2 31 | eps *= 2 32 | 33 | from math import sqrt 34 | print 'Expected optimal value is approximately %21.15e' % sqrt(eps) 35 | -------------------------------------------------------------------------------- /examples/fd/fd_run.py: -------------------------------------------------------------------------------- 1 | from opal.core.io import * 2 | from fd import fd 3 | from math import pi, sin, cos 4 | import sys 5 | 6 | f = sin ; df = cos # Target function and its derivative. 7 | x = pi/4 # This is where the derivative will be approximated. 8 | dfx = df(x) # "Exact" derivative at x. 9 | 10 | def run(param_file, problem): 11 | "Run FD with given parameters." 12 | 13 | params = read_params_from_file(param_file) 14 | h = params['h'] 15 | return {'ERROR': abs(dfx - fd(f,x,h))} 16 | 17 | 18 | if __name__ == '__main__': 19 | param_file = sys.argv[1] 20 | problem = sys.argv[2] 21 | output_file = sys.argv[3] 22 | 23 | # Solve, gather measures and write to file. 24 | measures = run(param_file, problem) 25 | write_measures_to_file(output_file, measures) 26 | 27 | -------------------------------------------------------------------------------- /examples/fd/test_fd.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | def test_fd_optimize(): 3 | import fd_optimize 4 | -------------------------------------------------------------------------------- /examples/ipopt/ipopt_composite_measures.py: -------------------------------------------------------------------------------- 1 | def avg_time(parameters, measures): 2 | n = len(measures['CPU']) 3 | if n == 0: 4 | return 0.0 5 | return (sum(measures["CPU"]) + 0.0)/(n + 0.0) 6 | 7 | def sum_eval(parameters, measures): 8 | return sum(measures['FEVAL']) + sum(measures['GEVAL']) +\ 9 | sum(measures['EQCVAL']) + sum(measures['EQJVAL']) +\ 10 | sum(measures['INCVAL']) + sum(measures['INJVAL']) 11 | 12 | def weighted_sum_eval(parameters, measures): 13 | result = 0.0 14 | for (feval, geval, eqcval, eqjval, incval, injval, weight) in \ 15 | zip(measures['FEVAL'], measures['GEVAL'], measures['EQCVAL'], \ 16 | measures['EQJVAL'], measures['INCVAL'], measures['INJVAL'], \ 17 | measures['WEIGHT']): 18 | result = result + weight*(feval + geval + eqcval + eqjval + incval + \ 19 | injval) 20 | return result 21 | 22 | def sum_ecode_square(parameters, measures): 23 | result = 0.0 24 | for val in measures['ECODE']: 25 | result = result + val*val 26 | return result 27 | 28 | 29 | def sum_ecode(parameters, measures): 30 | return sum(measures['ECODE']) 31 | 32 | def sum_unsolvability(parameters, measures): 33 | unsolvabilities = 0 34 | for eCode in measures['ECODE']: 35 | if eCode < 0: 36 | unsolvabilities = unsolvabilities + 1 37 | return unsolvabilities 38 | 39 | def sum_iteration(parameters, measures): 40 | return sum(measures['NITER']) 41 | 42 | -------------------------------------------------------------------------------- /examples/ipopt/ipopt_declaration.py: -------------------------------------------------------------------------------- 1 | from opal.core.algorithm import Algorithm 2 | from opal.core.parameter import Parameter 3 | from opal.core.measure import Measure 4 | 5 | # Define new algorithm. 6 | IPOPT = Algorithm(name='IPOPT', description='Interior Point for OPTimization') 7 | 8 | # Register executable for IPOPT. 9 | IPOPT.set_executable_command('python ipopt_run.py') 10 | 11 | # Define parameters. 12 | 13 | # 5. Line search parameters 14 | IPOPT.add_param(Parameter(name='tau_min', 15 | kind='real', 16 | bound=[0, 1], 17 | default=0.99, 18 | description='For fraction-to-boundary rule')) 19 | IPOPT.add_param(Parameter(name='s_theta', 20 | kind='real', 21 | bound=[0, None], 22 | default=1.1, 23 | description='Exponent for current constraint ' +\ 24 | 'violation')) 25 | IPOPT.add_param(Parameter(name='s_phi', 26 | kind='real', 27 | bound=[0, None], 28 | default=2.3, 29 | description='Exponent for linear barrier function ' +\ 30 | 'model')) 31 | IPOPT.add_param(Parameter(name='delta', 32 | kind='real', 33 | bound=[0, None], 34 | default=1.0, 35 | description='Multiplier for constraint violation')) 36 | IPOPT.add_param(Parameter(name='eta_phi', 37 | kind='real', 38 | bound=[0, None], 39 | default=1.0e-8, 40 | description='Multiplier for constraint violation')) 41 | IPOPT.add_param(Parameter(name='theta_min_fact', 42 | kind='real', 43 | bound=[0, None], 44 | default=1.0e-4, 45 | description='Factor for constraint violation ' +\ 46 | 'threshod')) 47 | IPOPT.add_param(Parameter(name='theta_max_fact', 48 | kind='real', 49 | bound=[0, None], 50 | default=1.0e4, 51 | description='Factor of upper bound for constraint '+\ 52 | 'violation')) 53 | IPOPT.add_param(Parameter(name='gamma_theta', 54 | kind='real', 55 | bound=[0, 1], 56 | default=1.0e-8, 57 | description='Relaxation factor in the filter ' +\ 58 | 'margin for the constraint violation')) 59 | IPOPT.add_param(Parameter(name='gamma_phi', 60 | kind='real', 61 | bound=[0, 1], 62 | default=1.0e-8, 63 | description='Relaxation factor in the filter ' +\ 64 | 'margin for barrier function')) 65 | IPOPT.add_param(Parameter(name='max_soc', 66 | kind='integer', 67 | bound=[0, None], 68 | default=4, 69 | description='Maximum number of iteration for ' +\ 70 | 'second order correction')) 71 | IPOPT.add_param(Parameter(name='kappa_soc', 72 | kind='real', 73 | bound=[0, 1], 74 | default=0.99, 75 | description='Maximum number of iteration for ' +\ 76 | 'second order correction')) 77 | 78 | # Define the feasible region. 79 | IPOPT.add_parameter_constraint('tau_min > 0') 80 | IPOPT.add_parameter_constraint('tau_min < 1') 81 | IPOPT.add_parameter_constraint('s_theta > 1') 82 | IPOPT.add_parameter_constraint('s_phi > 1') 83 | IPOPT.add_parameter_constraint('delta > 0') 84 | IPOPT.add_parameter_constraint('eta_phi > 0') 85 | IPOPT.add_parameter_constraint('eta_phi < 0.5') 86 | IPOPT.add_parameter_constraint('theta_min_fact > 0') 87 | IPOPT.add_parameter_constraint('theta_max_fact > 0') 88 | IPOPT.add_parameter_constraint('gamma_theta > 0') 89 | IPOPT.add_parameter_constraint('gamma_theta < 1') 90 | IPOPT.add_parameter_constraint('gamma_phi > 0') 91 | IPOPT.add_parameter_constraint('gamma_phi < 1') 92 | IPOPT.add_parameter_constraint('kappa_soc > 0') 93 | IPOPT.add_parameter_constraint('kappa_soc < 1') 94 | # Define and register measures. 95 | IPOPT.add_measure(Measure(name='CPU', 96 | kind='real', 97 | description='Computing time')) 98 | IPOPT.add_measure(Measure(name='FEVAL', 99 | kind='integer', 100 | description='Number of evaluation of objective function')) 101 | IPOPT.add_measure(Measure(name='EQCVAL', 102 | kind='integer', 103 | description='Number of evaluation of equality constraints')) 104 | IPOPT.add_measure(Measure(name='INCVAL', 105 | kind='integer', 106 | description='Number of evaluation of inequality constraints')) 107 | IPOPT.add_measure(Measure(name='GEVAL', 108 | kind='integer', 109 | description='Number of evaluation of function objective gradient')) 110 | IPOPT.add_measure(Measure(name='EQJVAL', 111 | kind='integer', 112 | description='Number of evaluation of equality constraint jacobian matrix')) 113 | IPOPT.add_measure(Measure(name='INJVAL', 114 | kind='integer', 115 | description='Number of evaluation of inequatily constraint jacobian matrix')) 116 | IPOPT.add_measure(Measure(name='ECODE', 117 | kind='integer', 118 | description='Exit code')) 119 | 120 | IPOPT.add_measure(Measure(name='NITER', 121 | kind='integer', 122 | description='Number of iteration')) 123 | 124 | IPOPT.add_measure(Measure(name='WEIGHT', 125 | kind='real', 126 | description='weight for a measure vector of a problem')) 127 | -------------------------------------------------------------------------------- /examples/ipopt/ipopt_optimize.py: -------------------------------------------------------------------------------- 1 | from opal import ModelStructure, ModelData, Model, MeasureFunction 2 | from ipopt_declaration import IPOPT 3 | 4 | import sys 5 | 6 | # Choose all parameters defined in declaration file 7 | params = [param for param in IPOPT.parameters 8 | if param.name in ['tau_min', 's_theta', 's_phi', 'delta', 9 | 'max_soc', 'kappa_soc']] 10 | 11 | # Choose all solvable problems 12 | #from ipopt_test_problems import ipopt_solvable_problems as problems 13 | #from ipopt_test_problems import test_problems as problems 14 | from ipopt_test_problems import CUTEr_constrained_problems, test_problems 15 | 16 | if len(sys.argv) > 1: 17 | f = open(sys.argv[1]) 18 | representativeProblems = eval(f.read()) 19 | f.close() 20 | 21 | problems = [ prob for prob in CUTEr_constrained_problems 22 | if prob.name in representativeProblems ] 23 | else: 24 | problems = CUTEr_constrained_problems 25 | problems = test_problems 26 | 27 | data = ModelData(IPOPT, problems, params) 28 | 29 | from ipopt_composite_measures import sum_eval, sum_unsolvability 30 | structure = ModelStructure(objective=MeasureFunction(sum_eval, addivity=1), 31 | constraints=[(None, sum_unsolvability, 0)]) 32 | 33 | # Instantiate black-box solver. 34 | #from opal.Platforms import LSF 35 | #LSF.set_parameter({'MAX_TASK':10}) 36 | 37 | from opal.Platforms import SunGrid 38 | SunGrid.set_config('-q','all.q') 39 | SunGrid.set_parameter({'MAX_TASK':10}) 40 | 41 | model = Model(modelData=data, modelStructure=structure, platform=SunGrid) 42 | 43 | if len(sys.argv) > 2: # The initial point is provided by external file 44 | f = open(sys.argv[2]) 45 | paramValues = eval(f.read()) 46 | f.close() 47 | model.initial_points = [] # Reset the initial point set 48 | for tag in paramValues: 49 | model.add_initial_point(paramValues[tag]) 50 | #print model.get_initial_points() 51 | 52 | # Solve parameter optimization problem. 53 | from opal.Solvers import NOMAD 54 | #NOMAD.set_parameter(name='MAX_BB_EVAL', value=100) 55 | #NOMAD.set_parameter(name='SCALING', value='scaling.txt') 56 | NOMAD.set_parameter(name='INITIAL_MESH_SIZE', 57 | value='(0.05 5 5 1 4 0.05)') 58 | #NOMAD.set_parameter(name='MIN_MESH_SIZE', value=1.0e-6) 59 | NOMAD.set_parameter(name='MAX_MESH_INDEX', value=6) 60 | NOMAD.set_parameter(name='DISPLAY_DEGREE', value=4) 61 | NOMAD.solve(blackbox=model) 62 | -------------------------------------------------------------------------------- /examples/ipopt/ipopt_run.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import pickle 4 | import re 5 | import tempfile 6 | import shutil 7 | from string import atof 8 | from string import atoi 9 | from opal.core.io import * 10 | 11 | 12 | 13 | def extract_measure(content, description, name, 14 | valueType = 'int',dem='\s+:\s+'): 15 | numberPattern = {'int':'-?\d+', 16 | 'real':'-?\d*\.\d+', 17 | 'float':'-?\d*\.\d+E(\+|-)\d+'} 18 | converters = {'int':int, 19 | 'real': float, 20 | 'float': float} 21 | 22 | matches = re.finditer(description + dem + '(?P<' + 23 | name + '>' + 24 | numberPattern[valueType] + ')', 25 | content) 26 | value = None 27 | for m in matches: 28 | if name not in m.groupdict().keys(): 29 | raise Exception('Could not to extract measure ' + name) 30 | continue 31 | value = converters[valueType](m.groupdict()[name]) 32 | return value 33 | 34 | def write_specfile(parameter_file, loc='.', name='ipopt.opt'): 35 | # Read parameters into a dictionary 36 | #parms = read_params_from_file(parameter_file) 37 | parms = {} 38 | 39 | # Write out ipopt.opt 40 | f = open(os.path.join(loc, name), 'w') 41 | for pName in parms: 42 | f.write( pName + ' ' + str(parms[pName]) + '\n') 43 | # Fix parameters 44 | f.write('linear_solver ma57\n') 45 | f.write('print_level 3\n') 46 | f.write('print_timing_statistics yes\n') 47 | f.close() 48 | return 49 | 50 | def get_measures(stats_file, weight=1.0): 51 | 52 | measures = {} 53 | f = open(stats_file) 54 | content = f.read() 55 | f.close() 56 | #print content 57 | measures['CPU'] = extract_measure( 58 | content=content, 59 | description='OverallAlgorithm', 60 | dem='\.*:\s+', 61 | name='CPU', 62 | valueType='real') 63 | measures['HTIME'] = extract_measure( 64 | content=content, 65 | description=' UpdateHessian', 66 | dem='\.*:\s+', 67 | name='HTIME', 68 | valueType='real') 69 | measures['DIRTIME'] = extract_measure( 70 | content=content, 71 | description=' ComputeSearchDirection', 72 | dem='\.*:\s+', 73 | name='DIRTIME', 74 | valueType='real') 75 | measures['PTRTIME'] = extract_measure( 76 | content=content, 77 | description=' ComputeAcceptableTrialPoint', 78 | dem='\.*:\s+', 79 | name='PTRTIME', 80 | valueType='real') 81 | measures['FTIME'] = extract_measure( 82 | content=content, 83 | description='Function Evaluations', 84 | dem='\.*:\s+', 85 | name='FTIME', 86 | valueType='real') 87 | measures['NITER'] = extract_measure( 88 | content=content, 89 | description='Number of Iterations', 90 | dem='\.+:\s+', 91 | name='NITER', 92 | valueType='int') 93 | 94 | measures['FEVAL'] = extract_measure( 95 | content=content, 96 | description='Number of objective function evaluations', 97 | dem='\s*=\s+', 98 | name='FEVAL', 99 | valueType='int') 100 | measures['GEVAL'] = extract_measure( 101 | content=content, 102 | description='Number of objective gradient evaluations', 103 | dem='\s*=\s+', 104 | name='GEVAL', 105 | valueType='int') 106 | measures['EQCVAL'] = extract_measure( 107 | content=content, 108 | description='Number of equality constraint evaluations', 109 | dem='\s*=\s+', 110 | name='EQCVAL', 111 | valueType='int') 112 | measures['INCVAL'] = extract_measure( 113 | content=content, 114 | description='Number of inequality constraint evaluations', 115 | dem='\s*=\s+', 116 | name='INCVAL', 117 | valueType='int') 118 | measures['EQJVAL'] = extract_measure( 119 | content=content, 120 | description='Number of equality constraint Jacobian evaluations', 121 | dem='\s*=\s+', 122 | name='EQJVAL', 123 | valueType='int') 124 | measures['INJVAL'] = extract_measure( 125 | content=content, 126 | description='Number of inequality constraint Jacobian evaluations', 127 | dem='\s*=\s+', 128 | name='INJVAL', 129 | valueType='int') 130 | measures['ECODE'] = extract_measure( 131 | content=content, 132 | description='Exit code', 133 | dem='\s*=\s+', 134 | name='ECODE', 135 | valueType='int') 136 | 137 | measures['WEIGHT'] = weight 138 | return measures 139 | 140 | 141 | def run(param_file, problem, keep=False): 142 | curDir = os.getcwd() 143 | if not keep: 144 | workDir = tempfile.mkdtemp() 145 | else: 146 | workDir = os.path.join(curDir,problem) 147 | if not os.path.exists(workDir): 148 | os.mkdir(workDir) 149 | 150 | os.chdir(workDir) 151 | write_specfile(param_file) 152 | os.system('sifdecode ' + problem + ' > /dev/null') 153 | os.system('runcuter -p ipopt > ' + problem + '.sol') 154 | measures = get_measures(problem + '.sol') 155 | os.chdir(curDir) 156 | if not keep: 157 | shutil.rmtree(workDir) 158 | return measures 159 | 160 | if __name__ == '__main__': 161 | param_file = sys.argv[1] 162 | problem = sys.argv[2] 163 | output_file = sys.argv[3] 164 | 165 | # Solve, gather measures and write to file. 166 | param_file = os.path.abspath(param_file) 167 | #measures = run(param_file, problem, keep=True) 168 | measures = run(param_file, problem) 169 | write_measures_to_file(output_file, measures) 170 | 171 | 172 | -------------------------------------------------------------------------------- /examples/test_examples.py: -------------------------------------------------------------------------------- 1 | 2 | def test_examples(): 3 | import os 4 | dirList = os.listdir('.') 5 | print 'We have ' + str(len(dirList)) + ' examples' 6 | 7 | -------------------------------------------------------------------------------- /examples/trunk/test_trunk.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | def test_trunk_optimize(): 3 | from trunk_optimize import prob 4 | from opal.Solvers import NOMAD 5 | 6 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=10) 7 | NOMAD.solve(blackbox=prob) 8 | 9 | if __name__ == '__main__': 10 | test_trunk_optimize() 11 | 12 | -------------------------------------------------------------------------------- /examples/trunk/trunk_declaration.py: -------------------------------------------------------------------------------- 1 | # Description of TRUNK. 2 | from opal.core.algorithm import Algorithm 3 | from opal.core.parameter import Parameter 4 | from opal.core.parameter import ParameterConstraint 5 | from opal.core.measure import Measure 6 | 7 | # Define Algorithm object. 8 | trunk = Algorithm(name='TRUNK', 9 | description='Trust Region for UNConstrained problems') 10 | 11 | # Register executable command. 12 | trunk.set_executable_command('python trunk_run.py') 13 | 14 | # Register parameters. 15 | trunk.add_param(Parameter(name='eta1', 16 | kind='real', 17 | default=0.25, 18 | bound=[0, 1], 19 | description='Gradient scaling cut-off')) 20 | trunk.add_param(Parameter(name='eta2', 21 | kind='real', 22 | default=0.75, 23 | bound=[0,1], 24 | description='Trust-region increase threashold')) 25 | trunk.add_param(Parameter(name='gamma1', 26 | kind='real', 27 | default=0.5, 28 | bound=[0,1], 29 | description='Trust-region shrink factor')) 30 | trunk.add_param(Parameter(name='gamma2', 31 | kind='real', 32 | default=1.000, 33 | bound=[0,1], 34 | description='Trust-region moderate shrink factor')) 35 | trunk.add_param(Parameter(name='gamma3', 36 | kind='real', 37 | default=2.000, 38 | bound=[1,None], 39 | description='Trust-region increase factor')) 40 | trunk.add_param(Parameter(name='maxit', 41 | kind='integer', 42 | default=1000, 43 | description='Maximum number of iterations')) 44 | trunk.add_param(Parameter(name='stptol', 45 | kind='real', 46 | default=1.0e-05, 47 | description='Stop tolerance')) 48 | trunk.add_param(Parameter(name='rdgrad', 49 | kind='real', 50 | default=1.0e-05, 51 | description='Relative decrease in gradient')) 52 | trunk.add_param(Parameter(name='delta0', 53 | kind='real', 54 | default=1.000, 55 | description='Initial trust-region radius')) 56 | trunk.add_param(Parameter(name='sband', 57 | kind='integer', 58 | default=5, 59 | description='Semi-bandwidth of band preconditioner')) 60 | trunk.add_param(Parameter(name='nmmem', 61 | kind='integer', 62 | default=10, 63 | description='Non-monotone algorithm memory')) 64 | trunk.add_param(Parameter(name='level', 65 | kind='real', 66 | default=0.1000, 67 | description='Level, used for interpolation')) 68 | 69 | # Register constraints on the parameters. 70 | 71 | trunk.add_parameter_constraint(ParameterConstraint('eta1 < eta2')) 72 | trunk.add_parameter_constraint(ParameterConstraint('eta1 > 0')) 73 | trunk.add_parameter_constraint(ParameterConstraint('eta2 < 1')) 74 | trunk.add_parameter_constraint(ParameterConstraint('gamma1 > 0')) 75 | trunk.add_parameter_constraint(ParameterConstraint('gamma1 <= gamma2')) 76 | #trunk.add_parameter_constraint(ParameterConstraint('gamma2 < 1')) 77 | trunk.add_parameter_constraint(ParameterConstraint('gamma3 > 1')) 78 | 79 | # Register atomic measures. 80 | trunk.add_measure(Measure(name='CPU', 81 | kind='real', 82 | description='Computing time')) 83 | trunk.add_measure(Measure(name='FEVAL', 84 | kind='integer', 85 | description='Number of function evaluations')) 86 | trunk.add_measure(Measure(name='GEVAL', 87 | kind='integer', 88 | description='Number of gradient evaluations')) 89 | trunk.add_measure(Measure(name='NITER', 90 | kind='integer', 91 | description='Number of iterations')) 92 | trunk.add_measure(Measure(name='CGITER', 93 | kind='integer', 94 | description='Number of CG iterations')) 95 | trunk.add_measure(Measure(name='RDGRAD', 96 | kind='real', 97 | description='Relative decrease in gradient achieved')) 98 | trunk.add_measure(Measure(name='FVAL', 99 | kind='real', 100 | description='Final objective function value')) 101 | trunk.add_measure(Measure(name='HEVAL', 102 | kind='integer', 103 | description='Number of Hessian matrix evaluations')) 104 | trunk.add_measure(Measure(name='FVAL0', 105 | kind='real', 106 | description='Initial objective function value')) 107 | trunk.add_measure(Measure(name='GNORM', 108 | kind='real', 109 | description='Gradient 2-norm at final point')) 110 | trunk.add_measure(Measure(name='DELTA', 111 | kind='real', 112 | description='Final trust-region radius')) 113 | trunk.add_measure(Measure(name='ECODE', 114 | kind='integer', 115 | description='Exit code')) 116 | 117 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | from trunk_declaration import trunk 3 | 4 | from opal import ModelStructure, ModelData, Model, MeasureFunction 5 | from opal.Solvers import NOMAD 6 | from opal.Platforms import SMP 7 | from opal.TestProblemCollections import CUTEr 8 | 9 | def sum_heval(parameters, measures): 10 | val = sum(measures['HEVAL']) 11 | return val 12 | 13 | def get_error(parameters, measures): 14 | val = sum(measures["ECODE"]) 15 | return val 16 | 17 | # Parameters being tuned and problem list. 18 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 19 | #params = [param for param in trunk.parameters if param.name in par_names] 20 | 21 | params = [trunk.parameters['eta1'], 22 | trunk.parameters['eta2'], 23 | trunk.parameters['gamma1'], 24 | trunk.parameters['gamma2'], 25 | trunk.parameters['gamma3'] 26 | ] 27 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 28 | 'BROYDN7D', 29 | 'BRYBND', 30 | 'CURLY10', 31 | # 'CURLY20', 32 | # 'CURLY30', 33 | 'CRAGGLVY', 34 | 'DIXON3DQ', 35 | 'EIGENALS', 36 | 'FMINSRF2', 37 | 'FMINSURF', 38 | 'GENROSE', 39 | 'HIELOW', 40 | 'MANCINO', 41 | 'NCB20', 42 | 'NCB20B', 43 | 'NONDQUAR', 44 | 'POWER', 45 | 'SENSORS', 46 | 'SINQUAD', 47 | 'TESTQUAD', 48 | 'TRIDIA', 49 | 'WOODS']] 50 | 51 | #SMP.set_parameter(name='MAX_PROC', value=5); 52 | 53 | # Define parameter optimization problem. 54 | data = ModelData(algorithm=trunk, 55 | problems=problems, 56 | parameters=params, 57 | measures=trunk.measures) 58 | 59 | struct = ModelStructure(objective=MeasureFunction(sum_heval, 60 | additivity=1), 61 | constraints=[(None, 62 | MeasureFunction(get_error, addivity=1), 63 | 0)]) # One constraint get_error(p) <= 0 64 | 65 | 66 | prob = Model(modelData=data, 67 | modelStructure=struct, 68 | platform='SMP', 69 | synchoronized=False, 70 | interruptible=True 71 | ) 72 | 73 | # Solve parameter optimization problem. 74 | 75 | if __name__ == '__main__': 76 | from opal.Solvers import NOMAD 77 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=10) 78 | NOMAD.solve(model=prob) 79 | 80 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize_lsf.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | # This is a parallel version in which the test problems are placed in a 3 | # LSF queue to be solved in parallel. This strategy effectively 4 | # parallelizes the black box. This is an alternative to the parallelization 5 | # implemented in trunk_optimize_opalmpi.py. 6 | from trunk_declaration import trunk 7 | from opal import ModelStructure, ModelData, Model 8 | from opal.Solvers import NOMAD 9 | 10 | from opal.TestProblemCollections import CUTEr 11 | from opal.Platforms import LSF 12 | 13 | def get_error(parameters, measures): 14 | val = sum(measures["FEVAL"]) 15 | return val 16 | 17 | # Parameters being tuned and problem list. 18 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 19 | params = [param for param in trunk.parameters if param.name in par_names] 20 | 21 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 22 | 'BROYDN7D', 23 | 'BRYBND', 24 | 'CURLY10', 25 | 'CURLY20', 26 | 'CURLY30', 27 | 'CRAGGLVY', 28 | 'DIXON3DQ', 29 | 'EIGENALS', 30 | 'FMINSRF2', 31 | 'FMINSURF', 32 | 'GENROSE', 33 | 'HIELOW', 34 | 'MANCINO', 35 | 'NCB20', 36 | 'NCB20B', 37 | 'NONDQUAR', 38 | 'NONDQUAR', 39 | 'POWER', 40 | 'SENSORS', 41 | 'SINQUAD', 42 | 'TESTQUAD', 43 | 'TRIDIA', 44 | 'WOODS']] 45 | 46 | # Define parameter optimization problem. 47 | LSF.set_config(parameterName="-m", 48 | parameterValue='"lin01 lin02 lin03 lin04"') 49 | LSF.set_config(parameterName="-q", 50 | parameterValue="fedora") 51 | data = ModelData(algorithm=trunk, 52 | problems=problems, 53 | parameters=params, 54 | platform=LSF) 55 | struct = ModelStructure(objective=get_error, 56 | constraints=[]) # Unconstrained 57 | blackbox = Model(modelData=data, modelStructure=struct) 58 | 59 | # Solve parameter optimization problem. 60 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=10) 61 | NOMAD.solve(model=blackbox) 62 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize_mpi.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | # This is a parallel version in which the black box solver evaluates the 3 | # worth of neighbors in parallel. The black box evaluation itself is 4 | # sequential. 5 | from trunk_declaration import trunk 6 | from opal import ModelStructure, ModelData, Model 7 | from opal.Solvers import NOMADMPI 8 | 9 | from opal.TestProblemCollections import CUTEr 10 | 11 | 12 | def get_error(parameters, measures): 13 | val = sum(measures["FEVAL"]) 14 | return val 15 | 16 | # Parameters being tuned and problem list. 17 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 18 | params = [param for param in trunk.parameters if param.name in par_names] 19 | 20 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 21 | 'BROYDN7D', 22 | 'BRYBND', 23 | 'CURLY10', 24 | 'CURLY20', 25 | 'CURLY30', 26 | 'CRAGGLVY', 27 | 'DIXON3DQ', 28 | 'EIGENALS', 29 | 'FMINSRF2', 30 | 'FMINSURF', 31 | 'GENROSE', 32 | 'HIELOW', 33 | 'MANCINO', 34 | 'NCB20', 35 | 'NCB20B', 36 | 'NONDQUAR', 37 | 'POWER', 38 | 'SENSORS', 39 | 'SINQUAD', 40 | 'TESTQUAD', 41 | 'TRIDIA', 42 | 'WOODS']] 43 | 44 | # Define parameter optimization problem. 45 | data = ModelData(algorithm=trunk, 46 | problems=problems, 47 | parameters=params) 48 | struct = ModelStructure(objective=get_error, 49 | constraints=[]) # Unconstrained 50 | blackbox = Model(modelData=data, modelStructure=struct) 51 | 52 | # Solve parameter optimization problem. 53 | NOMADMPI.set_mpi_config(name='np', value=8) 54 | NOMADMPI.set_mpi_config(name='-host', value='lin01,lin02,lin03,lin04') 55 | NOMADMPI.set_parameter(name='MAX_BB_EVAL', value=50) 56 | NOMADMPI.set_parameter(name='DISPLAY_DEGREE', value=2) 57 | NOMADMPI.solve(model=blackbox) 58 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize_opalmpi.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | # This is a parallel version in which the test problems are solved in 3 | # parallel. This parallelism is managed via MPI. This is an alternative to 4 | # the parallelization implemented in trunk_optimize_lsf.py. 5 | from trunk_declaration import trunk 6 | from opal import ModelStructure, ModelData, Model 7 | from opal.Solvers import NOMAD 8 | 9 | from opal.TestProblemCollections import CUTEr 10 | from opal.Platforms import OPALMPI 11 | 12 | def get_error(parameters, measures): 13 | val = sum(measures["FEVAL"]) 14 | return val 15 | 16 | # Parameters being tuned and problem list. 17 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 18 | params = [param for param in trunk.parameters if param.name in par_names] 19 | 20 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 21 | 'BROYDN7D', 22 | 'BRYBND', 23 | 'CURLY10', 24 | 'CURLY20', 25 | 'CURLY30', 26 | 'CRAGGLVY', 27 | 'DIXON3DQ', 28 | 'EIGENALS', 29 | 'FMINSRF2', 30 | 'FMINSURF', 31 | 'GENROSE', 32 | 'HIELOW', 33 | 'MANCINO', 34 | 'NCB20', 35 | 'NCB20B', 36 | 'NONDQUAR', 37 | 'POWER', 38 | 'SENSORS', 39 | 'SINQUAD', 40 | 'TESTQUAD', 41 | 'TRIDIA', 42 | 'WOODS']] 43 | 44 | 45 | # Define parameter optimization problem. 46 | 47 | data = ModelData(algorithm=trunk, 48 | problems=problems, 49 | parameters=params, 50 | platform=OPALMPI) 51 | struct = ModelStructure(objective=get_error, 52 | constraints=[]) # Unconstrained 53 | model = Model(modelData=data, modelStructure=struct) 54 | 55 | # Solve parameter optimization problem. 56 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=500) 57 | NOMAD.solve(blackbox=model) 58 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize_opalsmp_nomadmpi.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | # This is a parallel version in which the test problems are solved in 3 | # parallel in independent subprocesses. This strategy effectively 4 | # parallelizes the black box. This is an alternative to the parallelization 5 | # implemented in trunk_optimize_opalmpi.py. 6 | from trunk_declaration import trunk 7 | from opal import ModelStructure, ModelData, Model 8 | from opal.Solvers import NOMADMPI 9 | from opal.TestProblemCollections import CUTEr 10 | from opal.Platforms import SMP 11 | 12 | def get_error(parameters, measures): 13 | val = sum(measures["FEVAL"]) 14 | return val 15 | 16 | # Parameters being tuned and problem list. 17 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 18 | params = [param for param in trunk.parameters if param.name in par_names] 19 | 20 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 21 | 'BROYDN7D', 22 | 'BRYBND', 23 | 'CURLY10', 24 | 'CURLY20', 25 | 'CURLY30', 26 | 'CRAGGLVY', 27 | 'DIXON3DQ', 28 | 'EIGENALS', 29 | 'FMINSRF2', 30 | 'FMINSURF', 31 | 'GENROSE', 32 | 'HIELOW', 33 | 'MANCINO', 34 | 'NCB20', 35 | 'NCB20B', 36 | 'NONDQUAR', 37 | 'POWER', 38 | 'SENSORS', 39 | 'SINQUAD', 40 | 'TESTQUAD', 41 | 'TRIDIA', 42 | 'WOODS']] 43 | 44 | 45 | # Define parameter optimization problem. 46 | 47 | data = ModelData(algorithm=trunk, 48 | problems=problems, 49 | parameters=params) 50 | struct = ModelStructure(objective=get_error, 51 | constraints=[]) # Unconstrained 52 | model = Model(modelData=data, modelStructure=struct, platform=SMP) 53 | 54 | # Solve parameter optimization problem. 55 | NOMADMPI.set_mpi_config(name='np', value=5) 56 | NOMADMPI.set_parameter(name='MAX_BB_EVAL', value=5) 57 | NOMADMPI.set_parameter(name='DISPLAY_DEGREE', value=2) 58 | NOMADMPI.solve(blackbox=model) 59 | -------------------------------------------------------------------------------- /examples/trunk/trunk_optimize_surrogate.py: -------------------------------------------------------------------------------- 1 | # Define a parameter optimization problem in relation to the TRUNK solver. 2 | # This is the sequential version. 3 | from trunk_declaration import trunk 4 | from opal import ModelStructure, ModelData, Model 5 | from opal.Solvers import NOMAD 6 | from opal.TestProblemCollections import CUTEr 7 | 8 | def sum_heval(parameters, measures): 9 | val = sum(measures["HEVAL"]) 10 | return val 11 | 12 | def get_error(parameters,measures): 13 | val = sum(measures['ECODE']) 14 | return val 15 | 16 | # Parameters being tuned and problem list. 17 | par_names = ['eta1', 'eta2', 'gamma1', 'gamma2', 'gamma3'] 18 | params = [param for param in trunk.parameters if param.name in par_names] 19 | 20 | problems = [problem for problem in CUTEr if problem.name in ['BDQRTIC', 21 | 'BROYDN7D', 22 | 'BRYBND', 23 | # 'CURLY10', 24 | # 'CURLY20', 25 | # 'CURLY30', 26 | # 'CRAGGLVY', 27 | # 'DIXON3DQ', 28 | # 'EIGENALS', 29 | # 'FMINSRF2', 30 | # 'FMINSURF', 31 | # 'GENROSE', 32 | 'HIELOW', 33 | # 'MANCINO', 34 | # 'NCB20', 35 | # 'NCB20B', 36 | # 'NONDQUAR', 37 | 'POWER', 38 | 'SENSORS', 39 | 'SINQUAD', 40 | 'TESTQUAD', 41 | 'TRIDIA', 42 | 'WOODS']] 43 | 44 | # Define parameter optimization problem. 45 | data = ModelData(algorithm=trunk, 46 | problems=problems, 47 | parameters=params) 48 | struct = ModelStructure(objective=sum_heval, 49 | constraints=[(None,get_error, 0)]) 50 | model = Model(modelData=data, modelStructure=struct) 51 | 52 | # Define a surrogate 53 | 54 | surr_data = ModelData(algorithm=trunk, 55 | problems= [problem for problem in CUTEr \ 56 | if problem.name in ['BDQRTIC', 57 | 'BROYDN7D', 58 | 'BRYBND']], 59 | parameters=params) 60 | surr_struct = ModelStructure(objective=sum_heval, 61 | constraints=[]) 62 | surr_model = Model(modelData=surr_data, modelStructure=surr_struct, 63 | dataFile='surrogate.dat') 64 | 65 | # Solve parameter optimization problem. 66 | NOMAD.set_parameter(name='MAX_BB_EVAL', value=10) 67 | NOMAD.solve(blackbox=model, surrogate=surr_model) 68 | -------------------------------------------------------------------------------- /examples/trunk/trunk_run.py: -------------------------------------------------------------------------------- 1 | from opal.core.io import * 2 | from opal.core.tools import * 3 | 4 | from distutils.dir_util import copy_tree 5 | import tempfile 6 | import os 7 | import sys 8 | import shutil 9 | import re 10 | 11 | src = 'trunk.src' 12 | 13 | def get_measures(stats_file): 14 | 15 | measures = {} 16 | f = open(stats_file) 17 | content = f.read() 18 | f.close() 19 | measures['CPU'] = extract_measure(content=content, 20 | description='user', 21 | name='CPU', 22 | valueType='real') 23 | measures['NITER'] = extract_measure(content=content, 24 | description='\#iterations\.*', 25 | name='NITER', 26 | valueType='int') 27 | measures['CGITER'] = extract_measure(content=content, 28 | description='CG iterations\.*', 29 | name='CGITER', 30 | valueType='int') 31 | measures['FEVAL'] = extract_measure(content=content, 32 | description='Function evals\.*', 33 | name='FEVAL', 34 | valueType='int') 35 | measures['GEVAL'] = extract_measure(content=content, 36 | description='Gradient evals\.*', 37 | name='GEVAL', 38 | valueType='int') 39 | measures['HEVAL'] = extract_measure( 40 | content=content, 41 | description='Hessian-vector products\.*', 42 | name='HEVAL', 43 | valueType='int') 44 | measures['GNORM'] = extract_measure(content=content, 45 | description='Gradient 2-norm\.*', 46 | name='GNORM', 47 | valueType='float') 48 | measures['RDGRAD'] = extract_measure( 49 | content=content, 50 | description='Relative decrease in gradient\.*', 51 | name='RDGRAD', 52 | valueType='float') 53 | measures['DELTA'] = extract_measure( 54 | content=content, 55 | description='Final Trust-Region radius\.*', 56 | name='DELTA', 57 | valueType='float') 58 | measures['ECODE'] = extract_measure(content=content, 59 | description='Exit code\.*', 60 | name='ECODE', 61 | valueType='int') 62 | match = re.search('objective value\.*\s:\s+' + \ 63 | '(?P-?\d*\.\d+E(\+|-)\d+)/\s+' + \ 64 | '(?P-?\d*\.\d+E(\+|-)\d+)', 65 | content) 66 | if match is not None: 67 | measures['FVAL0'] = float(match.groupdict()['FVAL0']) 68 | measures['FVAL'] = float(match.groupdict()['FVAL']) 69 | return measures 70 | 71 | 72 | def write_specfile(param_file): 73 | params = read_params_from_file(param_file) 74 | f = open('trunk.spc','w') 75 | f.write('{0:<10d} ## Max. number of iterations : (I4)\n'\ 76 | .format(params['maxit'])) 77 | f.write('{0:<10.2e} ## Stopping tolerance : (D7.2)\n'\ 78 | .format(params['stptol'])) 79 | f.write('{0:<10.2e} ## Relative decrease in gradient : (D7.2)\n'\ 80 | .format(params['rdgrad'])) 81 | f.write('{0:<10.4f} \n'\ 82 | .format(params['eta1'])) 83 | f.write('{0:<10.4f} \n'\ 84 | .format(params['eta2'])) 85 | f.write('{0:<10.4f} \n'\ 86 | .format(params['gamma1'])) 87 | f.write('{0:<10.4f} \n'\ 88 | .format(params['gamma2'])) 89 | f.write('{0:<10.4f} \n'\ 90 | .format(params['gamma3'])) 91 | f.write('{0:<10.4f} ## Initial trust-region radius Delta : (F6.4)\n'\ 92 | .format(params['delta0'])) 93 | f.write("{0:<10} ## Use Powell's rule for Delta : (L1)\n"\ 94 | .format('F')) 95 | f.write('{0:<10} ## Use banded preconditioner : (L1)\n'\ 96 | .format('F')) 97 | f.write('{0:<10d} ## Semi-bandwidth if preconditioner : (I4)\n'\ 98 | .format(params['sband'])) 99 | f.write('{0:<10} ## Use a non-monotone strategy : (L1)\n'\ 100 | .format('F')) 101 | f.write('{0:<10d} ## Non-monotone algorithm memory : (I4)\n'\ 102 | .format(params['nmmem'])) 103 | f.write('{0:<10} ## Update Delta using polynomials : (L1)\n'\ 104 | .format('F')) 105 | f.write('{0:<10} ## If so, interpolate rho? : (L1)\n'\ 106 | .format('F')) 107 | f.write('{0:<10.4f} ## Level, used for interpolation : (F6.4)\n'\ 108 | .format(params['level'])) 109 | f.write('{0:<10} ## Reentry of GLTR upon rejection : (L1)\n'\ 110 | .format('F')) 111 | f.write('{0:<10} ## Display results as Trunk proceeds : (L1)\n'\ 112 | .format('F')) 113 | f.close() 114 | return 115 | 116 | 117 | def run(param_file, problem): 118 | curDir = os.getcwd() 119 | workDir = tempfile.mkdtemp() 120 | copy_tree(src, workDir) 121 | os.chdir(workDir) 122 | write_specfile(param_file) 123 | os.system('sifdecode ' + problem + ' > /dev/null') 124 | os.system('make trunkd > /dev/null') 125 | os.system('./trunkd > ' + problem + '.sol') 126 | measures = get_measures(problem + '.sol') 127 | os.chdir(curDir) 128 | shutil.rmtree(workDir) 129 | return measures 130 | 131 | 132 | if __name__ == '__main__': 133 | param_file = sys.argv[1] 134 | problem = sys.argv[2] 135 | output_file = sys.argv[3] 136 | 137 | # Solve, gather measures and write to file. 138 | param_file = os.path.abspath(param_file) 139 | measures = run(param_file, problem) 140 | write_measures_to_file(output_file, measures) 141 | 142 | -------------------------------------------------------------------------------- /nosetests.py: -------------------------------------------------------------------------------- 1 | 2 | from nose import main 3 | 4 | if __name__ == '__main__': 5 | main() 6 | -------------------------------------------------------------------------------- /opal/Platforms/__init__.py: -------------------------------------------------------------------------------- 1 | from lsf import LSF 2 | from linux import LINUX 3 | from mpi import OPALMPI 4 | from smp import SMP 5 | from sungrid import SunGrid 6 | 7 | supported_platforms = {'LINUX': LINUX, 8 | 'LSF': LSF, 9 | 'SMP': SMP, 10 | 'SunGrid': SunGrid} 11 | -------------------------------------------------------------------------------- /opal/Platforms/linux.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | 4 | from ..core.platform import Platform 5 | from ..core.platform import Task 6 | 7 | class LINUXTask(Task): 8 | def __init__(self, 9 | name=None, 10 | command=None, 11 | sessionTag=None, 12 | output='/dev/null', 13 | logHandlers=[]): 14 | Task.__init__(self, 15 | name=name, 16 | command=command, 17 | sessionTag=sessionTag, 18 | output=output, 19 | logHandlers=logHandlers) 20 | return 21 | 22 | def run(self): 23 | # Execute the command 24 | os.system(self.command + ' > ' + self.output) 25 | # Inform the fininish 26 | Task.run(self) 27 | return 28 | 29 | class LINUXPlatform(Platform): 30 | def __init__(self, logHandlers=[]): 31 | Platform.__init__(self, name='LINUX', 32 | logHandlers=logHandlers) 33 | self.message_handlers['cfp-execute'] = self.create_task 34 | return 35 | 36 | def create_task(self, info): 37 | ''' 38 | 39 | Handle a call for proposal of executing a command 40 | ''' 41 | if 'proposition' not in info.keys(): 42 | self.logger.log('Proposal of executing a command has not ' + \ 43 | 'information to prcess') 44 | return 45 | 46 | proposition = info['proposition'] 47 | command = proposition['command'] 48 | 49 | name = proposition['tag'] 50 | if 'queue' in proposition.keys(): 51 | queueTag = proposition['queue'] 52 | else: 53 | queueTag = None 54 | queueTag = proposition['queue'] 55 | task = LINUXTask(name=name, 56 | command=command, 57 | sessionTag=proposition['tag']) 58 | self.submit(task, queue=queueTag) 59 | return 60 | 61 | def cancel_tasks(self, info): 62 | ''' 63 | 64 | Handle message terminate experiment 65 | ''' 66 | return 67 | 68 | 69 | def test_a(self): 70 | print 'Hello' 71 | 72 | 73 | 74 | LINUX = LINUXPlatform() 75 | -------------------------------------------------------------------------------- /opal/Platforms/lsf.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import time 4 | 5 | from ..core.platform import Platform 6 | from ..core.platform import Task 7 | 8 | class LSFTask(Task): 9 | def __init__(self, name=None, 10 | taskId=None, 11 | command=None, 12 | lsfOptions=None, 13 | logHandlers=[]): 14 | self.output = "-N -oo /tmp/lsf-output.log" 15 | lsfCmd = "bsub " + \ 16 | " -J " + taskId + lsfOptions + command 17 | Task.__init__(self, 18 | name=name, 19 | taskId=taskId, 20 | command=lsfCmd, 21 | logHandlers=logHandlers) 22 | self.job_id = taskId 23 | return 24 | 25 | def run(self): 26 | os.system(self.command) 27 | self.wait('ended("' + self.job_id +')') 28 | Task.run(self) 29 | return 30 | 31 | def wait(self, condition): 32 | # This function playes in role of synchronyzers 33 | # 1 - Generate a synchronizing job including a segment code that 34 | # notifies to current process by socket (notifyToMaster) 35 | # 2 - Prepare a waiting socket: create, bind, .. 36 | # 3 - Submit the synchronizing with the condition specified in 37 | # the condition 38 | # 4 - Turn in waiting by listening the notify at created socket 39 | # Argument condition may be "ended(CUTEr-*)" 40 | #------------------- 41 | # Set default socket parameter 42 | #------------------- 43 | port = 19879 44 | hostname = socket.gethostname() 45 | ltime = time.localtime() 46 | keyStr = str(ltime.tm_year) + str(ltime.tm_mon) + str(ltime.tm_mday) +\ 47 | str(ltime.tm_hour) + str(ltime.tm_min) + str(ltime.tm_sec) 48 | #------------------------- 49 | # Prepare socket 50 | #----------- 51 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 52 | socketIsBound = 0 53 | #----------------- 54 | # Choose an available port to avoid conflit with the other routine 55 | # Particularly, the other parameter optimization 56 | while socketIsBound == 0: 57 | try: 58 | serversocket.bind((hostname, port)) 59 | socketIsBound = 1 60 | except: 61 | port = port + 1 62 | #print "waiting at",socket.gethostname(), port 63 | serversocket.listen(1) 64 | #----------------------- 65 | # Generating synchronizing job 66 | #---------------------- 67 | synchronizerFile = 'synchronizer_' + self.job_id + '.py' 68 | f = open('synchronizer.py','w') 69 | #synchronizerFile.write('#!/usr/bin/env python\n') 70 | f.write('import socket\n') 71 | f.write('port = ' + str(port) + '\n') 72 | f.write('s = socket.socket(socket.AF_INET, ' + \ 73 | 'socket.SOCK_STREAM)\n') 74 | f.write('s.connect(("' + hostname + '",' + \ 75 | str(port) + '))\n') 76 | f.write('s.send("'+ keyStr + '")\n') 77 | f.write('s.close()\n') 78 | f.close() 79 | 80 | #ltime = time.localtime() 81 | #timeStr = str(ltime.tm_year) + '-' + str(ltime.tm_mon) + '-' + \ 82 | # str(ltime.tm_mday) + ' ' + str(ltime.tm_hour) + ':' + \ 83 | # str(ltime.tm_min) + ':' + str(ltime.tm_sec) 84 | #os.system('echo ' + timeStr + ' Begin waiting >> lsf-sync.log') 85 | synchronizeCmd = 'bsub -w "' + condition + \ 86 | '" python ' + synchronizerFile + ' > /dev/null' 87 | os.system(synchronizeCmd) 88 | #----------------------- 89 | # Waiting for the notify from synchonizer 90 | # --------------------- 91 | recvKey = '' 92 | while recvKey != keyStr: 93 | (clientsocket, address) = serversocket.accept() 94 | recvKey = clientsocket.recv(len(keyStr)) 95 | clientsocket.close() 96 | # print address, "is connected" 97 | #-------------- 98 | # free the sockets if received a notification 99 | #----------------- 100 | 101 | #clientsocket.close() 102 | serversocket.close() 103 | #ltime = time.localtime() 104 | #timeStr = str(ltime.tm_year) + '-' + str(ltime.tm_mon) + '-' + \ 105 | # str(ltime.tm_mday) + ' ' + str(ltime.tm_hour) + ':' + \ 106 | # str(ltime.tm_min) + ':' + str(ltime.tm_sec) 107 | #os.system('echo ' + timeStr + ' End waiting >> lsf-sync.log') 108 | os.remove(synchronizerFile) 109 | return 110 | 111 | 112 | 113 | class LSFPlatform(Platform): 114 | def __init__(self, maxTask=3, synchronous=False, logHandlers=[]): 115 | Platform.__init__(self, 116 | name='LSF', 117 | maxTask=maxTask, 118 | logHandlers=logHandlers) 119 | self.configuration = {} 120 | self.message_handlers['cfp-execute'] = self.create_task 121 | pass 122 | 123 | def set_config(self, parameterName, parameterValue): 124 | self.configuration[parameterName] = parameterValue 125 | return 126 | 127 | def initialize(self, testId): 128 | return 129 | 130 | def create_task(self, info): 131 | ''' 132 | 133 | Handle a call for proposal of executing a command through LSF platform 134 | ''' 135 | 136 | if 'proposition' not in info.keys(): 137 | self.logger.log('Proposal of executing a command has not ' + \ 138 | 'information to process') 139 | return 140 | execCmd = info['proposition']['command'] 141 | tag = info['proposition']['tag'] 142 | if 'queue' in info['proposition'].keys(): 143 | queueTag = info['proposition']['queue'] 144 | else: 145 | queueTag = None 146 | 147 | # str(ltime.tm_year) + str(ltime.tm_mon) + str(ltime.tm_mday) + \ 148 | # str(ltime.tm_hour) + str(ltime.tm_min) + str(ltime.tm_sec) 149 | optionStr = " " 150 | for param in self.configuration.keys(): 151 | optionStr = optionStr + param + " " + \ 152 | self.configuration[param] + " " 153 | if queueTag is not None: 154 | optionStr = " -g " + queueTag + optionStr 155 | task = LSFTask(name=tag, 156 | taskId=tag, 157 | command=execCmd, 158 | lsfOptions=optionStr) 159 | self.submit(task, queue=queueTag) 160 | return 161 | 162 | LSF = LSFPlatform() 163 | -------------------------------------------------------------------------------- /opal/Platforms/mpi.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import time 4 | 5 | from ..core.platform import Platform 6 | from ..core import log 7 | 8 | class MPIPlatform(Platform): 9 | def __init__(self,logHandlers=[],**kwargs): 10 | Platform.__init__(self,'MPI',**kwargs) 11 | #self.communicator = MPI.COMM_WORLD 12 | self.children = [] 13 | self.wrapper_name = '' 14 | self.configuration = {} 15 | self.logger = log.OPALLogger(name='mpiPlatform', handlers=logHandlers) 16 | pass 17 | 18 | def set_config(self, parameterName, parameterValue): 19 | self.configuration[parameterName] = parameterValue 20 | return 21 | 22 | def initialize(self, testId): 23 | self.wrapper_name = 'run_wrapper_' + testId + '.py' 24 | if not os.path.exists(self.wrapper_name): 25 | self.create_wrapper() 26 | self.children = [] 27 | #self.logger.log('Platform is initialized') 28 | return 29 | 30 | def execute(self, command, output='/dev/null'): 31 | jobId = str(hash(command)) 32 | # str(ltime.tm_year) + str(ltime.tm_mon) + str(ltime.tm_mday) + \ 33 | # str(ltime.tm_hour) + str(ltime.tm_min) + str(ltime.tm_sec) 34 | optionStr = " " 35 | for param in self.configuration.keys(): 36 | optionStr = optionStr + param + " " + self.configuration[param] + " " 37 | #child = self.communicator.Spawn('python', 38 | # [self.wrapper_name, command]) 39 | from mpi4py import MPI 40 | #self.logger.log('Execute command: '+ command) 41 | child = MPI.COMM_WORLD.Spawn('python', 42 | [self.wrapper_name, command]) 43 | self.children.append(child) 44 | return 45 | 46 | def create_wrapper(self): 47 | tab = ' '*4 48 | f = open(self.wrapper_name,'w') 49 | f.write('import sys\n') 50 | f.write('import os\n') 51 | f.write('from mpi4py import MPI\n') 52 | f.write('parent = MPI.COMM_WORLD.Get_parent()\n') 53 | f.write('exeCmd = ""\n') 54 | f.write('for argv in sys.argv[1:]:\n') 55 | f.write(tab + 'exeCmd = exeCmd + argv + " "\n') 56 | #f.write('print exeCmd\n') 57 | f.write('os.system(exeCmd)\n') 58 | f.write('parent.Barrier()\n') 59 | f.write('parent.Disconnect()\n') 60 | f.close() 61 | 62 | 63 | def waitForCondition(self,condition): 64 | for child in self.children: 65 | child.Barrier() 66 | child.Disconnect() 67 | os.remove(self.wrapper_name) 68 | self.children = [] 69 | return 70 | 71 | 72 | OPALMPI = MPIPlatform() 73 | -------------------------------------------------------------------------------- /opal/Platforms/smp.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import time 4 | import subprocess 5 | import threading 6 | import shlex 7 | 8 | from ..core.platform import Platform 9 | from ..core.platform import Task 10 | 11 | from ..core import log 12 | 13 | 14 | class SMPTask(Task): 15 | """ 16 | 17 | Each task run on this platform need to 18 | some stubs to communicate with the platform 19 | 20 | """ 21 | def __init__(self, name=None, taskId=None, command=None, sessionTag=None): 22 | Task.__init__(self, 23 | name=name, 24 | taskId=taskId, 25 | command=command, 26 | sessionTag=sessionTag) 27 | self.proc = None 28 | self.pid = None 29 | return 30 | 31 | def run(self): 32 | #cmd = shlex.split(self.command) 33 | #self.proc = subprocess.Popen(args=cmd) 34 | cmd = self.command + '> /dev/null' 35 | self.proc = subprocess.Popen(args=cmd, shell=True) 36 | self.pid = self.proc.pid 37 | if self.proc.poll() is None: # check if child process is still running 38 | self.proc.wait() # wait until the child process finish 39 | # Inform the task is finished 40 | Task.run(self) 41 | return 42 | 43 | class SMPPlatform(Platform): 44 | def __init__(self, maxTask=2, logHandlers=[]): 45 | Platform.__init__(self, name='SMP', 46 | maxTask=maxTask, 47 | synchronous=False, 48 | logHandlers=logHandlers) 49 | self.configuration = {} 50 | #self.logger = log.OPALLogger(name='smpPlatform', handlers=logHandlers) 51 | self.message_handlers['cfp-execute'] = self.create_task 52 | pass 53 | 54 | def set_config(self, parameterName, parameterValue): 55 | self.configuration[parameterName] = parameterValue 56 | return 57 | 58 | 59 | def initialize(self, testId): 60 | #self.children = [] 61 | #self.logger.log('Platform is initialized for the test ' + testId) 62 | return 63 | 64 | # Message handlers 65 | 66 | def create_task(self, info): 67 | ''' 68 | 69 | Handle a call for proposal of executing a command 70 | ''' 71 | if 'proposition' not in info.keys(): 72 | self.logger.log('Proposal of executing a command has not ' + \ 73 | 'information to prcess') 74 | return 75 | 76 | proposition = info['proposition'] 77 | command = proposition['command'] 78 | name = proposition['tag'] 79 | if 'queue' in proposition.keys(): 80 | queueTag = proposition['queue'] 81 | else: 82 | queueTag = None 83 | task = SMPTask(name=name, 84 | command=command, 85 | sessionTag=proposition['tag']) 86 | self.submit(task, queue=queueTag) 87 | return 88 | 89 | 90 | 91 | 92 | SMP = SMPPlatform() 93 | -------------------------------------------------------------------------------- /opal/Platforms/sungrid.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import os 3 | import time 4 | 5 | from ..core.platform import Platform 6 | from ..core.platform import Task 7 | 8 | class SunGridTask(Task): 9 | def __init__(self, name=None, 10 | taskId=None, 11 | command=None, 12 | options=None, 13 | logHandlers=[]): 14 | self.job_id = taskId 15 | sungridCmd = "qsub -cwd -V " + \ 16 | '-o ' + self.job_id + '-stdout.log ' +\ 17 | '-e ' + self.job_id + '-stderr.log ' +\ 18 | "-N " + self.job_id + ' ' +\ 19 | options + ' ' +\ 20 | '-b y ' + command + \ 21 | ' > /dev/null' 22 | 23 | Task.__init__(self, 24 | name=name, 25 | taskId=taskId, 26 | command=sungridCmd, 27 | logHandlers=logHandlers) 28 | #self.logger.log(sungridCmd) 29 | return 30 | 31 | def run(self): 32 | os.system(self.command) 33 | self.wait() 34 | os.remove(self.job_id + '-stdout.log') 35 | os.remove(self.job_id + '-stderr.log') 36 | Task.run(self) 37 | return 38 | 39 | def wait(self): 40 | # This function playes in role of synchronyzers 41 | # 1 - Generate a synchronizing job including a segment code that 42 | # notifies to current process by socket (notifyToMaster) 43 | # 2 - Prepare a waiting socket: create, bind, .. 44 | # 3 - Submit the synchronizing with the condition specified in 45 | # the condition 46 | # 4 - Turn in waiting by listening the notify at created socket 47 | # Argument condition may be "ended(CUTEr-*)" 48 | #------------------- 49 | # Set default socket parameter 50 | #------------------- 51 | port = 19879 52 | hostname = socket.gethostname() 53 | ltime = time.localtime() 54 | keyStr = str(ltime.tm_year) + str(ltime.tm_mon) + str(ltime.tm_mday) +\ 55 | str(ltime.tm_hour) + str(ltime.tm_min) + str(ltime.tm_sec) 56 | #------------------------- 57 | # Prepare socket 58 | #----------- 59 | serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 60 | socketIsBound = 0 61 | #----------------- 62 | # Choose an available port to avoid conflit with the other routine 63 | # Particularly, the other parameter optimization 64 | while socketIsBound == 0: 65 | try: 66 | serversocket.bind((hostname, port)) 67 | socketIsBound = 1 68 | except: 69 | port = port + 1 70 | #print "waiting at",socket.gethostname(), port 71 | serversocket.listen(1) 72 | #----------------------- 73 | # Generating synchronizing job 74 | #---------------------- 75 | synchronizerFile = 'synchronizer_' + self.job_id + '.py' 76 | f = open(synchronizerFile, 'w') 77 | #synchronizerFile.write('#!/usr/bin/env python\n') 78 | f.write('import socket\n') 79 | f.write('port = ' + str(port) + '\n') 80 | f.write('s = socket.socket(socket.AF_INET, ' + \ 81 | 'socket.SOCK_STREAM)\n') 82 | f.write('s.connect(("' + hostname + '",' + \ 83 | str(port) + '))\n') 84 | f.write('s.send("'+ keyStr + '")\n') 85 | f.write('s.close()\n') 86 | f.close() 87 | 88 | #ltime = time.localtime() 89 | #timeStr = str(ltime.tm_year) + '-' + str(ltime.tm_mon) + '-' + \ 90 | # str(ltime.tm_mday) + ' ' + str(ltime.tm_hour) + ':' + \ 91 | # str(ltime.tm_min) + ':' + str(ltime.tm_sec) 92 | #os.system('echo ' + timeStr + ' Begin waiting >> lsf-sync.log') 93 | synchronizeCmd = 'qsub -cwd -V ' +\ 94 | '-N sync_' + self.job_id + ' ' +\ 95 | '-o sync_' + self.job_id + '-stdout.log ' +\ 96 | '-e sync_' + self.job_id + '-stderr.log ' +\ 97 | '-hold_jid ' + self.job_id + ' ' +\ 98 | '-b y python ' + synchronizerFile + ' > /dev/null' 99 | os.system(synchronizeCmd) 100 | #----------------------- 101 | # Waiting for the notify from synchonizer 102 | # --------------------- 103 | recvKey = '' 104 | while recvKey != keyStr: 105 | (clientsocket, address) = serversocket.accept() 106 | recvKey = clientsocket.recv(len(keyStr)) 107 | clientsocket.close() 108 | # print address, "is connected" 109 | #-------------- 110 | # free the sockets if received a notification 111 | #----------------- 112 | 113 | #clientsocket.close() 114 | serversocket.close() 115 | #ltime = time.localtime() 116 | #timeStr = str(ltime.tm_year) + '-' + str(ltime.tm_mon) + '-' + \ 117 | # str(ltime.tm_mday) + ' ' + str(ltime.tm_hour) + ':' + \ 118 | # str(ltime.tm_min) + ':' + str(ltime.tm_sec) 119 | #os.system('echo ' + timeStr + ' End waiting >> lsf-sync.log') 120 | os.remove(synchronizerFile) 121 | os.remove('sync_' + self.job_id + '-stdout.log') 122 | os.remove('sync_' + self.job_id + '-stderr.log') 123 | return 124 | 125 | class SunGridPlatform(Platform): 126 | def __init__(self, maxTask=3, synchronous=False, logHandlers=[]): 127 | Platform.__init__(self, 128 | name='SunGrid', 129 | maxTask=maxTask, 130 | logHandlers=logHandlers) 131 | self.configuration = {} 132 | self.message_handlers['cfp-execute'] = self.create_task 133 | pass 134 | 135 | def set_config(self, parameterName, parameterValue=None): 136 | ''' 137 | Configuration can be express as option string and store in 138 | OPTIONS fields of setting attribute 139 | ''' 140 | if self.settings['OPTIONS'] is None: 141 | self.settings['OPTIONS'] = parameterName + ' ' + parameterValue 142 | else: 143 | self.settings['OPTIONS'] = self.settings['OPTIONS'] + ' ' +\ 144 | parameterName + ' ' + parameterValue 145 | self.configuration[parameterName] = parameterValue 146 | return 147 | 148 | def initialize(self, testId): 149 | return 150 | 151 | def create_task(self, info): 152 | ''' 153 | 154 | Handle a call for proposal of executing a command through SunGrid 155 | platform 156 | ''' 157 | 158 | if 'proposition' not in info.keys(): 159 | self.logger.log('Proposal of executing a command has not ' + \ 160 | 'information to process') 161 | return 162 | execCmd = info['proposition']['command'] 163 | tag = info['proposition']['tag'] 164 | if 'queue' in info['proposition'].keys(): 165 | queueTag = info['proposition']['queue'] 166 | else: 167 | queueTag = None 168 | 169 | # str(ltime.tm_year) + str(ltime.tm_mon) + str(ltime.tm_mday) + \ 170 | # str(ltime.tm_hour) + str(ltime.tm_min) + str(ltime.tm_sec) 171 | 172 | optionStr = self.settings['OPTIONS'] 173 | 174 | task = SunGridTask(name=tag, 175 | taskId='SGE_' + tag, 176 | command=execCmd, 177 | options=optionStr) 178 | self.submit(task, queue=queueTag) 179 | return 180 | 181 | SunGrid= SunGridPlatform() 182 | -------------------------------------------------------------------------------- /opal/Platforms/test_platforms.py: -------------------------------------------------------------------------------- 1 | def test_linux_platform(): 2 | #assert 'b' == 'b' 3 | from ..core.mafrw import Environment 4 | from linux import LINUX 5 | 6 | env = Environment(name='test platform environment') 7 | LINUX.register(env) 8 | LINUX.submit('ls') 9 | 10 | -------------------------------------------------------------------------------- /opal/Solvers/__init__.py: -------------------------------------------------------------------------------- 1 | #from NOMAD import NOMADBlackbox 2 | from nomad import NOMAD 3 | from nomad import NOMADMPI 4 | -------------------------------------------------------------------------------- /opal/TestProblemCollections/CUTEr.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | import os.path 3 | import pickle 4 | import sys 5 | #from paropt.components.testenv import CUTEr as testEnvironment 6 | 7 | from ..core.testproblem import * 8 | 9 | from cuterfactory import CUTErFactory 10 | from cuterfactory import CUTErQuery 11 | 12 | #data_file = os.path.join(os.path.dirname(os.path.abspath(sys.modules[__name__].__file__)),'CUTEr.data') 13 | data_file = os.path.join(os.path.expanduser('~'),'.opal/CUTEr-1.data') 14 | #print data_file 15 | # Object definition 16 | try: 17 | f = open(data_file,'r') 18 | CUTEr = pickle.load(f) 19 | f.close() 20 | except IOError: 21 | classfDir = os.environ['MASTSIF'] 22 | classfName='CLASSF.DB' # Standard name for CUTEr classify file 23 | classfFile = os.path.join(classfDir, classfName) 24 | CUTEr_factory = CUTErFactory(classifyFile=classfFile) 25 | CUTEr = CUTEr_factory.generate_collection() 26 | CUTEr.HS = CUTEr.select(CUTErQuery(name='HS\d+')) 27 | f = open(data_file,'w') 28 | pickle.dump(CUTEr,f) 29 | f.close() 30 | -------------------------------------------------------------------------------- /opal/TestProblemCollections/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from CUTEr import CUTEr 3 | from cuterfactory import CUTErQuery 4 | except: 5 | print 'Something went wrong while trying to import CUTEr.' 6 | print 'Skipping.' 7 | -------------------------------------------------------------------------------- /opal/TestProblemCollections/cuterfactory.py: -------------------------------------------------------------------------------- 1 | import os 2 | import shutil 3 | import re 4 | from ..core.testproblem import * 5 | 6 | class CUTErTestProblem(OptimizationTestProblem): 7 | 8 | def __init__(self, 9 | name=None, 10 | description=None, 11 | classifyStr=None, 12 | nvar=0, 13 | ncon=0, 14 | paramString=None, 15 | **kwargs): 16 | OptimizationTestProblem.__init__(self, 17 | name=name, 18 | description=description, 19 | classifyStr=classifyStr, 20 | nvar=nvar, 21 | ncon=ncon, 22 | **kwargs) 23 | self.parameter_string = paramString 24 | 25 | class CUTErQuery: 26 | 27 | def __init__(self,qName=None, 28 | namePattern='', 29 | nMin=0,nMax=1000000, 30 | mMin=0,mMax=1000000, 31 | objectiveType='NCLQSO', 32 | constraintType='UXBNLQO', 33 | smoothType='IR', 34 | infoOrder=0, 35 | problemType="AMR", 36 | internalVar='YN', 37 | **kwargs): 38 | """ 39 | An example of a query 40 | query = Query(namePattern='HS', 41 | nMin=0, 42 | nMax=10, 43 | objectiveType="N", 44 | constraintType="U") 45 | """ 46 | self.name_pattern = namePattern 47 | self.nMin = nMin 48 | self.nMax = nMax 49 | self.mMin = mMin 50 | self.mMax = mMax 51 | self.objectiveType = objectiveType 52 | self.constraintType = constraintType 53 | self.smoothType = smoothType 54 | self.infoOrder = infoOrder 55 | self.problemType = problemType 56 | self.internalVar = internalVar 57 | 58 | def match(self, problem): 59 | #print self.nMax, self.mMax, probDescStr, 60 | descFields = problem.get_classify_string().split("-") 61 | for i in range(len(descFields)): 62 | descFields[i] = descFields[i].strip() 63 | #descFields[0:] = descFields[0:].strip() 64 | if re.compile(self.name_pattern).match(problem.get_name()) is None: 65 | return False 66 | if self.objectiveType.count(descFields[0][0]) <= 0: 67 | #print self.objectiveType, 'is not sastified' 68 | return False 69 | if self.constraintType.count(descFields[0][1]) <= 0: 70 | #print self.constraintType, 'is not sastified' 71 | return False 72 | if self.smoothType.count(descFields[0][2]) <= 0: 73 | #print self.smoothType, 'is not sastified' 74 | return False 75 | if self.infoOrder > int(descFields[0][3:]): 76 | #print 'info order is not sastified' 77 | return False 78 | if self.problemType.count(descFields[1][0]) <= 0: 79 | #print self.problemType, 'is not satisfied' 80 | return False 81 | if self.internalVar.count(descFields[1][1]) <= 0: 82 | return False 83 | if descFields[2].count("V") <= 0: 84 | if self.nMin > int(descFields[2]): 85 | #print descFields[2], 'variables is not satisifed' 86 | return False 87 | if self.nMax < int(descFields[2]): 88 | #print descFields[2], 'variables is not satisifed' 89 | return False 90 | if descFields[3].count("V") <= 0: 91 | if self.mMin > int(descFields[3]): 92 | #print descFields[3], 'constraints is not satisifed' 93 | return False 94 | if self.mMax < int(descFields[3]): 95 | #print descFields[3], 'constraints is not satisifed' 96 | return False 97 | #print 'Query is matched' 98 | return True 99 | 100 | #========== 101 | 102 | class CUTErFactory: 103 | def __init__(self,classifyFile=None,**kwargs): 104 | self.classifyFile = classifyFile 105 | self.decoder = 'sifdecode' 106 | self.dbDir = os.environ['MASTSIF'] 107 | pass 108 | 109 | def extract(self, **kwargs): 110 | queryResult = [] 111 | queryPharse = Query(**kwargs) 112 | if self.classifyFile == None: 113 | return queryResult 114 | f = open(self.classifyFile,'r') 115 | lines = f.readlines() 116 | f.close() 117 | for line in lines: 118 | line = line.strip() 119 | if len(line) <= 2: 120 | continue 121 | #print line 122 | fields = line.split(' ',1) 123 | if queryPharse.match(fields[0].strip(),fields[1].strip()): 124 | #print fields[0], 'is added' 125 | queryResult.append(fields[0].strip()) 126 | return queryResult 127 | 128 | def generate_collection(self): 129 | f = open(self.classifyFile, 'r') 130 | lines = f.readlines() 131 | f.close() 132 | CUTEr = ProblemCollection(name='CUTEr collection') 133 | for line in lines: 134 | line = line.strip() 135 | if len(line) <= 2: 136 | # Emtry line with new line symbol 137 | continue 138 | #print line 139 | fields = line.split(' ',1) 140 | prob = self.generate_problem(fields[0].strip(),fields[1].strip()) 141 | if prob is not None: 142 | CUTEr.add_problem(prob) 143 | return CUTEr 144 | 145 | def generate_problem(self,problem_name,classify_string=None,param=None): 146 | decode_cmd = self.decoder 147 | if param is None: 148 | decode_cmd = decode_cmd + ' ' + problem_name 149 | else: 150 | decode_cmd = decode_cmd + ' -param ' + param + ' ' + problem_name 151 | f = os.popen(decode_cmd) 152 | decode_log = f.read() 153 | f.close() 154 | variable_query = re.compile('[0-9]+[ a-z]+variable[s]?') 155 | constraint_query = re.compile('[0-9]+[ a-z]+constraint[s]?') 156 | number_query = re.compile('\d+') 157 | nvar = 0 158 | variable_declarations = variable_query.findall(decode_log) 159 | #print problem_name, 160 | for var_decl in variable_declarations: 161 | #print var_decl, 162 | nvar = nvar + int(number_query.findall(var_decl)[0]) 163 | #print '' 164 | constraint_declarations = constraint_query.findall(decode_log) 165 | ncon = 0 166 | for cons_decl in constraint_declarations: 167 | ncon = ncon + int(number_query.findall(cons_decl)[0]) 168 | if (nvar + ncon <= 0): 169 | return None 170 | # There is no problem nvar + ncon = 0 171 | problem = CUTErTestProblem(name=problem_name, 172 | classifyStr=classify_string, 173 | nvar=nvar, 174 | ncon=ncon) 175 | return problem 176 | -------------------------------------------------------------------------------- /opal/__init__.py: -------------------------------------------------------------------------------- 1 | from core.modelstructure import ModelStructure, MeasureFunction 2 | from core.modeldata import ModelData 3 | from core.model import Model 4 | from core.parameter import Parameter 5 | from core.measure import Measure 6 | from core.algorithm import Algorithm 7 | from core.testproblem import TestProblem 8 | 9 | 10 | -------------------------------------------------------------------------------- /opal/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | import ConfigParser as cfg # In python 3, this module is changed to configparser 3 | from Platforms import LINUX as platform 4 | 5 | def create_default_configuration(): 6 | configuration = cfg.ConfigParser() 7 | configuration.add_section('SYSTEM') 8 | configuration.set('SYSTEM','Python','#!/usr/bin/env python') 9 | return configuration 10 | 11 | def read_config(): 12 | configFile = os.environ['HOME'] + '/.opal/opal.cfg' 13 | if not os.path.exists(configFile): 14 | return create_default_configuration() 15 | configuration = cfg.ConfigParser() 16 | configuration.read(configFile) 17 | return configuration 18 | 19 | configuration = read_config() 20 | python = configuration.get('SYSTEM','Python') 21 | #paroptRootPackage = 'dev.paropt' 22 | -------------------------------------------------------------------------------- /opal/core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PythonOptimizers/opal/b6e12bafe7210910a6df2a9b59829cde584153cb/opal/core/__init__.py -------------------------------------------------------------------------------- /opal/core/datamanager.py: -------------------------------------------------------------------------------- 1 | import os 2 | import string 3 | import types 4 | import time 5 | import shutil 6 | import log 7 | import copy 8 | #import logging 9 | 10 | #import utility 11 | from testproblem import TestProblem 12 | from mafrw import Agent 13 | 14 | from .. import config 15 | 16 | 17 | class DataManager(Agent): 18 | """ 19 | 20 | An object of this class is responsable to collect data, 21 | support access to data of a test corresponding to one set 22 | of parameter 23 | 24 | During a session working of data generator, it is activated 25 | at first, wait for signal of a task to collect the data and 26 | store data following its rules. Normally, the data is stored 27 | in external memory (for example a file) but a part can be loaded 28 | into memory (a variable of DataController object). 29 | 30 | The other components needing data sends to this object a 31 | request and get the data. 32 | """ 33 | def __init__(self, 34 | name='data manager', 35 | rows=None, 36 | columns=None, 37 | storage=None, 38 | logHandlers=[]): 39 | self.file_name = 'data_storage.txt' 40 | Agent.__init__(self, name=name, logHandlers=logHandlers) 41 | self.message_handlers['inform-measure-values'] = self.add_data 42 | self.message_handlers['cfp-collect'] = self.collect_data 43 | return 44 | 45 | # Management functionality 46 | def update(self, problem, parameterTag, data): 47 | return 48 | 49 | def find(self, query): 50 | return 51 | 52 | # Message handlers 53 | def add_data(self, info): 54 | if info is None: 55 | return 56 | 57 | paramTag = info['proposition']['parameter-tag'] 58 | prob = info['proposition']['problem'] 59 | data = info['proposition']['values'] 60 | # Update the entry 61 | self.update(parameterTag=paramTag, 62 | problem=prob, 63 | data=data) 64 | # Get all data entry corresponding to the tag 65 | dataEntry = self.find(self, query={'tag':paramTag}) 66 | # Send a message informing availbility of data 67 | if dataEntry.is_complete(): 68 | msg = Message(sender=self.id, 69 | performative='inform', 70 | content={'proposition':{'what':'data-availability', 71 | 'how':'complete', 72 | 'data':dataEntry} 73 | } 74 | ) 75 | else: 76 | msg = Message(sender=self.id, 77 | performative='inform', 78 | content={'proposition':{'what':'data-availability', 79 | 'how':'partial', 80 | 'data':dataEntry} 81 | } 82 | ) 83 | self.send_message(msg) 84 | return 85 | 86 | def find_data(self, info): 87 | 88 | (paramValues, problem) = message.content['proposition'] 89 | measureValues = self.query_data(parameters=paramValues, 90 | problem=problem) 91 | # If getting data is successful 92 | if measureValues is not None: 93 | # Create a reply message whose content contains the 94 | # measure values 95 | msgCont = self.encrypt(measureValues) 96 | msg = Message(sender=self.id, 97 | content=msgCont, 98 | performative='inform', 99 | reference=message.id) 100 | return 101 | 102 | def collect_data(self, message): 103 | (paramValues, problem, measureFile) = message.content['proposition'] 104 | f = open(measureFile) 105 | f.close() 106 | return 107 | 108 | # Private methods 109 | def query_data(self, parameters=None, problem=None): 110 | return None 111 | -------------------------------------------------------------------------------- /opal/core/io.py: -------------------------------------------------------------------------------- 1 | # Simple helper functions for input and output. 2 | 3 | def read_params_from_file(filename): 4 | converters = {'categorical':str, 'integer':int, 'real':float} 5 | fp = open(filename, 'rb') 6 | params = {} 7 | for line in fp: 8 | words = line.strip('\n').split(':') 9 | params[words[0]] = converters[words[1]](words[2]) 10 | fp.close() 11 | return params 12 | 13 | 14 | def write_measures_to_file(filename, measures): 15 | fp = open(filename, 'w') 16 | for measure in measures: 17 | print >> fp, measure, measures[measure] 18 | fp.close() 19 | return 20 | 21 | -------------------------------------------------------------------------------- /opal/core/log.py: -------------------------------------------------------------------------------- 1 | import re 2 | import logging 3 | 4 | class HandlerDescription: 5 | def __init__(self, handler): 6 | self.file_name = handler.baseFilename 7 | self.level = handler.level 8 | 9 | def generate_handler(self): 10 | handler = logging.FileHandler(filename=self.file_name) 11 | handler.set_level(self.level) 12 | return handler 13 | 14 | class OPALLogger: 15 | ''' 16 | 17 | We specialize logging facility of Python by this class to support 18 | the ability of pickling an logger with handlers that are the streamming 19 | objects 20 | ''' 21 | 22 | def __init__(self, name=None, handlers=[]): 23 | self.name = name 24 | self.initialize() 25 | # Initialize an empty list of descriptions 26 | # of the user-required handlers 27 | self.handler_descriptions = [] 28 | # Get the description of the user-required handlers 29 | # and add it to logger 30 | for hdlr in handlers: 31 | self.handler_descriptions.append(HandlerDescription(hdlr)) 32 | self.logger.addHandler(hdlr) 33 | return 34 | 35 | def initialize(self): 36 | self.logger = logging.getLogger(self.name) 37 | self.logger.setLevel(logging.DEBUG) # Set level to highest level so 38 | # that actual level depends on the 39 | # handler level 40 | # A default handler is created for logging to file with INFO level 41 | handler = logging.FileHandler(filename='/var/tmp/opal.log') 42 | handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s: %(message)s')) 43 | handler.setLevel(logging.INFO) 44 | self.logger.addHandler(handler) 45 | return 46 | 47 | def __getstate__(self): 48 | # To serialize a OPALLogger object, we save only 49 | # the name and the descriptions of the user-required handlers 50 | dict = {} 51 | dict['handler_descriptions'] = self.handler_descriptions 52 | dict['name'] = self.name 53 | return dict 54 | 55 | def __setstate__(self, dict): 56 | # The expected dict is two-element dictionary. 57 | # The first element of dict has key is 'handler_descriptions' 58 | # and has value is a list of description of handlers. The 59 | # second one is the name of logger. 60 | self.name = dict['name'] 61 | # Initialize the logger with the specified name 62 | self.initialize() 63 | # Create the handler descriptions for unpickled object 64 | # and create handlers for the logger 65 | self.handler_descriptions = dict['handler_descriptions'] 66 | for desc in self.handler_descriptions: 67 | handler = desc.generate_handler() 68 | self.logger.addHandler(handler) 69 | return 70 | 71 | def log(self, message, level=logging.INFO): 72 | self.logger.log(level, message + '\n') 73 | return 74 | 75 | 76 | class Debugger: 77 | def __init__(self, fileName='/var/tmp/opal-debug.log'): 78 | self.logger = logging.getLogger('DEBUG') 79 | self.logger.setLevel(logging.DEBUG) 80 | handler = logging.FileHandler(filename=fileName) 81 | handler.setLevel(logging.DEBUG) 82 | handler.setFormatter(logging.Formatter(\ 83 | '%(asctime)s - %(name)s: %(message)s')) 84 | self.logger.addHandler(handler) 85 | return 86 | 87 | def log(self, message, level=logging.DEBUG): 88 | self.logger.log(level, message) 89 | return 90 | 91 | debugger = Debugger() 92 | 93 | 94 | -------------------------------------------------------------------------------- /opal/core/measure.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | from data import Data 4 | from data import DataTable 5 | from tools import TableFormatter 6 | 7 | 8 | class Measure(Data): 9 | ''' 10 | 11 | A Measure object represent for an observation from output of 12 | algorithm running. It has two aspect 13 | - Data: its value is value of an observation 14 | - Functionality: It encapsulates the way to extract measure value 15 | from the output. 16 | ''' 17 | 18 | def __init__(self, name=None, description='', kind=None, **kwargs): 19 | Data.__init__(self, name=name, description=description, type=kind) 20 | return 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /opal/core/model.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import os.path 4 | import pickle 5 | import log 6 | 7 | from platform import Platform 8 | from ..Platforms import LINUX 9 | 10 | #from opal.core.modelstructure import ModelEvaluator 11 | 12 | __docformat__ = 'restructuredtext' 13 | 14 | 15 | class Model: 16 | def __init__(self, modelData=None, 17 | modelStructure=None, 18 | evaluatingOptions=None, 19 | dataFile='blackbox.dat', 20 | **kwargs): 21 | """ 22 | 23 | A `BlackBoxModel` encapsulates the 24 | information of a parameter optimization problem. 25 | From the parameter problem point of view, this class has 26 | two components: model data and model struture. 27 | 28 | Example:: 29 | 30 | blackbox = Model(modelStructure, modelData) 31 | 32 | An object of this class must contain a link to a solver. 33 | The link to a solver is created by the solver and added to the 34 | BlackBoxModel object upon solving the problem. 35 | 36 | """ 37 | 38 | self.data = modelData 39 | self.structure = modelStructure 40 | #self.runFileName = runFileName 41 | self.data_file = dataFile 42 | # The evaluating_options attribute accepts only 43 | # the options of simple type like boolean, integer 44 | # or string. In general, it accepts the options 45 | # of picklable data type. 46 | 47 | self.evaluating_options = {} 48 | # Update the running options from data 49 | self.evaluating_options.update(modelData.running_options) 50 | # If there is an option with the same name, it is overwritten by 51 | # the setting in model 52 | if evaluatingOptions is not None: 53 | self.evaluating_options.update(evaluatingOptions) 54 | self.evaluating_options.update(kwargs) 55 | 56 | # Get the information about used platform. Normally, platform object 57 | # is not be picklable, So we try to get the information to save 58 | # along with the model data, and use it to reconstruct the platform 59 | # object in run-time. 60 | # By default, LINUX is used 61 | self.platform_description = {'name':'LINUX', 62 | 'settings':{}} 63 | if 'platform' in self.evaluating_options.keys(): 64 | platform = self.evaluating_options['platform'] 65 | if type(platform) == type('a platform name'): 66 | self.platform_description['name'] = platform 67 | elif isinstance(platform, Platform): # A Platform object 68 | self.platform_description['name'] = platform.name 69 | self.platform_description['settings'] = platform.settings 70 | else: # Unable to recognize the specified platfom 71 | pass # Do nothing and use the default platform 72 | del self.evaluating_options['platform'] # Remove platform setting 73 | self.initialize() 74 | return 75 | 76 | def initialize(self): 77 | # Transformation to information of an optimization model 78 | # The variables are the parameters 79 | self.variables = self.data.parameters 80 | # Refomulate the constraints 81 | self.inequality_constraints = [] # c_i(x) <= 0 82 | self.equality_constraints = [] # c_e(x) = 0 83 | for constraint in self.structure.constraints: 84 | if constraint.lower_bound == constraint.upper_bound: 85 | self.equality_constraints.append(constraint) 86 | else: 87 | if constraint.lower_bound is not None: 88 | self.inequality_constraints.append(constraint) 89 | if constraint.upper_bound is not None: 90 | self.inequality_constraints.append(constraint) 91 | 92 | self.bounds = [var.bound for var in self.variables] 93 | 94 | # Initial points has at least one point that is the default values 95 | # of the parameters. 96 | self.initial_points = [[var.value for var in self.variables]] 97 | 98 | # The "simple constraints" that contain only the function of 99 | # parameters. This constraints will be verified before running 100 | # the test. 101 | # In the futre, the bound constraints will be considered as 102 | # simple_constraints too 103 | self.simple_constraints = [] 104 | pass 105 | 106 | # The methods to get information of a general model 107 | 108 | def get_n_variable(self): 109 | return len(self.variables) 110 | 111 | def get_n_constraints(self): 112 | return len(self.inequality_constraints) + len(self.equality_constraints) 113 | 114 | def get_initial_points(self): 115 | return self.initial_points 116 | 117 | def add_initial_point(self, point): 118 | converters = {'real':float, 119 | 'integer':int, 120 | 'categorical':str} 121 | initialPoint = [] 122 | for param, val in map(None, self.variables, point): 123 | if param is None: # The point is longer 124 | pass # do nothing 125 | elif val is None: # Set to default value 126 | initialPoint.append(param.get_default()) 127 | else: # Convert automatically to the corresponding type 128 | initialPoint.append(converters[param.kind](val)) 129 | self.initial_points.append(initialPoint) 130 | 131 | def get_bound_constraints(self): 132 | return self.bounds 133 | 134 | # The methods to get information of a OPAL model 135 | 136 | def get_algorithm(self): 137 | return self.data.get_algorithm() 138 | 139 | def get_parameters(self): 140 | return self.data.get_parameters() 141 | 142 | def get_problems(self): 143 | return self.data.get_problems() 144 | 145 | def get_measures(self): 146 | return self.data.get_measures() 147 | 148 | def get_structure(self): 149 | return self.structure 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /opal/core/modeldata.py: -------------------------------------------------------------------------------- 1 | import os 2 | import string 3 | import types 4 | import time 5 | import shutil 6 | import log 7 | import copy 8 | #import logging 9 | 10 | #import utility 11 | from testproblem import TestProblem 12 | 13 | from .. import config 14 | 15 | 16 | 17 | # ============================= 18 | class ModelData: 19 | """ 20 | This class represents a data generator for a parameter optimization 21 | problem. The data is the values of the elementary measures that are needed 22 | to formulate the problem. To specify a data generator, we need provide: 23 | 24 | 1. The algorithm 25 | 2. the set of elementary measures concerned 26 | 3. the set of parameters to control 27 | 4. the test problems set. 28 | """ 29 | 30 | def __init__(self, 31 | algorithm, 32 | problems=[], 33 | parameters=None, 34 | measures=None, 35 | neighborhoods=[], 36 | **kwargs): 37 | # The core variables 38 | self.algorithm = algorithm 39 | if (problems is None) or (len(problems) == 0): 40 | self.problems = [TestProblem(name='TESTPROB')] 41 | else: 42 | self.problems = problems 43 | 44 | if parameters is None: 45 | self.parameters = algorithm.parameters 46 | else: 47 | self.parameters = parameters 48 | 49 | if measures is None: 50 | self.measures = algorithm.measures 51 | else: 52 | self.measures = measures 53 | # The information of parameter space can be provided by definitions 54 | # of neighborhood. 55 | self.neighborhoods = neighborhoods 56 | 57 | self.running_options = {} 58 | self.running_options.update(kwargs) 59 | return 60 | 61 | def get_problems(self): 62 | return self.problems 63 | 64 | def get_algorithm(self): 65 | return self.algorithm 66 | 67 | def get_parameters(self): 68 | return self.parameters 69 | 70 | def get_measures(self): 71 | return self.measures 72 | 73 | def save(self, fileName): 74 | return 75 | 76 | def load(self, fileName): 77 | return 78 | 79 | -------------------------------------------------------------------------------- /opal/core/modelevaluator.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import os.path 4 | import pickle 5 | import log 6 | import hashlib 7 | 8 | from .mafrw import Agent 9 | from .mafrw import Message 10 | from .datagenerator import DataGenerator 11 | from .structureevaluator import StructureEvaluator 12 | from ..Platforms import supported_platforms 13 | 14 | #from opal.core.modelstructure import ModelEvaluator 15 | 16 | __docformat__ = 'restructuredtext' 17 | 18 | 19 | class ModelEvaluator(Agent): 20 | def __init__(self, 21 | name='model evaluator', 22 | model=None, 23 | modelFile=None, 24 | options={}, 25 | logHandlers=[]): 26 | Agent.__init__(self, name=name, logHandlers=logHandlers) 27 | self.options = {'platform': 'LINUX', 28 | 'synchronized': False, 29 | 'interruptible': True} 30 | self.options.update(options) 31 | if model is None: 32 | if modelFile is not None: 33 | # The model is loaded by pickling 34 | # Be able to be serialized is a requirement for 35 | # a model object 36 | f = open(modelFile) 37 | model = pickle.load(f) 38 | f.close() 39 | 40 | self.model = model 41 | self.model_file = modelFile 42 | self.options.update(self.model.evaluating_options) 43 | 44 | # if platform option is provided by a string representing the name of 45 | # a OPAL-supported platform 46 | 47 | self.message_handlers['cfp-evaluate-point'] = \ 48 | self.activate_parameter_evaluation 49 | self.message_handlers['inform-experiment-failed'] = \ 50 | self.handle_experiment_failed 51 | self.message_handlers['inform-objective-partially-exceed'] = \ 52 | self.estimate_partially_model 53 | self.message_handlers['inform-constraint-partially-violated'] = \ 54 | self.estimate_partially_model 55 | return 56 | 57 | def register(self, environment): 58 | ''' 59 | 60 | After adding his name in the environment database, it will look for 61 | the agents that work as data manager, experiment manager and structure 62 | computer. 63 | If it could not find one of these agents within environment, it will 64 | create them and let them register to environment 65 | 66 | The find process is realized by sending a test message to environment 67 | and wait for replying. 68 | ''' 69 | Agent.register(self, environment) 70 | 71 | if self.model is None: 72 | return 73 | 74 | # Find the necessary collaborators. If could find it, create the 75 | # predefinded collaborators 76 | 77 | if self.find_collaborator('data generator', environment) is None: 78 | dataGenerator =\ 79 | DataGenerator(algorithm=self.model.get_algorithm(), 80 | parameters=self.model.get_parameters(), 81 | problems=self.model.get_problems(), 82 | platform=self.model.platform_description) 83 | dataGenerator.register(environment) 84 | 85 | if self.find_collaborator('structure evaluator', environment) is None: 86 | structureEvaluator = \ 87 | StructureEvaluator(structure=self.model.structure, 88 | problems=self.model.get_problems(), 89 | measures=self.model.get_measures()) 90 | structureEvaluator.register(environment) 91 | 92 | return 93 | 94 | def find_collaborator(self, name, environment): 95 | return None 96 | 97 | def create_tag(self, point): 98 | valuesStr = '_' 99 | for coordinate in point: 100 | valuesStr = valuesStr + str(coordinate) + '_' 101 | return hashlib.sha1(valuesStr).hexdigest() 102 | 103 | # Message handlers 104 | 105 | def activate_parameter_evaluation(self, info): 106 | parameterValues = info['proposition']['point'] 107 | if 'tag' in info['proposition'].keys(): 108 | parameterTag = info['proposition']['tag'] 109 | else: 110 | parameterTag = self.create_tag(parameterValues) 111 | 112 | message = Message(sender=self.id, 113 | performative='cfp', 114 | content={'action':'evaluate-parameter', 115 | 'proposition':{'parameter':parameterValues, 116 | 'tag':parameterTag} 117 | }) 118 | self.send_message(message) 119 | return 120 | 121 | def handle_experiment_failed(self, info): 122 | paramTag = info['proposition']['parameter-tag'] 123 | reason = info['proposition']['why'] 124 | # Send an inform message about the model-value with the value 125 | # is set to None. That indicates that there is something wrong in model 126 | # evaluation. 127 | message = Message(sender=self.id, 128 | performative='inform', 129 | content={'proposition':{'what':'model-value', 130 | 'values':None, 131 | 'why':reason, 132 | 'parameter-tag':paramTag 133 | } 134 | }) 135 | self.send_message(message) 136 | return 137 | 138 | def estimate_partially_model(self, info): 139 | 140 | paramTag = info['proposition']['parameter-tag'] 141 | message = Message(sender=self.id, 142 | performative='inform', 143 | content={'proposition':{'what':'model-value', 144 | 'values':None, 145 | 'why':'parameters invalid', 146 | 'parameter-tag':paramTag 147 | } 148 | }) 149 | self.send_message(message) 150 | return 151 | 152 | def stop(self, info=None): 153 | ''' 154 | 155 | Message handlers for STOP signal 156 | ''' 157 | # the model is saved back to file 158 | f = open(self.model_file, 'w') 159 | pickle.dump(self.model, f) 160 | f.close() 161 | Agent.stop(self, info) 162 | return 163 | 164 | 165 | -------------------------------------------------------------------------------- /opal/core/opalproblem.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import os.path 4 | import pickle 5 | import log 6 | 7 | #from opal.core.modelstructure import ModelEvaluator 8 | 9 | __docformat__ = 'restructuredtext' 10 | 11 | class BlackBox: 12 | """ 13 | This class manages the communication with the direct solver. 14 | The specific implementation depends on the solver used. For example, when 15 | the solver is NOMAD, an object of this class represents 16 | an executable file whose I/O methods depend on the specific solver. 17 | """ 18 | def __init__(self, solver=None, model=None, **kwargs): 19 | self.solver = solver 20 | self.model = model 21 | pass 22 | 23 | def run(self, *args, **kwargs): 24 | inputValues = [] 25 | paramValues = [] 26 | #print args 27 | (inputValues, paramValues) = self.read_input(*args, **kwargs) 28 | if self.model is None: 29 | return 30 | #print inputValues 31 | (objective,constraints) = self.model.evaluate(inputValues) 32 | self.write_output(objective,constraints) 33 | return 34 | 35 | def read_input(self,*args,**kwargs): 36 | return (None,None) 37 | 38 | def write_output(self,objectiveValue, constraintValues): 39 | return 40 | 41 | def set_parameter(self,*args,**kwargs): 42 | return 43 | 44 | class BlackBoxModel: 45 | def __init__(self, modelData=None, modelStructure=None, 46 | runFileName='blackbox.py', dataFile='blackbox.dat', 47 | logHandlers=[], **kwargs): 48 | """ 49 | 50 | A `BlackBoxModel` encapsulates the 51 | information of a parameter optimization problem. 52 | From the parameter problem point of view, this class has 53 | two components: model data and model struture. 54 | 55 | Example:: 56 | 57 | blackbox = BlackBoxModel(modelStructure, modelData) 58 | 59 | An object of this class must contain a link to a solver. 60 | The link to a solver is created by the solver and added to the 61 | BlackBoxModel object upon solving the problem. 62 | 63 | """ 64 | 65 | self.model_data = modelData 66 | self.model_structure = modelStructure 67 | #self.runFileName = runFileName 68 | self.data_file = dataFile 69 | self.logger = log.OPALLogger(name='opalBlackboxModel', 70 | handlers=logHandlers) 71 | 72 | 73 | activeParameters = self.model_data.get_parameters() 74 | 75 | self.n_var = len(activeParameters) 76 | self.m_con = len(self.model_structure.constraints) 77 | self.initial_points = [param.value for param in activeParameters] 78 | 79 | self.bounds = [param.bound for param in activeParameters] 80 | # The "simple constraints" that contain only the function of 81 | # parameters. This constraints will be verified before running 82 | # the test. 83 | # In the futre, the bound constraints will be considered as 84 | # simple_constraints too 85 | self.simple_constraints = [] 86 | 87 | 88 | #self.solver = None 89 | #self.surrogate = None 90 | # if no solver is specified, the blackbox is a general 91 | # executable file with two arguments: input file and parameter file 92 | # The output is standard screen 93 | self.save() 94 | pass 95 | 96 | #def set_options(self,**kwargs): 97 | # return 98 | 99 | #def has_surrogate(self): 100 | # return self.surrogate is not None 101 | 102 | #def get_surrogate(self): 103 | # return self.surrogate 104 | 105 | 106 | def evaluate(self, inputValues): 107 | """ 108 | Evaluate the model at given point 109 | Input: evaluated point coordinate 110 | Output: Value of objective function and constrains values list 111 | In the case of error, two None values are returned 112 | """ 113 | self.logger.log('Begin a blackbox evaluation') 114 | self.model_data.run(inputValues) 115 | testResult = self.model_data.get_test_result() 116 | #print 'ho ho after getTestResult', self.modelData.measures[0],\ 117 | # self.modelData.measures[0].valuetable 118 | # An evaluator object may be redudant, remove it in the future 119 | #modelEvaluator = ModelEvaluator(self.model_structure, 120 | # self.model_data.measures) 121 | (funcObj, constraints) = self.model_structure.evaluate(testResult) 122 | #print funcObj 123 | #print constraints 124 | self.logger.log('End of blackbox evaluation') 125 | return (funcObj, constraints) 126 | 127 | def save(self): 128 | #try: 129 | blackboxDataFile = open(self.data_file, "w") 130 | pickle.dump(self, blackboxDataFile) 131 | blackboxDataFile.close() 132 | #except TypeError: 133 | # print "Error in saving" 134 | return 135 | 136 | #def log(self): 137 | # if self.model_data.log != None: 138 | # self.model_data.log(self.logFileName) 139 | # if self.model_structure.log != None: 140 | # self.model_structure.log(self.logFileName) 141 | # return 142 | 143 | def get_iniitial_points(self): 144 | return self.initial_points 145 | 146 | def get_bound_constraints(self): 147 | return self.bounds 148 | 149 | #def generate_surrogate(self): 150 | # reducedModelData = self.model_data.reduce_problem_set() 151 | # data_fname = self.dataFileName.strip('.dat') + '_surrogate.dat' 152 | # log_fname = self.logFileName.strip('.log') + '_surrogate.log' 153 | # surrogate = BlackBoxModel(modelData=reducedModelData, 154 | # modelStructure=self.model_structure, 155 | # dataFileName=data_fname, 156 | # logFileName=log_fame) 157 | # return surrogate 158 | -------------------------------------------------------------------------------- /opal/core/parameter.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | from opal.core.data import Data, DataSet 4 | 5 | class Parameter(Data): 6 | """ 7 | An abstract class to represent real, integer and categorical algorithmic 8 | parameters. Examples: 9 | 10 | >>> x = Parameter() # A real parameter with no default value 11 | >>> n = Parameter(kind='integer', default=3) 12 | >>> choice = Parameter(kind='categorical', default='left') 13 | 14 | Parameters can be given a name: 15 | 16 | >>> delmin = Parameter(default=1.0e-3, name='DELMIN') 17 | 18 | Their value can be changed from their default value: 19 | 20 | >>> delmin.set_value(0.1) 21 | 22 | Their default value is still available: 23 | 24 | >>> print delmin.get_default() 25 | 1.0e-3 26 | 27 | The bounds on a parameter may be a tuple indicating the lower and upper 28 | bounds if the parameter has an ordered kind, such as integer or real. 29 | Otherwise, `bound` is a set of feasible values. 30 | """ 31 | 32 | def __init__(self, kind='real', default=None, bound=None, name=None, 33 | description='', **kwargs): 34 | if kind not in ['real', 'integer', 'binary', 'categorical']: 35 | raise TypeError, 'kind must be real, integer or categorical' 36 | 37 | if kind == 'real' and type(default) != type(0.0): 38 | raise ValueError, 'default value must agree with type' 39 | 40 | if kind == 'integer' and type(default) != type(0): 41 | raise ValueError, 'default value must agree with type' 42 | 43 | self.kind = kind 44 | 45 | self.is_real = (kind == 'real') 46 | self.is_integer = (kind == 'integer') 47 | self.is_categorical = (kind == 'categorical') 48 | 49 | # The attribute value store the value of parameter in run time. 50 | # this is a run-time information 51 | # The _default is a description 52 | if default is not None: 53 | if kind == 'real' and type(default) != type(0.0): 54 | raise ValueError, 'default value must agree with type' 55 | if kind == 'integer' and type(default) != type(0): 56 | raise ValueError, 'default value must agree with type' 57 | self._default = default 58 | else: 59 | if self.kind == 'real': 60 | self._default = 0.0 61 | elif self.kind == 'integer': 62 | self._default = 0 63 | elif self.kind == 'binary': 64 | self._default = True 65 | else: 66 | self._default = 'something' 67 | 68 | Data.__init__(self, 69 | name=name, 70 | description=description, 71 | type=kind, 72 | value=self._default, 73 | dimension=1, 74 | domain=bound) 75 | self.bound = bound 76 | return 77 | 78 | def get_default(self): 79 | "Return default value" 80 | return self._default 81 | 82 | def set_default(self,value): 83 | "Set default value." 84 | if self.is_real: 85 | self._default = float(value) 86 | elif self.is_integer: 87 | self._default = int(value) 88 | else: 89 | self._default = value 90 | self.value = self._default 91 | return 92 | 93 | def set_value(self, value): 94 | "Set parameter value to a non-default value." 95 | if value is None: 96 | self.value = self._default 97 | return 98 | if self.is_real: 99 | self.value = float(value) 100 | elif self.is_integer: 101 | self.value = int(value) 102 | else: 103 | self.value = value 104 | return 105 | 106 | def set_as_const(self): 107 | "Treat parameter as a constant." 108 | self.kind = 'const' 109 | return 110 | 111 | def get_kind(self): 112 | "Return parameter kind." 113 | return self.kind 114 | 115 | def is_const(self): 116 | "Return True if parameter is being treated as a constant." 117 | return self.kind == 'const' 118 | 119 | def set_bound(self, bound): 120 | """ 121 | 122 | Set bounds on the parameter. For parameters of ordered kind, 123 | `set_bound((None, 0))` means that the lower bound is unchanged while 124 | the upper bound is reset to zero. For parameters of unordered kind, 125 | `set_bound` simply reassigns the list of feasible values. 126 | """ 127 | if self.is_categorical: 128 | self.bound = bound 129 | else: 130 | if self.bound is None: 131 | self.bound = (None, None) 132 | if bound[0] is not None: 133 | self.bound[0] = bound[0] 134 | if bound[1] is not None: 135 | self.bound[1] = bound[1] 136 | return 137 | 138 | def get_bound(self): 139 | """ 140 | 141 | Return bounds on the parameter. 142 | """ 143 | return self.bound 144 | 145 | def is_valid(self, value=None): 146 | """ 147 | 148 | Checks whether or not the specified value falls within the allowed 149 | range for this parameter. If `value` is None, the current value of 150 | the parameter is used. 151 | """ 152 | 153 | if value is not None: 154 | valueToVerify = value 155 | else: 156 | valueToVerify = self.value 157 | if self.bound is None: 158 | return True 159 | if self.is_categorical: 160 | return valueToVerify in self.bound 161 | # There is the error in transforming from string to int or float 162 | # For example, the value 0.0010000000 (in string in input file) is 163 | # 0.00100000000001 after forcing it as real number 164 | # Pay attention to verify the bound at bounded point 165 | if self.bound[0] is not None: 166 | if valueToVerify < self.bound[0]: 167 | return False 168 | if self.bound[1] is not None: 169 | if valueToVerify > self.bound[1]: 170 | return False 171 | return True 172 | 173 | def export_to_dict(self): 174 | """ 175 | 176 | Convert `Parameter` object to a dictionary. 177 | 178 | .. warning:: 179 | 180 | This does not include the bounds!!! 181 | """ 182 | return {'kind':self.kind, 183 | 'name':self.name, 184 | 'value':self.value, 185 | 'default':self._default} 186 | 187 | 188 | class ParameterConstraint: 189 | """ 190 | .. warning:: 191 | 192 | Document this class!!! 193 | """ 194 | 195 | violated = False 196 | def __init__(self,constraintStr='',*argv): 197 | self.constraintStr = constraintStr 198 | pass 199 | 200 | def __call__(self,parameters): 201 | constraintStr = self.constraintStr 202 | for param in parameters : 203 | constraintStr = constraintStr.replace(param.name,str(param.value)) 204 | return eval(constraintStr) 205 | 206 | 207 | def _test(): 208 | import doctest 209 | return doctest.testmod() 210 | 211 | 212 | def test_parameter_class(): 213 | p = Parameter(name='real_param') 214 | return 215 | 216 | if __name__ == "__main__": 217 | _test() 218 | 219 | -------------------------------------------------------------------------------- /opal/core/platform.py: -------------------------------------------------------------------------------- 1 | from mafrw import Agent 2 | from mafrw import Message 3 | 4 | class Task(Agent): 5 | def __init__(self, 6 | name=None, 7 | taskId=None, 8 | command=None, 9 | sessionTag=None, 10 | input=None, 11 | output='/dev/null', 12 | logHandlers=[]): 13 | ''' 14 | 15 | Each task object correspond to an application of the target 16 | algorithm on a test problem. 17 | 18 | ''' 19 | self.task_id = taskId # task_id is assigned by platform 20 | self.command = command 21 | self.output = output 22 | if name is None: 23 | Agent.__init__(self, name=command, logHandlers=logHandlers) 24 | else: 25 | Agent.__init__(self, name=name, logHandlers=logHandlers) 26 | if sessionTag is None: 27 | self.session_tag = self.name 28 | else: 29 | self.session_tag = sessionTag 30 | return 31 | 32 | def run(self): 33 | ''' 34 | 35 | The common activity of all task is send a message that informs 36 | termination of its work 37 | ''' 38 | message = Message(sender=self.id, 39 | performative='inform', 40 | receiver=None, 41 | content={'proposition':{'who':self.name, 42 | 'what':'task-finish', 43 | 'how':'no-error'} 44 | } 45 | ) 46 | self.send_message(message) 47 | message = Message(sender=self.id, 48 | performative='cfp', 49 | receiver=None, 50 | content={'action':'collect-result', 51 | 'proposition':{'session-tag':self.session_tag} 52 | } 53 | ) 54 | self.send_message(message) 55 | self.unregister() 56 | return 57 | 58 | 59 | 60 | class QueueSystem: 61 | # The default queue system managed the tasks in one or many queue 62 | # where each queue is identified by name 63 | def __init__(self): 64 | self.tasks = {'default':[]} 65 | return 66 | 67 | def get_length(self): 68 | length = 0 69 | for queueTag in self.tasks: 70 | length = length + len(self.tasks[queueTag]) 71 | return length 72 | 73 | def append(self, task, queue=None): 74 | if (queue is None) or (queue is 'default'): 75 | self.tasks['default'].append(task) 76 | else: 77 | if queue in self.tasks.keys(): 78 | self.tasks[queue].append(task) 79 | else: 80 | self.tasks[queue] = [task] 81 | return 82 | 83 | def pop(self, queue=None): 84 | if (queue is None) or (queue is 'default'): 85 | if len(self.tasks['default']) > 0 : 86 | return self.tasks['default'].pop() 87 | for queue in self.tasks.keys(): 88 | if queue is not 'default': 89 | return self.tasks[queue].pop() 90 | raise Exception('The task queue is empty') 91 | 92 | if queue in self.tasks.keys(): 93 | task = self.tasks[queue].pop() 94 | # Remove the queue if it is empty 95 | if len(self.tasks[queue]) == 0: 96 | del self.tasks[queue] 97 | return task 98 | raise Exception('The task queue does not exist') 99 | 100 | 101 | def remove_tasks(self, queue=None): 102 | if (queue is None) or (queue is 'default'): 103 | del self.tasks['default'][0:] 104 | return 105 | if queue in self.tasks.keys(): 106 | del self.tasks[queue] 107 | return 108 | return 109 | 110 | class Platform(Agent): 111 | def __init__(self, 112 | name='platform', 113 | maxTask=1, 114 | synchronous=False, 115 | queueSystem=None, 116 | settings=None, 117 | logHandlers=[], 118 | **kwargs): 119 | # A platform can contains many queues 120 | if queueSystem is None: 121 | self.queue_system = QueueSystem() 122 | else: 123 | self.queue_system = queueSystem 124 | self.settings = {'MAX_TASK':maxTask, 125 | 'SYNCHRONOUS':synchronous, 126 | 'OPTIONS':None} 127 | if settings is not None: 128 | self.settings.update(settings) 129 | self.settings.update(kwargs) 130 | 131 | # Running information 132 | self.running = {} 133 | self.task_id = 0 134 | Agent.__init__(self, name=name, logHandlers=logHandlers) 135 | self.message_handlers['inform-task-finish'] = self.finalize_task 136 | self.message_handlers['cfp-cancel-queue'] = self.cancel_queue 137 | return 138 | 139 | def set_parameter(self, settings=None, **kwargs): 140 | if settings is not None: 141 | self.settings.update(settings) 142 | self.settings.update(kwargs) 143 | return 144 | 145 | def submit(self, task, queue=None): 146 | # A task is created by each platform 147 | task.register(self.environment) 148 | self.queue_system.append(task, queue) 149 | #self.logger.log('Task ' + task.name + ' is added to queue') 150 | return task.id 151 | 152 | def finalize_task(self, info): 153 | taskName = info['proposition']['who'] 154 | del self.running[taskName] 155 | return 156 | 157 | def run(self): 158 | while self.working : 159 | if not self.settings['SYNCHRONOUS'] or len(self.running) == 0: 160 | # Submit task when there is no 161 | # running task 162 | #self.logger.log('Begin a launching session, we have ' + \ 163 | # str(len(self.queue)) + ' task') 164 | while (len(self.running) < self.settings['MAX_TASK']) and \ 165 | (self.queue_system.get_length() > 0): 166 | task = self.queue_system.pop() 167 | self.running[task.name] = task 168 | task.start() 169 | #self.logger.log('Task: ' + str(task.name) + ' is launched') 170 | # Work as an agent 171 | messages = self.fetch_messages() 172 | for msg in messages: 173 | self.handle_message(msg) 174 | del messages 175 | return 176 | 177 | # Message handlers 178 | 179 | def cancel_queue(self, info): 180 | if 'queue' in info['proposition'].keys(): 181 | queueTag = info['proposition']['queue'] 182 | else: 183 | queueTag = None 184 | self.queue_system.remove_tasks(queue=queueTag) 185 | return 186 | 187 | 188 | -------------------------------------------------------------------------------- /opal/core/savablefunction.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os.path 3 | import marshal 4 | import new 5 | import log 6 | 7 | class SavableFunction: 8 | """ 9 | This class contains the information of a measure function that 10 | built up from the parameter and elementary measure \varphi(p,\mu) 11 | """ 12 | def __init__(self, function=None, name=None,**kwargs): 13 | if function is None: 14 | raise Exception('The savable function definition is invalid') 15 | # The information of a function include all possible description 16 | # such as convexity, ... Any information is accepted 17 | # We concentrate on a property called possitively-additive. 18 | # A function objective is called possitively-additive if function value 19 | # of partial data is always less than or equal to the data-full one 20 | 21 | self.information = {} 22 | self.information.update(kwargs) 23 | # It's important to define a function with two arguments: 24 | #the parameter and the measure 25 | # We check if the given function sastifies this constraint: 26 | 27 | self.func = function 28 | if name is None: 29 | self.name = function.__code__.co_name 30 | else: 31 | self.name = name 32 | #self.name = function.__code__.co_name 33 | #self.code_string = None 34 | pass 35 | 36 | def evaluate(self, *args, **kwargs): 37 | if self.func is None: 38 | raise Exception('The measure function is not defined') 39 | return self.func(*args, **kwargs) 40 | #self.load() 41 | #value = self.func(*args, **kwargs) 42 | #del self.func 43 | #self.func = None # Keep self.func is None for the next pickling 44 | #return value 45 | 46 | def __getstate__(self): 47 | content = {} 48 | content['code'] = marshal.dumps(self.func.__code__) 49 | content['information'] = self.information 50 | content['name'] = self.name 51 | return content 52 | 53 | def __setstate__(self, content): 54 | self.func = new.function(marshal.loads(content['code']),globals()) 55 | self.information = content['information'] 56 | self.name = content['name'] 57 | return 58 | 59 | def __call__(self,*args,**kwargs): 60 | return self.evaluate(*args,**kwargs) 61 | 62 | 63 | -------------------------------------------------------------------------------- /opal/core/set.py: -------------------------------------------------------------------------------- 1 | class Set: 2 | """ 3 | 4 | Set is a group of elements distinguished by identity (given by identify() 5 | method). The Set class cover the apsects of two Python built-in data 6 | structures: dict and list. It keeps the order of the element like it added 7 | to Set. This means that we can access an element by its position. Each 8 | elements in the Set is assigned a key that is actually the identity of 9 | elements. A requirement applied to the elements of a Set object is each 10 | element has a method that show its identity. 11 | """ 12 | def __init__(self,name="", elements=[], *argv, **kwargv): 13 | self.name = name 14 | self.indices = {} 15 | self.db = [] 16 | if len(elements) > 0: 17 | index = 0 18 | for elem in elements: 19 | self.indices[elem.identify()] = index 20 | self.db.append(elem) 21 | index = index + 1 22 | return 23 | 24 | def __getitem__(self, id): 25 | ''' 26 | 27 | A data set object provide two ways to access an element: by order or by 28 | identity that provided by methode {\sf identify()} 29 | ''' 30 | if (type(id) == type(0)): 31 | return self.db[id] 32 | else: 33 | return self.db[self.indices[id]] 34 | 35 | def __len__(self): 36 | return len(self.db) 37 | 38 | def __contains__(self, elem): 39 | ''' 40 | 41 | There are two way to verify the existence of an element in a DataSet 42 | object. 43 | Either element or its identity can be provided for the verification. 44 | ''' 45 | # if this is an empty DataSet object the False signal is returned 46 | # immediately 47 | if len(self.indices) <= 0: 48 | return False 49 | idType = type(self.indices.keys()[0]) 50 | # Identity is provided to the verifcation 51 | if type(elem) == idType: 52 | return (elem in self.indices.keys()) 53 | # Element is provided 54 | else: 55 | try: 56 | return (elem.identify() in self.indices.keys()) 57 | except: 58 | return False 59 | 60 | def append(self, elem): 61 | ''' 62 | 63 | Add an element to the set 64 | ''' 65 | # An element with the same name is in the set. Nothing to add 66 | if elem.identify() in self.indices: 67 | return 68 | self.indices[elem.identify()] = len(self.db) 69 | self.db.append(elem) 70 | return 71 | 72 | def remove(self, elem): 73 | ''' 74 | 75 | Remove an element from the set. 76 | ''' 77 | if len(self.inidces) <= 0: 78 | return 79 | idType = type(self.indices.keys()[0]) 80 | if type(elem) == idType: 81 | try: 82 | index = self.indices[elem] 83 | except: 84 | raise IndexError 85 | else: 86 | try: 87 | index = self.indices[elem.identify()] 88 | except: 89 | raise IndexError 90 | i = index + 1 91 | # Update the indices 92 | while i < len(self.db): 93 | id = self.db[i].identify() 94 | self.indices[id] = self.indices[id] - 1 95 | i = i + 1 96 | # Remove the element from the database and remove its index 97 | id = self.db[index].identify() 98 | self.db.remove(self.db[index]) 99 | del self.indices[id] 100 | return 101 | 102 | def select(self, query): 103 | queryResult = Set(name='query-result') 104 | for elem in self.db: 105 | if query.match(elem): 106 | queryResult.append(prob) 107 | return queryResult 108 | -------------------------------------------------------------------------------- /opal/core/solver.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | class Solver: 4 | 5 | def __init__(self, name='', command=None, input=None, parameter='', 6 | output=None, **kwargs): 7 | self.name = name 8 | self.command = command 9 | self.args = [input, parameter, output] 10 | return 11 | 12 | #def run(self): 13 | # cmdStr = self.command 14 | # for argv in self.args: 15 | # if argv != None: 16 | # cmdStr = cmdStr + ' ' + str(argv) 17 | # os.system(cmdStr) 18 | # return 19 | 20 | def solve(self, problem, **kwargs): 21 | """ 22 | The solve method return a process describing the solving process 23 | according solver's algorithm. 24 | The solving process is either an iterative process or batch process. 25 | In the case of an iterative process, the user can interfere to 26 | solving process in each iteration. 27 | Otherwise, the user just runs the process and get final result 28 | Two form of invoking a solver 29 | 30 | >>> solvingProc = aSolver.solve(problem) 31 | >>> finalResult = solvingProc.run(problem.initial_point) 32 | 33 | >>> solvingProc = aSolver.solve(problem) 34 | >>> solvingProc.initialize(problem.initial_point) 35 | >>> while solvingProc.next() : 36 | >>> result = solvingProc.get_status() 37 | 38 | The advantage of this appoach is that, the solving process can 39 | be invoked with different initial information, for example the 40 | initial point 41 | """ 42 | 43 | return None 44 | -------------------------------------------------------------------------------- /opal/core/statsmeasure.py: -------------------------------------------------------------------------------- 1 | class StatisticalMeasure: 2 | def average(measureName): 3 | return lambda p,m : m[measureName].mean() 4 | average = staticmethod(average) 5 | 6 | 7 | -------------------------------------------------------------------------------- /opal/core/test_core.py: -------------------------------------------------------------------------------- 1 | def test_multi_agent_framework(): 2 | from mafrw import Agent 3 | from mafrw import Environment 4 | 5 | agent = Agent() 6 | env = Environment() 7 | 8 | agent.register(env) 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /opal/core/testproblem.py: -------------------------------------------------------------------------------- 1 | __docformat__ = 'restructuredText' 2 | 3 | from set import Set 4 | 5 | class TestProblem: 6 | """ 7 | Abstract class to describe a test problem in general form. 8 | Every test problem class is a sub-class of this class. 9 | The ``TestProblem`` class contains only basic information about the 10 | test problem: the problem name and a description (both strings). 11 | Example: 12 | 13 | >>> chem=TestProblem(name='Nuke', description='Chemical reactor') 14 | >>> print chem.name, chem.description 15 | """ 16 | 17 | def __init__(self, name='Test Problem', description=None, classifyStr=None, 18 | **kwargs): 19 | self.name = name 20 | self.description = description 21 | self.classify_string = classifyStr 22 | 23 | def get_name(self): 24 | return self.name 25 | 26 | def identify(self): 27 | return self.name 28 | 29 | def get_description(self): 30 | return self.description 31 | 32 | def get_classify_string(self): 33 | return self.classify_string 34 | 35 | 36 | class OptimizationTestProblem(TestProblem): 37 | """ 38 | An abstract class to represent a test problem in the field of optimization. 39 | Example: 40 | 41 | >>> hs26 = OptimizationTestProblem(name='HS26', nvar=3, ncon=1) 42 | >>> print hs26.name, hs26.nvar, hs26.ncon 43 | HS26 3 1 44 | """ 45 | def __init__(self, 46 | name='Optimization Problem', 47 | description=None, 48 | classifyStr=None, 49 | nvar=0, 50 | ncon=0, 51 | **kwargs): 52 | TestProblem.__init__(self, 53 | name=name, 54 | description=description, 55 | classifyStr=classifyStr, 56 | **kwargs) 57 | self.nvar = nvar 58 | self.ncon = ncon 59 | 60 | 61 | class ProblemSet(Set): 62 | """ 63 | An abstract class to represent a test set from which lists of 64 | specific problems may be extracted, and which may be passed to a solver. 65 | Example: 66 | 67 | >>> HS = ProblemSet(name='Hock and Schittkowski set') 68 | >>> hs13 = TestProblem(name='HS13', nvar=2, ncon=1) 69 | >>> hs26 = TestProblem(name='HS26', nvar=3, ncon=1) 70 | >>> HS.add_problem(hs13) 71 | >>> HS.add_problem(hs26) 72 | >>> print [prob.name for prob in HS] 73 | ['HS13', 'HS26'] 74 | 75 | In the above example, note that a `ProblemSet` is iterable. 76 | """ 77 | 78 | def __init__(self, name='Problem-Set', **kwargs): 79 | Set.__init__(self, name=name, **kwargs) 80 | return 81 | 82 | def add_problem(self, problem): 83 | "Add problem to collection." 84 | if isinstance(problem, TestProblem): 85 | self.append(problem) 86 | else: 87 | raise TypeError, 'Problem must be a TestProblem' 88 | 89 | def remove_problem(self, problem): 90 | self.remove(problem) 91 | 92 | 93 | def select(self, query): 94 | """ 95 | Return the list of problems matching the given query. 96 | The `query` object is any object that possesses a `match()` method. 97 | The result of `match(name, string)` must be True if `name` matches 98 | `string`. During the query, `name` is the problem name and `string` 99 | is its classification string. 100 | """ 101 | queryResult = ProblemSet(name='query result') 102 | for prob in self.db: 103 | if query.match(prob): 104 | queryResult.append(prob) 105 | return queryResult 106 | 107 | 108 | class ProblemCollection(ProblemSet): 109 | """ 110 | An abstract class to represet a collection of test problems. A collection 111 | is made up of subcollections, each of which is a `ProblemSet`. 112 | 113 | Example: 114 | 115 | >>> HS = ProblemSet(name='Hock and Schittkowski set') 116 | >>> hs13 = TestProblem(name='HS13', nvar=2, ncon=1) 117 | >>> hs26 = TestProblem(name='HS26', nvar=3, ncon=1) 118 | >>> HS.add_problem(hs13) 119 | >>> HS.add_problem(hs26) 120 | >>> NCVXQP = ProblemSet(name='Nonconvex Quadratic Programs') 121 | >>> ncvxqp2 = TestProblem(name='NCVXQP2', nvar=1000, ncon=2500) 122 | >>> NCVXQP.add_problem(ncvxqp2) 123 | >>> CUTEr = ProblemCollection(name='CUTEr collection') 124 | >>> CUTEr.add_subcollection(HS) 125 | >>> CUTEr.add_subcollection(NCVXQP) 126 | >>> print [coll.name for coll in CUTEr.subcollections] 127 | ['Hock and Schittkowski set', 'Nonconvex Quadratic Programs'] 128 | >>> print [prob.name for prob in CUTEr.all_problems()] 129 | ['HS13', 'HS26', 'NCVXQP2'] 130 | """ 131 | 132 | def __init__(self, name=None, description=None, **kwargs): 133 | self.name = name 134 | self.description = description 135 | ProblemSet.__init__(self, name='set of problems', **kwargs) 136 | self.subcollections = Set(name='sub-collections') # List of 137 | # subcollections of 138 | # this collection 139 | 140 | def __len__(self): 141 | size = ProblemSet.__len__(self) 142 | for collection in self.subcollections: 143 | size = size + collection.__len__() 144 | return size 145 | 146 | def __getitem__(self, key): 147 | try: 148 | return ProblemSet.__getitem__(self, key) 149 | except IndexError: 150 | for collection in self.subcollections: 151 | try: 152 | return collection.__getitem__(key) 153 | except IndexError: 154 | pass # Try to get from other collections 155 | # If all collections are searched wihtout result 156 | # an exception of index error is raised 157 | raise IndexError, 'Element can not be found in the set' 158 | 159 | def __contains__(self,prob): 160 | if ProblemSet.__contains__(self, prob): 161 | return True 162 | for collection in self.subcollections: 163 | # Search recursively in the subcollections 164 | if collection.__contains__(prob): 165 | return True 166 | return False 167 | 168 | def identify(self): 169 | return self.name 170 | 171 | def find_sub_collection(self, collectionId): 172 | for collection in self.subcollections: 173 | if collection.identify() is collectionId: 174 | return collection 175 | result = collection.find_sub_collection(collectionId) 176 | if result is not None: 177 | return result 178 | return None # No subcollection can be found 179 | 180 | def add_subcollection(self, collection): 181 | "Add a subcollection to this collection." 182 | if isinstance(collection, ProblemCollection): 183 | self.subcollections.append(collection) 184 | else: 185 | raise TypeError, 'Collection must be a ProblemCollection object' 186 | 187 | 188 | def _test(): 189 | import doctest 190 | return doctest.testmod() 191 | 192 | if __name__ == "__main__": 193 | _test() 194 | -------------------------------------------------------------------------------- /opal/core/tools.py: -------------------------------------------------------------------------------- 1 | # Miscellaneous tools. 2 | import re 3 | 4 | def extract_measure(content, description, name, valueType = 'int'): 5 | numberPattern = {'int':'\d+', 6 | 'real':'-?\d*\.\d+', 7 | 'float':'-?\d*\.\d+E(\+|-)\d+'} 8 | converters = {'int':int, 9 | 'real': float, 10 | 'float': float} 11 | 12 | matches = re.finditer(description + '\s+:\s+(?P<' + 13 | name + '>' + 14 | numberPattern[valueType] + ')', 15 | content) 16 | value = None 17 | for m in matches: 18 | if name not in m.groupdict().keys(): 19 | raise Exception('Could not to extract measure ' + name) 20 | continue 21 | value = converters[valueType](m.groupdict()[name]) 22 | return value 23 | 24 | 25 | class TableFormatter: 26 | def __init__(self, fieldDelimiter=' ', recordDelimiter='\n'): 27 | self.field_delimiter = fieldDelimiter 28 | self.record_delimiter = recordDelimiter 29 | self.row_template = None 30 | return 31 | 32 | def set_header(self, headers=None, *args): 33 | cols = [] 34 | if headers is not None: 35 | cols.extend(headers) 36 | cols.extend(args) 37 | if len(cols) == 0: 38 | return None 39 | self.row_template = '{0:<}' 40 | headerStr = 'PROB' 41 | for col in cols: 42 | self.row_template = self.row_template + self.field_delimiter + \ 43 | '{1['+ col + ']:>}' 44 | headerStr = headerStr + self.field_delimiter + col 45 | self.row_template = self.row_template + self.record_delimiter 46 | headerStr = headerStr + self.record_delimiter 47 | return headerStr 48 | 49 | def format(self, problem, record, **kwargs): 50 | record.update(kwargs) 51 | if len(record) == 0: 52 | return None 53 | try: 54 | return self.row_template.format(problem, record) 55 | except KeyError: 56 | return None 57 | -------------------------------------------------------------------------------- /opal/test_opal.py: -------------------------------------------------------------------------------- 1 | def test_opal(): 2 | return 3 | 4 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | 3 | setup(name='OPAL - OPtimization of ALgorithm', 4 | version='1.3', 5 | description='Algorithmic Parameter Optimization', 6 | author='Charles Audet, Cong-Kien Dang, Dominique Orban', 7 | author_email='cong-kien.dang@polymtl.ca', 8 | url='http://www.gerad.ca/~kiendc/build/hmtl', 9 | packages=['opal', 10 | 'opal.core', 11 | 'opal.Platforms', 12 | 'opal.Solvers', 13 | 'opal.TestProblemCollections'] 14 | ) 15 | 16 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 3 | This file for provoking a serie of tests relating all basic componnents 4 | in OPAL. It is used to provoke as well as the simple examples that are 5 | in the `examples` directory. 6 | 7 | The `nose` package is required to run the tests. 8 | 9 | For testing OPAL installation, just launch at shell prompt a command: 10 | 11 | shell$ python test.py 12 | 13 | For running a examples, for example the `finite-difference` examples: 14 | 15 | shell$ python test.py -w examples/fd 16 | ''' 17 | 18 | if __name__ == '__main__': 19 | try: 20 | from nose import main 21 | main() 22 | except NameError: 23 | print 'The NOSE package is required' 24 | --------------------------------------------------------------------------------