diff --git a/.clang-format b/.clang-format index 8c9c0b1..482f3cc 100644 --- a/.clang-format +++ b/.clang-format @@ -17,7 +17,7 @@ AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: MultiLine +AlwaysBreakTemplateDeclarations: true BinPackArguments: true BinPackParameters: false #MODIFIED BraceWrapping: diff --git a/.gitignore b/.gitignore index a5be5aa..bb0ac59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +_skbuild/ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e7f7a9..16369b9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ message(STATUS "PERM version: ${PERM_VERSION}") set(CMAKE_INCLUDE_CURRENT_DIR ON) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") +include(GNUInstallDirs) # Define CMAKE_INSTALL_xxx: LIBDIR, INCLUDEDIR option(PERM_BUILD_TESTING "Enable Tests" ON) option(PERM_BUILD_ENABLE_VALGRIND "Enable Valgrind as a memchecker for tests (require debug symbols)" OFF) diff --git a/cmake/PERMConfig.cmake.in b/cmake/PERMConfig.cmake.in index 90b2b77..c8e7174 100644 --- a/cmake/PERMConfig.cmake.in +++ b/cmake/PERMConfig.cmake.in @@ -3,6 +3,6 @@ include(CMakeFindDependencyMacro) get_filename_component(PERM_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -if(NOT TARGET Perm) +if(NOT TARGET PERMCore) include ("${PERM_CMAKE_DIR}/PERMTargets.cmake") endif() diff --git a/cmake/PERMModuleMacros.cmake b/cmake/PERMModuleMacros.cmake index a93664d..e8d5741 100644 --- a/cmake/PERMModuleMacros.cmake +++ b/cmake/PERMModuleMacros.cmake @@ -9,18 +9,18 @@ # ${MODULE_${MODULE_NAME}_DEPENDS} # ${GTEST_LIBRARIES}) macro(perm_add_gtests) - foreach(test_file ${MODULE_${MODULE_NAME}_TESTS}) + foreach(test_file ${test_files}) string(REGEX REPLACE "\\.[^.]*$" "" test_name "${test_file}") add_executable(${test_name} ${test_file}) target_link_libraries(${test_name} PRIVATE - ${MODULE_${MODULE_NAME}_TEST_DEPENDS} + PERMCore + ${GTEST_LIBRARIES} ) - target_include_directories(${test_name} SYSTEM PRIVATE - ${MODULE_${MODULE_NAME}_TEST_SYSTEM_INCLUDE_DIRS}) + # target_include_directories(${test_name} SYSTEM PRIVATE) gtest_discover_tests( ${test_name} - TEST_PREFIX ${MODULE_NAME}||${test_name}|| - PROPERTIES LABELS ${MODULE_NAME} + TEST_PREFIX PERM||${test_name}|| + PROPERTIES LABELS PERM ) endforeach() endmacro(perm_add_gtests) diff --git a/developer_requirements.txt b/developer_requirements.txt new file mode 100644 index 0000000..9fc69c9 --- /dev/null +++ b/developer_requirements.txt @@ -0,0 +1,3 @@ + cmake + ninja + scikit-build diff --git a/include/perm.hpp b/include/perm.hpp index a0c258b..b6bb1f5 100644 --- a/include/perm.hpp +++ b/include/perm.hpp @@ -6,9 +6,35 @@ #ifndef PERM_HPP #define PERM_HPP +#include "perm_common_types.hpp" +#include // For size_t +#include +#include + namespace perm { +struct parameters_in_t { + size_t steps = 1000; + size_t monomers = 100; + /// Used only if num_monomers = 0 + float_t end_to_end_distance = 0.0; + void print(std::ostream &os) const; +}; + +struct parameters_out_t { + parameters_out_t() = default; + parameters_out_t(const parameters_in_t &input) : in(input){}; + single_chain_t chain; + parameters_in_t in; + float_t energy = 0.0; + void print(std::ostream &os) const; +}; - void hola(); +single_chain_t random_walk_lattice_2D(const size_t &monomers); +parameters_out_t run_simple_sampling(const parameters_in_t ¶meters); +float_t +energy(const single_chain_t &chain, + const std::function &, const vec3D_t &)> + &energy_pair_func); -} //end ns +} // namespace perm #endif diff --git a/include/perm_common_types.hpp b/include/perm_common_types.hpp new file mode 100644 index 0000000..3664cb5 --- /dev/null +++ b/include/perm_common_types.hpp @@ -0,0 +1,61 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef PERM_COMMON_TYPES_HPP +#define PERM_COMMON_TYPES_HPP +#include +#include + +namespace perm { +/// float type (hard-coded better than templated for now) +using float_t = double; + +template +struct vec3D_t { + T x; + T y; + T z; + void print(std::ostream &os) const { + os << x << " " << y << " " << z << std::endl; + } + friend bool operator==(const vec3D_t &lhs, const vec3D_t &rhs) { + return lhs.x == lhs.x && lhs.y == lhs.y && lhs.z == lhs.z; + } + T &operator[](const size_t index) { + return (index == 0 ? x : (index == 1 ? y : z)); + } + const T &operator[](const size_t index) const { + return (index == 0 ? x : (index == 1 ? y : z)); + } + constexpr size_t size() { return 3; }; +}; + +template +vec3D_t plus(const vec3D_t &lhs, const vec3D_t &rhs) { + vec3D_t out; + out.x = lhs.x + rhs.x; + out.y = lhs.y + rhs.y; + out.z = lhs.z + rhs.z; + return out; +} + +template +struct single_chain_t { + /// Number of monomers in the single-chain polymer + size_t monomers = 0; + /** Ordered collection of points, + * start: points[0], + * end: points[num_monomers - 1] + */ + std::vector> points; + void print(std::ostream &os) const { + os << "chain.monomers= " << monomers << std::endl; + for (const auto &p : points) { + p.print(os); + } + } +}; +} // namespace perm +#endif diff --git a/include/perm_rng.hpp b/include/perm_rng.hpp new file mode 100644 index 0000000..485d727 --- /dev/null +++ b/include/perm_rng.hpp @@ -0,0 +1,78 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef PERM_RNG_HPP +#define PERM_RNG_HPP + +#include "perm_common_types.hpp" +#include +namespace RNG { + +inline std::mt19937 &engine() { + /// seed generation + static thread_local std::random_device rdev{}; + /// engine instantiation: e + static thread_local std::mt19937 e{rdev()}; + // static thread_local std::mt19937 e{4342}; + return e; +} + +/// Randomize reseed the input engine with a random generate seed. +inline void randomize_engine(std::mt19937 &eng) { + std::random_device rd{}; + eng.seed(rd()); +} + +/// Uniform random distribution from double [0.0,1) +inline double rand01() { + static thread_local std::uniform_real_distribution uid(0.0, 1.0); + return uid(engine()); +} + +/** + * Return 1 with probability p + * @param p must be lesser or equal than 1 + * @return 1 with probability p, 0 if not. + */ +inline bool random_bool(const double p) { return (rand01() < p) ? 1 : 0; } + +/** + * Uniform random distribution from int [min,max] + * @param min + * @param max + * @return int from [min,max] + */ +inline int rand_range_int(const int &min, const int &max) { + // note that inside function static variables doesn't interfer if they have + // the same name + std::uniform_int_distribution uid(min, max); + return uid(engine()); +} + +inline perm::vec3D_t rand_lattice_2D() { + // note that inside function static variables doesn't interfer if they have + // the same name + std::uniform_int_distribution uid(0, 3); + const auto lattice_int = uid(engine()); + switch (lattice_int) { + case 0 /* -x */: + return perm::vec3D_t{-1, 0, 0}; + break; + case 1 /* +x */: + return perm::vec3D_t{1, 0, 0}; + break; + case 2 /* -y */: + return perm::vec3D_t{0, -1, 0}; + break; + case 3 /* +y */: + return perm::vec3D_t{0, 1, 0}; + break; + } + // Not really needed, unreachable, but warnings if removed in gcc + return perm::vec3D_t{999, 999, 999}; +} +} // namespace RNG + +#endif diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7533528 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "wheel", "scikit-build", "cmake", "ninja"] diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b1e706d --- /dev/null +++ b/setup.py @@ -0,0 +1,57 @@ +from __future__ import print_function +from os import sys, path + +try: + from skbuild import setup +except ImportError: + print('scikit-build is required to build from source.', file=sys.stderr) + print('Please run:', file=sys.stderr) + print('', file=sys.stderr) + print(' python -m pip install scikit-build') + sys.exit(1) + +sys.path.append(path.dirname(path.dirname(path.abspath(__file__)))) + +with open('README.md', 'r') as fp: + readme = fp.read() +with open('developer_requirements.txt', 'r') as fp: + developer_requirements = list(filter(bool, (line.strip() for line in fp))) + +setup( + name='perm', + version='0.1', + author='Pablo Hernandez-Cerdan', + author_email='pablo.hernandez.cerdan@outlook.com', + packages=['perm'], + download_url=r'https://github.com/phcerdan/perm/releases', + description=r'PERM: Prune and Enrichment Rosenbluth Method', + long_description=readme, + classifiers=[ + "OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Programming Language :: Python", + "Programming Language :: C++", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Education", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering", + "Topic :: Scientific/Engineering :: Physics", + "Topic :: Scientific/Engineering :: Information Analysis", + "Topic :: Software Development :: Libraries", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX", + "Operating System :: Unix", + "Operating System :: MacOS" + ], + license='MPL2', + keywords='PERM montecarlo SAW polymer simulation', + url=r'https://github.com/phcerdan/perm', + install_requires=[], + cmake_args=[ + '-DBUILD_SHARED_LIBS:BOOL=TRUE', + '-DPERM_BUILD_TESTING:BOOL=FALSE', + '-DPERM_WRAP_PYTHON:BOOL=TRUE', + # '-DCMAKE_BUILD_TYPE:STRING=Release', + ] + ) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d7d684..1f525b8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ set(PERMCore_sources perm.cpp + perm_common_types.cpp ) add_library(PERMCore ${PERMCore_sources} ) @@ -7,8 +8,7 @@ target_include_directories(PERMCore PUBLIC $ $ ) -target_link_libraries(PERMCore - ) +set_property(TARGET PERMCore PROPERTY POSITION_INDEPENDENT_CODE ON) # install targets install(TARGETS PERMCore EXPORT PERMTargets diff --git a/src/perm.cpp b/src/perm.cpp index acc14d7..b17267d 100644 --- a/src/perm.cpp +++ b/src/perm.cpp @@ -3,21 +3,58 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - #include "perm.hpp" +#include "perm_rng.hpp" #include namespace perm { - using precision_t = float; - struct parameters { - size_t steps = 1000; - size_t num_monomers = 100; - /// Used only if num_monomers = 0 - precision_t end_to_end_distance = 0.0; +void parameters_in_t::print(std::ostream &os) const { + os << "steps= " << steps << std::endl; + os << "monomers= " << monomers << std::endl; + os << "end_to_end_distance= " << end_to_end_distance << std::endl; +} + +void parameters_out_t::print(std::ostream &os) const { + in.print(os); + os << "energy= " << energy << std::endl; + chain.print(os); +} + +parameters_out_t run_simple_sampling(const parameters_in_t ¶meters_in) { + parameters_out_t parameters_out(parameters_in); + auto &chain = parameters_out.chain; + chain.points.emplace_back(vec3D_t{0, 0, 0}); + chain.monomers++; + return parameters_out; +} + +single_chain_t random_walk_lattice_2D(const size_t &monomers) { + single_chain_t chain; + chain.points.emplace_back(vec3D_t{0, 0, 0}); + chain.monomers++; + while (chain.monomers < monomers) { + chain.points.emplace_back( + perm::plus(chain.points.back(), RNG::rand_lattice_2D())); + chain.monomers++; + } + return chain; +} + +float_t +energy(const single_chain_t &chain, + const std::function &, const vec3D_t &)> + &energy_pair_func) { + + if (chain.monomers == 0 || chain.points.empty()) { + return 0.0; } - void hola() { - std::cout << "HOLA" << std::endl; + auto &points = chain.points; + double sum = 0.0; + for (size_t i = 0; i != points.size() - 1; i++) { + sum += energy_pair_func(points[i], points[i + 1]); } + return sum; } +} // namespace perm diff --git a/src/perm_common_types.cpp b/src/perm_common_types.cpp new file mode 100644 index 0000000..078495f --- /dev/null +++ b/src/perm_common_types.cpp @@ -0,0 +1,8 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perm_common_types.hpp" + +namespace perm {} // end namespace perm diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e69de29..b2e3eca 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -0,0 +1,4 @@ +set(test_files + test_perm.cpp + ) +perm_add_gtests() diff --git a/test/test_perm.cpp b/test/test_perm.cpp new file mode 100644 index 0000000..3d85600 --- /dev/null +++ b/test/test_perm.cpp @@ -0,0 +1,13 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perm.hpp" +#include "gmock/gmock.h" + +TEST(PERM, random_walk_lattice_2D) { + size_t monomers = 100; + auto chain = perm::random_walk_lattice_2D(monomers); + chain.print(std::cout); +} diff --git a/wrap/CMakeLists.txt b/wrap/CMakeLists.txt new file mode 100644 index 0000000..525d9a2 --- /dev/null +++ b/wrap/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(perm) diff --git a/wrap/perm/CMakeLists.txt b/wrap/perm/CMakeLists.txt new file mode 100644 index 0000000..25d0609 --- /dev/null +++ b/wrap/perm/CMakeLists.txt @@ -0,0 +1,43 @@ +set(python_module_name _perm) +pybind11_add_module(${python_module_name} MODULE + perm_init_py.cpp + perm_py.cpp + perm_common_types_py.cpp + ) +target_link_libraries(${python_module_name} PRIVATE PERMCore) + +install(TARGETS ${python_module_name} DESTINATION perm) + +# build tree +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +# install tree +install(FILES __init__.py DESTINATION perm) + +# # PythonExtensions is provided by scikit-build: pip install scikit-build +# find_package(PythonExtensions REQUIRED MODULE) +# if(DEFINED PythonExtensions_DIR OR PythonExtensions_DIR) +# message(STATUS "scikit-build cmake package found in ${PythonExtensions_DIR}") +# python_extension_module(${python_module_name} MODULE) +# else() +# message(AUTHOR_WARNING "'scikit-build' not found, python wrappings won't be packaged") +# message(AUTHOR_WARNING "CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}") +# endif() + +if(PERM_BUILD_TESTING) + set(test_folder "${CMAKE_CURRENT_SOURCE_DIR}/test_python") + set(python_tests_ + test_perm.py + ) + + # test files should start with "test_" + # unittest functions (in .py) should start with "test_" for discover to work + foreach(python_test ${python_tests_}) + add_test(NAME python||${python_module_name}||${python_test} + COMMAND ${PYTHON_EXECUTABLE} + -m unittest discover + -s ${test_folder} + -p ${python_test} + ) + endforeach() +endif() diff --git a/wrap/perm/__init__.py b/wrap/perm/__init__.py new file mode 100644 index 0000000..28c6c42 --- /dev/null +++ b/wrap/perm/__init__.py @@ -0,0 +1 @@ +import ._perm as perm diff --git a/wrap/perm/perm_common_py.hpp b/wrap/perm/perm_common_py.hpp new file mode 100644 index 0000000..d258c34 --- /dev/null +++ b/wrap/perm/perm_common_py.hpp @@ -0,0 +1,12 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef PERM_COMMON_PY_HPP +#define PERM_COMMON_PY_HPP + +#include "perm_common_types.hpp" +#include +PYBIND11_MAKE_OPAQUE(std::vector>); +#endif diff --git a/wrap/perm/perm_common_types_py.cpp b/wrap/perm/perm_common_types_py.cpp new file mode 100644 index 0000000..b61f27b --- /dev/null +++ b/wrap/perm/perm_common_types_py.cpp @@ -0,0 +1,69 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perm_common_py.hpp" +#include "perm_common_types.hpp" +#include +#include +#include +#include + +namespace py = pybind11; +using namespace perm; + +void init_perm_common_types(py::module &m) { + py::class_>(m, "vec3D") + .def(py::init()) + .def(py::init([](const int &x, const int &y, const int &z) { + return vec3D_t{x, y, z}; + })) + .def_readwrite("x", &vec3D_t::x) + .def_readwrite("y", &vec3D_t::y) + .def_readwrite("z", &vec3D_t::z) + .def("__add__", + [](const vec3D_t &lhs, const vec3D_t &rhs) { + return perm::plus(lhs, rhs); + }) + .def("__eq__", [](const vec3D_t &lhs, + const vec3D_t &rhs) { return lhs == rhs; }) + .def("__getitem__", + [](const vec3D_t &vec, size_t i) { + if (i >= 3) + throw py::index_error(); + return vec[i]; + }) + .def("__setitem__", + [](vec3D_t &vec, size_t i, int new_value) { + if (i >= 3) + throw py::index_error(); + vec[i] = new_value; + }) + .def("__len__", &vec3D_t::size) + .def("__array__", + [](const vec3D_t &vec) { + py::array_t out(3); + auto r = out.mutable_unchecked<1>(); + r(0) = vec.x; + r(1) = vec.y; + r(2) = vec.z; + return out; + }) + .def("__repr__", [](const vec3D_t &vec) { + std::stringstream os; + vec.print(os); + return os.str(); + }); + py::bind_vector>>(m, "points_vector", + py::module_local(false)); + py::class_>(m, "single_chain") + .def(py::init()) + .def_readwrite("monomers", &single_chain_t::monomers) + .def_readwrite("points", &single_chain_t::points) + .def("__repr__", [](const single_chain_t &chain) { + std::stringstream os; + chain.print(os); + return os.str(); + }); +} diff --git a/wrap/perm/perm_init_py.cpp b/wrap/perm/perm_init_py.cpp new file mode 100644 index 0000000..90bd0d0 --- /dev/null +++ b/wrap/perm/perm_init_py.cpp @@ -0,0 +1,22 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perm_common_types.hpp" +#include +// #include +// for PYBIND11_NUMPY_DTYPE(perm::vec3D_t, x, y, z); +// to pass numpy arrays to c++. UNUSED for now + +namespace py = pybind11; +void init_perm_common_types(py::module &); +void init_perm(py::module &); + +// using vec3D_int_t = perm::vec3D_t; + +PYBIND11_MODULE(_perm, m) { + m.doc() = "_perm"; // optional module docstring + init_perm_common_types(m); + init_perm(m); +} diff --git a/wrap/perm/perm_py.cpp b/wrap/perm/perm_py.cpp new file mode 100644 index 0000000..f07a568 --- /dev/null +++ b/wrap/perm/perm_py.cpp @@ -0,0 +1,13 @@ +/* Copyright (C) 2019 Pablo Hernandez-Cerdan + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perm.hpp" +#include +namespace py = pybind11; +using namespace perm; + +void init_perm(py::module &m) { + m.def("random_walk_lattice_2D", &random_walk_lattice_2D); +} diff --git a/wrap/perm/test_python/test_perm.py b/wrap/perm/test_python/test_perm.py new file mode 100644 index 0000000..993c1f6 --- /dev/null +++ b/wrap/perm/test_python/test_perm.py @@ -0,0 +1,67 @@ +# Copyright (C) 2019 Pablo Hernandez-Cerdan +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import _perm as perm +import unittest +import matplotlib.pyplot as plt + +import numpy as np + +class TestPerm(unittest.TestCase): + def test_vec3D(self): + print("test_vec3D") + vec0 = perm.vec3D() + print(vec0) + vec1 = perm.vec3D(1,1,1) + print(vec1) + plus = vec0 + vec1 + self.assertEqual(plus, vec1) + + def test_vec3D_numpy(self): + print("test_vec3D_numpy") + vec0 = perm.vec3D() + arr = np.array(vec0) + print(arr.shape) + self.assertEqual(arr[0], vec0.x) + self.assertEqual(arr[1], vec0.y) + self.assertEqual(arr[2], vec0.z) + vec0.x = 3 + self.assertEqual(vec0.x, 3) + + def test_single_chain(self): + print("test_single_chain") + chain = perm.single_chain() + self.assertEqual(len(chain.points), 0) + chain.points.append(perm.vec3D(1,2,3)) + chain.monomers = 1 + self.assertEqual(len(chain.points), 1) + self.assertEqual(chain.points[0].x, 1) + self.assertEqual(chain.points[0].y, 2) + self.assertEqual(chain.points[0].z, 3) + # operator[] + self.assertEqual(chain.points[0][0], 1) + self.assertEqual(chain.points[0][1], 2) + self.assertEqual(chain.points[0][2], 3) + + + def test_random_walk_lattice_2D(self): + print("test_random_walk_lattice_2D") + chain = perm.random_walk_lattice_2D(5) + print(chain) + + def plot_chain(self): + chain = perm.random_walk_lattice_2D(200) + xdata = [] + ydata = [] + zdata = [] + for p in chain.points: + xdata.append(p.x) + ydata.append(p.y) + zdata.append(p.z) + plt.plot(xdata, ydata) + + +if __name__ == "__main__": + unittest.main()