diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6f552f --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +.pytest_cache/ + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg +.idea/ + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log + +# Sphinx documentation +docs/_build/ +doc/ + +# PyBuilder +target/ + +#Ipython Notebook +.ipynb_checkpoints + +#Pycharm files +*.iml + +# merging stuff +*.orig +*~ + +# Paths in repository +mcml.py + +# images etc +*.tif +*.nrrd +*.caffemodel + +# C++ stuff +build* +*.user diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..221b5b7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,38 @@ +======================================================================= +Copyright (c) 2003-2012 German Cancer Research Center, +Division of Medical and Biological Informatics +All rights reserved. + +Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the +following conditions are met: + + * Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + + * Neither the name of the German Cancer Research Center, + nor the names of its contributors may be used to endorse + or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +======================================================================= diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..00aff1a --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +init: + pip install -r requirements.txt + +test: + python -m unittest discover + +install_develop: + python setup.py develop + +install: + python setup.py install + +documentation: + sphinx-apidoc -e -f samplepackage -o doc/ diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..2329568 --- /dev/null +++ b/README.rst @@ -0,0 +1,106 @@ +Hyppopy +======================== + +The friendly Hyppo that helps you to find your inner blackbox optimum. + +It is adapted from `this github example `_ +(`Learn more `_) and tries to follow the instructions on `this guide `_. + +The actual code can be found in :py:mod:`samplepackage.thinker`. It implements a toy class +which "thinks" random thoughts. +The tests for this class are located in :py:mod:`samplepackage.tests`. Python will automatically +discover tests if you name them test_*.py +Look at :py:meth:`samplepackage.tests.test_advanced` for a simple unittest example. + +Install Dependencies +-------------------- +either use:: + + pip install -r requirements.txt + +or:: + + make init + + +Install This Package +-------------------- +You have two choices: + +#. "normal" install. This will install the current version. +#. install a development version. Here the package will be installed, but only as a link to your current codebase. See `here `_ for a better explanation :-) + +After you installed your package, it can be imported via:: + + import samplepackage + +in your python console. + +Install Development Version: +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +either use:: + + python setup.py develop + +or:: + + make install_develop + +"Normal" Install +^^^^^^^^^^^^^^^ + +either use:: + + python setup.py install + +or:: + + make install + + +run tests +-------------------- + +either run:: + + python -m unittest discover + +or:: + + make test + + +execute tutorial +-------------------- +In your console, navigate to the tutorials subfolder and start ipython notebook. + + +run scripts +-------------------- +Scripts can be found in subfolder bin/. They are declared as entry points +(see setup.py in the project root). This means you can call them by calling the entry points +directly in console! + + +build documentation +-------------------- + +First the documentation has to be refreshed by typing:: + + sphinx-apidoc -e -f samplepackage -o doc/ + +or:: + + make documentation + +in the projects root folder (the one with setup.py). This will automatically create +all the files necessary for sphinx (the documentation builder) to create the +html documentation. +Then, navigate to doc/ and type:: + + make html + +To build the documentation. Note that sphinx needs to be available in your python +installation (e.g. install requirements.txt as mentioned above). +The documentation main page can then be found in doc/_build/html/index.html diff --git a/bin/hyppopy_exe.py b/bin/hyppopy_exe.py new file mode 100644 index 0000000..086846b --- /dev/null +++ b/bin/hyppopy_exe.py @@ -0,0 +1,19 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +from hyppopy.cmdtools import * + + +if __name__ == '__main__': + cmd_workflow() diff --git a/hyppopy/__init__.py b/hyppopy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hyppopy/cmdtools.py b/hyppopy/cmdtools.py new file mode 100644 index 0000000..e29f5bd --- /dev/null +++ b/hyppopy/cmdtools.py @@ -0,0 +1,31 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +import argparse + +import logging +LOG = logging.getLogger('hyppopy') + +from hypopy.solver_factory import SolverFactory + + +def cmd_workflow(): + parser = argparse.ArgumentParser(description="") + + parser.add_argument('-v', '--verbosity', type=int, required=False, default=0, + help='number of thoughts our thinker should produce') + + + args_dict = vars(parser.parse_args()) + factory = SolverFactory.instance() diff --git a/hyppopy/isolver.py b/hyppopy/isolver.py new file mode 100644 index 0000000..41445d4 --- /dev/null +++ b/hyppopy/isolver.py @@ -0,0 +1,33 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +import logging +LOG = logging.getLogger('hyppopy') + + +class ISolver(object): + loss_function = None + + def set_loss_function(self, func): + """ + set loss function + """ + self.loss_function = func + + def execute(self, *args, **kwargs): + raise NotImplementedError() + + @property + def name(self): + return self.__name__ \ No newline at end of file diff --git a/hyppopy/settings.py b/hyppopy/settings.py new file mode 100644 index 0000000..57fd76a --- /dev/null +++ b/hyppopy/settings.py @@ -0,0 +1,34 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +import os +import sys +import logging + +ROOT = os.path.join(os.path.dirname(__file__), "..") +LOGFILENAME = os.path.join(ROOT, 'logfile.log') +PLUGIN_DEFAULT_DIR = os.path.join(ROOT, *("hyppopy", "solver")) +sys.path.insert(0, ROOT) + +#LOG = logging.getLogger() +logging.getLogger('hyppopy').setLevel(logging.DEBUG) +logging.basicConfig(filename=LOGFILENAME, filemode='w', format='%(name)s - %(levelname)s - %(message)s') + +''' +LOG.debug('debug message') +LOG.info('info message') +LOG.warning('warning message') +LOG.error('error message') +LOG.critical('critical message') +''' diff --git a/hyppopy/solver/__init__.py b/hyppopy/solver/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hyppopy/solver/hyperopt_plugin.py b/hyppopy/solver/hyperopt_plugin.py new file mode 100644 index 0000000..660ba27 --- /dev/null +++ b/hyppopy/solver/hyperopt_plugin.py @@ -0,0 +1,28 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +from yapsy.IPlugin import IPlugin +import logging +LOG = logging.getLogger('hyppopy') + +from hyppopy.isolver import ISolver + + +class HyperoptPlugin(IPlugin, ISolver): + + def __init__(self): + self.__name__ = "HyperoptPlugin" + + def execute(self, *args, **kwargs): + pass \ No newline at end of file diff --git a/hyppopy/solver/hyperopt_plugin.yapsy-plugin b/hyppopy/solver/hyperopt_plugin.yapsy-plugin new file mode 100644 index 0000000..6042a58 --- /dev/null +++ b/hyppopy/solver/hyperopt_plugin.yapsy-plugin @@ -0,0 +1,9 @@ +[Core] +Name = Hyperopt +Module = hyperopt_plugin + +[Documentation] +Author = Sven Wanner +Version = 0.1 +Website = https://github.com/hyperopt/hyperopt +Description = Hyperopt Solver Plugin \ No newline at end of file diff --git a/hyppopy/solver/optunity_plugin.py b/hyppopy/solver/optunity_plugin.py new file mode 100644 index 0000000..c04c509 --- /dev/null +++ b/hyppopy/solver/optunity_plugin.py @@ -0,0 +1,28 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +from yapsy.IPlugin import IPlugin +import logging +LOG = logging.getLogger('hyppopy') + +from hyppopy.isolver import ISolver + + +class OptunityPlugin(IPlugin, ISolver): + + def __init__(self): + self.__name__ = "OptunityPlugin" + + def execute(self, *args, **kwargs): + pass \ No newline at end of file diff --git a/hyppopy/solver/optunity_plugin.yapsy-plugin b/hyppopy/solver/optunity_plugin.yapsy-plugin new file mode 100644 index 0000000..43e8a47 --- /dev/null +++ b/hyppopy/solver/optunity_plugin.yapsy-plugin @@ -0,0 +1,9 @@ +[Core] +Name = Optunity +Module = optunity_plugin + +[Documentation] +Author = Sven Wanner +Version = 0.1 +Website = https://optunity.readthedocs.io/en/latest/ +Description = Optunity Solver Plugin \ No newline at end of file diff --git a/hyppopy/solver_factory.py b/hyppopy/solver_factory.py new file mode 100644 index 0000000..025b155 --- /dev/null +++ b/hyppopy/solver_factory.py @@ -0,0 +1,76 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +from yapsy.PluginManager import PluginManager + +from .settings import PLUGIN_DEFAULT_DIR +import logging +LOG = logging.getLogger('hyppopy') + + +class SolverFactory(object): + _instance = None + _plugin_dirs = [] + _plugins = {} + + def __init__(self): + if SolverFactory._instance is not None: + pass + else: + LOG.debug("__init__()") + SolverFactory._instance = self + self.reset() + self.load_plugins() + + + @staticmethod + def instance(): + """ + Singleton instance access + :return: [SolverFactory] instance + """ + LOG.debug("instance()") + if SolverFactory._instance is None: + SolverFactory() + return SolverFactory._instance + + def add_plugin_dir(self, dir): + """ + Add plugin directory + """ + LOG.debug(f"add_plugin_dir({dir})") + self._plugin_dirs.append(dir) + + def reset(self): + """ + Reset solver factory + """ + LOG.debug("reset()") + self._plugins = {} + self._plugin_dirs = [] + self.add_plugin_dir(PLUGIN_DEFAULT_DIR) + + def load_plugins(self): + """ + Load plugin modules from plugin paths + """ + LOG.debug("load_plugins()") + LOG.debug(f"setPluginPlaces(" + " ".join(map(str, self._plugin_dirs))) + manager = PluginManager() + manager.setPluginPlaces(self._plugin_dirs) + manager.collectPlugins() + for plugin in manager.getAllPlugins(): + self._plugins[plugin.plugin_object.name] = plugin.plugin_object + LOG.info(f"Plugin: {plugin.plugin_object.name} loaded") + diff --git a/hyppopy/tests/__init__.py b/hyppopy/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hyppopy/tests/test_pluginmechanism.py b/hyppopy/tests/test_pluginmechanism.py new file mode 100644 index 0000000..c5ed9c6 --- /dev/null +++ b/hyppopy/tests/test_pluginmechanism.py @@ -0,0 +1,35 @@ +# DKFZ +# +# Copyright (c) German Cancer Research Center, +# Division of Medical and Biological Informatics. +# All rights reserved. +# +# This software is distributed WITHOUT ANY WARRANTY; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. +# +# See LICENSE.txt or http://www.mitk.org for details. + +# -*- coding: utf-8 -*- + +import unittest + +from hyppopy.solver_factory import SolverFactory + + +class PluginMechanismTestSuite(unittest.TestCase): + """Advanced test cases.""" + + def setUp(self): + pass + + def test_1(self): + """ + + :return: + """ + factory = SolverFactory.instance() + + +if __name__ == '__main__': + unittest.main() diff --git a/hyppopy/workflows/__init__.py b/hyppopy/workflows/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..31ec439 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +# sphinx is used for building the documentation +sphinx + +# xmlrunner is used in tests.py and needed to get nicely formatted output for +# jenkins to interpret. +xmlrunner + +# yapsy is a plugin manager package +yapsy + +# you can also specify specific version here, as e.g. +# Framework==0.9.4 +# Library>=0.2 diff --git a/run_tests_jenkins.py b/run_tests_jenkins.py new file mode 100644 index 0000000..2cb29d0 --- /dev/null +++ b/run_tests_jenkins.py @@ -0,0 +1,9 @@ +# this small script runs the unittest on our package and creates xml output. +# The xml output can be parsed by jenkins to create nicely formatted test output + +if __name__ == '__main__': + import xmlrunner + import unittest + runner = xmlrunner.XMLTestRunner('python_tests_xml') + runner.run(unittest.TestLoader().discover('hyppopy')) + unittest.main(testRunner=xmlrunner.XMLTestRunner(output='test-reports')) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7666019 --- /dev/null +++ b/setup.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +from setuptools import setup, find_packages + + +with open('README.rst') as f: + readme = f.read() + +with open('LICENSE') as f: + license = f.read() + +setup( + name='hyppopy', + version='0.0.0', + description='Hyper-Parameter Optimization Toolbox for Blackboxfunction Optimization', + long_description=readme, + # if you want, put your own name here + # (this would likely result in people sending you emails) + author='SvenWanner@DKFZ', + author_email='s.wanner@dkfz.de', + url='', + license=license, + packages=find_packages(exclude=('bin', '*test*', 'doc', 'hypopy')), + # the requirements to install this project. + # Since this one is so simple this is empty. + install_requires=[], + # a more sophisticated project might have something like: + #install_requires=['numpy>=1.11.0', 'scipy>=0.17', 'scikit-learn'] + + # after running setup.py, you will be able to call hypopy_exe + # from the console as if it was a normal binary. It will call the function + # main in bin/hypopy_exe.py + entry_points={ + 'console_scripts': ['hypopy_exe=bin.hypopy_exe:main'], + } +) +