Skip to content

Commit

Permalink
Merge pull request #207 from bluescarni/pr/island_iter
Browse files Browse the repository at this point in the history
Implementation of the extract() functionality for island, plus other stuff
  • Loading branch information
bluescarni authored Aug 15, 2018
2 parents 9b13cea + e791461 commit 4ba4e9e
Show file tree
Hide file tree
Showing 20 changed files with 405 additions and 84 deletions.
34 changes: 20 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ env:
matrix:
include:
- env: PAGMO_BUILD="DebugGCC48"
dist: trusty
compiler: gcc
os: linux
addons:
Expand All @@ -28,9 +29,9 @@ matrix:
- g++-4.8
- binutils-gold
- env: PAGMO_BUILD="ReleaseGCC48"
dist: trusty
compiler: gcc
os: linux
dist: precise
addons:
apt:
sources:
Expand All @@ -39,50 +40,54 @@ matrix:
- gcc-4.8
- g++-4.8
- binutils-gold
- env: PAGMO_BUILD="CoverageGCC5"
- env: PAGMO_BUILD="CoverageGCC6"
dist: trusty
compiler: gcc
os: linux
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-5
- g++-5
- gcc-6
- g++-6
- binutils-gold
- env: PAGMO_BUILD="DebugGCC6"
- env: PAGMO_BUILD="DebugGCC7"
dist: trusty
compiler: gcc
os: linux
dist: precise
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-6
- g++-6
- gcc-7
- g++-7
- binutils-gold
- env: PAGMO_BUILD="DebugClang38"
- env: PAGMO_BUILD="DebugClang50"
dist: trusty
compiler: clang
os: linux
addons:
apt:
sources:
- llvm-toolchain-precise-3.8
- llvm-toolchain-trusty-5.0
- ubuntu-toolchain-r-test
packages:
- clang-3.8
- env: PAGMO_BUILD="ReleaseClang38"
- clang-5.0
- env: PAGMO_BUILD="ReleaseClang50"
dist: trusty
compiler: clang
os: linux
addons:
apt:
sources:
- llvm-toolchain-precise-3.8
- llvm-toolchain-trusty-5.0
- ubuntu-toolchain-r-test
packages:
- clang-3.8
- clang-5.0
- env: PAGMO_BUILD="Python36"
dist: trusty
compiler: gcc
os: linux
addons:
Expand All @@ -93,6 +98,7 @@ matrix:
- gcc-4.8
- g++-4.8
- env: PAGMO_BUILD="Python27"
dist: trusty
compiler: gcc
os: linux
addons:
Expand Down
7 changes: 6 additions & 1 deletion doc/sphinx/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Changelog
New
~~~

- Implement the UDI extraction functionality for :cpp:class:`~pagmo::island` (`#207 <https://github.com/esa/pagmo2/pull/207>`__).

- pip pygmo package for Python 3.7 (Linux) (`#196 <https://github.com/esa/pagmo2/pull/196>`__).

- Implement the :class:`~pygmo.decorator_problem` Python meta-problem (`#195 <https://github.com/esa/pagmo2/pull/195>`__).
Expand All @@ -16,6 +18,8 @@ New
Changes
~~~~~~~

- The build system now respects the ``CMAKE_CXX_STANDARD`` CMake setting (`#207 <https://github.com/esa/pagmo2/pull/207>`__).

- Ensure that, in :cpp:class:`~pagmo::thread_island`, the algorithm used for the evolution replaces the original algorithm
at the end of the evolution (`#203 <https://github.com/esa/pagmo2/pull/203>`__).

Expand All @@ -29,7 +33,8 @@ Fix
- Fixes for compiler warnings in GCC 8 (`#197 <https://github.com/esa/pagmo2/pull/197>`__).

- Various documentation and CI fixes and enhancements (`#195 <https://github.com/esa/pagmo2/pull/195>`__,
`#196 <https://github.com/esa/pagmo2/pull/196>`__, `#204 <https://github.com/esa/pagmo2/pull/204>`__).
`#196 <https://github.com/esa/pagmo2/pull/196>`__, `#204 <https://github.com/esa/pagmo2/pull/204>`__,
`#207 <https://github.com/esa/pagmo2/pull/207>`__).

2.8 (2018-07-12)
----------------
Expand Down
12 changes: 9 additions & 3 deletions doc/sphinx/docs/examples/getting_started.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
#include <pagmo/pagmo.hpp>
#include <iostream>

#include <pagmo/algorithm.hpp>
#include <pagmo/algorithms/sade.hpp>
#include <pagmo/archipelago.hpp>
#include <pagmo/problem.hpp>
#include <pagmo/problems/schwefel.hpp>

using namespace pagmo;

Expand All @@ -18,10 +24,10 @@ int main()
archi.evolve(10);

// 5 - Wait for the evolutions to be finished
archi.wait();
archi.wait_check();

// 6 - Print the fitness of the best solution in each island
for (const auto &isl : archi) {
print(isl.get_population().champion_f(), "\n");
std::cout << isl.get_population().champion_f()[0] << '\n';
}
}
64 changes: 63 additions & 1 deletion include/pagmo/island.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -381,9 +381,9 @@ struct island_data {
std::unique_ptr<isl_inner_base> isl_ptr;
// Algo and pop need a mutex to regulate concurrent access
// while the island is evolving.
std::mutex algo_mutex;
// NOTE: see the explanation in island::get_algorithm() about why
// we store algo/pop as shared_ptrs.
std::mutex algo_mutex;
std::shared_ptr<algorithm> algo;
std::mutex pop_mutex;
std::shared_ptr<population> pop;
Expand Down Expand Up @@ -756,6 +756,68 @@ class island
}
return *this;
}
/// Extract a const pointer to the UDI used for construction.
/**
* This method will extract a const pointer to the internal instance of the UDI. If \p T is not the same type
* as the UDI used during construction (after removal of cv and reference qualifiers), this method will
* return \p nullptr.
*
* \verbatim embed:rst:leading-asterisk
* .. note::
*
* The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime
* of ``this``, and ``delete`` must never be called on the pointer.
*
* \endverbatim
*
* @return a const pointer to the internal UDI, or \p nullptr
* if \p T does not correspond exactly to the original UDI type used
* in the constructor.
*/
template <typename T>
const T *extract() const
{
auto isl = dynamic_cast<const detail::isl_inner<T> *>(m_ptr->isl_ptr.get());
return isl == nullptr ? nullptr : &(isl->m_value);
}
/// Extract a pointer to the UDI used for construction.
/**
* This method will extract a pointer to the internal instance of the UDI. If \p T is not the same type
* as the UDI used during construction (after removal of cv and reference qualifiers), this method will
* return \p nullptr.
*
* \verbatim embed:rst:leading-asterisk
* .. note::
*
* The returned value is a raw non-owning pointer: the lifetime of the pointee is tied to the lifetime
* of ``this``, and ``delete`` must never be called on the pointer.
*
* .. note::
*
* The ability to extract a mutable pointer is provided only in order to allow to call non-const
* methods on the internal UDI instance. Assigning a new UDI via this pointer is undefined behaviour.
*
* \endverbatim
*
* @return a pointer to the internal UDI, or \p nullptr
* if \p T does not correspond exactly to the original UDI type used
* in the constructor.
*/
template <typename T>
T *extract()
{
auto isl = dynamic_cast<detail::isl_inner<T> *>(m_ptr->isl_ptr.get());
return isl == nullptr ? nullptr : &(isl->m_value);
}
/// Check if the UDI used for construction is of type \p T.
/**
* @return \p true if the UDI used in construction is of type \p T, \p false otherwise.
*/
template <typename T>
bool is() const
{
return extract<T>() != nullptr;
}
/// Launch evolution.
/**
* This method will evolve the island's pagmo::population using the
Expand Down
7 changes: 5 additions & 2 deletions pygmo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/pygmo/config.hpp" DESTINATION
YACMA_PYTHON_MODULE(core core.cpp docstrings.cpp expose_algorithms_0.cpp expose_algorithms_1.cpp expose_problems_0.cpp expose_problems_1.cpp expose_islands.cpp)
target_link_libraries(core PRIVATE ${PYGMO_BP_TARGET} Boost::disable_autolinking Pagmo::pagmo NumPy::numpy pygmo)
target_compile_options(core PRIVATE "$<$<CONFIG:DEBUG>:${PAGMO_CXX_FLAGS_DEBUG}>" "$<$<CONFIG:RELEASE>:${PAGMO_CXX_FLAGS_RELEASE}>")
set_property(TARGET core PROPERTY CXX_STANDARD 11)
# Let's setup the target C++ standard, but only if the user did not provide it manually.
if(NOT CMAKE_CXX_STANDARD)
set_property(TARGET core PROPERTY CXX_STANDARD 11)
endif()
set_property(TARGET core PROPERTY CXX_STANDARD_REQUIRED YES)
set_property(TARGET core PROPERTY CXX_EXTENSIONS NO)

Expand All @@ -74,7 +77,7 @@ install(TARGETS core
add_subdirectory(plotting)

# Add the Python files.
install(FILES __init__.py test.py _patch_problem.py _patch_algorithm.py _problem_test.py
install(FILES __init__.py test.py _patch_problem.py _patch_algorithm.py _patch_island.py _problem_test.py
_algorithm_test.py _island_test.py _py_islands.py _py_problems.py "${CMAKE_CURRENT_BINARY_DIR}/_version.py"
DESTINATION ${PYGMO_INSTALL_PATH})

Expand Down
4 changes: 3 additions & 1 deletion pygmo/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,12 @@
# Patch the problem class.
from . import _patch_problem


# Patch the algorithm class.
from . import _patch_algorithm

# Patch the island class.
from . import _patch_island


class thread_safety(object):
"""Thread safety level.
Expand Down
5 changes: 3 additions & 2 deletions pygmo/_algorithm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,9 @@ def evolve(self, pop):
self.assertFalse(algo.extract(a) is None)
self.assertTrue(algo.is_(a))
self.assertTrue(isinstance(algo.evolve(population()), population))
# Assert that the global variable was copied into p, not simply
# referenced.
# Assert that a_inst was deep-copied into algo:
# the instance in algo will have its own copy of glob
# and it will not be a reference the outside object.
self.assertEqual(len(glob), 0)
self.assertEqual(len(algo.extract(a).g), 1)
algo = algorithm(de())
Expand Down
84 changes: 84 additions & 0 deletions pygmo/_island_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class island_test_case(_ut.TestCase):

def runTest(self):
self.run_basic_tests()
self.run_extract_tests()
self.run_concurrent_access_tests()
self.run_evolve_tests()
self.run_get_busy_wait_tests()
Expand All @@ -105,6 +106,9 @@ def run_basic_tests(self):
isl = island()
self.assertTrue(isl.get_algorithm().is_(null_algorithm))
self.assertTrue(isl.get_population().problem.is_(null_problem))
self.assertTrue(isl.extract(thread_island) is not None)
self.assertTrue(isl.extract(_udi_01) is None)
self.assertTrue(isl.extract(int) is None)
self.assertEqual(len(isl.get_population()), 0)
isl = island(algo=de(), prob=rosenbrock(), size=10)
self.assertTrue(isl.get_algorithm().is_(de))
Expand All @@ -126,6 +130,32 @@ def run_basic_tests(self):
self.assertRaises(NotImplementedError, lambda: island(prob=rosenbrock(), udi=_udi_02(),
size=11, algo=de(), seed=15))

# Verify that the constructor copies the UDI instance.
udi_01_inst = _udi_01()
isl = island(udi=udi_01_inst, algo=de(), prob=rosenbrock(), size=10)
self.assertTrue(id(isl.extract(thread_island)) != id(udi_01_inst))

# Local island using local variable.
glob = []

class loc_01(object):
def __init__(self, g):
self.g = g

def run_evolve(self, algo, pop):
self.g.append(1)
return algo, pop

loc_inst = loc_01(glob)
isl = island(udi=loc_inst, algo=de(), prob=rosenbrock(), size=20)
isl.evolve(10)
isl.wait_check()
# Assert that loc_inst was deep-copied into isl:
# the instance in isl will have its own copy of glob
# and it will not be a reference the outside object.
self.assertEqual(len(glob), 0)
self.assertEqual(len(isl.extract(loc_01).g), 10)

isl = island(prob=rosenbrock(), udi=_udi_03(),
size=11, algo=de(), seed=15)
isl.evolve()
Expand Down Expand Up @@ -251,6 +281,60 @@ def run_stateful_algo_tests(self):
isl.wait_check()
self.assertTrue(isl.get_algorithm().extract(_stateful_algo)._n == 20)

def run_extract_tests(self):
from .core import island, _test_island, null_problem, null_algorithm, thread_island
import sys

# First we try with a C++ test island.
isl = island(udi=_test_island(), algo=null_algorithm(),
prob=null_problem(), size=1)
# Verify the refcount of p is increased after extract().
rc = sys.getrefcount(isl)
tisl = isl.extract(_test_island)
self.assertFalse(tisl is None)
self.assertTrue(isl.is_(_test_island))
self.assertEqual(sys.getrefcount(isl), rc + 1)
del tisl
self.assertEqual(sys.getrefcount(isl), rc)
# Verify we are modifying the inner object.
isl.extract(_test_island).set_n(5)
self.assertEqual(isl.extract(_test_island).get_n(), 5)
# Try to extract the wrong C++ island type.
self.assertTrue(isl.extract(thread_island) is None)
self.assertFalse(isl.is_(thread_island))

class tisland(object):

def __init__(self):
self._n = 1

def get_n(self):
return self._n

def set_n(self, n):
self._n = n

def run_evolve(self, algo, pop):
return algo, pop

# Test with Python problem.
isl = island(udi=tisland(), algo=null_algorithm(),
prob=null_problem(), size=1)
rc = sys.getrefcount(isl)
tisl = isl.extract(tisland)
self.assertFalse(tisl is None)
self.assertTrue(isl.is_(tisland))
# Reference count does not increase because
# tisland is stored as a proper Python object
# with its own refcount.
self.assertEqual(sys.getrefcount(isl), rc)
self.assertEqual(tisl.get_n(), 1)
tisl.set_n(12)
self.assertEqual(isl.extract(tisland).get_n(), 12)
# Try to extract the wrong Python island type.
self.assertTrue(isl.extract(_udi_01) is None)
self.assertFalse(isl.is_(_udi_01))


class mp_island_test_case(_ut.TestCase):
"""Test case for the :class:`~pygmo.mp_island` class.
Expand Down
Loading

0 comments on commit 4ba4e9e

Please sign in to comment.