From ccb581ce8a83d0d3d8e89c60c93c72297b225a99 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 09:50:49 -0400 Subject: [PATCH 01/23] Removed deprecated cpp triangulation --- CMakeLists.txt | 71 -------------- build.sh | 3 - py_polytope.cpp | 124 ------------------------- weighted.cpp | 116 ----------------------- weighted_polytope.hpp | 208 ------------------------------------------ 5 files changed, 522 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100755 build.sh delete mode 100644 py_polytope.cpp delete mode 100644 weighted.cpp delete mode 100644 weighted_polytope.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index b464b85..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,71 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(triangulation-generator VERSION 0.1 LANGUAGES CXX) - -if(APPLE) - set(CMAKE_THREAD_LIBS_INIT "-lpthread") - set(CMAKE_HAVE_THREADS_LIBRARY 1) - set(CMAKE_USE_WIN32_THREADS_INIT 0) - set(CMAKE_USE_PTHREADS_INIT 1) - set(THREADS_PREFER_PTHREAD_FLAG ON) -endif() - - -# Define options -option(BUILD_PY_BINDINGS "Builds Python bindings" ON) -option(DEBUG_MODE "Adds debug flag to compiler" OFF) -option(SANITIZE_ADDRESS "Enables address sanitizer" OFF) - -# Set to C++14 -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -std=c++14") -set(CMAKE_BUILD_TYPE DEBUG) - -if (DEBUG_MODE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") -endif() # DEBUG MODE - -if (SANITIZE_ADDRESS) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") -endif() # SANITIZE_ADDRESS - - -############# LOAD PACKAGES ############# - -# CGAL and its components -find_package(CGAL QUIET COMPONENTS) - -if (NOT CGAL_FOUND) - message(STATUS "This project requires the CGAL library, and will not be compiled.") - return() -endif() # CGAL_FOUND - - -# Boost and its components -# set(Boost_USE_STATIC_LIBS ON) -find_package(Boost REQUIRED) -find_package(Boost COMPONENTS program_options REQUIRED) - -if (BUILD_PY_BINDINGS) - find_package(Boost COMPONENTS python REQUIRED) - find_package (Python COMPONENTS Interpreter Development) -endif() # BUILD_PY_BINDINGS - -if (NOT Boost_FOUND) - message(STATUS "This project requires the Boost library, and will not be compiled.") - return() -endif() # Boost_FOUND - -include_directories( - ${PROJECT_SOURCE_DIR} - ${PYTHON_INCLUDE_DIR} - ${Boost_INCLUDE_DIRS} - /opt/homebrew/include/eigen3) - - -## Add executables -add_executable(weighted weighted.cpp) -target_link_libraries(weighted CGAL::CGAL ${Boost_PROGRAM_OPTIONS_LIBRARY}) - -if (BUILD_PY_BINDINGS) - add_library(py_polytope MODULE py_polytope.cpp) - target_link_libraries(py_polytope CGAL::CGAL Boost::python ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_LIBRARIES} Python::Python) -endif() # BUILD_PY_BINDINGS diff --git a/build.sh b/build.sh deleted file mode 100755 index 24f0bb9..0000000 --- a/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -mkdir build -cd build && cmake -DDEBUG_MODE=ON .. && make -j -mv libpy_polytope.so py_polytope.so diff --git a/py_polytope.cpp b/py_polytope.cpp deleted file mode 100644 index 8c76178..0000000 --- a/py_polytope.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include -using std::cout; - -#include -using std::shared_ptr; - -#include -using std::vector; - -#include -using PolytopeCPP::WeightedPoint; -using PolytopeCPP::Point; -using PolytopeCPP::Real; - -#include - -namespace py = boost::python; - -template -vector to_vector(const py::object& iterable) { - return vector( - py::stl_input_iterator(iterable), - py::stl_input_iterator()); -} - - -class Polytope { - private: - typedef shared_ptr ptr_Polytope; - ptr_Polytope polytope; - - public: - Polytope(const py::object& vertices, const py::object& heights = py::object()) { - vector points; - - int dim = -1; - - auto vertices_vect = to_vector(vertices); - vector heights_vect; - if (heights != py::object()) { - heights_vect = to_vector(heights); - } else { - heights_vect = std::vector(vertices_vect.size(), 1.0f); - } - - if (vertices_vect.size() != heights_vect.size()) throw std::runtime_error( - "Array size mismatch between \"points\" and \"heights\". Received: points.size() = " + - std::to_string(vertices_vect.size()) + " and heights.size() = " + std::to_string(heights_vect.size())); - - - for (int j = 0; j < vertices_vect.size(); ++j) { - auto coords = vertices_vect.at(j); - auto height = heights_vect.at(j); - auto coords_vect = to_vector(coords); - if (dim == -1) - dim = coords_vect.size(); - else if (dim != coords_vect.size()) - throw std::runtime_error("Inconsistent dimension. Expected: " + std::to_string(dim) + " but received: " + std::to_string(coords_vect.size())); - - points.push_back( - WeightedPoint( - Point(dim, coords_vect.data(), coords_vect.data() + coords_vect.size()), height)); - } - - polytope = ptr_Polytope(new PolytopeCPP::Polytope(dim, points)); - } - - - py::object get_facets() { - py::list facets; - - vector> facets_vect; - this->polytope->get_facets(facets_vect); - - for (auto& pts : facets_vect) { - py::list points; - for (auto& pt : pts) { - py::list coords; - for (auto c_iter = pt.cartesian_begin(); c_iter != pt.cartesian_end(); ++c_iter) { - coords.append(*c_iter); - } - points.append(coords); - } - facets.append(points); - } - - return facets; - } - - - py::tuple get_oriented_facets_of_hull() { - py::list facets; - py::list orientations; - - vector facets_vect; - - this->polytope->get_facets(facets_vect); - - for (PolytopeCPP::Facet& f : facets_vect) { - vector pts; - int orientation = this->polytope->get_finite_points(f, pts); - orientations.append(orientation); - - py::list points; - for (auto& wp : pts) { - py::list coords; - auto p = wp.point(); - for (auto c_iter = p.cartesian_begin(); c_iter != p.cartesian_end(); ++c_iter) { - coords.append(*c_iter); - } - points.append(coords); - } - facets.append(points); - } - - return py::make_tuple(facets, orientations); - } -}; - - -BOOST_PYTHON_MODULE(py_polytope) { - py::class_("Polytope", py::init()) - .def("getFacets", &Polytope::get_facets); -} diff --git a/weighted.cpp b/weighted.cpp deleted file mode 100644 index c6dda1b..0000000 --- a/weighted.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include -#include - -#include -using std::cout; - -#include -using std::ofstream; -using std::ifstream; - -#include - -#include -using std::vector; - -#include -using std::string; - -#include -using std::istringstream; - -#include - -#include -namespace po = boost::program_options; - - -#include - -#include -#include - -// Define dynamic Kernel -using DDim = CGAL::Dynamic_dimension_tag; -using K = CGAL::Epick_d; -using Triangulation = CGAL::Regular_triangulation; -using Point = K::Point_d; -using WeightedPoint = K::Weighted_point_d; -using Facet = Triangulation::Facet; - -typedef float Real; - - -void load_points(string path_to_vertices, vector& out, int& dim) { - ifstream f(path_to_vertices); - if (!f) { - throw std::runtime_error("Unable to open file: " + path_to_vertices); - } - - dim = -1; - - string line; - while (f >> line) { - istringstream ss(line); - string token; - vector coords; - while(std::getline(ss, token, ',')) { - coords.push_back(atof(token.c_str())); - } - - if (dim == -1) - dim = coords.size(); - else if (dim != coords.size()) - throw std::runtime_error("Inconsistent dimension for line '" + line + "'. Expected: " + std::to_string(dim) + " but received: " + std::to_string(coords.size())); - - out.push_back( - WeightedPoint( - Point(coords.size(), coords.data(), coords.data() + coords.size()), (1.0*random())/RAND_MAX)); - } -} - - -int main(int argc, char** argv) { - // Parse args & load vertices - po::options_description desc("Allowed options"); - desc.add_options() - ("help,h", "Show this help message.") - ("input,i", po::value()->required(), "Path to the file containing vertices.") - ("pyformat,f", "If specified, uses python array format for output.") - ("output,o", po::value(), "Path to the output."); - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - if (vm.count("help")) { - cout << desc << "\n"; - return EXIT_SUCCESS; - } - - try { - po::notify(vm); - } catch (std::exception& e) { - cout << "Error: " << e.what() << "\n"; - return EXIT_FAILURE; - } - - vector points; - int dim; - string path_to_vertices = vm["input"].as(); - try { - load_points(path_to_vertices, points, dim); - } catch (std::exception& e) { - cout << "Error: " << e.what() << "\n"; - return EXIT_FAILURE; - } - - - PolytopeCPP::Polytope p(dim, points); - cout << p.compute_volume() << "\n"; - - - vector< vector > facets; - p.get_facets(facets); - - cout << (p << PolytopeCPP::PrintingFormat::PYTHON) << "\n"; - return EXIT_SUCCESS; -} diff --git a/weighted_polytope.hpp b/weighted_polytope.hpp deleted file mode 100644 index 7c61860..0000000 --- a/weighted_polytope.hpp +++ /dev/null @@ -1,208 +0,0 @@ -/** - * @file weighted_polytope.hpp - * @brief Contains methods to compute various properties of a polytope with weighted points. - */ - -#ifndef POLYTOPE_HPP_ -#define POLYTOPE_HPP_ - -#include -using std::vector; - -#include -#include - - -namespace PolytopeCPP { - - -// Define dynamic Kernel -using DDim = CGAL::Dynamic_dimension_tag; -using K = CGAL::Epick_d; - -using Triangulation = CGAL::Regular_triangulation; - -using Point = K::Point_d; -using WeightedPoint = K::Weighted_point_d; -using Facet = Triangulation::Facet; - -using Real = float; - - -enum PrintingFormat { - NONE = 0, - PYTHON = 1 -}; - - -class Polytope { - private: - Triangulation _t; - int _dim; - PrintingFormat _format; - - - public: - Polytope(int dim, vector& points) : _t(dim), _dim(dim), _format(NONE) { - _t.insert(points.begin(), points.end()); - } - - - Polytope(int dim, vector& points) : _t(dim), _dim(dim), _format(NONE) { - vector w_points; - for (auto p : points) - w_points.push_back(WeightedPoint(p, 1.0f)); - _t.insert(w_points.begin(), w_points.end()); - } - - - Polytope(int dim, vector& points, vector& heights) : _t(dim), _dim(dim), _format(NONE) { - if (points.size() != heights.size()) throw std::runtime_error( - "Array size mismatch between \"points\" and \"heights\". Received: points.size() = " + - std::to_string(points.size()) + " and heights.size() = " + std::to_string(heights.size())); - - - for (int j = 0; j < points.size(); ++j) { - Real h0 = 0; - for (int k = 0; k < _dim; ++k) { - h0 += points.at(j)[k]*points.at(j)[k]; - } - heights[j] = h0 - heights[j]; - } - - - vector w_points; - for (int j = 0; j < points.size(); ++j) - w_points.push_back(WeightedPoint(points.at(j), heights.at(j))); - - _t.insert(w_points.begin(), w_points.end()); - } - - - /** - * @brief Get the finite points object - * @return Sign of the orientation. - */ - int get_finite_points(Facet& facet, vector& out) { - int count = 0; - // Compute boundary intersected w/ complement of infinite_vertex. - int sign = 1.0; - for (auto v_iter = facet.full_cell()->vertices_begin(); v_iter != facet.full_cell()->vertices_end(); ++v_iter) { - if (*v_iter == _t.infinite_vertex()) { - sign = pow(-1, count); - continue; - } - out.push_back((*v_iter)->point()); - ++count; - } - - return sign; - } - - - void get_facets(vector& facets, bool only_adjacent_to_inf = true) { - for (auto cell_iter = _t.full_cells_begin(); cell_iter != _t.full_cells_end(); ++cell_iter) { - // Only pick facets adjacent to the infinite vertex - if (!_t.is_infinite(cell_iter) && only_adjacent_to_inf) continue; - facets.push_back( - Facet(cell_iter, cell_iter->index(_t.infinite_vertex()))); - } - } - - - void get_facets(vector< vector >& facets, bool only_adjacent_to_inf = true) { - for (auto cell_iter = _t.full_cells_begin(); cell_iter != _t.full_cells_end(); ++cell_iter) { - if (!_t.is_infinite(cell_iter) && only_adjacent_to_inf) continue; - vector points; - // for (auto v_iter = cell_iter->vertices_begin(); v_iter != cell_iter->vertices_end(); ++v_iter) { - // if ((*v_iter)->point().point().size() > 0) - // points.push_back((*v_iter)->point().point()); - // } - - for (int j = 0; j < _dim + 1; ++j) { - points.push_back(cell_iter->vertex(j)->point().point()); - } - facets.push_back(points); - } - } - - - double determinant(Facet& facet) { - vector finite_points; - int sign = get_finite_points(facet, finite_points); - - Eigen::MatrixXf vol_mat(_t.current_dimension(), _t.current_dimension()); - for (int i = 0; i < finite_points.size(); ++i) { - auto p = finite_points.at(i).point(); - vector coords( - p.cartesian_begin(), - p.cartesian_end()); - vol_mat.row(i) = Eigen::Map(coords.data(), coords.size()); - } - - return sign*(vol_mat.determinant()); - } - - - /** - * @brief Computes volume of the convex hull. - * @note THe normalization coefficient 1/dim! is omitted. - * @return Signed volume - */ - double compute_volume() { - double volume = 0.0f; - const int dim = _t.current_dimension(); - - for (auto cell_iter = _t.full_cells_begin(); cell_iter != _t.full_cells_end(); ++cell_iter) { - // Only pick facets adjacent to the infinite vertex - if (!_t.is_infinite(cell_iter)) continue; - Facet facet(cell_iter, cell_iter->index(_t.infinite_vertex())); - volume += determinant(facet); - } - - return volume; /// tgamma(dim + 1); - } - - - Polytope& operator<<(PrintingFormat format) { - this->_format = format; - return *this; - } - - - friend std::ostream& operator<<(std::ostream& stream, Polytope& other) { - bool pyformat = (other._format == PrintingFormat::PYTHON); - if (pyformat) stream << "["; - for (auto cell_iter = other._t.full_cells_begin(); cell_iter != other._t.full_cells_end(); ++cell_iter) { - // Only pick facets adjacent to the infinite vertex - if (!other._t.is_infinite(cell_iter)) continue; - Facet facet(cell_iter, cell_iter->index(other._t.infinite_vertex())); - - if (pyformat) stream << "["; - for (auto v_iter = facet.full_cell()->vertices_begin(); v_iter != facet.full_cell()->vertices_end(); ++v_iter) { - // Skip infinite vertex - if (*v_iter == other._t.infinite_vertex()) continue; - if (pyformat) stream << "["; - for (int k = 0; k < other._dim; ++k) { - stream << (*v_iter)->point().point()[k] << ((k == other._dim - 1) ? "" : ","); - } - if (pyformat) stream << ((std::next(v_iter) == facet.full_cell()->vertices_end()) ? "]" : "],"); - else stream << "\n"; - } - if (pyformat) stream << ((std::next(cell_iter) == other._t.full_cells_end()) ? "]" : "],\n"); - else stream << "\n"; - } - if (pyformat) stream << "]\n"; - - return stream; - } - -}; - - - -} // PolytopeCPP - - - -#endif // POLYTOPE_HPP_ From ef37f8c378d532a011136b872289be1e43d9199a Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 10:44:30 -0400 Subject: [PATCH 02/23] Added Environment interface. Added MultiEnvironment --- environment.py | 171 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 environment.py diff --git a/environment.py b/environment.py new file mode 100644 index 0000000..8c7d358 --- /dev/null +++ b/environment.py @@ -0,0 +1,171 @@ +""" +environment.py +-------------- +""" + +import abc +from copy import deepcopy +from typing import Tuple, List + +import numpy as np +from cytools import Polytope +from notebooks.integer_rref import i4mat_rref + + +class Environment(object): + @abc.abstractmethod + def R(self, state) -> Tuple[float, bool]: + """Computes fitness function. + + @param state: Specifies current state. + + @return Tuple (reward, terminated). + """ + + @abc.abstractmethod + def act(self, state, action) -> Tuple[List, float]: + """ + @param state: Current state. + @param action: Action using which to act on the state. + + @return Tuple (next state, fitness of the next state). + """ + + @property + @abc.abstractmethod + def num_actions(self): + """ + @return Number of actions. + """ + + +class MultiEnvironment(Environment): + def __init__(self, environments: List[Environment]): + self._environments = environments + + @staticmethod + def _combine_r_vals(r_val_1, r_val_2): + return r_val_1[0] + r_val_2[0], r_val_1[1] & r_val_2[1] + + def R(self, state) -> Tuple[float, bool]: + """ + @params state: List of states. + """ + r_val = (0.0, True) + + for i, environment in enumerate(self._environments): + r_val_curr = environment.R(state[i]) + r_val = self._combine_r_vals( + r_val_curr, r_val) + # r_val += r_val_curr + # terminated &= terminated_curr + + return r_val + + def act(self, state, action): + new_states = [] + r_val = (0.0, True) + for s_curr, a_curr, env_curr in zip(state, action, self._environments): + new_state, r_val_curr = env_curr.act(s_curr, a_curr) + + new_states.append(new_state) + r_val = self._combine_r_vals( + r_val_curr, r_val) + return new_states, r_val + + def add(self, other: Environment): + """ + Adds a new environment. + """ + self._environments.append(other) + + def __add__(self, other: Environment): + self.add(other) + + +class SubpolytopeEnvironment(Environment): + def __init__(self, polytope: Polytope, fibration_dim: int): + self._p = polytope + self._points = polytope.points()[1:] + self._d = fibration_dim + self._num_actions = fibration_dim + + def random_state(self): + return np.random.choice(self._points.shape[0], size=(self._d)) + + @staticmethod + def reduce_polytope(vertices): + vertices_copy = np.array(vertices, copy=True) + W = np.asarray(i4mat_rref(vertices.shape[0], vertices.shape[1], vertices_copy)[0]).astype(np.float64) + local_vertices = np.round(vertices@np.linalg.pinv(W)) + idx = np.argwhere(np.all(local_vertices[..., :] == 0, axis=0)) + + return np.delete(local_vertices, idx, axis=1) + + def intersect(self, state): + vertices_basis = [] + for pt_id in state: + vertices_basis.append(self._points[pt_id]) + + vertices_basis = np.asarray(vertices_basis) + vertices = [] + for pt in self._points: + if np.linalg.matrix_rank( + np.append(vertices_basis, [pt], axis=0)) == self._d: + vertices.append(pt) + return np.asarray(vertices) + + def R(self, state): + vertices = self.intersect(state) + + reward = 0.0 + reward -= (np.linalg.matrix_rank(vertices) - self._d)**2 + + if len(vertices.shape) < 2: + reward -= 10. + else: + vertices_reduced = np.asarray(self.reduce_polytope(vertices), np.int32) + if vertices_reduced.size != 0: + p_reduced = Polytope(vertices_reduced) + reward += (1.0 if p_reduced.is_reflexive() else -1.0) + reward -= (p_reduced.dimension() - self._d)**2 + else: + reward -= 10 + # try: + # p_reduced = Polytope(np.asarray(self.reduce_polytope(vertices), np.int32)) + # reward += (1.0 if p_reduced.is_reflexive() else -1.0) + # reward -= (p_reduced.dimension() - self._d)**2 + # except: + # reward -= 1 + + return reward, reward > 0 + + def act(self, state, action): + new_state = deepcopy(state) + new_state[action] = ((new_state[action] + 1) % (self._points.shape[0])) + + return new_state, self.R(new_state) + + @property + def num_actions(self): + return self._d + + @property + def all_actions(self): + return [i for i in range(self._d)] + + +if __name__ == "__main__": + p = Polytope([ + [1,0,0,0], + [0,1,0,0], + [0,0,1,0], + [0,0,0,1], + [-1,-1,0,0], + [-1,-1,-1,-1]]) + subpoly = SubpolytopeEnvironment(p, 2) + state = subpoly.random_state() + print(subpoly.R(state)) + + multi = MultiEnvironment([subpoly, subpoly]) + print(multi.R([state, state])) \ No newline at end of file From 1f31db90f424864abae807d2f2a0bae6eeec0038 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 10:51:31 -0400 Subject: [PATCH 03/23] Added random_state to env interface --- environment.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/environment.py b/environment.py index 8c7d358..6ffdc01 100644 --- a/environment.py +++ b/environment.py @@ -13,6 +13,12 @@ class Environment(object): + @abc.abstractmethod + def random_state(): + """ + Generates a random state (or a list thereof). + """ + @abc.abstractmethod def R(self, state) -> Tuple[float, bool]: """Computes fitness function. @@ -43,6 +49,9 @@ class MultiEnvironment(Environment): def __init__(self, environments: List[Environment]): self._environments = environments + def random_state(self): + return [*map(lambda x: x.random_state(), self._environments)] + @staticmethod def _combine_r_vals(r_val_1, r_val_2): return r_val_1[0] + r_val_2[0], r_val_1[1] & r_val_2[1] @@ -168,4 +177,7 @@ def all_actions(self): print(subpoly.R(state)) multi = MultiEnvironment([subpoly, subpoly]) - print(multi.R([state, state])) \ No newline at end of file + print(multi.R([state, state])) + + random_multi_state = multi.random_state() + print(multi.R(random_multi_state)) From b4660e4ff49e313731a23bca70f1e1bdd97b63df Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 11:38:17 -0400 Subject: [PATCH 04/23] Updated naming: R() -> fitness() --- environment.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/environment.py b/environment.py index 6ffdc01..aa87719 100644 --- a/environment.py +++ b/environment.py @@ -20,7 +20,7 @@ def random_state(): """ @abc.abstractmethod - def R(self, state) -> Tuple[float, bool]: + def fitness(self, state) -> Tuple[float, bool]: """Computes fitness function. @param state: Specifies current state. @@ -56,19 +56,22 @@ def random_state(self): def _combine_r_vals(r_val_1, r_val_2): return r_val_1[0] + r_val_2[0], r_val_1[1] & r_val_2[1] - def R(self, state) -> Tuple[float, bool]: + def fitness(self, state) -> Tuple[float, bool]: """ @params state: List of states. """ r_val = (0.0, True) for i, environment in enumerate(self._environments): - r_val_curr = environment.R(state[i]) + r_val_curr = environment.fitness(state[i]) r_val = self._combine_r_vals( r_val_curr, r_val) # r_val += r_val_curr # terminated &= terminated_curr + # TODO compatibility. + # NOTE: In some cases doing one search depends if the other one is valid. + return r_val def act(self, state, action): @@ -88,8 +91,8 @@ def add(self, other: Environment): """ self._environments.append(other) - def __add__(self, other: Environment): - self.add(other) + # def __add__(self, other: Environment): + # self.add(other) class SubpolytopeEnvironment(Environment): @@ -124,7 +127,7 @@ def intersect(self, state): vertices.append(pt) return np.asarray(vertices) - def R(self, state): + def fitness(self, state): vertices = self.intersect(state) reward = 0.0 @@ -153,7 +156,7 @@ def act(self, state, action): new_state = deepcopy(state) new_state[action] = ((new_state[action] + 1) % (self._points.shape[0])) - return new_state, self.R(new_state) + return new_state, self.fitness(new_state) @property def num_actions(self): @@ -174,10 +177,12 @@ def all_actions(self): [-1,-1,-1,-1]]) subpoly = SubpolytopeEnvironment(p, 2) state = subpoly.random_state() - print(subpoly.R(state)) + print(subpoly.fitness(state)) multi = MultiEnvironment([subpoly, subpoly]) - print(multi.R([state, state])) + print(multi.fitness([state, state])) + multi.add(subpoly) + multi.add(subpoly) random_multi_state = multi.random_state() - print(multi.R(random_multi_state)) + print(multi.fitness(random_multi_state), random_multi_state) From 1279c560eb8e839fa90d12d16a7f810af95efc9d Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 14:21:37 -0400 Subject: [PATCH 05/23] Added agent --- agent.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ environment.py | 8 ++-- 2 files changed, 106 insertions(+), 3 deletions(-) create mode 100644 agent.py diff --git a/agent.py b/agent.py new file mode 100644 index 0000000..32fe65c --- /dev/null +++ b/agent.py @@ -0,0 +1,101 @@ +""" +agent.py +-------- +""" + +import abc + +import random +from collections import deque + +import numpy as np +from tensorflow import keras as tfk + + +class Agent(object): + def __init__(self, model: tfk.Sequential, target_model: tfk.Sequential, buffer_size: int): + """ + @param model: Specifies the main model used for training. + @param target_model: Specifies the target model which is updated after some number of training steps. Ensures stability. + @param buffer_size: Size of the replay buffer. + """ + self._memory = deque(maxlen=buffer_size) + self._gamma = 0.95 + self._epsilon = 1.0 + self._epsilon_min = 0.01 + self._epsilon_decay = 0.995 + self._policy_lr = 0.7 + + self._model = model + self._target_model = target_model + + self._num_actions = model.output_shape[-1] + self.update_target_model() + + def store(self, state: np.ndarray, action: int, reward: float, next_state: np.ndarray, terminated: bool): + """ + Stores (s_t, a_t, r_t, s_t+1, terminated) into memory. + """ + self._memory.append([state, action, reward, next_state, terminated]) + + @property + def current_memory_size(self): + """ + @return Size of the part of the buffer that has been filled. + """ + return len(self._memory) + + def update_target_model(self): + """ + Copies the weights of the main model into target model. + """ + self._target_model.set_weights(self._model.get_weights()) + + def act(self, state: np.ndarray) -> int: + """ + @return integer corresponding to an action. + """ + if np.random.rand() <= self._epsilon: + return random.randrange(self._num_actions) + + state = np.expand_dims(state.flatten(), axis=0) + Q_a = self._model(state) + return np.argmax(Q_a) + + def replay(self, batch_size): + """ + Replays the buffer and trains the model. + @param batch_size: Specifies the number of elements to be sampled from memory during replay. + @return Training history. + """ + minibatch = random.sample(self._memory, batch_size) + + states_batch = [] + next_states_batch = [] + for state, _, _, next_state, _ in minibatch: + states_batch.append(state) + next_states_batch.append(next_state) + states_batch = np.asarray(states_batch) + next_states_batch = np.asarray(next_states_batch) + + Q_s = self._model.predict(states_batch, verbose = 0) + Q_s_next = self._target_model.predict(next_states_batch, verbose = 0) + + X = [] + Y = [] + + for idx, (state, action, reward, next_state, terminated) in enumerate(minibatch): + maxQ_next = reward if terminated else ( + reward + self._gamma * np.max(Q_s_next[idx])) + + Q_s[idx][action] = (1.0 - self._policy_lr)*Q_s[idx][action] + self._policy_lr * maxQ_next + + X.append(state) + Y.append(Q_s[idx]) + + + history = self._model.fit(np.asarray(X), np.asarray(Y), batch_size = batch_size, shuffle = True, verbose = 0) + if self._epsilon > self._epsilon_min: + self._epsilon *= self._epsilon_decay + + return history diff --git a/environment.py b/environment.py index aa87719..7491ef9 100644 --- a/environment.py +++ b/environment.py @@ -71,6 +71,7 @@ def fitness(self, state) -> Tuple[float, bool]: # TODO compatibility. # NOTE: In some cases doing one search depends if the other one is valid. + # TODO: make it into a graph with (u->v)∈E if v depends on u. Pass path to root. return r_val @@ -91,8 +92,9 @@ def add(self, other: Environment): """ self._environments.append(other) - # def __add__(self, other: Environment): - # self.add(other) + def __iadd__(self, other: Environment): + self.add(other) + return self class SubpolytopeEnvironment(Environment): @@ -183,6 +185,6 @@ def all_actions(self): print(multi.fitness([state, state])) multi.add(subpoly) - multi.add(subpoly) + multi += subpoly random_multi_state = multi.random_state() print(multi.fitness(random_multi_state), random_multi_state) From 392aa7a575ac2483ccb17f8dce3134bd104c1728 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 15:11:57 -0400 Subject: [PATCH 06/23] Added utils for training agents --- utils.py | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 utils.py diff --git a/utils.py b/utils.py new file mode 100644 index 0000000..4add721 --- /dev/null +++ b/utils.py @@ -0,0 +1,62 @@ +""" +utils.py +-------- +""" +from tqdm import trange + +from copy import deepcopy + +import numpy as np +from agent import Agent +from environment import Environment + + +def train_agent(env: Environment, agent: Agent, num_epochs = 1024, max_steps = 32, batch_size = 128, min_memory_size = 1024, verbosity = 0) -> np.ndarray: + """ + @return Array of (epochs, loss_vals). Shape: (Num_epochs, 2). + """ + steps_to_update_target_model = 0 + epochs = trange(num_epochs) if verbosity > 0 else range(num_epochs) + loss_vals = [] + + for epoch in epochs: + state = env.random_state() + terminated = False + total_loss = 0.0 + count = 0 + + for _ in range(max_steps): + steps_to_update_target_model += 1 + action = agent.act(state) + new_state, (fitness, done) = env.act(state, action) + + reward = 0 + if done: + reward = 10 + terminated = True + else: + reward = -1. + (fitness - env.fitness(state)[0]) + + agent.store(state, action, reward, new_state, terminated) + + if terminated or (steps_to_update_target_model % 4 == 0): + if agent.current_memory_size > min_memory_size: + history = agent.replay(batch_size) + total_loss += history.history['loss'][-1] + count += 1 + + # Move + state = deepcopy(new_state) + + if terminated: + if steps_to_update_target_model >= 100: + agent.update_target_model() + steps_to_update_target_model = 0 + + if terminated: + break + if verbosity > 0: + epochs.set_description(f"Epoch {epoch}, loss = {total_loss / (count+1e-10):.02f}") + if agent.current_memory_size > min_memory_size: + loss_vals.append([epoch, total_loss / (count+1e-10)]) + return np.asarray(loss_vals) From c1d8c14f0010029661e6ec643909126e75664d9b Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 16:05:35 -0400 Subject: [PATCH 07/23] Added walk_agent(). Updated num_actions --- environment.py | 6 ++++++ utils.py | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/environment.py b/environment.py index 7491ef9..cff2774 100644 --- a/environment.py +++ b/environment.py @@ -5,6 +5,7 @@ import abc from copy import deepcopy +from functools import reduce from typing import Tuple, List import numpy as np @@ -96,6 +97,10 @@ def __iadd__(self, other: Environment): self.add(other) return self + @property + def num_actions(self): + return reduce(lambda x,y: x*y, map(lambda x: x.num_actions, self._environments)) + class SubpolytopeEnvironment(Environment): def __init__(self, polytope: Polytope, fibration_dim: int): @@ -188,3 +193,4 @@ def all_actions(self): multi += subpoly random_multi_state = multi.random_state() print(multi.fitness(random_multi_state), random_multi_state) + print(multi.num_actions) diff --git a/utils.py b/utils.py index 4add721..1a2f7d3 100644 --- a/utils.py +++ b/utils.py @@ -60,3 +60,14 @@ def train_agent(env: Environment, agent: Agent, num_epochs = 1024, max_steps = 3 if agent.current_memory_size > min_memory_size: loss_vals.append([epoch, total_loss / (count+1e-10)]) return np.asarray(loss_vals) + + +def walk_agent(state, env: Environment, agent: Agent, max_steps = 32): + path = [state] + for _ in range(max_steps): + action = agent.act(state) + state, (_, done) = env.act(state, action) + path.append(state) + if done: + break + return path From 32ab1e435940a5d35e4c1939acdc3ad3258fa298 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 10 Jun 2024 21:35:58 -0400 Subject: [PATCH 08/23] Added TriangulationEnvironment --- environment.py | 54 ++++++++++++------- .../RL_fib_and_triang.ipynb | 0 .../RL_fib_and_triang_K3.ipynb | 0 .../RL_subpolytope.ipynb | 0 4 files changed, 35 insertions(+), 19 deletions(-) rename RL_fib_and_triang.ipynb => notebooks/RL_fib_and_triang.ipynb (100%) rename RL_fib_and_triang_K3.ipynb => notebooks/RL_fib_and_triang_K3.ipynb (100%) rename RL_subpolytope.ipynb => notebooks/RL_subpolytope.ipynb (100%) diff --git a/environment.py b/environment.py index cff2774..2c57f6d 100644 --- a/environment.py +++ b/environment.py @@ -8,6 +8,8 @@ from functools import reduce from typing import Tuple, List +from Elli import utils + import numpy as np from cytools import Polytope from notebooks.integer_rref import i4mat_rref @@ -174,23 +176,37 @@ def all_actions(self): return [i for i in range(self._d)] +class TriangulationEnvironment(Environment): + def __init__(self, polytope: Environment): + self._p = polytope + self._two_face_Ts = utils.get_two_face_triangs(polytope) + self._max_num_triangs = max(len(x) for x in self._two_face_Ts) + self._action_list = utils.get_T_actions(self._two_face_Ts) + + def random_state(self): + return utils.random_T_state(self._two_face_Ts, self._max_num_triangs) + + def fitness(self, state) -> Tuple[float, bool]: + f_val = utils.T_fitness(self._p, self._two_face_Ts, state) + return f_val, f_val == 1 + + def act(self, state, action) -> Tuple[List, float]: + new_state = utils.T_act(state, self._action_list[action]) + return new_state, self.fitness(new_state) + + @property + def num_actions(self): + return self._max_num_triangs + + + if __name__ == "__main__": - p = Polytope([ - [1,0,0,0], - [0,1,0,0], - [0,0,1,0], - [0,0,0,1], - [-1,-1,0,0], - [-1,-1,-1,-1]]) - subpoly = SubpolytopeEnvironment(p, 2) - state = subpoly.random_state() - print(subpoly.fitness(state)) - - multi = MultiEnvironment([subpoly, subpoly]) - print(multi.fitness([state, state])) - - multi.add(subpoly) - multi += subpoly - random_multi_state = multi.random_state() - print(multi.fitness(random_multi_state), random_multi_state) - print(multi.num_actions) + from cytools import fetch_polytopes + all_polys = fetch_polytopes(h11=3, lattice="N", limit=100, as_list=True) + p = all_polys[15] + + t_env = TriangulationEnvironment(p) + state = t_env.random_state() + print(state) + print(t_env.fitness(state)) + print(t_env.act(state, 1)) diff --git a/RL_fib_and_triang.ipynb b/notebooks/RL_fib_and_triang.ipynb similarity index 100% rename from RL_fib_and_triang.ipynb rename to notebooks/RL_fib_and_triang.ipynb diff --git a/RL_fib_and_triang_K3.ipynb b/notebooks/RL_fib_and_triang_K3.ipynb similarity index 100% rename from RL_fib_and_triang_K3.ipynb rename to notebooks/RL_fib_and_triang_K3.ipynb diff --git a/RL_subpolytope.ipynb b/notebooks/RL_subpolytope.ipynb similarity index 100% rename from RL_subpolytope.ipynb rename to notebooks/RL_subpolytope.ipynb From 5dd257c9e263b8a4181e447d4f3dd6b7e2ce7c27 Mon Sep 17 00:00:00 2001 From: Elli Heyes <44784866+elliheyes@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:07:15 +0100 Subject: [PATCH 09/23] Update Readme.md Added a few sentences. --- Readme.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 405ddf6..e6399b6 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,10 @@ # Triangulation-Generator +In this package we use a deep Q-learning reinforcement learning model to generate fine regular star triangulations of reflexive polytopes. These triangulations provide resolutions to non-terminal singularities in the ambient toric Fano variety and Calabi-Yau hypersurfaces constructed from the polytope. + +One can also look for added geometric information, such as fibration structures in the Calabi-Yau hypersurfaces and holomorphic vector bundles that satisfy the anomaly cancellation and slope stability conditions in E8 heterotic string compactification. + +For more information, please see the arxiv preprint - arXiv:2405.21017. + ## Dependencies -* [CGAL](https://github.com/CGAL/cgal). -* [Boost program-options](https://www.boost.org). -- * program-options - if compiling executables. -- * Boost python - if compiling with python bindings using with `BUILD_PY_BINDINGS=ON` flag. +* This package uses functions from CYtools (https://cy.tools/). Please first instal this package before attempting to run scripts in this repository. From 8fc0bbb7fbc8a594d4e30a4a5dc1611ef6542145 Mon Sep 17 00:00:00 2001 From: Elli Heyes <44784866+elliheyes@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:41:07 +0100 Subject: [PATCH 10/23] Delete example.py Old file - deleted. --- example.py | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 example.py diff --git a/example.py b/example.py deleted file mode 100644 index 4c1d6ac..0000000 --- a/example.py +++ /dev/null @@ -1,7 +0,0 @@ -from GA import random_pop, evol_pop - -points = [[1,0,0],[0,1,0],[0,0,1],[-1,-1,-1]] - -initial_pop = random_pop(points, 100) - -term_states = evol_pop(initial_pop, 100, numcuts=1, mutrate=0.01) \ No newline at end of file From b54e11c333c1c4cfbfa48328210d54203029941f Mon Sep 17 00:00:00 2001 From: Elli Heyes <44784866+elliheyes@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:42:28 +0100 Subject: [PATCH 11/23] Delete Elli/poly/GA_poly.py Old files deleted. --- Elli/poly/GA_poly.py | 254 ------------------------------------------- 1 file changed, 254 deletions(-) delete mode 100644 Elli/poly/GA_poly.py diff --git a/Elli/poly/GA_poly.py b/Elli/poly/GA_poly.py deleted file mode 100644 index 75f4455..0000000 --- a/Elli/poly/GA_poly.py +++ /dev/null @@ -1,254 +0,0 @@ -# author: elli heyes (elli.heyes@city.ac.uk) -# date last edited: 28/11/2023 -import copy -import random -import numpy as np -from cytools import Polytope -from fitness_poly import fitness - - -class state: - """"Polytope state object - .points is the points matrix of the polytope - .dim is the dimension of the polytope - .max_coeff is the absolute maximum coefficient value - .fitness is the fitness of the triangulation - .terminal is 1 if the state is good and 0 otherwise""" - def __init__(self, points, dim, max_coeff): - self.points = points - self.dim = dim - self.max_coeff = max_coeff - self.max_verts = len(points) - - self.fitness = 0. - self.terminal = 0 - - def compute_fitness(self, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - self.fitness = fitness(self.points, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - if self.fitness == 0: - self.terminal = 1 - else: - self.terminal = 0 - - -class population: - """"Population: - .state_list is the list of states - .pop_size is the population size - .max_fitness is the maximum fitness score - .av_fitness is the average fitness score - .num_term is the number of terminal states""" - def __init__(self, state_list): - self.state_list = state_list - self.pop_size = len(state_list) - - self.max_fitness = 0. - self.av_fitness = 0. - self.num_term = 0. - - self.compute_max_fitness() - self.compute_av_fitness() - self.compute_num_term() - - def compute_max_fitness(self): - max_fit = self.state_list[0].fitness - for i in range(1,self.pop_size): - if self.state_list[i].fitness > max_fit: - max_fit = self.state_list[i].fitness - self.max_fitness = max_fit - - def compute_av_fitness(self): - sum_fit = 0 - for i in range(self.pop_size): - sum_fit += self.state_list[i].fitness - self.av_fitness = sum_fit / self.pop_size - - def compute_num_term(self): - total_term = 0 - for i in range(self.pop_size): - if self.state_list[i].terminal: - total_term += 1 - self.num_term = total_term - - def mutate_pop(self, mut_rate, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - # determine the number of mutations to perform - num_points = self.pop_size*self.state_list[0].max_verts*self.state_list[0].dim - num_mut = round(num_points*mut_rate) - - for i in range(num_mut): - # determine a random state in the population - state_pos = random.choice(range(self.pop_size)) - - # determine a random point in the polytope - point_pos = random.choice(range(len(self.state_list[state_pos].points))) - - # determine a random coordinate in the point - coord_pos = random.choice(range(1,len(self.state_list[state_pos].points[point_pos]))) - - # mutate the point - self.state_list[state_pos].points[point_pos][coord_pos] = random.choice(range(-self.state_list[state_pos].max_coeff,self.state_list[state_pos].max_coeff)) - - # update fitness - self.state_list[state_pos].compute_fitness(h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - - # update max fitness, average fitness and number of terminal states - self.compute_max_fitness() - self.compute_av_fitness() - self.compute_num_term() - - -def crossover(state1, state2, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Cross two states.""" - # determine a random point in the polytopes - point_pos = random.choice(range(state1.max_verts)) - - # determine a random coordinate in the point - coord_pos = random.choice(range(state1.dim)) - - # swap the relevant parts of the bit lists - new_points1 = copy.deepcopy(state1.points) - new_points2 = copy.deepcopy(state2.points) - for i in range(point_pos,len(new_points1)): - if i == point_pos: - start = coord_pos - else: - start = 0 - for j in range(start,len(new_points1[i])): - new_points1[i][j] = state2.points[i][j] - new_points2[i][j] = state1.points[i][j] - - # define the new states - new_state1 = state(points=new_points1, dim=state1.dim, max_coeff=state1.max_coeff) - new_state2 = state(points=new_points2, dim=state2.dim, max_coeff=state2.max_coeff) - - # update the fitness - new_state1.compute_fitness(h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - new_state2.compute_fitness(h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - - return new_state1, new_state2 - - -def random_state(dim, max_verts, max_coeff, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Generate a random polytope state.""" - points = [] - for i in range(max_verts): - point = [] - for j in range(dim): - point.append(random.choice(range(-max_coeff,max_coeff))) - points.append(point) - - S = state(points=points, dim=dim, max_coeff=max_coeff) - S.compute_fitness(h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - - return S - - -def random_pop(pop_size, dim, max_verts, max_coeff, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Generate a random population.""" - state_list = [] - for i in range(pop_size): - state_list.append(random_state(dim, max_verts, max_coeff, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav)) - - pop = population(state_list) - pop.compute_max_fitness() - pop.compute_av_fitness() - pop.compute_num_term() - - return pop - - -def sort_pop(pop): - """"Sort a population based on the fitness scores.""" - fitness_scores = [pop.state_list[i].fitness for i in range(pop.size)] - sorted_indices = np.argsort(np.array(fitness_scores)) - sorted_state_list = [pop.state_list[i] for i in sorted_indices] - return population(sorted_state_list) - - -def select_and_cross(pop, p, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Select two pairs of individuals from the population and cross them.""" - indices = random.choices(range(pop.pop_size), p, k=2) - state1, state2 = crossover(pop.state_list[indices[0]], pop.state_list[indices[1]], h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - return [state1, state2] - - -def next_pop(pop, mut_rate=0.01, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Update a population by performing selection, crossover and mutation.""" - df = pop.max_fitness - pop.av_fitness - if df <= 0: - p = [1/pop.pop_size for i in range(pop.pop_size)] - else: - p = [((3-1)*(pop.state_list[i].fitness-pop.av_fitness)+df)/df/pop.pop_size for i in range(pop.pop_size)] - - state_list = [] - for i in range(int(pop.pop_size/2)): - state_list = state_list + select_and_cross(pop, p, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - new_pop = population(state_list) - - new_pop.mutate_pop(mut_rate=mut_rate, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - - return new_pop - - -def term_states(pop): - """"Select terminal states from a population.""" - states = [] - for i in range(pop.pop_size): - if pop.state_list[i].terminal == 1: - P = Polytope(pop.state_list[i].points) - states.append(P) - return states - - -def remove_redundancy(term_states): - """"Remove redundancy in a list of terminal states.""" - reduced_states = [] - for i in range(len(term_states)): - equiv = 0 - for j in range(len(reduced_states)): - if term_states[i].is_linearly_equivalent(reduced_states[j]): - equiv = 1 - break - if not equiv: - reduced_states.append(term_states[i]) - return reduced_states - - -def evol_pop(pop, num_gen, mut_rate, monitor=True, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Evolve a population over generations and extract terminal states.""" - - term_states_list = remove_redundancy(term_states(pop)) - - if monitor: - print("Total # Terminal States Average Fitness Maximum Fitness") - for i in range(num_gen): - pop = next_pop(pop, mut_rate=mut_rate, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - - term_states_list = term_states_list + term_states(pop) - - if monitor: - print(" "+str(len(term_states_list))+" "+str(round(pop.av_fitness,2))+ - " "+str(round(pop.max_fitness,2))) - - term_states_list = remove_redundancy(term_states_list) - print("Total # of reduced terminal states: "+str(len(term_states_list))) - - return term_states_list - - -def search(num_run, num_gen, pop_size, mut_rate, dim, max_coeff, max_verts, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - """"Evolve several random populations over generations and extract terminal states.""" - - terminal_states = [] - print("Total # Terminal States") - for i in range(num_run): - initial_pop = random_pop(pop_size, polydim, maxcoeff, maxvert) - - terminal_states = terminal_states + evol_pop(initial_pop, num_gen, mut_rate, monitor=False, h11=h11, h12=h12, h13=h13, h22=h22, chi=chi, fav=fav) - terminal_states = remove_redundancy(terminal_states) - - print(" "+str(len(terminal_states))) - - return terminal_states - - From 8b14253f5349ef3264d449b963da977f3dddbbba Mon Sep 17 00:00:00 2001 From: Elli Heyes <44784866+elliheyes@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:42:36 +0100 Subject: [PATCH 12/23] Delete Elli/poly/Working_P.ipynb Old files deleted. --- Elli/poly/Working_P.ipynb | 179 -------------------------------------- 1 file changed, 179 deletions(-) delete mode 100644 Elli/poly/Working_P.ipynb diff --git a/Elli/poly/Working_P.ipynb b/Elli/poly/Working_P.ipynb deleted file mode 100644 index 78769ec..0000000 --- a/Elli/poly/Working_P.ipynb +++ /dev/null @@ -1,179 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "c1bedd1b-1097-4a96-9088-cc29ab5b13b9", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "from cytools import Polytope\n", - "from GA_poly import state, random_pop, evol_pop" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "2a088d9e-50db-4819-aaf2-a1b2a3ce6b78", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "DIM = 4 # polytope dimension \n", - "MAXCOEFF = 3 # absolute maximum coefficient value\n", - "MAXVERTS = 8 # maximum number of vertices\n", - "POPSIZE = 100 # population size\n", - "NUMGEN = 50 # number of generations\n", - "MUTRATE = 0.01 # mutation rate" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "523f1dad-d5ab-4bd8-b498-421862264a76", - "metadata": { - "tags": [] - }, - "outputs": [], - "source": [ - "initial_pop = random_pop(POPSIZE, DIM, MAXVERTS, MAXCOEFF, fav=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "aff9f647-4744-43c8-984f-2d7c2ff543a4", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Total # Terminal States Average Fitness Maximum Fitness\n", - " 0 -18.9 -6.15\n", - " 0 -17.32 -4.85\n", - " 0 -15.77 -4.75\n", - " 0 -13.83 -3.64\n", - " 0 -11.75 -3.64\n", - " 0 -10.12 -2.75\n", - " 0 -8.41 -1.55\n", - " 0 -6.69 -2.56\n", - " 0 -6.2 -1.93\n", - " 0 -5.04 -1.38\n", - " 0 -4.33 -1.31\n", - " 0 -4.29 -0.5\n", - " 0 -3.58 -0.5\n", - " 0 -3.27 -0.7\n", - " 0 -3.03 -0.45\n", - " 0 -2.61 -0.38\n", - " 0 -2.02 -0.36\n", - " 0 -1.91 -0.21\n", - " 0 -1.58 -0.29\n", - " 0 -1.29 -0.29\n", - " 0 -1.2 -0.33\n", - " 0 -0.92 -0.2\n", - " 0 -0.74 -0.15\n", - " 0 -0.68 -0.14\n", - " 0 -0.67 -0.14\n", - " 1 -0.72 0.0\n", - " 3 -0.64 0.0\n", - " 8 -0.62 0.0\n", - " 15 -0.55 0.0\n", - " 27 -0.55 0.0\n", - " 37 -0.47 0.0\n", - " 46 -0.63 0.0\n", - " 58 -0.49 0.0\n", - " 76 -0.34 0.0\n", - " 104 -0.32 0.0\n", - " 151 -0.3 0.0\n", - " 201 -0.26 0.0\n", - " 256 -0.36 0.0\n", - " 310 -0.34 0.0\n", - " 360 -0.35 0.0\n", - " 408 -0.42 0.0\n", - " 461 -0.3 0.0\n", - " 524 -0.37 0.0\n", - " 588 -0.27 0.0\n", - " 655 -0.32 0.0\n", - " 726 -0.27 0.0\n", - " 786 -0.38 0.0\n", - " 860 -0.22 0.0\n", - " 933 -0.26 0.0\n", - " 1003 -0.28 0.0\n", - "Total # of reduced terminal states: 56\n" - ] - } - ], - "source": [ - "terminal_states = evol_pop(initial_pop, NUMGEN, MUTRATE, monitor=True, fav=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "ad828a8c-9c30-41a3-acb4-62575c814ea7", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 0, 0, 0, 0],\n", - " [-1, 1, 1, -1],\n", - " [ 1, -2, -1, 1],\n", - " [ 1, 0, 1, -1],\n", - " [-1, 1, 1, 0],\n", - " [-1, 2, 1, 1],\n", - " [ 0, -1, -1, 2],\n", - " [ 0, 0, -1, 0],\n", - " [ 0, 1, 1, 0],\n", - " [ 1, -1, 0, 0],\n", - " [ 0, 0, 0, 1]])" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "terminal_states[0].points()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "04fb7f9d-e531-42f0-9932-98e605dc6518", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.2" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From c0ef19ef8d4d6a10b0ef7b3280017412066d683e Mon Sep 17 00:00:00 2001 From: Elli Heyes <44784866+elliheyes@users.noreply.github.com> Date: Tue, 11 Jun 2024 09:42:45 +0100 Subject: [PATCH 13/23] Delete Elli/poly/fitness_poly.py Old files deleted. --- Elli/poly/fitness_poly.py | 56 --------------------------------------- 1 file changed, 56 deletions(-) delete mode 100644 Elli/poly/fitness_poly.py diff --git a/Elli/poly/fitness_poly.py b/Elli/poly/fitness_poly.py deleted file mode 100644 index 3029e9b..0000000 --- a/Elli/poly/fitness_poly.py +++ /dev/null @@ -1,56 +0,0 @@ -# author: elli heyes (elli.heyes@city.ac.uk) -# date last edited: 28/11/2023 -import numpy as np -from cytools import Polytope - -def IP(poly): - pts = [list(item) for item in poly.points()] - origin = [0 for i in range(poly.dim())] - return len(poly.interior_points()) == 1 and origin in pts - -def lattice_dists(poly): - return poly.inequalities()[:,-1] - -def fitness(points, h11=None, h12=None, h13=None, h22=None, chi=None, fav=False): - w1 = w2 = w3 = w4 = w5 = w6 = w7 = w8 = 1 - - poly = Polytope(points) - - term1 = w1 * (IP(poly) - 1) - term2 = - w2 * np.sum(np.abs(d:=lattice_dists(poly) - 1)) / len(d) - - term3 = term4 = term5 = term6 = term7 = term8 = 0 - if h11 != None: - if poly.is_reflexive(): - term3 = - w3 * abs(h11 - poly.h11(lattice="N")) - else: - term3 = -100 - if h12 != None: - if poly.is_reflexive(): - term4 = - w4 * abs(h12 - poly.h12(lattice="N")) - else: - term4 = -100 - if h13 != None: - if poly.is_reflexive(): - term5 = - w5 * abs(h13 - poly.h13(lattice="N")) - else: - term5 = -100 - if h22 != None: - if poly.is_reflexive(): - term6 = - w6 * abs(h22 - poly.h22(lattice="N")) - else: - term6 = -100 - if chi != None: - if poly.is_reflexive(): - term7 = - w7 * abs(chi - poly.chi(lattice="N")) - else: - term7 = -100 - if fav == True: - if poly.is_reflexive(): - if not poly.is_favorable(lattice="N"): - term8 = - w8 * 1 - else: - term8 = -100 - - return term1 + term2 + term3 + term4 + term5 + term6 + term7 - From 169b48c4ab521015c85a9aadac9989e06dc5aa36 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 09:15:23 -0400 Subject: [PATCH 14/23] Updated Readme with usage instructions --- Readme.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Readme.md b/Readme.md index e6399b6..c8f23b0 100644 --- a/Readme.md +++ b/Readme.md @@ -8,3 +8,37 @@ For more information, please see the arxiv preprint - arXiv:2405.21017. ## Dependencies * This package uses functions from CYtools (https://cy.tools/). Please first instal this package before attempting to run scripts in this repository. + + +## Usage +```python +# Initialize Environment +p = Polytope([ + [ 1, 0, 0, 0], + [ 0, 1, 0, 0], + [ 0, 0, 1, 0], + [ 0, 0, 0, 1], + [-1,-1, 0, 0], + [-1,-1,-1,-1]]) +s_env = SubpolytopeEnvironment(p, 2) + +# Initialize agent +model = tfk.Sequential([ + Input((s_env.random_state().shape[0],)), + Dense(64, activation='relu'), + Dense(128, activation='relu'), + Dense(s_env.num_actions, activation='linear') +]) +target_model = tfk.models.clone_model(model) + +optim = tfk.optimizers.Adam(learning_rate = 1e-3) +model.compile( + loss = tfk.losses.MeanSquaredError(), + optimizer = optim, + metrics = [tfk.metrics.MeanAbsoluteError()]) + +agent = Agent(model, target_model, buffer_size = 2**11) + +# Train the agent +train_agent(s_env, agent, num_epochs = 2048, verbosity = 1) +``` \ No newline at end of file From 468cce282921920aab2b4147e416b4aceef2440e Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 09:57:17 -0400 Subject: [PATCH 15/23] Updated MultiEnv to handle all state shapes --- Readme.md | 5 ++--- agent.py | 8 +++---- environment.py | 61 +++++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/Readme.md b/Readme.md index c8f23b0..ddc9296 100644 --- a/Readme.md +++ b/Readme.md @@ -29,7 +29,6 @@ model = tfk.Sequential([ Dense(128, activation='relu'), Dense(s_env.num_actions, activation='linear') ]) -target_model = tfk.models.clone_model(model) optim = tfk.optimizers.Adam(learning_rate = 1e-3) model.compile( @@ -37,8 +36,8 @@ model.compile( optimizer = optim, metrics = [tfk.metrics.MeanAbsoluteError()]) -agent = Agent(model, target_model, buffer_size = 2**11) +agent = Agent(model) # Train the agent train_agent(s_env, agent, num_epochs = 2048, verbosity = 1) -``` \ No newline at end of file +``` diff --git a/agent.py b/agent.py index 32fe65c..74b5c6f 100644 --- a/agent.py +++ b/agent.py @@ -13,11 +13,11 @@ class Agent(object): - def __init__(self, model: tfk.Sequential, target_model: tfk.Sequential, buffer_size: int): + def __init__(self, model: tfk.Sequential, target_model: tfk.Sequential = None, buffer_size: int = 2**11): """ @param model: Specifies the main model used for training. - @param target_model: Specifies the target model which is updated after some number of training steps. Ensures stability. - @param buffer_size: Size of the replay buffer. + @param target_model: Specifies the target model which is updated after some number of training steps. Ensures stability. (Default: None). + @param buffer_size: Size of the replay buffer. (Default: 2**11). """ self._memory = deque(maxlen=buffer_size) self._gamma = 0.95 @@ -27,7 +27,7 @@ def __init__(self, model: tfk.Sequential, target_model: tfk.Sequential, buffer_s self._policy_lr = 0.7 self._model = model - self._target_model = target_model + self._target_model = tfk.models.clone_model(model) if target_model is None else target_model self._num_actions = model.output_shape[-1] self.update_target_model() diff --git a/environment.py b/environment.py index 2c57f6d..59ed848 100644 --- a/environment.py +++ b/environment.py @@ -19,7 +19,7 @@ class Environment(object): @abc.abstractmethod def random_state(): """ - Generates a random state (or a list thereof). + Generates a random state. """ @abc.abstractmethod @@ -51,9 +51,26 @@ def num_actions(self): class MultiEnvironment(Environment): def __init__(self, environments: List[Environment]): self._environments = environments + self._state_shapes = None + + def _restore_shape(self, flat_state): + if self._state_shapes is None: + self._state_shapes = [*map(lambda x: np.asarray(x.random_state()).shape, self._environments)] + num_envs = len(self._environments) + + states = [] + shift_counter = 0 + for i in range(num_envs): + block_size = np.prod(self._state_shapes[i]) + states.append(flat_state[shift_counter:shift_counter+block_size].reshape(self._state_shapes[i])) + shift_counter += block_size + return states def random_state(self): - return [*map(lambda x: x.random_state(), self._environments)] + states = [*map(lambda x: x.random_state(), self._environments)] + if self._state_shapes is None: + self._state_shapes = [*map(lambda x: np.asarray(x).shape, states)] + return np.concatenate([*map(lambda x: np.asarray(x).reshape(-1), states)]) @staticmethod def _combine_r_vals(r_val_1, r_val_2): @@ -63,14 +80,13 @@ def fitness(self, state) -> Tuple[float, bool]: """ @params state: List of states. """ + state = self._restore_shape(state) r_val = (0.0, True) for i, environment in enumerate(self._environments): r_val_curr = environment.fitness(state[i]) r_val = self._combine_r_vals( r_val_curr, r_val) - # r_val += r_val_curr - # terminated &= terminated_curr # TODO compatibility. # NOTE: In some cases doing one search depends if the other one is valid. @@ -79,6 +95,8 @@ def fitness(self, state) -> Tuple[float, bool]: return r_val def act(self, state, action): + state = self._restore_shape(state) + new_states = [] r_val = (0.0, True) for s_curr, a_curr, env_curr in zip(state, action, self._environments): @@ -183,6 +201,9 @@ def __init__(self, polytope: Environment): self._max_num_triangs = max(len(x) for x in self._two_face_Ts) self._action_list = utils.get_T_actions(self._two_face_Ts) + def get_triangulation(self, state): + return utils.combine_triangulation(self._p, self._two_face_Ts, state) + def random_state(self): return utils.random_T_state(self._two_face_Ts, self._max_num_triangs) @@ -200,13 +221,33 @@ def num_actions(self): +class FibrationEnvironment(MultiEnvironment): + def __init__(self, polytope: Environment, fibration_dim: int): + super().__init__(environments = [ + TriangulationEnvironment(polytope), + SubpolytopeEnvironment(polytope, fibration_dim) + ]) + self._p = polytope + + def fitness(self, state): + fitness, done = super().fitness(state) + + # TODO compatibility + # if done: + # t_src = self._t_env.get_triangulation(state[0]) + return fitness, done + if __name__ == "__main__": from cytools import fetch_polytopes - all_polys = fetch_polytopes(h11=3, lattice="N", limit=100, as_list=True) + all_polys = fetch_polytopes(h11=15, lattice="N", limit=100, as_list=True) p = all_polys[15] - t_env = TriangulationEnvironment(p) - state = t_env.random_state() - print(state) - print(t_env.fitness(state)) - print(t_env.act(state, 1)) + t = p.triangulate() + for t_1 in t.neighbor_triangulations(): + print(len(t_1.neighbor_triangulations()[0].neighbor_triangulations())) + + # t_env = TriangulationEnvironment(p) + # state = t_env.random_state() + # print(state) + # print(t_env.fitness(state)) + # print(t_env.act(state, 1)) From 9c41842628fc1bb2c7cee6537d4ec1dbf251f09e Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 13:18:16 -0400 Subject: [PATCH 16/23] Added HTriangulationEnvironment --- environment.py | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/environment.py b/environment.py index 59ed848..ba564e8 100644 --- a/environment.py +++ b/environment.py @@ -17,7 +17,7 @@ class Environment(object): @abc.abstractmethod - def random_state(): + def random_state(self): """ Generates a random state. """ @@ -220,6 +220,43 @@ def num_actions(self): return self._max_num_triangs +class HTriangulationEnvironment(Environment): + def __init__(self, polytope: Polytope, step_size: float = 0.5): + self._p = polytope + self._num_actions = polytope.points().shape[0] + self._step_size = step_size + + def random_state(self): + return np.random.random(self._num_actions) + + def fitness(self, state): + triang = self._p.triangulate(heights = state, check_heights=False) + + reward = 0.0 + if triang.is_fine(): + reward += 1.0 + if triang.is_star(): + reward += 1.0 + # # Always true + # if triang.is_regular(): + # reward += 1.0 + + return reward, reward == 2.0 + + def act(self, state, action): + shift = np.zeros(self._num_actions) + sgn = 1.0 + if action >= self._num_actions: + sgn = -1.0 + shift[action % self._num_actions] = sgn*self._step_size + + new_state = state + shift + return new_state, self.fitness(new_state) + + @property + def num_actions(self): + return self._num_actions*2 + class FibrationEnvironment(MultiEnvironment): def __init__(self, polytope: Environment, fibration_dim: int): From d5ad5b3d21076cfa5857b7252a4ab9c24eb4da08 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 13:37:08 -0400 Subject: [PATCH 17/23] Updated Readme --- Readme.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index ddc9296..a8021a0 100644 --- a/Readme.md +++ b/Readme.md @@ -1,16 +1,24 @@ # Triangulation-Generator -In this package we use a deep Q-learning reinforcement learning model to generate fine regular star triangulations of reflexive polytopes. These triangulations provide resolutions to non-terminal singularities in the ambient toric Fano variety and Calabi-Yau hypersurfaces constructed from the polytope. +In this package we use a deep Q-learning reinforcement learning model to generate fine regular star triangulations of reflexive polytopes. These triangulations provide resolutions to non-terminal singularities in the ambient toric Fano variety and Calabi-Yau hypersurfaces constructed from the polytope. One can also look for added geometric information, such as fibration structures in the Calabi-Yau hypersurfaces and holomorphic vector bundles that satisfy the anomaly cancellation and slope stability conditions in E8 heterotic string compactification. -For more information, please see the arxiv preprint - arXiv:2405.21017. +For more information, please see the arxiv preprint - [arXiv:2405.21017](https://arxiv.org/abs/2405.21017). ## Dependencies -* This package uses functions from CYtools (https://cy.tools/). Please first instal this package before attempting to run scripts in this repository. +* This package uses functions from CYtools (https://cy.tools/). Please first install this package before attempting to run scripts in this repository. -## Usage +## Quickstart +Currently supported environments are: +|Environment | Description| Arguments | +| --- | --- | --- | +| ```TriangulationEnvironment(```
 ```polytope)```| Uses two-face encoding for generating triangulations. | **polytope**: Polytope. | +| ```HTriangulationEnvironment(```
 ```polytope)``` | Uses height encoding for generating triangulations. | **polytope**: Polytope. | +| ```SubpolytopeEnvironment(```
 ```polytope, fibration_dim)``` | Uses subspace encoding to generate subpolytope. | **polytope**: Polytope.
**fibration_dim**: Dimension of subpolytope. | + +An example code for generating subpolytopes is shown below: ```python # Initialize Environment p = Polytope([ @@ -41,3 +49,19 @@ agent = Agent(model) # Train the agent train_agent(s_env, agent, num_epochs = 2048, verbosity = 1) ``` + + +## Citation +To cite our paper: +```bibtex +@article{Berglund:2024reu, + author = "Berglund, Per and Butbaia, Giorgi and He, Yang-Hui and Heyes, Elli and Hirst, Edward and Jejjala, Vishnu", + title = "{Generating Triangulations and Fibrations with Reinforcement Learning}", + eprint = "2405.21017", + archivePrefix = "arXiv", + primaryClass = "hep-th", + reportNumber = "QMUL-PH-24-10", + month = "5", + year = "2024" +} +``` \ No newline at end of file From c6ba2b3265d9478ffe360eafa32c9fd645e4e0a2 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 14:18:43 -0400 Subject: [PATCH 18/23] Fixed penalty in HTriangulationEnvironment --- Readme.md | 8 ++++---- environment.py | 6 +++--- utils.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Readme.md b/Readme.md index a8021a0..b336e9d 100644 --- a/Readme.md +++ b/Readme.md @@ -2,7 +2,7 @@ In this package we use a deep Q-learning reinforcement learning model to generate fine regular star triangulations of reflexive polytopes. These triangulations provide resolutions to non-terminal singularities in the ambient toric Fano variety and Calabi-Yau hypersurfaces constructed from the polytope. -One can also look for added geometric information, such as fibration structures in the Calabi-Yau hypersurfaces and holomorphic vector bundles that satisfy the anomaly cancellation and slope stability conditions in E8 heterotic string compactification. +One can also look for added geometric information, such as fibration structures in the Calabi-Yau hypersurfaces and holomorphic vector bundles that satisfy the anomaly cancellation and slope stability conditions in $E_8$ heterotic string compactification. For more information, please see the arxiv preprint - [arXiv:2405.21017](https://arxiv.org/abs/2405.21017). @@ -14,9 +14,9 @@ For more information, please see the arxiv preprint - [arXiv:2405.21017](https:/ Currently supported environments are: |Environment | Description| Arguments | | --- | --- | --- | -| ```TriangulationEnvironment(```
 ```polytope)```| Uses two-face encoding for generating triangulations. | **polytope**: Polytope. | -| ```HTriangulationEnvironment(```
 ```polytope)``` | Uses height encoding for generating triangulations. | **polytope**: Polytope. | -| ```SubpolytopeEnvironment(```
 ```polytope, fibration_dim)``` | Uses subspace encoding to generate subpolytope. | **polytope**: Polytope.
**fibration_dim**: Dimension of subpolytope. | +| ```TriangulationEnvironment(```
 ```polytope)```| Uses two-face encoding for generating triangulations. | - **polytope**: Polytope. | +| ```HTriangulationEnvironment(```
 ```polytope)``` | Uses height encoding for generating triangulations. | - **polytope**: Polytope. | +| ```SubpolytopeEnvironment(```
 ```polytope, fibration_dim)``` | Uses subspace encoding to generate subpolytope. | - **polytope**: Polytope.
- **fibration_dim**: Dimension of subpolytope. | An example code for generating subpolytopes is shown below: ```python diff --git a/environment.py b/environment.py index ba564e8..5942b67 100644 --- a/environment.py +++ b/environment.py @@ -232,11 +232,11 @@ def random_state(self): def fitness(self, state): triang = self._p.triangulate(heights = state, check_heights=False) - reward = 0.0 + reward = -1.0 if triang.is_fine(): - reward += 1.0 + reward += 1.5 if triang.is_star(): - reward += 1.0 + reward += 1.5 # # Always true # if triang.is_regular(): # reward += 1.0 diff --git a/utils.py b/utils.py index 1a2f7d3..4dbd180 100644 --- a/utils.py +++ b/utils.py @@ -56,7 +56,7 @@ def train_agent(env: Environment, agent: Agent, num_epochs = 1024, max_steps = 3 if terminated: break if verbosity > 0: - epochs.set_description(f"Epoch {epoch}, loss = {total_loss / (count+1e-10):.02f}") + epochs.set_description(f"Epoch {epoch}, loss = {total_loss / (count+1e-10):e}") if agent.current_memory_size > min_memory_size: loss_vals.append([epoch, total_loss / (count+1e-10)]) return np.asarray(loss_vals) From e392313ca2911b711ea6d2e969567df1f4710df8 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 21:38:07 -0400 Subject: [PATCH 19/23] Fully implemented FibrationEnvironment. Updated Readme. Minor fixes. --- Readme.md | 3 +- agent.py | 12 +++++ environment.py | 140 ++++++++++++++++++++++++++++++++++++++++++------- utils.py | 6 +-- 4 files changed, 139 insertions(+), 22 deletions(-) diff --git a/Readme.md b/Readme.md index b336e9d..9280bd0 100644 --- a/Readme.md +++ b/Readme.md @@ -17,6 +17,7 @@ Currently supported environments are: | ```TriangulationEnvironment(```
 ```polytope)```| Uses two-face encoding for generating triangulations. | - **polytope**: Polytope. | | ```HTriangulationEnvironment(```
 ```polytope)``` | Uses height encoding for generating triangulations. | - **polytope**: Polytope. | | ```SubpolytopeEnvironment(```
 ```polytope, fibration_dim)``` | Uses subspace encoding to generate subpolytope. | - **polytope**: Polytope.
- **fibration_dim**: Dimension of subpolytope. | +| ```FibrationEnvironment(```
 ```polytope, fibration_dim)``` | A multi-environment, combining Triangulation and subpolytope environments for the purpose of constructing fibrations. An additional compatibility condition forces the triangulation to be consistent with the choice of subpolytope. | - **polytope**: Polytope.
- **fibration_dim**: Dimension of subpolytope. | An example code for generating subpolytopes is shown below: ```python @@ -47,7 +48,7 @@ model.compile( agent = Agent(model) # Train the agent -train_agent(s_env, agent, num_epochs = 2048, verbosity = 1) +agent.fit(s_env, num_epochs = 2048, verbosity = 1) ``` diff --git a/agent.py b/agent.py index 74b5c6f..a9f2c07 100644 --- a/agent.py +++ b/agent.py @@ -10,6 +10,8 @@ import numpy as np from tensorflow import keras as tfk +from utils import train_agent +from environment import Environment class Agent(object): @@ -62,6 +64,16 @@ def act(self, state: np.ndarray) -> int: Q_a = self._model(state) return np.argmax(Q_a) + def fit(self, env: Environment, num_epochs = 1024, max_steps = 32, batch_size = 128, min_memory_size = 1024, verbosity = 0): + return train_agent( + agent = self, + env = env, + num_epochs = num_epochs, + max_steps = max_steps, + batch_size = batch_size, + min_memory_size = min_memory_size, + verbosity = verbosity) + def replay(self, batch_size): """ Replays the buffer and trains the model. diff --git a/environment.py b/environment.py index 5942b67..722f4e2 100644 --- a/environment.py +++ b/environment.py @@ -12,6 +12,7 @@ import numpy as np from cytools import Polytope +from cytools.triangulation import Triangulation from notebooks.integer_rref import i4mat_rref @@ -32,10 +33,10 @@ def fitness(self, state) -> Tuple[float, bool]: """ @abc.abstractmethod - def act(self, state, action) -> Tuple[List, float]: + def act(self, state, action: int) -> Tuple[List, float]: """ @param state: Current state. - @param action: Action using which to act on the state. + @param action: Index of the action using which to act on the state. @return Tuple (next state, fitness of the next state). """ @@ -66,11 +67,14 @@ def _restore_shape(self, flat_state): shift_counter += block_size return states + def _flatten_state(self, state): + return np.concatenate([*map(lambda x: np.asarray(x).reshape(-1), state)]) + def random_state(self): states = [*map(lambda x: x.random_state(), self._environments)] if self._state_shapes is None: self._state_shapes = [*map(lambda x: np.asarray(x).shape, states)] - return np.concatenate([*map(lambda x: np.asarray(x).reshape(-1), states)]) + return self._flatten_state(states) @staticmethod def _combine_r_vals(r_val_1, r_val_2): @@ -87,25 +91,37 @@ def fitness(self, state) -> Tuple[float, bool]: r_val_curr = environment.fitness(state[i]) r_val = self._combine_r_vals( r_val_curr, r_val) - - # TODO compatibility. - # NOTE: In some cases doing one search depends if the other one is valid. - # TODO: make it into a graph with (u->v)∈E if v depends on u. Pass path to root. - return r_val def act(self, state, action): state = self._restore_shape(state) + # Map action over the list. + action_nums = [*map(lambda x: x.num_actions, self._environments)] + + # idx = x1 + x2 L1 + x3 L1 L2 + x4 L1 L2 L3 + + # x1 = idx % L1 + # idx = (idx - x1) / L1 + # # idx = x2 + x3 L2 + ... + # x2 = idx % L2 + # idx = (idx - x2) / L2 + # ... + + actions = [] + action_idx = action + for i in range(len(action_nums)): + actions.append(action_idx % action_nums[i]) + action_idx = (action_idx - actions[-1])//action_nums[i] new_states = [] r_val = (0.0, True) - for s_curr, a_curr, env_curr in zip(state, action, self._environments): + for s_curr, a_curr, env_curr in zip(state, actions, self._environments): new_state, r_val_curr = env_curr.act(s_curr, a_curr) new_states.append(new_state) r_val = self._combine_r_vals( r_val_curr, r_val) - return new_states, r_val + return self._flatten_state(new_states), r_val def add(self, other: Environment): """ @@ -143,7 +159,7 @@ def reduce_polytope(vertices): def intersect(self, state): vertices_basis = [] - for pt_id in state: + for pt_id in np.asarray(state, np.int32): vertices_basis.append(self._points[pt_id]) vertices_basis = np.asarray(vertices_basis) @@ -226,11 +242,14 @@ def __init__(self, polytope: Polytope, step_size: float = 0.5): self._num_actions = polytope.points().shape[0] self._step_size = step_size + def get_triangulation(self, state): + return self._p.triangulate(heights = state, check_heights = False) + def random_state(self): return np.random.random(self._num_actions) def fitness(self, state): - triang = self._p.triangulate(heights = state, check_heights=False) + triang = self.get_triangulation(state) reward = -1.0 if triang.is_fine(): @@ -258,21 +277,106 @@ def num_actions(self): return self._num_actions*2 +# TODO: Move into the class +def get_indices(p, subp): + return [np.where(np.all(v == p, axis=1))[0][0] for v in subp] + +def boundary(simplices): + dsimplices = [] + for s in simplices: + for i in range(1, len(s)): + dsimplices.append( + np.append(s[:i], s[(i+1):])) + + dsimplices = np.asarray(dsimplices) + return dsimplices + +def restrict(dsimplices, subp_vertices): + sub_simplices = np.where(np.all(np.isin(dsimplices, subp_vertices), axis=1))[0] + sub_simplices = dsimplices[sub_simplices] + + local_sub_simplices = [] + for s in sub_simplices: + local_s = [] + for v in s: + local_s.append(np.where(subp_vertices == v)[0][0]) + local_sub_simplices.append(local_s) + return np.unique(local_sub_simplices, axis=0) + +def project(vertices): + vertices_copy = np.array(vertices, copy=True) + W = np.asarray(i4mat_rref(vertices.shape[0], vertices.shape[1], vertices_copy)[0]).astype(np.float64) + local_vertices = np.round(vertices@np.linalg.pinv(W)) + idx = np.argwhere(np.all(local_vertices[..., :] == 0, axis=0)) + + return np.delete(local_vertices, idx, axis=1) + +def compose(x, *args): + out = x + for f in args: + out = f(out) + return out + + class FibrationEnvironment(MultiEnvironment): def __init__(self, polytope: Environment, fibration_dim: int): super().__init__(environments = [ - TriangulationEnvironment(polytope), + HTriangulationEnvironment(polytope), SubpolytopeEnvironment(polytope, fibration_dim) ]) self._p = polytope + self._d = fibration_dim + + def _compatibility_fitness(self, state): + done = True + state = self._restore_shape(state) + r_compatibility = 0.0 + if done: + triang = self._environments[0].get_triangulation(state[0]) + vertices = self._environments[1].intersect(state[1]) + + subsimplices = restrict( + dsimplices = compose(triang.simplices(), *([boundary]*(self._p.dimension() - self._d))), #boundary(t.simplices()), + subp_vertices = get_indices( + self._p.points(), Polytope(vertices).points())) + + triang_pts = project(Polytope(vertices).points()) + + subpoly = Polytope(np.asarray(triang_pts, np.int32)) + triang_pts_idx = subpoly.points_to_indices(triang_pts) + + t_sub = Triangulation( + poly = subpoly, + pts = triang_pts_idx, + simplices = subsimplices, + check_input_simplices=False) + + # Verify fine condition + t_valid = t_sub.is_valid() + if t_valid: + for cond in [t_sub.is_fine(), t_sub.is_regular(), t_sub.is_star()]: + r_compatibility += (1 if cond else -1) + t_valid = t_valid and cond + done &= t_valid + + return r_compatibility, done def fitness(self, state): - fitness, done = super().fitness(state) + r_val = super().fitness(state) + if r_val[-1]: + r_val = self._combine_r_vals( + r_val, + self._compatibility_fitness(state)) + return r_val + + def act(self, state, action): + new_state, r_val = super().act(state, action) + if r_val[-1]: + r_val = self._combine_r_vals( + r_val, + self._compatibility_fitness(new_state)) + return new_state, r_val - # TODO compatibility - # if done: - # t_src = self._t_env.get_triangulation(state[0]) - return fitness, done if __name__ == "__main__": from cytools import fetch_polytopes diff --git a/utils.py b/utils.py index 4dbd180..532a0d9 100644 --- a/utils.py +++ b/utils.py @@ -7,11 +7,11 @@ from copy import deepcopy import numpy as np -from agent import Agent +# from agent import Agent from environment import Environment -def train_agent(env: Environment, agent: Agent, num_epochs = 1024, max_steps = 32, batch_size = 128, min_memory_size = 1024, verbosity = 0) -> np.ndarray: +def train_agent(env: Environment, agent, num_epochs = 1024, max_steps = 32, batch_size = 128, min_memory_size = 1024, verbosity = 0) -> np.ndarray: """ @return Array of (epochs, loss_vals). Shape: (Num_epochs, 2). """ @@ -62,7 +62,7 @@ def train_agent(env: Environment, agent: Agent, num_epochs = 1024, max_steps = 3 return np.asarray(loss_vals) -def walk_agent(state, env: Environment, agent: Agent, max_steps = 32): +def walk_agent(state, env: Environment, agent, max_steps = 32): path = [state] for _ in range(max_steps): action = agent.act(state) From ee238a14642db57c68dfe1e3b6ef674a8712c9c6 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Tue, 11 Jun 2024 21:45:13 -0400 Subject: [PATCH 20/23] Replaced main example in Readme with FibrationEnvironment(p,2) --- Readme.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Readme.md b/Readme.md index 9280bd0..5c3357f 100644 --- a/Readme.md +++ b/Readme.md @@ -19,17 +19,18 @@ Currently supported environments are: | ```SubpolytopeEnvironment(```
 ```polytope, fibration_dim)``` | Uses subspace encoding to generate subpolytope. | - **polytope**: Polytope.
- **fibration_dim**: Dimension of subpolytope. | | ```FibrationEnvironment(```
 ```polytope, fibration_dim)``` | A multi-environment, combining Triangulation and subpolytope environments for the purpose of constructing fibrations. An additional compatibility condition forces the triangulation to be consistent with the choice of subpolytope. | - **polytope**: Polytope.
- **fibration_dim**: Dimension of subpolytope. | -An example code for generating subpolytopes is shown below: +An example code for generating elliptic fibrations with compatible triangulations using ```FibrationEnvironment``` is shown below: ```python # Initialize Environment p = Polytope([ - [ 1, 0, 0, 0], - [ 0, 1, 0, 0], - [ 0, 0, 1, 0], - [ 0, 0, 0, 1], - [-1,-1, 0, 0], - [-1,-1,-1,-1]]) -s_env = SubpolytopeEnvironment(p, 2) + [-1, -1, 1, -1], + [ 0, 0, 0, 1], + [ 0, 1, 0, 0], + [ 1, 0, 0, 0], + [-1, 0, -1, 0], + [ 0, -1, -1, 0], + [ 0, 0, 1, 0]]) +s_env = FibrationEnvironment(p, 2) # Initialize agent model = tfk.Sequential([ From c0c56c7f98887314c173aef0a5821fdfb86f5966 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Wed, 12 Jun 2024 02:04:00 -0400 Subject: [PATCH 21/23] Added get_structure(...) and Agent.walk(...). Updated Readme --- Readme.md | 15 +++++++++++---- agent.py | 9 ++++++++- environment.py | 10 ++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/Readme.md b/Readme.md index 5c3357f..22b29e7 100644 --- a/Readme.md +++ b/Readme.md @@ -30,14 +30,14 @@ p = Polytope([ [-1, 0, -1, 0], [ 0, -1, -1, 0], [ 0, 0, 1, 0]]) -s_env = FibrationEnvironment(p, 2) +env = FibrationEnvironment(p, 2) # Initialize agent model = tfk.Sequential([ - Input((s_env.random_state().shape[0],)), + Input((env.random_state().shape[0],)), Dense(64, activation='relu'), Dense(128, activation='relu'), - Dense(s_env.num_actions, activation='linear') + Dense(env.num_actions, activation='linear') ]) optim = tfk.optimizers.Adam(learning_rate = 1e-3) @@ -49,9 +49,16 @@ model.compile( agent = Agent(model) # Train the agent -agent.fit(s_env, num_epochs = 2048, verbosity = 1) +agent.fit(env, num_epochs = 2048, verbosity = 1) ``` +A terminal state can be then obtained by starting from a random state and allowing agent to walk using the trained model: +```python +path = agent.walk(env.random_state(), env) +# Extract triangulation and subpolytope data +triang, subpoly = env.get_structure(path[-1]) +... +``` ## Citation To cite our paper: diff --git a/agent.py b/agent.py index a9f2c07..407e731 100644 --- a/agent.py +++ b/agent.py @@ -10,8 +10,8 @@ import numpy as np from tensorflow import keras as tfk -from utils import train_agent from environment import Environment +from utils import train_agent, walk_agent class Agent(object): @@ -74,6 +74,13 @@ def fit(self, env: Environment, num_epochs = 1024, max_steps = 32, batch_size = min_memory_size = min_memory_size, verbosity = verbosity) + def walk(self, state, env: Environment, max_steps = 32): + return walk_agent( + agent = self, + state = state, + env = env, + max_steps = max_steps) + def replay(self, batch_size): """ Replays the buffer and trains the model. diff --git a/environment.py b/environment.py index 722f4e2..b4f16ad 100644 --- a/environment.py +++ b/environment.py @@ -327,6 +327,16 @@ def __init__(self, polytope: Environment, fibration_dim: int): self._p = polytope self._d = fibration_dim + def get_structure(self, state) -> Tuple[Triangulation, Polytope]: + """ + @return A tuple consisting of: + 1. Triangulation corresponding to the state. + 2. A subpolytope corresponding to the state. + """ + state = self._restore_shape(state) + return self._environments[0].get_triangulation(state[0]),\ + Polytope(self._environments[1].intersect(state[1])) + def _compatibility_fitness(self, state): done = True state = self._restore_shape(state) From 5584e9185d990d42b2abda84fa17459154406c3c Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Wed, 12 Jun 2024 02:26:58 -0400 Subject: [PATCH 22/23] Added example of fibration env --- examples/fibration_env.ipynb | 192 +++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 examples/fibration_env.ipynb diff --git a/examples/fibration_env.ipynb b/examples/fibration_env.ipynb new file mode 100644 index 0000000..9b10ee1 --- /dev/null +++ b/examples/fibration_env.ipynb @@ -0,0 +1,192 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_34623/2677491238.py:12: FutureWarning: ``set_style`` is deprecated: Naming convention is changing to match mpl. Use ``mplhep.style.use()``.\n", + " mplhep.style.set_style(\"CMS\")\n" + ] + } + ], + "source": [ + "from agent import Agent\n", + "from tensorflow import keras as tfk\n", + "from tensorflow.keras.layers import Dense, Input\n", + "\n", + "from environment import *\n", + "from utils import train_agent\n", + "\n", + "from tqdm import trange\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import mplhep\n", + "mplhep.style.set_style(\"CMS\")\n", + "\n", + "from cytools import fetch_polytopes" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Epoch 2047, loss = 3.878148e-02: 100%|█████████████████████████████████████████████████████████████████████████████████████| 2048/2048 [12:19<00:00, 2.77it/s]\n" + ] + }, + { + "data": { + "text/plain": [ + "array([[4.10000000e+01, 3.14436734e-01],\n", + " [4.20000000e+01, 2.99400646e-01],\n", + " [4.30000000e+01, 3.16598833e-01],\n", + " ...,\n", + " [2.04500000e+03, 4.54782601e-02],\n", + " [2.04600000e+03, 3.38788480e-02],\n", + " [2.04700000e+03, 3.87814753e-02]])" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "p = Polytope([\n", + " [-1, -1, 1, -1],\n", + " [ 0, 0, 0, 1],\n", + " [ 0, 1, 0, 0],\n", + " [ 1, 0, 0, 0],\n", + " [-1, 0, -1, 0],\n", + " [ 0, -1, -1, 0],\n", + " [ 0, 0, 1, 0]])\n", + "s_env = FibrationEnvironment(p, 2)\n", + "\n", + "# Initialize agent\n", + "model = tfk.Sequential([\n", + " Input((s_env.random_state().shape[0],)),\n", + " Dense(64, activation='relu'),\n", + " Dense(128, activation='relu'),\n", + " Dense(s_env.num_actions, activation='linear')\n", + "])\n", + "\n", + "optim = tfk.optimizers.Adam(learning_rate = 1e-3)\n", + "model.compile(\n", + " loss = tfk.losses.MeanSquaredError(),\n", + " optimizer = optim,\n", + " metrics = [tfk.metrics.MeanAbsoluteError()])\n", + "\n", + "agent = Agent(model)\n", + "\n", + "# Train the agent\n", + "loss_vals = agent.fit(s_env, num_epochs = 2048, verbosity = 1)\n", + "loss_vals" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "fig = plt.figure(figsize=(9,9))\n", + "ax = fig.add_subplot(111)\n", + "ax.plot(loss_vals[:,0], loss_vals[:,1])\n", + "ax.set_xlabel(\"Epoch\")\n", + "ax.set_ylabel(\"Loss\")\n", + "ax.grid(True, 'both')" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(6.0, True)" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "path = agent.walk(s_env.random_state(), s_env)\n", + "s_env.fitness(path[-1])" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(A fine, regular, star triangulation of a 4-dimensional point configuration with 8 points in ZZ^4,\n", + " A 2-dimensional lattice polytope in ZZ^4)" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "triang, subpoly = s_env.get_structure(path[-1])\n", + "triang, subpoly" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 5854b4d3075be8a1d63069dd85f6969823fd8c73 Mon Sep 17 00:00:00 2001 From: Giorgi Butbaia Date: Mon, 17 Jun 2024 22:16:44 -0400 Subject: [PATCH 23/23] Add option to disable is_star() condition --- environment.py | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/environment.py b/environment.py index b4f16ad..2db8a61 100644 --- a/environment.py +++ b/environment.py @@ -237,10 +237,16 @@ def num_actions(self): class HTriangulationEnvironment(Environment): - def __init__(self, polytope: Polytope, step_size: float = 0.5): + def __init__(self, polytope: Polytope, step_size: float = 0.5, check_star = True): + """ + @param polytope: Polytope. + @param step_size: Specifies size of each step in the height space. (default: 0.5) + @param check_star: If True, checks if the triangulation is star. (default: True) + """ self._p = polytope self._num_actions = polytope.points().shape[0] self._step_size = step_size + self._check_star = check_star def get_triangulation(self, state): return self._p.triangulate(heights = state, check_heights = False) @@ -252,15 +258,23 @@ def fitness(self, state): triang = self.get_triangulation(state) reward = -1.0 + is_frst = True + if triang.is_fine(): - reward += 1.5 - if triang.is_star(): - reward += 1.5 + reward += 3.0 + else: + is_frst = False + if self._check_star: + if triang.is_star(): + reward += 3.0 + else: + is_frst = False + # # Always true # if triang.is_regular(): # reward += 1.0 - return reward, reward == 2.0 + return reward, is_frst def act(self, state, action): shift = np.zeros(self._num_actions) @@ -319,13 +333,14 @@ def compose(x, *args): class FibrationEnvironment(MultiEnvironment): - def __init__(self, polytope: Environment, fibration_dim: int): + def __init__(self, polytope: Environment, fibration_dim: int, check_star = True): super().__init__(environments = [ - HTriangulationEnvironment(polytope), + HTriangulationEnvironment(polytope, check_star = check_star), SubpolytopeEnvironment(polytope, fibration_dim) ]) self._p = polytope self._d = fibration_dim + self._check_star = check_star def get_structure(self, state) -> Tuple[Triangulation, Polytope]: """ @@ -364,7 +379,7 @@ def _compatibility_fitness(self, state): # Verify fine condition t_valid = t_sub.is_valid() if t_valid: - for cond in [t_sub.is_fine(), t_sub.is_regular(), t_sub.is_star()]: + for cond in [t_sub.is_fine(), t_sub.is_regular()] + ([t_sub.is_star()] if self._check_star else []): # is_star is no longer enforced r_compatibility += (1 if cond else -1) t_valid = t_valid and cond done &= t_valid