From 1bd54f22a81c869b2054ac91ad45c3fef42bd539 Mon Sep 17 00:00:00 2001 From: hariszaf Date: Wed, 30 Sep 2020 11:24:28 +0300 Subject: [PATCH] Max ball param in generate_samples and rounding (#115) * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update setup.py * Update bindings.h * Update setup.py * Update setup_old.py * Update bindings.cpp * Update setup.py * Update setup.py * Update volestipy.pyx * Update test1.py * Create test1_old.py * Update test1.py * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update bindings.h * Update bindings.cpp * Update bindings.h * Update bindings.cpp * Update volestipy.pyx * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update bindings.h * Update bindings.cpp * Update volestipy.pyx * Update bindings.h * Update bindings.cpp * Update bindings.h * Update setup.py * Update bindings.cpp * Update bindings.h * Update bindings.cpp * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update bindings.cpp * Update volestipy.pyx * Update volume_cb_hpolytope.cpp * Update test1.py * Update bindings.cpp * Update test1.py * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update bindings.cpp * Update volestipy.pyx * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Create .gitignore * Delete test1_old.py * Delete setup_old.py * Delete bindings_old.h * Delete bindings_old.cpp * Delete volestipy_old.pyx * Update volestipy.pyx * Update bindings.cpp * Update bindings.h * Update .gitignore * Update volume_cb_hpolytope.cpp * Update test1.py * Update test2.py * Update bindings.h * Update setup.py * Update credits.md * on .gitignore: files on test/Testing/Temporary/ were removed from the .gitignore file * first attempt - not working - for rounding * rounding function: does not work; trying to figure it out * round_val now works; still new_A and new_b need to be included * Create metabolic_net_pipeline.ipynb * Update metabolic_net_pipeline.ipynb * Update metabolic_net_pipeline.ipynb * Update metabolic_net_pipeline.ipynb * Update metabolic_net_pipeline.ipynb * Update metabolic_net_pipeline.ipynb * Update volestipy.pyx * Update bindings.cpp * Create test_rounding.py * Create test1.py * Create test2.py * Delete test2.py * Update test1.py * Create metabolic_net_pipeline-checkpoint.ipynb * Update setup.py * Update .gitignore * Delete test1.py git rm test1.py * Delete test2.py git rm test2.py * Update bindings.h new class for the preprocessing and the get_full_dimensional_polytope() function in the bindings.h * Update bindings.cpp new class for the preprocessing and the get_full_dimensional_polytope() function in the bindings.cpp * Update volestipy.pyx new class for the preprocessing and the get_full_dimensional_polytope() function in the volestipy.pyx * Update bindings.h working on the lowDimHPolytopeCPP class - just a draft with the main ideas, not a stable version * Update bindings.cpp working on the lowDimHPolytopeCPP class - just a draft with the main ideas, not a stable version * Update volestipy.pyx working on the lowDimHPolytopeCPP class - just a draft with the main ideas, not a stable version * Update bindings.h set member variables for lowDimHPolytopeCPP class * Update bindings.cpp remove unessecary vars * Update volestipy.pyx remove unecessary vars in self.full_dim_polytope * Update bindings.h build the instructor for the full_dimensional_polytope() function * Update bindings.cpp 1st draft for the get_full_dimensional_polytope() function * Update volestipy.pyx 1st draft for the python interface of the get_full_dimensional_polytope() function * Update bindings.h using transpose matrices for N and A_full removing the "extra" from the shift and b_full vectors as it is not needed * Update bindings.cpp 2nd draft for the lowDimHPolytopeCPP class. we changed the N and A_full matrices to transpose to feed them in the cpp file like this. we removed the _extra from the vectors * Update volestipy.pyx 2nd draft for the lowDimHPolytopeCPP class. changed "_extra" vectors when needed. first draft that actually compiles * Create test_get_full_dim_polytope.py test file for the get_full_dimensional_polytope function not ready yet * Update test_get_full_dim_polytope.py changed the Aeq * Update test_get_full_dim_polytope.py final test for the get_full_dimensional_polytope() function * Update bindings.cpp print the N transpose and the full A transpose matrices from the C++ code * Update volestipy.pyx Attention! What C++ returns is the transpose matrix. Thus, the [i,j] element of the full A is the [j,i] of what C++ returns. That is what we fixed here * Update test_get_full_dim_polytope.py print all the outputs of the get_full_dimensional_polytope() function * Update bindings.cpp remove test prints * Update volestipy.pyx remove test printing statements add all the output in the return statement on the get_full_dim_polytope() improved comments * Delete metabolic_net_pipeline.ipynb remove the jupyter notebook * Delete metabolic_net_pipeline-checkpoint.ipynb remove the hidden directory for the jupyter notebook * Update volestipy.pyx Exceptions for the low_dim_polytope_cpp constructor added. Deletion of the A_full and the b_full variables after the initialization of the object. * Update bindings.h CheBall was removed from the case of the lowDimHPolytopeCPP * Update volestipy.pyx just some functions of gurobipy * Update volestipy.pyx first draft for the pre_process() python function * Create test_preprocess.py a test file for the pre_process() function * Update volestipy.pyx correct obj function. Aeq line was replaced by a such from A. * Update volestipy.pyx make dependencies more readable * Update volestipy.pyx test sparse function * Update test_preprocess.py change dimensions * Update volestipy.pyx loop for all the lines of A and models for each of those and its minus * Update test_preprocess.py change the dimensions * Update volestipy.pyx draft to check whether it works fine! * Update volestipy.pyx change name in model.addConstr from "c2" to "c" in all the constraints described, fixed the solutions remove unecessary print statements * Update test_preprocess.py add print statement for the results of the pre_process() function * Update test_preprocess.py build Aeq in a way to be more like to a stoichiometric matrix * Update volestipy.pyx add model.update() and model.display() function every time we add constraints or change the objective function * Update volestipy.pyx correct typo in comment * Update volestipy.pyx add model.update() after the obj function for the minus A[i,] * Update volestipy.pyx add print statements * Update volestipy.pyx attempt to solve the issue with the solutions * Update volestipy.pyx addMConstrs * Update volestipy.pyx setMObjective() * Update volestipy.pyx correct objectives() * Update volestipy.pyx make minus obj function as it should be * Update volestipy.pyx remove print not needed statements make code more readable * Update test_preprocess.py change permission in test * Update test_preprocess.py add import volestipy in test_preprocess.py * Update volestipy.pyx remove solutions and their corresponding print statements add new line in the end of the file * Update volestipy.pyx correct comment * add bigg file of e.coli in .mat format * add a BIGG file in .json format * add function to read bigg files in .json format; keep the Aeq * develop the read json format bigg file function * add test file for reading json bigg files * add function for reading json bigg files * new directory for the bigg example files * improved function for reading json bigg files; Aeq is now m*n * print metabolites and reaction in the test for json * add function to read .mat bigg files * one test file for reading both json and mat bigg files * remove unecessary print statements * comment in the head of the file describing its purpose * update documentation on how to install volestipy * improved documentation for the dependencies * remember to explain how to get lpsolve * remember to explain how to get lpsolve * remember to explain how to get lpsolve * remember to explain how to get lpsolve * test with RECON1 for the pre-processing step were performed successfully * export .npy files with the outcome of the pre_process function so the user can load them any time * change the input file to e_coli_core * print files with the output of get_full_dim() and rounding() ; start function for inner ball * small changes to check data types * convertions to numpy arrays * complete read-preprocess-get_full_dim steps * add data types in .gitignore file * add a test with all the steps of the pipeline * draft for max ball * test for computing max ball * include get_max_ball() function * remove last empty lines * add emppty last line * lp_solve replaced by lpsolve * rounding step included in the full pipeline test * add comput_max_ball in the pipeline * fixed type for the r variable; sre_parse related issue * remove unecessary library * clean up a bit * Update volestipy.pyx empty last line * Update bindings.cpp add empty last line * improve rounding * fix svd rounding * add max_ball arguments in the rounding function * add max_ball if statement in rounding funcion * fix cheball in rounding * change variable name * add max ball in rounding function * add semicolomn * add extra variable inner_point_for_c to feed the .cpp with the inner point * change test file to include the max ball output as parameter to the rounding function * replace integer zero values in the bydefault inner point list, with fload zeros; this way we fixed bug according to which the inner_point_for_c was waiting for double but got long * replace if statement for max ball in rounding * add arguments in generate_samples() for the case that max_ball has been included * add cases for running generate_samples depending max ball input * feed sampling with max_ball params * add part for generate samples * change sampling function to support max ball and L params * change the way set_L and max_ball bool vars are set * python interface initialization * add accelerated_billiard variable * remove wrong '=' sign * remove const from end of void set_InnerBall functions * include sampling on rounded polytope using max ball function * max ball on rounded polytope * change by default number_of_points_to_burn * complete test pipeline * function for mapping sampled points to the initial polytope added * remove blank lines * remove blank line * clean code; split long lines * add blank last line * add features till get full dimensional polytope * before plotiing * plol it * histogram added * reaction 35 for plotting * add print statement for dimension * testing recon1 * testing for recon1 * notebook checkpoints * add returning min and max fluxes vectors in pre-processing * ignore png files * return float numpy types from read function * add tests for e coli and plot samples * e coli full example * further chechpoints Co-authored-by: Tolis --- .gitignore | 5 + R-proj/src/volume.cpp | 2 +- include/convex_bodies/ballintersectconvex.h | 2 +- include/convex_bodies/hpolytope.h | 5 + include/convex_bodies/vpolyintersectvpoly.h | 5 + include/convex_bodies/vpolytope.h | 5 + include/convex_bodies/zpolytope.h | 5 + .../preprocess/max_inscribed_ellipsoid.hpp | 2 +- .../max_inscribed_ellipsoid_rounding.hpp | 2 +- include/preprocess/svd_rounding.hpp | 12 +- .../metabolic_net_pipeline-checkpoint.ipynb | 1957 +++++++++++++++++ volestipy/metabolic_net_pipeline.ipynb | 1957 +++++++++++++++++ volestipy/tests/test_compute_max_ball.py | 4 +- volestipy/tests/test_ecoli_full_pipeline.py | 89 + volestipy/tests/test_full_pipeline.py | 92 +- volestipy/tests/test_read_bigg_files.py | 4 +- volestipy/volestipy/include/bindings.h | 10 +- volestipy/volestipy/src/bindings.cpp | 164 +- volestipy/volestipy/volestipy.pyx | 257 ++- 19 files changed, 4404 insertions(+), 175 deletions(-) create mode 100644 .gitignore create mode 100644 volestipy/.ipynb_checkpoints/metabolic_net_pipeline-checkpoint.ipynb create mode 100644 volestipy/metabolic_net_pipeline.ipynb create mode 100755 volestipy/tests/test_ecoli_full_pipeline.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..dbf367d9c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ + +test/Testing/Temporary/CTestCostData.txt +*.log +.Rproj.user +*.png diff --git a/R-proj/src/volume.cpp b/R-proj/src/volume.cpp index 2826a545c..242969ede 100644 --- a/R-proj/src/volume.cpp +++ b/R-proj/src/volume.cpp @@ -241,7 +241,7 @@ double volume (Rcpp::Reference P, } else if (Rcpp::as(rounding).compare(std::string("none")) == 0) { rounding_method = none; } - + NT e; if (!Rcpp::as(settings).containsElementNamed("algorithm")) { diff --git a/include/convex_bodies/ballintersectconvex.h b/include/convex_bodies/ballintersectconvex.h index 5a7eea9e6..3609c1986 100644 --- a/include/convex_bodies/ballintersectconvex.h +++ b/include/convex_bodies/ballintersectconvex.h @@ -35,7 +35,7 @@ class BallIntersectPolytope { { return P.InnerBall(); } - + MT get_mat() const { return P.get_mat(); } diff --git a/include/convex_bodies/hpolytope.h b/include/convex_bodies/hpolytope.h index 7c7a54104..8c3bfaf0a 100644 --- a/include/convex_bodies/hpolytope.h +++ b/include/convex_bodies/hpolytope.h @@ -88,6 +88,11 @@ class HPolytope { return _inner_ball; } + void set_InnerBall(std::pair const& innerball) //const + { + _inner_ball = innerball; + } + //Compute Chebyshev ball of H-polytope P:= Ax<=b //Use LpSolve library std::pair ComputeInnerBall() diff --git a/include/convex_bodies/vpolyintersectvpoly.h b/include/convex_bodies/vpolyintersectvpoly.h index 83240553a..3924fbe54 100644 --- a/include/convex_bodies/vpolyintersectvpoly.h +++ b/include/convex_bodies/vpolyintersectvpoly.h @@ -159,6 +159,11 @@ class IntersectionOfVpoly { } + void set_InnerBall(std::pair const& innerball) const + { + _inner_ball = innerball; + } + /* unsigned int num_of_v = 0; unsigned int d = dimension(); diff --git a/include/convex_bodies/vpolytope.h b/include/convex_bodies/vpolytope.h index 79509cfc1..e4b7613c1 100644 --- a/include/convex_bodies/vpolytope.h +++ b/include/convex_bodies/vpolytope.h @@ -164,6 +164,11 @@ class VPolytope { return _inner_ball; } + void set_InnerBall(std::pair const& innerball) //const + { + _inner_ball = innerball; + } + // return dimension unsigned int dimension() const { return _d; diff --git a/include/convex_bodies/zpolytope.h b/include/convex_bodies/zpolytope.h index a1a7bcc9e..4d70b8a46 100644 --- a/include/convex_bodies/zpolytope.h +++ b/include/convex_bodies/zpolytope.h @@ -269,6 +269,11 @@ class Zonotope { return _inner_ball; } + void set_InnerBall(std::pair const& innerball) //const + { + _inner_ball = innerball; + } + // return the number of generators int num_of_generators() const { diff --git a/include/preprocess/max_inscribed_ellipsoid.hpp b/include/preprocess/max_inscribed_ellipsoid.hpp index 8a5f560c5..b1d110fee 100644 --- a/include/preprocess/max_inscribed_ellipsoid.hpp +++ b/include/preprocess/max_inscribed_ellipsoid.hpp @@ -222,4 +222,4 @@ std::pair, bool> max_inscribed_ellipsoid(MT A, VT b, VT const& } -#endif +#endif diff --git a/include/preprocess/max_inscribed_ellipsoid_rounding.hpp b/include/preprocess/max_inscribed_ellipsoid_rounding.hpp index 6000e6833..0e6489176 100644 --- a/include/preprocess/max_inscribed_ellipsoid_rounding.hpp +++ b/include/preprocess/max_inscribed_ellipsoid_rounding.hpp @@ -74,4 +74,4 @@ std::tuple max_inscribed_ellipsoid_rounding(Polytope &P, return result; } -#endif +#endif diff --git a/include/preprocess/svd_rounding.hpp b/include/preprocess/svd_rounding.hpp index 47f5bd1f5..e62c03d28 100644 --- a/include/preprocess/svd_rounding.hpp +++ b/include/preprocess/svd_rounding.hpp @@ -12,13 +12,13 @@ #define SVD_ROUNDING_HPP -template +template < typename WalkTypePolicy, typename Polytope, typename Point, - typename MT, - typename VT, + typename MT, + typename VT, typename RandomNumberGenerator > void svd_on_sample(Polytope &P, Point &p, unsigned int const& num_rounding_steps, MT &V, VT &s, VT &Means, @@ -29,7 +29,7 @@ void svd_on_sample(Polytope &P, Point &p, unsigned int const& num_rounding_steps Polytope, RandomNumberGenerator > walk; - + typedef RandomPointGenerator RandomPointGenerator; PushBackWalkPolicy push_back_policy; @@ -71,7 +71,7 @@ void svd_on_sample(Polytope &P, Point &p, unsigned int const& num_rounding_steps } -template +template < typename WalkTypePolicy, typename MT, @@ -82,7 +82,7 @@ template typename RandomNumberGenerator > -std::tuple svd_rounding(Polytope &P, +std::tuple svd_rounding(Polytope &P, std::pair &InnerBall, const unsigned int &walk_length, RandomNumberGenerator &rng) diff --git a/volestipy/.ipynb_checkpoints/metabolic_net_pipeline-checkpoint.ipynb b/volestipy/.ipynb_checkpoints/metabolic_net_pipeline-checkpoint.ipynb new file mode 100644 index 000000000..a986c4014 --- /dev/null +++ b/volestipy/.ipynb_checkpoints/metabolic_net_pipeline-checkpoint.ipynb @@ -0,0 +1,1957 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Metabolic network analysis using *volestipy*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aim of this notebook is to present the complete pipeline for random sampling in a metabolic network using the ```volesitpy``` library. As input, we will use a BIGG model of *E.coli* in its ```.json``` format. \n", + "\n", + "Other formats, such as ```.mat``` are supported by ```volestipy``` but this is not in the scope of this tutorial. \n", + "\n", + "**Attention!**\n", + "This tutorial assumes that you have already compiled the ```volestipy``` library, following the steps described [here](https://github.com/hariszaf/volume_approximation_bio/tree/develop/volestipy)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dependencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With respect to this ```jupyter notebook```.\n", + "First you need to create a **conda environment** by making use of at least Python 3.6. \n", + "Then open the notebook using the ```jupyter notebook``` command after entering the conda evironment you built. \n", + "\n", + "For example, considering that the base environment of ```conda``` includes Python 3.6:\n", + "\n", + "```conda activate```\n", + "\n", + "```jupyter notebook```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To use Jupyter with a certain conda environment we also need to run the followings:\n", + "\n", + "````conda install ipykernel\n", + "ipython kernel install --name MY_CONDA_ENV --user\n", + "````" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before showing how you can exploit the *volestipy* software, we first need to get all the relative dependencies. \n", + "\n", + "This demo uses [Anaconda](https://www.anaconda.com/products/individual) which you can download following [these](https://www.digitalocean.com/community/tutorials/how-to-install-anaconda-on-ubuntu-18-04-quickstart) instructions.\n", + "\n", + "Furtheremore, special, powerful mathematical optimization solvers like [Gurobi](https://www.gurobi.com/) are also used. You can get Gurobi following the steps described [here](https://support.gurobi.com/hc/en-us/articles/360044290292-Installing-Gurobi-for-Python). Keep in mind that you will need a Gurobi license. To do this, you need to create a Gurobi user account and then follow the instructions for a license you will find there." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The main libraries you need to run this pipeline are the following:\n", + "\n", + "* ```numpy```\n", + "* ```gurobipy``` and of course\n", + "* ```volestipy```\n", + "\n", + "You will also need a library for plotting, like ```matplotib``` but this is up to you!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get any libraries that need to run commands as ```sudo``` you need to make a file including **only** your password and replace ```/home/haris/Desktop/running/metabolic_network_pipeline_volestipy/my_project_virtual_env/error.txt``` with the corresponding path. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to make possible to install what is needed in this conda evironment we use the ```getpass``` library that prompts the user for a password without echoing." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import getpass \n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So, with respect to the ```numpy``` library, let us first get it in our conda environment. \n", + "This is going to take a while. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!conda install --yes --prefix {sys.prefix} numpy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can import it. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Assuming you have already ```gurobipy``` on your computer, you may just add its path on your conda environment with the following command." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sys.path.append('/usr/local/lib/python3.6/dist-packages/gurobipy/')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, you can install ```gurobipy``` on the conda enviroment directly. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Get GUROBI through anaconda - You can find more about installing Gurobi here: \n", + "# https://support.gurobi.com/hc/en-us/articles/360044290292-Installing-Gurobi-for-Python\n", + "!conda install -y -c gurobi gurobi\n", + "print(\"*** The Gurobi solver library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After executing one of the above ways to get `gurobipy`, import this library and check if everything is working fine. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using license file /home/haris/gurobi.lic\n", + "Academic license - for non-commercial use only\n", + "\n", + "*** Gurobi test has been completed successfully. ***\n", + "\n" + ] + } + ], + "source": [ + "import gurobipy as gp\n", + "from gurobipy import GRB\n", + "\n", + "# This is just a test that the Gurobi solver is well installed\n", + "\n", + "# Create a new model\n", + "m = gp.Model(\"mip1\")\n", + "\n", + "print(\"\\n*** Gurobi test has been completed successfully. ***\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Likewise, for the `scipy` library. Install it through conda on this environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!conda install --yes --prefix {sys.prefix} scipy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We do not need to import `scipy` here, however the `volestipy` does that. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we have to compile and then import the ```volestipy``` library. To this end, we first need to get the `cython` library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pip install Cython" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then run the following command as it was from our terminal. It is the `!` that allows for the latter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!LDFLAGS=\"-L/usr/lib/lp_solve/\" python3 setup.py install --user" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from volestipy import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are ready to read our network BIGG file and run the necessary steps to get our random points from its correspoding polytope." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read your network file" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have downloaded a BIGG model of *E. coli* which you may find [here](http://bigg.ucsd.edu/models/e_coli_core) in its ```.json``` format. We keep this file as a variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "input_file = '/home/haris/bigg_files/e_coli_core.json'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we run the ```volestipy``` function to read it." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "read it all\n" + ] + } + ], + "source": [ + "read_e_coli = read_json_file(input_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may see the whole BIGG file, simply by printing the ```read_ecoli_core``` variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[ 1., 0., 0., ..., 0., 0., 0.],\n", + " [ 0., 1., 0., ..., 0., 0., 0.],\n", + " [ 0., 0., 1., ..., 0., 0., 0.],\n", + " ...,\n", + " [ 0., 0., 0., ..., -1., 0., 0.],\n", + " [ 0., 0., 0., ..., 0., -1., 0.],\n", + " [ 0., 0., 0., ..., 0., 0., -1.]]),\n", + " array([1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 0. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , -0. , -0. , 1000. ,\n", + " 1000. , -0. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , -0. , 1000. , 1000. , -8.39, -0. ,\n", + " 1000. , -0. , 1000. , -0. , 1000. , 1000. , -0. ,\n", + " -0. , 1000. , 1000. , 1000. , -0. , 1000. , -0. ,\n", + " -0. , 1000. , 1000. , -0. , 1000. , -0. , 1000. ,\n", + " 1000. , -0. , 1000. , 1000. , 1000. , -0. , -0. ,\n", + " -0. , 1000. , -0. , -0. , -0. , -0. , 10. ,\n", + " -0. , -0. , 1000. , 1000. , -0. , -0. , 1000. ,\n", + " 1000. , 1000. , -0. , -0. , 1000. , -0. , -0. ,\n", + " 1000. , -0. , -0. , 1000. , -0. , 1000. , 1000. ,\n", + " -0. , -0. , -0. , 1000. , -0. , -0. , 1000. ,\n", + " -0. , 1000. , 1000. , -0. , 1000. , -0. , -0. ,\n", + " 1000. , -0. , -0. , -0. , -0. , 1000. , 1000. ,\n", + " -0. ]),\n", + " array([[ 1., 0., 0., ..., 0., 0., 0.],\n", + " [-1., 0., 0., ..., 0., 0., 0.],\n", + " [-1., 0., 1., ..., 0., 0., 0.],\n", + " ...,\n", + " [ 0., 0., 0., ..., 0., 0., 0.],\n", + " [ 0., 0., 0., ..., 1., 0., 0.],\n", + " [ 0., 0., 0., ..., 0., 0., 0.]]),\n", + " array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0.]),\n", + " ['adp_c',\n", + " 'atp_c',\n", + " 'f6p_c',\n", + " 'fdp_c',\n", + " 'h_c',\n", + " 'accoa_c',\n", + " 'coa_c',\n", + " 'for_c',\n", + " 'pyr_c',\n", + " 'g6p_c',\n", + " '13dpg_c',\n", + " '3pg_c',\n", + " '6pgc_c',\n", + " '6pgl_c',\n", + " 'h2o_c',\n", + " 'acald_c',\n", + " 'nad_c',\n", + " 'nadh_c',\n", + " 'akg_c',\n", + " 'akg_e',\n", + " 'h_e',\n", + " '2pg_c',\n", + " 'pi_c',\n", + " 'pi_e',\n", + " 'etoh_c',\n", + " 'acald_e',\n", + " 'ac_c',\n", + " 'actp_c',\n", + " 'co2_c',\n", + " 'oaa_c',\n", + " 'pep_c',\n", + " 'acon_C_c',\n", + " 'cit_c',\n", + " 'icit_c',\n", + " 'ac_e',\n", + " 'amp_c',\n", + " 'succoa_c',\n", + " 'e4p_c',\n", + " 'g3p_c',\n", + " 'gln__L_c',\n", + " 'glu__L_c',\n", + " 'nadp_c',\n", + " 'nadph_c',\n", + " 'r5p_c',\n", + " 'pyr_e',\n", + " 'co2_e',\n", + " 'ru5p__D_c',\n", + " 'xu5p__D_c',\n", + " 'succ_c',\n", + " 'succ_e',\n", + " 'o2_c',\n", + " 'q8_c',\n", + " 'q8h2_c',\n", + " 'lac__D_c',\n", + " 'lac__D_e',\n", + " 'etoh_e',\n", + " 'fum_c',\n", + " 's7p_c',\n", + " 'dhap_c',\n", + " 'for_e',\n", + " 'fru_e',\n", + " 'fum_e',\n", + " 'glc__D_e',\n", + " 'gln__L_e',\n", + " 'glu__L_e',\n", + " 'h2o_e',\n", + " 'mal__L_e',\n", + " 'nh4_e',\n", + " 'o2_e',\n", + " 'mal__L_c',\n", + " 'nh4_c',\n", + " 'glx_c'],\n", + " ['PFK',\n", + " 'PFL',\n", + " 'PGI',\n", + " 'PGK',\n", + " 'PGL',\n", + " 'ACALD',\n", + " 'AKGt2r',\n", + " 'PGM',\n", + " 'PIt2r',\n", + " 'ALCD2x',\n", + " 'ACALDt',\n", + " 'ACKr',\n", + " 'PPC',\n", + " 'ACONTa',\n", + " 'ACONTb',\n", + " 'ATPM',\n", + " 'PPCK',\n", + " 'ACt2r',\n", + " 'PPS',\n", + " 'ADK1',\n", + " 'AKGDH',\n", + " 'ATPS4r',\n", + " 'PTAr',\n", + " 'PYK',\n", + " 'BIOMASS_Ecoli_core_w_GAM',\n", + " 'PYRt2',\n", + " 'CO2t',\n", + " 'RPE',\n", + " 'CS',\n", + " 'RPI',\n", + " 'SUCCt2_2',\n", + " 'CYTBD',\n", + " 'D_LACt2',\n", + " 'ENO',\n", + " 'SUCCt3',\n", + " 'ETOHt2r',\n", + " 'SUCDi',\n", + " 'SUCOAS',\n", + " 'TALA',\n", + " 'THD2',\n", + " 'TKT1',\n", + " 'TKT2',\n", + " 'TPI',\n", + " 'EX_ac_e',\n", + " 'EX_acald_e',\n", + " 'EX_akg_e',\n", + " 'EX_co2_e',\n", + " 'EX_etoh_e',\n", + " 'EX_for_e',\n", + " 'EX_fru_e',\n", + " 'EX_fum_e',\n", + " 'EX_glc__D_e',\n", + " 'EX_gln__L_e',\n", + " 'EX_glu__L_e',\n", + " 'EX_h_e',\n", + " 'EX_h2o_e',\n", + " 'EX_lac__D_e',\n", + " 'EX_mal__L_e',\n", + " 'EX_nh4_e',\n", + " 'EX_o2_e',\n", + " 'EX_pi_e',\n", + " 'EX_pyr_e',\n", + " 'EX_succ_e',\n", + " 'FBA',\n", + " 'FBP',\n", + " 'FORt2',\n", + " 'FORt',\n", + " 'FRD7',\n", + " 'FRUpts2',\n", + " 'FUM',\n", + " 'FUMt2_2',\n", + " 'G6PDH2r',\n", + " 'GAPD',\n", + " 'GLCpts',\n", + " 'GLNS',\n", + " 'GLNabc',\n", + " 'GLUDy',\n", + " 'GLUN',\n", + " 'GLUSy',\n", + " 'GLUt2r',\n", + " 'GND',\n", + " 'H2Ot',\n", + " 'ICDHyr',\n", + " 'ICL',\n", + " 'LDH_D',\n", + " 'MALS',\n", + " 'MALt2_2',\n", + " 'MDH',\n", + " 'ME1',\n", + " 'ME2',\n", + " 'NADH16',\n", + " 'NADTRHD',\n", + " 'NH4t',\n", + " 'O2t',\n", + " 'PDH'])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "read_e_coli" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the ```read_ecoli_core``` variable is a tuple, we can get its different features in a straight forward way:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "A = read_e_coli[0]\n", + "b = read_e_coli[1]\n", + "Aeq = read_e_coli[2]\n", + "beq = read_e_coli[3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the ```Aeq``` variable is the stoichiometric matrix of the metabolic network under study, while in the ```beq``` variable we have its steady state. The variables ```A``` and ```b``` allow us to represent the upper and the lower bounds of the reactions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look on these variables. ```Aeq``` our stoichiometric matrix has dimensions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Aeq.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "meaning we have 72 metabolites that take part in 95 reactions. So, our network is built from these 95 reactions and their corresponding fluxes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And let us also keep the reactions of the network in a variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "reactions = read_e_coli[5]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "atps4r = reactions[21]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can proceed in the necessary pre-processing steps for getting the polytope that derives from this metabolic network. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preprocess" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In terms of making things faster, we run a pre process step in order to run our pipeline in a more efficient, from a computational point of view, way." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Minimize\n", + " \n", + "Subject To\n", + " c[0] : = 0.0\n", + " c[1] : = 0.0\n", + " c[2] : = 0.0\n", + " c[3] : = 0.0\n", + " c[4] : = 0.0\n", + " c[5] : = 0.0\n", + " c[6] : = 0.0\n", + " c[7] : = 0.0\n", + " c[8] : = 0.0\n", + " c[9] : = 0.0\n", + " c[10] : = 0.0\n", + " c[11] : = 0.0\n", + " c[12] : = 0.0\n", + " c[13] : = 0.0\n", + " c[14] : = 0.0\n", + " c[15] : = 0.0\n", + " c[16] : = 0.0\n", + " c[17] : = 0.0\n", + " c[18] : = 0.0\n", + " c[19] : = 0.0\n", + " c[20] : = 0.0\n", + " c[21] : = 0.0\n", + " c[22] : = 0.0\n", + " c[23] : = 0.0\n", + " c[24] : = 0.0\n", + " c[25] : = 0.0\n", + " c[26] : = 0.0\n", + " c[27] : = 0.0\n", + " c[28] : = 0.0\n", + " c[29] : = 0.0\n", + " c[30] : = 0.0\n", + " c[31] : = 0.0\n", + " c[32] : = 0.0\n", + " c[33] : = 0.0\n", + " c[34] : = 0.0\n", + " c[35] : = 0.0\n", + " c[36] : = 0.0\n", + " c[37] : = 0.0\n", + " c[38] : = 0.0\n", + " c[39] : = 0.0\n", + " c[40] : = 0.0\n", + " c[41] : = 0.0\n", + " c[42] : = 0.0\n", + " c[43] : = 0.0\n", + " c[44] : = 0.0\n", + " c[45] : = 0.0\n", + " c[46] : = 0.0\n", + " c[47] : = 0.0\n", + " c[48] : = 0.0\n", + " c[49] : = 0.0\n", + " c[50] : = 0.0\n", + " c[51] : = 0.0\n", + " c[52] : = 0.0\n", + " c[53] : = 0.0\n", + " c[54] : = 0.0\n", + " c[55] : = 0.0\n", + " c[56] : = 0.0\n", + " c[57] : = 0.0\n", + " c[58] : = 0.0\n", + " c[59] : = 0.0\n", + " c[60] : = 0.0\n", + " c[61] : = 0.0\n", + " c[62] : = 0.0\n", + " c[63] : = 0.0\n", + " c[64] : = 0.0\n", + " c[65] : = 0.0\n", + " c[66] : = 0.0\n", + " c[67] : = 0.0\n", + " c[68] : = 0.0\n", + " c[69] : = 0.0\n", + " c[70] : = 0.0\n", + " c[71] : = 0.0\n", + " d[0] : <= 1000.0\n", + " d[1] : <= 1000.0\n", + " d[2] : <= 1000.0\n", + " d[3] : <= 1000.0\n", + " d[4] : <= 1000.0\n", + " d[5] : <= 1000.0\n", + " d[6] : <= 1000.0\n", + " d[7] : <= 1000.0\n", + " d[8] : <= 1000.0\n", + " d[9] : <= 1000.0\n", + " d[10] : <= 1000.0\n", + " d[11] : <= 1000.0\n", + " d[12] : <= 1000.0\n", + " d[13] : <= 1000.0\n", + " d[14] : <= 1000.0\n", + " d[15] : <= 1000.0\n", + " d[16] : <= 1000.0\n", + " d[17] : <= 1000.0\n", + " d[18] : <= 1000.0\n", + " d[19] : <= 1000.0\n", + " d[20] : <= 1000.0\n", + " d[21] : <= 1000.0\n", + " d[22] : <= 1000.0\n", + " d[23] : <= 1000.0\n", + " d[24] : <= 1000.0\n", + " d[25] : <= 1000.0\n", + " d[26] : <= 1000.0\n", + " d[27] : <= 1000.0\n", + " d[28] : <= 1000.0\n", + " d[29] : <= 1000.0\n", + " d[30] : <= 1000.0\n", + " d[31] : <= 1000.0\n", + " d[32] : <= 1000.0\n", + " d[33] : <= 1000.0\n", + " d[34] : <= 1000.0\n", + " d[35] : <= 1000.0\n", + " d[36] : <= 1000.0\n", + " d[37] : <= 1000.0\n", + " d[38] : <= 1000.0\n", + " d[39] : <= 1000.0\n", + " d[40] : <= 1000.0\n", + " d[41] : <= 1000.0\n", + " d[42] : <= 1000.0\n", + " d[43] : <= 1000.0\n", + " d[44] : <= 1000.0\n", + " d[45] : <= 1000.0\n", + " d[46] : <= 1000.0\n", + " d[47] : <= 1000.0\n", + " d[48] : <= 1000.0\n", + " d[49] : <= 1000.0\n", + " d[50] : <= 1000.0\n", + " d[51] : <= 1000.0\n", + " d[52] : <= 1000.0\n", + " d[53] : <= 1000.0\n", + " d[54] : <= 1000.0\n", + " d[55] : <= 1000.0\n", + " d[56] : <= 1000.0\n", + " d[57] : <= 1000.0\n", + " d[58] : <= 1000.0\n", + " d[59] : <= 1000.0\n", + " d[60] : <= 1000.0\n", + " d[61] : <= 1000.0\n", + " d[62] : <= 1000.0\n", + " d[63] : <= 1000.0\n", + " d[64] : <= 1000.0\n", + " d[65] : <= 1000.0\n", + " d[66] : <= 0.0\n", + " d[67] : <= 1000.0\n", + " d[68] : <= 1000.0\n", + " d[69] : <= 1000.0\n", + " d[70] : <= 1000.0\n", + " d[71] : <= 1000.0\n", + " d[72] : <= 1000.0\n", + " d[73] : <= 1000.0\n", + " d[74] : <= 1000.0\n", + " d[75] : <= 1000.0\n", + " d[76] : <= 1000.0\n", + " d[77] : <= 1000.0\n", + " d[78] : <= 1000.0\n", + " d[79] : <= 1000.0\n", + " d[80] : <= 1000.0\n", + " d[81] : <= 1000.0\n", + " d[82] : <= 1000.0\n", + " d[83] : <= 1000.0\n", + " d[84] : <= 1000.0\n", + " d[85] : <= 1000.0\n", + " d[86] : <= 1000.0\n", + " d[87] : <= 1000.0\n", + " d[88] : <= 1000.0\n", + " d[89] : <= 1000.0\n", + " d[90] : <= 1000.0\n", + " d[91] : <= 1000.0\n", + " d[92] : <= 1000.0\n", + " d[93] : <= 1000.0\n", + " d[94] : <= 1000.0\n", + " d[95] : <= -0.0\n", + " d[96] : <= -0.0\n", + " d[97] : <= 1000.0\n", + " d[98] : <= 1000.0\n", + " d[99] : <= -0.0\n", + " d[100] : <= 1000.0\n", + " d[101] : <= 1000.0\n", + " d[102] : <= 1000.0\n", + " d[103] : <= 1000.0\n", + " d[104] : <= 1000.0\n", + " d[105] : <= 1000.0\n", + " d[106] : <= 1000.0\n", + " d[107] : <= -0.0\n", + " d[108] : <= 1000.0\n", + " d[109] : <= 1000.0\n", + " d[110] : <= -8.39\n", + " d[111] : <= -0.0\n", + " d[112] : <= 1000.0\n", + " d[113] : <= -0.0\n", + " d[114] : <= 1000.0\n", + " d[115] : <= -0.0\n", + " d[116] : <= 1000.0\n", + " d[117] : <= 1000.0\n", + " d[118] : <= -0.0\n", + " d[119] : <= -0.0\n", + " d[120] : <= 1000.0\n", + " d[121] : <= 1000.0\n", + " d[122] : <= 1000.0\n", + " d[123] : <= -0.0\n", + " d[124] : <= 1000.0\n", + " d[125] : <= -0.0\n", + " d[126] : <= -0.0\n", + " d[127] : <= 1000.0\n", + " d[128] : <= 1000.0\n", + " d[129] : <= -0.0\n", + " d[130] : <= 1000.0\n", + " d[131] : <= -0.0\n", + " d[132] : <= 1000.0\n", + " d[133] : <= 1000.0\n", + " d[134] : <= -0.0\n", + " d[135] : <= 1000.0\n", + " d[136] : <= 1000.0\n", + " d[137] : <= 1000.0\n", + " d[138] : <= -0.0\n", + " d[139] : <= -0.0\n", + " d[140] : <= -0.0\n", + " d[141] : <= 1000.0\n", + " d[142] : <= -0.0\n", + " d[143] : <= -0.0\n", + " d[144] : <= -0.0\n", + " d[145] : <= -0.0\n", + " d[146] : <= 10.0\n", + " d[147] : <= -0.0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " d[148] : <= -0.0\n", + " d[149] : <= 1000.0\n", + " d[150] : <= 1000.0\n", + " d[151] : <= -0.0\n", + " d[152] : <= -0.0\n", + " d[153] : <= 1000.0\n", + " d[154] : <= 1000.0\n", + " d[155] : <= 1000.0\n", + " d[156] : <= -0.0\n", + " d[157] : <= -0.0\n", + " d[158] : <= 1000.0\n", + " d[159] : <= -0.0\n", + " d[160] : <= -0.0\n", + " d[161] : <= 1000.0\n", + " d[162] : <= -0.0\n", + " d[163] : <= -0.0\n", + " d[164] : <= 1000.0\n", + " d[165] : <= -0.0\n", + " d[166] : <= 1000.0\n", + " d[167] : <= 1000.0\n", + " d[168] : <= -0.0\n", + " d[169] : <= -0.0\n", + " d[170] : <= -0.0\n", + " d[171] : <= 1000.0\n", + " d[172] : <= -0.0\n", + " d[173] : <= -0.0\n", + " d[174] : <= 1000.0\n", + " d[175] : <= -0.0\n", + " d[176] : <= 1000.0\n", + " d[177] : <= 1000.0\n", + " d[178] : <= -0.0\n", + " d[179] : <= 1000.0\n", + " d[180] : <= -0.0\n", + " d[181] : <= -0.0\n", + " d[182] : <= 1000.0\n", + " d[183] : <= -0.0\n", + " d[184] : <= -0.0\n", + " d[185] : <= -0.0\n", + " d[186] : <= -0.0\n", + " d[187] : <= 1000.0\n", + " d[188] : <= 1000.0\n", + " d[189] : <= -0.0\n", + "Bounds\n", + " x[0] free\n", + " x[1] free\n", + " x[2] free\n", + " x[3] free\n", + " x[4] free\n", + " x[5] free\n", + " x[6] free\n", + " x[7] free\n", + " x[8] free\n", + " x[9] free\n", + " x[10] free\n", + " x[11] free\n", + " x[12] free\n", + " x[13] free\n", + " x[14] free\n", + " x[15] free\n", + " x[16] free\n", + " x[17] free\n", + " x[18] free\n", + " x[19] free\n", + " x[20] free\n", + " x[21] free\n", + " x[22] free\n", + " x[23] free\n", + " x[24] free\n", + " x[25] free\n", + " x[26] free\n", + " x[27] free\n", + " x[28] free\n", + " x[29] free\n", + " x[30] free\n", + " x[31] free\n", + " x[32] free\n", + " x[33] free\n", + " x[34] free\n", + " x[35] free\n", + " x[36] free\n", + " x[37] free\n", + " x[38] free\n", + " x[39] free\n", + " x[40] free\n", + " x[41] free\n", + " x[42] free\n", + " x[43] free\n", + " x[44] free\n", + " x[45] free\n", + " x[46] free\n", + " x[47] free\n", + " x[48] free\n", + " x[49] free\n", + " x[50] free\n", + " x[51] free\n", + " x[52] free\n", + " x[53] free\n", + " x[54] free\n", + " x[55] free\n", + " x[56] free\n", + " x[57] free\n", + " x[58] free\n", + " x[59] free\n", + " x[60] free\n", + " x[61] free\n", + " x[62] free\n", + " x[63] free\n", + " x[64] free\n", + " x[65] free\n", + " x[66] free\n", + " x[67] free\n", + " x[68] free\n", + " x[69] free\n", + " x[70] free\n", + " x[71] free\n", + " x[72] free\n", + " x[73] free\n", + " x[74] free\n", + " x[75] free\n", + " x[76] free\n", + " x[77] free\n", + " x[78] free\n", + " x[79] free\n", + " x[80] free\n", + " x[81] free\n", + " x[82] free\n", + " x[83] free\n", + " x[84] free\n", + " x[85] free\n", + " x[86] free\n", + " x[87] free\n", + " x[88] free\n", + " x[89] free\n", + " x[90] free\n", + " x[91] free\n", + " x[92] free\n", + " x[93] free\n", + " x[94] free\n" + ] + } + ], + "source": [ + "proc = pre_process(A, b, Aeq, beq)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From this, we get the processed A, b, Aeq and beq and we keep them in distinct variables correspodingly." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "A_proc = proc[0]\n", + "b_proc = proc[1]\n", + "Aeq_proc = proc[2]\n", + "beq_proc = proc[3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case you the ```pre_process``` step had already run, you may load its output using the following commands:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/A_preprocessed.npy')\n", + "b_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/b_preprocessed.npy')\n", + "Aeq_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/Aeq_preprocessed.npy')\n", + "beq_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/beq_preprocessed.npy')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Aeq_proc.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Full dimensional (not always required step)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are able to use the pre processed polytope to get the full dimensional polytope that derives from our initial one. To this end we first build an object for the ```low_dim_HPolytope``` class for the pre-processed polytope. " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "low_hp = low_dim_HPolytope(A_proc, b_proc, Aeq_proc, beq_proc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then we run the ```full_dimensiolal_polytope``` function of ```volestipy``` to get it. " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "get_fd_hp = low_hp.full_dimensiolal_polytope()\n", + "\n", + "A_fd = get_fd_hp[0].A\n", + "b_fd = get_fd_hp[0].b\n", + "N = get_fd_hp[1]\n", + "N_shift = get_fd_hp[2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once we have the full dimensional polytope, we are able to get the max ball of that." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "max_ball_center_point, max_ball_radius = get_max_ball(A_fd, b_fd)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can use this max ball for rounding the full dimensional polytope. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Rounding" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the A and b of the full dimensional polytope, we build a new HPolytope object." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "hp = HPolytope(A_fd, b_fd)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we use the max ball to round it." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "rounding_output_max_ellipsoid = hp.rounding(rounding_method = \"max_ellipsoid\", \n", + " inner_point = max_ball_center_point, \n", + " radius = max_ball_radius)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now get the features or the rounded polytope." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_A = rounding_output_max_ellipsoid[0]\n", + "rounded_b = rounding_output_max_ellipsoid[1]\n", + "rounded_T = rounding_output_max_ellipsoid[2]\n", + "rounded_shift = rounding_output_max_ellipsoid[3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And use the to get the max ball of this full dimensional, rounded polytope." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_center_point, rounded_radius = get_max_ball(rounded_A, rounded_b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look at that:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[-1.0827203738869838e-08,\n", + " 5.46699607224613e-09,\n", + " -1.9440816473264214e-09,\n", + " 4.202258767454394e-09,\n", + " -5.720196183334541e-09,\n", + " -2.34495800347931e-09,\n", + " 3.4714599880184695e-09,\n", + " -1.0610740112672796e-10,\n", + " 1.5374959601778526e-09,\n", + " 6.363085780165716e-09,\n", + " 7.47879143571297e-09,\n", + " 4.875192491832598e-10,\n", + " -1.5540451275577207e-09,\n", + " 1.8233604962779356e-09,\n", + " -6.1940535936238185e-09,\n", + " -3.027059547527763e-10,\n", + " 5.372701921624584e-09,\n", + " 1.8968608527828443e-09,\n", + " 8.502848362572111e-10,\n", + " 1.4118646354600406e-09,\n", + " -6.156855514982069e-10,\n", + " 8.125766689870477e-10,\n", + " 5.389284100671947e-10,\n", + " -1.7114008103486753e-10]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rounded_center_point" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.0000000081541534" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rounded_radius" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sampling" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we build the full dimenionsal rounded polytope. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_polytope = HPolytope(rounded_A, rounded_b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keep the dimension of the rounded polytope" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "24" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d = rounded_polytope.dimensions\n", + "d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And calculate the value of the L parameter for the sampling function according the following formula:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "L_value = 4 * d * rounded_radius" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And using the latter max ball, we sample on it" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "samples = rounded_polytope.generate_samples(walk_len = 5, \n", + " number_of_points = 10000, \n", + " number_of_points_to_burn = 50, \n", + " radius = rounded_radius, \n", + " inner_point = rounded_center_point,\n", + " L = L_value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And these are the points sampled: " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[-1.08272037e-08, 5.46699607e-09, -1.94408165e-09, ...,\n", + " -3.83700337e-01, 5.38928410e-10, -1.71140081e-10],\n", + " [-1.08272037e-08, 5.46699607e-09, -1.94408165e-09, ...,\n", + " -3.83700337e-01, 5.38928410e-10, -1.71140081e-10],\n", + " [-1.08272037e-08, 5.46699607e-09, 5.03033014e-01, ...,\n", + " -3.83700337e-01, 1.45401219e-02, -1.71140081e-10],\n", + " ...,\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00],\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00],\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00]])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "samples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, these samples \"live\" in the world of the rounded, full dimensional polytope. Thus, we need to map them back in our initial polyopte. To do that we run one last ```volestipy``` function, using the features returned from the ```rounding``` and the ```full_dimensional``` functions. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "mapped_samples = map_samples_on_initial_polytope(samples, rounded_T, rounded_shift, N, N_shift)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look on our final points and their dimension. " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(95, 10000)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mapped_samples.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis, plots etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use the ```matplotlib``` library to plot our random samples. First, we download it to our environment." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting matplotlib\n", + " Using cached matplotlib-3.3.2-cp36-cp36m-manylinux1_x86_64.whl (11.6 MB)\n", + "Collecting kiwisolver>=1.0.1\n", + " Using cached kiwisolver-1.2.0-cp36-cp36m-manylinux1_x86_64.whl (88 kB)\n", + "Collecting cycler>=0.10\n", + " Using cached cycler-0.10.0-py2.py3-none-any.whl (6.5 kB)\n", + "Collecting pillow>=6.2.0\n", + " Using cached Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl (2.2 MB)\n", + "Requirement already satisfied: python-dateutil>=2.1 in /home/haris/.local/lib/python3.6/site-packages (from matplotlib) (2.8.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in /home/haris/.local/lib/python3.6/site-packages (from matplotlib) (2.4.0)\n", + "Requirement already satisfied: numpy>=1.15 in /home/haris/anaconda3/envs/py36/lib/python3.6/site-packages (from matplotlib) (1.19.1)\n", + "Collecting certifi>=2020.06.20\n", + " Downloading certifi-2020.6.20-py2.py3-none-any.whl (156 kB)\n", + "\u001b[K |████████████████████████████████| 156 kB 576 kB/s eta 0:00:01\n", + "\u001b[?25hRequirement already satisfied: six in /home/haris/.local/lib/python3.6/site-packages (from cycler>=0.10->matplotlib) (1.12.0)\n", + "Installing collected packages: kiwisolver, cycler, pillow, certifi, matplotlib\n", + " Attempting uninstall: certifi\n", + " Found existing installation: certifi 2019.6.16\n", + " Uninstalling certifi-2019.6.16:\n", + " Successfully uninstalled certifi-2019.6.16\n", + "\u001b[31mERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.\n", + "\n", + "We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.\n", + "\n", + "requests 2.22.0 requires chardet<3.1.0,>=3.0.2, which is not installed.\n", + "cwltool 1.0.20190621234233 requires future, which is not installed.\u001b[0m\n", + "Successfully installed certifi-2020.6.20 cycler-0.10.0 kiwisolver-1.2.0 matplotlib-3.3.2 pillow-7.2.0\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "pip install matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can import it." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us assume now that we are insteresd in the Ethanol reversible transport via proton symport reaction. This is called ```ETOHt2r```. As you can see, this is the 36th element in our ```reactions``` list." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'PTAr'" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reactions[22]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We keep all the fluxes' values from the points sampled for this reactions in a variable. And we print its shape to be sure that we have got this right." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(10000,)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fluxes = mapped_samples[22,:]\n", + "fluxes.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can get the minimum and the maximum value of ETOHt2r flux." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(8.488618241774088, -4.3178112120710377e-14)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "maxElement = np.amax(fluxes)\n", + "minElement = np.amin(fluxes)\n", + "maxElement, minElement" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now we may plot our samples! " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x = np.array([x for x in range(samples.shape[0])])\n", + "plt.plot(x, fluxes)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And also as an histogram!" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(fluxes, bins='auto', histtype='bar', rwidth=0.7)\n", + "plt.show" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case you need to work with ```.mat``` files you need to implement some further steps that are not in the interest of this tutorial. \n", + "\n", + "To read a ```.mat``` file you need some extra Python libraries, as it is quite a challenging task. If you are more interested in that, you can read this article [here](https://scipy-cookbook.readthedocs.io/items/Reading_mat_files.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the h5py library in case you are working with .mat files of 7.3 release of Matlab and after \n", + "#!sudo -H -S pip install h5py < /home/haris/Desktop/running/metabolic_network_pipeline_volestipy/\\\n", + "#my_project_virtual_env/error.txt\n", + "#print(\"*** The h5py library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the tables library to read .mat files\n", + "#!sudo -H -S pip3 install tables < /home/haris/Desktop/running/metabolic_network_pipeline_volestipy\\\n", + "#/my_project_virtual_env/error.txt\n", + "#print(\"*** The tables library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Matlab up to 7.1 = mat files created with Matlab up to version 7.1 can be read using the mio module part of scipy.io.\n", + "#from scipy.io import loadmat \n", + "#\n", + "## Beginning at release 7.3 of Matlab, mat files are actually saved using the HDF5 format by default (except if you use the -vX flag at save time, see in Matlab). These files can be read in Python using, for instance, the PyTables or h5py package\n", + "#import tables \n", + "#import h5py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the ggplot - oriented Python library\n", + "#!sudo -H -S pip3 install -t \"/home/haris/anaconda3/lib/python3.7/site-packages/\" --upgrade pandas plotnine \\\n", + "#< /home/haris/Desktop/running/metabolic_network_pipeline_volestipy/my_project_virtual_env/error.txt\n", + "#print(\"*** The ggplot for Python library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#mat_file_with_loadmat = loadmat('/home/haris/Downloads/e_coli_core.mat')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While this one is in case of ```.mat``` files created by releases of Matlab later after the 7.3\n", + "This command will not run in any other case.\n", + "For this demo we will use the ```loadmat``` option." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# mat_file_with_tables = h5py.File('/home/haris/Downloads/e_coli_core.mat')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now you can see your metabolic network. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(mat_file_with_loadmat)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#data_from_mat = mat_file_with_loadmat\n", + "#print(\"the data type of the variable with the network as it was read is: \" + str(type(data_from_mat)))\n", + "\n", + "#s_matrix = data_from_mat.keys()\n", + "#print(\"\\nthe keys of this dictionaries are: \")\n", + "#print(s_matrix)\n", + "\n", + "#e_coli_np_void = data_from_mat['e_coli_core'][0][0]\n", + "#print(\"\\nHowever, if we keep the key:value pair of this dictionary, called 'e_coli_core' where the necessary \\\n", + "#information is located, we can see that its type is: \" + str(type(e_coli_np_void)) + \"\\n\\n\")\n", + "\n", + "#print(\"number of dimensions of the np.void data type equals to:\" + str(e_coli_np_void.ndim) + \"\\n\")\n", + "\n", + "#print(type(e_coli_np_void))\n", + "#print(len(e_coli_np_void))\n", + "\n", + "\n", + "\n", + "## metabolites\n", + "#print(type(e_coli_np_void[0]))\n", + "#print(e_coli_np_void[0].shape)\n", + "\n", + "#print(type(e_coli_np_void[0][0]))\n", + "#print(e_coli_np_void[0][0].shape)\n", + "\n", + "#print(e_coli_np_void[0][:3,])\n", + "#metabolites = [item[0][0] for item in e_coli_np_void[0]]\n", + "#print(metabolites)\n", + "\n", + "## genes\n", + "#print(type(e_coli_np_void[4]))\n", + "#print(e_coli_np_void[4].shape)\n", + "#print(e_coli_np_void[4][:3,])\n", + "\n", + "## reactions\n", + "#print(type(e_coli_np_void[7]))\n", + "#print(e_coli_np_void[7].shape)\n", + "#print(e_coli_np_void[7][:3,])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#for key,value in data_from_mat.items():\n", + "# print(str(key) + \"\\t\" + str(value))\n", + "# print(\"\\n\\n\\n\\n\\n\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.6.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/volestipy/metabolic_net_pipeline.ipynb b/volestipy/metabolic_net_pipeline.ipynb new file mode 100644 index 000000000..a986c4014 --- /dev/null +++ b/volestipy/metabolic_net_pipeline.ipynb @@ -0,0 +1,1957 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Metabolic network analysis using *volestipy*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aim of this notebook is to present the complete pipeline for random sampling in a metabolic network using the ```volesitpy``` library. As input, we will use a BIGG model of *E.coli* in its ```.json``` format. \n", + "\n", + "Other formats, such as ```.mat``` are supported by ```volestipy``` but this is not in the scope of this tutorial. \n", + "\n", + "**Attention!**\n", + "This tutorial assumes that you have already compiled the ```volestipy``` library, following the steps described [here](https://github.com/hariszaf/volume_approximation_bio/tree/develop/volestipy)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Dependencies" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With respect to this ```jupyter notebook```.\n", + "First you need to create a **conda environment** by making use of at least Python 3.6. \n", + "Then open the notebook using the ```jupyter notebook``` command after entering the conda evironment you built. \n", + "\n", + "For example, considering that the base environment of ```conda``` includes Python 3.6:\n", + "\n", + "```conda activate```\n", + "\n", + "```jupyter notebook```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To use Jupyter with a certain conda environment we also need to run the followings:\n", + "\n", + "````conda install ipykernel\n", + "ipython kernel install --name MY_CONDA_ENV --user\n", + "````" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before showing how you can exploit the *volestipy* software, we first need to get all the relative dependencies. \n", + "\n", + "This demo uses [Anaconda](https://www.anaconda.com/products/individual) which you can download following [these](https://www.digitalocean.com/community/tutorials/how-to-install-anaconda-on-ubuntu-18-04-quickstart) instructions.\n", + "\n", + "Furtheremore, special, powerful mathematical optimization solvers like [Gurobi](https://www.gurobi.com/) are also used. You can get Gurobi following the steps described [here](https://support.gurobi.com/hc/en-us/articles/360044290292-Installing-Gurobi-for-Python). Keep in mind that you will need a Gurobi license. To do this, you need to create a Gurobi user account and then follow the instructions for a license you will find there." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The main libraries you need to run this pipeline are the following:\n", + "\n", + "* ```numpy```\n", + "* ```gurobipy``` and of course\n", + "* ```volestipy```\n", + "\n", + "You will also need a library for plotting, like ```matplotib``` but this is up to you!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To get any libraries that need to run commands as ```sudo``` you need to make a file including **only** your password and replace ```/home/haris/Desktop/running/metabolic_network_pipeline_volestipy/my_project_virtual_env/error.txt``` with the corresponding path. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In order to make possible to install what is needed in this conda evironment we use the ```getpass``` library that prompts the user for a password without echoing." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "import getpass \n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "So, with respect to the ```numpy``` library, let us first get it in our conda environment. \n", + "This is going to take a while. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!conda install --yes --prefix {sys.prefix} numpy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can import it. " + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Assuming you have already ```gurobipy``` on your computer, you may just add its path on your conda environment with the following command." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sys.path.append('/usr/local/lib/python3.6/dist-packages/gurobipy/')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Otherwise, you can install ```gurobipy``` on the conda enviroment directly. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Get GUROBI through anaconda - You can find more about installing Gurobi here: \n", + "# https://support.gurobi.com/hc/en-us/articles/360044290292-Installing-Gurobi-for-Python\n", + "!conda install -y -c gurobi gurobi\n", + "print(\"*** The Gurobi solver library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After executing one of the above ways to get `gurobipy`, import this library and check if everything is working fine. " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Using license file /home/haris/gurobi.lic\n", + "Academic license - for non-commercial use only\n", + "\n", + "*** Gurobi test has been completed successfully. ***\n", + "\n" + ] + } + ], + "source": [ + "import gurobipy as gp\n", + "from gurobipy import GRB\n", + "\n", + "# This is just a test that the Gurobi solver is well installed\n", + "\n", + "# Create a new model\n", + "m = gp.Model(\"mip1\")\n", + "\n", + "print(\"\\n*** Gurobi test has been completed successfully. ***\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Likewise, for the `scipy` library. Install it through conda on this environment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!conda install --yes --prefix {sys.prefix} scipy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We do not need to import `scipy` here, however the `volestipy` does that. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we have to compile and then import the ```volestipy``` library. To this end, we first need to get the `cython` library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pip install Cython" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then run the following command as it was from our terminal. It is the `!` that allows for the latter." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!LDFLAGS=\"-L/usr/lib/lp_solve/\" python3 setup.py install --user" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from volestipy import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are ready to read our network BIGG file and run the necessary steps to get our random points from its correspoding polytope." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Read your network file" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have downloaded a BIGG model of *E. coli* which you may find [here](http://bigg.ucsd.edu/models/e_coli_core) in its ```.json``` format. We keep this file as a variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "input_file = '/home/haris/bigg_files/e_coli_core.json'" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we run the ```volestipy``` function to read it." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "read it all\n" + ] + } + ], + "source": [ + "read_e_coli = read_json_file(input_file)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You may see the whole BIGG file, simply by printing the ```read_ecoli_core``` variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([[ 1., 0., 0., ..., 0., 0., 0.],\n", + " [ 0., 1., 0., ..., 0., 0., 0.],\n", + " [ 0., 0., 1., ..., 0., 0., 0.],\n", + " ...,\n", + " [ 0., 0., 0., ..., -1., 0., 0.],\n", + " [ 0., 0., 0., ..., 0., -1., 0.],\n", + " [ 0., 0., 0., ..., 0., 0., -1.]]),\n", + " array([1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 0. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , 1000. , 1000. , -0. , -0. , 1000. ,\n", + " 1000. , -0. , 1000. , 1000. , 1000. , 1000. , 1000. ,\n", + " 1000. , 1000. , -0. , 1000. , 1000. , -8.39, -0. ,\n", + " 1000. , -0. , 1000. , -0. , 1000. , 1000. , -0. ,\n", + " -0. , 1000. , 1000. , 1000. , -0. , 1000. , -0. ,\n", + " -0. , 1000. , 1000. , -0. , 1000. , -0. , 1000. ,\n", + " 1000. , -0. , 1000. , 1000. , 1000. , -0. , -0. ,\n", + " -0. , 1000. , -0. , -0. , -0. , -0. , 10. ,\n", + " -0. , -0. , 1000. , 1000. , -0. , -0. , 1000. ,\n", + " 1000. , 1000. , -0. , -0. , 1000. , -0. , -0. ,\n", + " 1000. , -0. , -0. , 1000. , -0. , 1000. , 1000. ,\n", + " -0. , -0. , -0. , 1000. , -0. , -0. , 1000. ,\n", + " -0. , 1000. , 1000. , -0. , 1000. , -0. , -0. ,\n", + " 1000. , -0. , -0. , -0. , -0. , 1000. , 1000. ,\n", + " -0. ]),\n", + " array([[ 1., 0., 0., ..., 0., 0., 0.],\n", + " [-1., 0., 0., ..., 0., 0., 0.],\n", + " [-1., 0., 1., ..., 0., 0., 0.],\n", + " ...,\n", + " [ 0., 0., 0., ..., 0., 0., 0.],\n", + " [ 0., 0., 0., ..., 1., 0., 0.],\n", + " [ 0., 0., 0., ..., 0., 0., 0.]]),\n", + " array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,\n", + " 0., 0., 0., 0.]),\n", + " ['adp_c',\n", + " 'atp_c',\n", + " 'f6p_c',\n", + " 'fdp_c',\n", + " 'h_c',\n", + " 'accoa_c',\n", + " 'coa_c',\n", + " 'for_c',\n", + " 'pyr_c',\n", + " 'g6p_c',\n", + " '13dpg_c',\n", + " '3pg_c',\n", + " '6pgc_c',\n", + " '6pgl_c',\n", + " 'h2o_c',\n", + " 'acald_c',\n", + " 'nad_c',\n", + " 'nadh_c',\n", + " 'akg_c',\n", + " 'akg_e',\n", + " 'h_e',\n", + " '2pg_c',\n", + " 'pi_c',\n", + " 'pi_e',\n", + " 'etoh_c',\n", + " 'acald_e',\n", + " 'ac_c',\n", + " 'actp_c',\n", + " 'co2_c',\n", + " 'oaa_c',\n", + " 'pep_c',\n", + " 'acon_C_c',\n", + " 'cit_c',\n", + " 'icit_c',\n", + " 'ac_e',\n", + " 'amp_c',\n", + " 'succoa_c',\n", + " 'e4p_c',\n", + " 'g3p_c',\n", + " 'gln__L_c',\n", + " 'glu__L_c',\n", + " 'nadp_c',\n", + " 'nadph_c',\n", + " 'r5p_c',\n", + " 'pyr_e',\n", + " 'co2_e',\n", + " 'ru5p__D_c',\n", + " 'xu5p__D_c',\n", + " 'succ_c',\n", + " 'succ_e',\n", + " 'o2_c',\n", + " 'q8_c',\n", + " 'q8h2_c',\n", + " 'lac__D_c',\n", + " 'lac__D_e',\n", + " 'etoh_e',\n", + " 'fum_c',\n", + " 's7p_c',\n", + " 'dhap_c',\n", + " 'for_e',\n", + " 'fru_e',\n", + " 'fum_e',\n", + " 'glc__D_e',\n", + " 'gln__L_e',\n", + " 'glu__L_e',\n", + " 'h2o_e',\n", + " 'mal__L_e',\n", + " 'nh4_e',\n", + " 'o2_e',\n", + " 'mal__L_c',\n", + " 'nh4_c',\n", + " 'glx_c'],\n", + " ['PFK',\n", + " 'PFL',\n", + " 'PGI',\n", + " 'PGK',\n", + " 'PGL',\n", + " 'ACALD',\n", + " 'AKGt2r',\n", + " 'PGM',\n", + " 'PIt2r',\n", + " 'ALCD2x',\n", + " 'ACALDt',\n", + " 'ACKr',\n", + " 'PPC',\n", + " 'ACONTa',\n", + " 'ACONTb',\n", + " 'ATPM',\n", + " 'PPCK',\n", + " 'ACt2r',\n", + " 'PPS',\n", + " 'ADK1',\n", + " 'AKGDH',\n", + " 'ATPS4r',\n", + " 'PTAr',\n", + " 'PYK',\n", + " 'BIOMASS_Ecoli_core_w_GAM',\n", + " 'PYRt2',\n", + " 'CO2t',\n", + " 'RPE',\n", + " 'CS',\n", + " 'RPI',\n", + " 'SUCCt2_2',\n", + " 'CYTBD',\n", + " 'D_LACt2',\n", + " 'ENO',\n", + " 'SUCCt3',\n", + " 'ETOHt2r',\n", + " 'SUCDi',\n", + " 'SUCOAS',\n", + " 'TALA',\n", + " 'THD2',\n", + " 'TKT1',\n", + " 'TKT2',\n", + " 'TPI',\n", + " 'EX_ac_e',\n", + " 'EX_acald_e',\n", + " 'EX_akg_e',\n", + " 'EX_co2_e',\n", + " 'EX_etoh_e',\n", + " 'EX_for_e',\n", + " 'EX_fru_e',\n", + " 'EX_fum_e',\n", + " 'EX_glc__D_e',\n", + " 'EX_gln__L_e',\n", + " 'EX_glu__L_e',\n", + " 'EX_h_e',\n", + " 'EX_h2o_e',\n", + " 'EX_lac__D_e',\n", + " 'EX_mal__L_e',\n", + " 'EX_nh4_e',\n", + " 'EX_o2_e',\n", + " 'EX_pi_e',\n", + " 'EX_pyr_e',\n", + " 'EX_succ_e',\n", + " 'FBA',\n", + " 'FBP',\n", + " 'FORt2',\n", + " 'FORt',\n", + " 'FRD7',\n", + " 'FRUpts2',\n", + " 'FUM',\n", + " 'FUMt2_2',\n", + " 'G6PDH2r',\n", + " 'GAPD',\n", + " 'GLCpts',\n", + " 'GLNS',\n", + " 'GLNabc',\n", + " 'GLUDy',\n", + " 'GLUN',\n", + " 'GLUSy',\n", + " 'GLUt2r',\n", + " 'GND',\n", + " 'H2Ot',\n", + " 'ICDHyr',\n", + " 'ICL',\n", + " 'LDH_D',\n", + " 'MALS',\n", + " 'MALt2_2',\n", + " 'MDH',\n", + " 'ME1',\n", + " 'ME2',\n", + " 'NADH16',\n", + " 'NADTRHD',\n", + " 'NH4t',\n", + " 'O2t',\n", + " 'PDH'])" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "read_e_coli" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As the ```read_ecoli_core``` variable is a tuple, we can get its different features in a straight forward way:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "A = read_e_coli[0]\n", + "b = read_e_coli[1]\n", + "Aeq = read_e_coli[2]\n", + "beq = read_e_coli[3]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "b.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the ```Aeq``` variable is the stoichiometric matrix of the metabolic network under study, while in the ```beq``` variable we have its steady state. The variables ```A``` and ```b``` allow us to represent the upper and the lower bounds of the reactions." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look on these variables. ```Aeq``` our stoichiometric matrix has dimensions:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Aeq.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "meaning we have 72 metabolites that take part in 95 reactions. So, our network is built from these 95 reactions and their corresponding fluxes." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And let us also keep the reactions of the network in a variable. " + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "reactions = read_e_coli[5]" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "atps4r = reactions[21]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can proceed in the necessary pre-processing steps for getting the polytope that derives from this metabolic network. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preprocess" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In terms of making things faster, we run a pre process step in order to run our pipeline in a more efficient, from a computational point of view, way." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Minimize\n", + " \n", + "Subject To\n", + " c[0] : = 0.0\n", + " c[1] : = 0.0\n", + " c[2] : = 0.0\n", + " c[3] : = 0.0\n", + " c[4] : = 0.0\n", + " c[5] : = 0.0\n", + " c[6] : = 0.0\n", + " c[7] : = 0.0\n", + " c[8] : = 0.0\n", + " c[9] : = 0.0\n", + " c[10] : = 0.0\n", + " c[11] : = 0.0\n", + " c[12] : = 0.0\n", + " c[13] : = 0.0\n", + " c[14] : = 0.0\n", + " c[15] : = 0.0\n", + " c[16] : = 0.0\n", + " c[17] : = 0.0\n", + " c[18] : = 0.0\n", + " c[19] : = 0.0\n", + " c[20] : = 0.0\n", + " c[21] : = 0.0\n", + " c[22] : = 0.0\n", + " c[23] : = 0.0\n", + " c[24] : = 0.0\n", + " c[25] : = 0.0\n", + " c[26] : = 0.0\n", + " c[27] : = 0.0\n", + " c[28] : = 0.0\n", + " c[29] : = 0.0\n", + " c[30] : = 0.0\n", + " c[31] : = 0.0\n", + " c[32] : = 0.0\n", + " c[33] : = 0.0\n", + " c[34] : = 0.0\n", + " c[35] : = 0.0\n", + " c[36] : = 0.0\n", + " c[37] : = 0.0\n", + " c[38] : = 0.0\n", + " c[39] : = 0.0\n", + " c[40] : = 0.0\n", + " c[41] : = 0.0\n", + " c[42] : = 0.0\n", + " c[43] : = 0.0\n", + " c[44] : = 0.0\n", + " c[45] : = 0.0\n", + " c[46] : = 0.0\n", + " c[47] : = 0.0\n", + " c[48] : = 0.0\n", + " c[49] : = 0.0\n", + " c[50] : = 0.0\n", + " c[51] : = 0.0\n", + " c[52] : = 0.0\n", + " c[53] : = 0.0\n", + " c[54] : = 0.0\n", + " c[55] : = 0.0\n", + " c[56] : = 0.0\n", + " c[57] : = 0.0\n", + " c[58] : = 0.0\n", + " c[59] : = 0.0\n", + " c[60] : = 0.0\n", + " c[61] : = 0.0\n", + " c[62] : = 0.0\n", + " c[63] : = 0.0\n", + " c[64] : = 0.0\n", + " c[65] : = 0.0\n", + " c[66] : = 0.0\n", + " c[67] : = 0.0\n", + " c[68] : = 0.0\n", + " c[69] : = 0.0\n", + " c[70] : = 0.0\n", + " c[71] : = 0.0\n", + " d[0] : <= 1000.0\n", + " d[1] : <= 1000.0\n", + " d[2] : <= 1000.0\n", + " d[3] : <= 1000.0\n", + " d[4] : <= 1000.0\n", + " d[5] : <= 1000.0\n", + " d[6] : <= 1000.0\n", + " d[7] : <= 1000.0\n", + " d[8] : <= 1000.0\n", + " d[9] : <= 1000.0\n", + " d[10] : <= 1000.0\n", + " d[11] : <= 1000.0\n", + " d[12] : <= 1000.0\n", + " d[13] : <= 1000.0\n", + " d[14] : <= 1000.0\n", + " d[15] : <= 1000.0\n", + " d[16] : <= 1000.0\n", + " d[17] : <= 1000.0\n", + " d[18] : <= 1000.0\n", + " d[19] : <= 1000.0\n", + " d[20] : <= 1000.0\n", + " d[21] : <= 1000.0\n", + " d[22] : <= 1000.0\n", + " d[23] : <= 1000.0\n", + " d[24] : <= 1000.0\n", + " d[25] : <= 1000.0\n", + " d[26] : <= 1000.0\n", + " d[27] : <= 1000.0\n", + " d[28] : <= 1000.0\n", + " d[29] : <= 1000.0\n", + " d[30] : <= 1000.0\n", + " d[31] : <= 1000.0\n", + " d[32] : <= 1000.0\n", + " d[33] : <= 1000.0\n", + " d[34] : <= 1000.0\n", + " d[35] : <= 1000.0\n", + " d[36] : <= 1000.0\n", + " d[37] : <= 1000.0\n", + " d[38] : <= 1000.0\n", + " d[39] : <= 1000.0\n", + " d[40] : <= 1000.0\n", + " d[41] : <= 1000.0\n", + " d[42] : <= 1000.0\n", + " d[43] : <= 1000.0\n", + " d[44] : <= 1000.0\n", + " d[45] : <= 1000.0\n", + " d[46] : <= 1000.0\n", + " d[47] : <= 1000.0\n", + " d[48] : <= 1000.0\n", + " d[49] : <= 1000.0\n", + " d[50] : <= 1000.0\n", + " d[51] : <= 1000.0\n", + " d[52] : <= 1000.0\n", + " d[53] : <= 1000.0\n", + " d[54] : <= 1000.0\n", + " d[55] : <= 1000.0\n", + " d[56] : <= 1000.0\n", + " d[57] : <= 1000.0\n", + " d[58] : <= 1000.0\n", + " d[59] : <= 1000.0\n", + " d[60] : <= 1000.0\n", + " d[61] : <= 1000.0\n", + " d[62] : <= 1000.0\n", + " d[63] : <= 1000.0\n", + " d[64] : <= 1000.0\n", + " d[65] : <= 1000.0\n", + " d[66] : <= 0.0\n", + " d[67] : <= 1000.0\n", + " d[68] : <= 1000.0\n", + " d[69] : <= 1000.0\n", + " d[70] : <= 1000.0\n", + " d[71] : <= 1000.0\n", + " d[72] : <= 1000.0\n", + " d[73] : <= 1000.0\n", + " d[74] : <= 1000.0\n", + " d[75] : <= 1000.0\n", + " d[76] : <= 1000.0\n", + " d[77] : <= 1000.0\n", + " d[78] : <= 1000.0\n", + " d[79] : <= 1000.0\n", + " d[80] : <= 1000.0\n", + " d[81] : <= 1000.0\n", + " d[82] : <= 1000.0\n", + " d[83] : <= 1000.0\n", + " d[84] : <= 1000.0\n", + " d[85] : <= 1000.0\n", + " d[86] : <= 1000.0\n", + " d[87] : <= 1000.0\n", + " d[88] : <= 1000.0\n", + " d[89] : <= 1000.0\n", + " d[90] : <= 1000.0\n", + " d[91] : <= 1000.0\n", + " d[92] : <= 1000.0\n", + " d[93] : <= 1000.0\n", + " d[94] : <= 1000.0\n", + " d[95] : <= -0.0\n", + " d[96] : <= -0.0\n", + " d[97] : <= 1000.0\n", + " d[98] : <= 1000.0\n", + " d[99] : <= -0.0\n", + " d[100] : <= 1000.0\n", + " d[101] : <= 1000.0\n", + " d[102] : <= 1000.0\n", + " d[103] : <= 1000.0\n", + " d[104] : <= 1000.0\n", + " d[105] : <= 1000.0\n", + " d[106] : <= 1000.0\n", + " d[107] : <= -0.0\n", + " d[108] : <= 1000.0\n", + " d[109] : <= 1000.0\n", + " d[110] : <= -8.39\n", + " d[111] : <= -0.0\n", + " d[112] : <= 1000.0\n", + " d[113] : <= -0.0\n", + " d[114] : <= 1000.0\n", + " d[115] : <= -0.0\n", + " d[116] : <= 1000.0\n", + " d[117] : <= 1000.0\n", + " d[118] : <= -0.0\n", + " d[119] : <= -0.0\n", + " d[120] : <= 1000.0\n", + " d[121] : <= 1000.0\n", + " d[122] : <= 1000.0\n", + " d[123] : <= -0.0\n", + " d[124] : <= 1000.0\n", + " d[125] : <= -0.0\n", + " d[126] : <= -0.0\n", + " d[127] : <= 1000.0\n", + " d[128] : <= 1000.0\n", + " d[129] : <= -0.0\n", + " d[130] : <= 1000.0\n", + " d[131] : <= -0.0\n", + " d[132] : <= 1000.0\n", + " d[133] : <= 1000.0\n", + " d[134] : <= -0.0\n", + " d[135] : <= 1000.0\n", + " d[136] : <= 1000.0\n", + " d[137] : <= 1000.0\n", + " d[138] : <= -0.0\n", + " d[139] : <= -0.0\n", + " d[140] : <= -0.0\n", + " d[141] : <= 1000.0\n", + " d[142] : <= -0.0\n", + " d[143] : <= -0.0\n", + " d[144] : <= -0.0\n", + " d[145] : <= -0.0\n", + " d[146] : <= 10.0\n", + " d[147] : <= -0.0\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " d[148] : <= -0.0\n", + " d[149] : <= 1000.0\n", + " d[150] : <= 1000.0\n", + " d[151] : <= -0.0\n", + " d[152] : <= -0.0\n", + " d[153] : <= 1000.0\n", + " d[154] : <= 1000.0\n", + " d[155] : <= 1000.0\n", + " d[156] : <= -0.0\n", + " d[157] : <= -0.0\n", + " d[158] : <= 1000.0\n", + " d[159] : <= -0.0\n", + " d[160] : <= -0.0\n", + " d[161] : <= 1000.0\n", + " d[162] : <= -0.0\n", + " d[163] : <= -0.0\n", + " d[164] : <= 1000.0\n", + " d[165] : <= -0.0\n", + " d[166] : <= 1000.0\n", + " d[167] : <= 1000.0\n", + " d[168] : <= -0.0\n", + " d[169] : <= -0.0\n", + " d[170] : <= -0.0\n", + " d[171] : <= 1000.0\n", + " d[172] : <= -0.0\n", + " d[173] : <= -0.0\n", + " d[174] : <= 1000.0\n", + " d[175] : <= -0.0\n", + " d[176] : <= 1000.0\n", + " d[177] : <= 1000.0\n", + " d[178] : <= -0.0\n", + " d[179] : <= 1000.0\n", + " d[180] : <= -0.0\n", + " d[181] : <= -0.0\n", + " d[182] : <= 1000.0\n", + " d[183] : <= -0.0\n", + " d[184] : <= -0.0\n", + " d[185] : <= -0.0\n", + " d[186] : <= -0.0\n", + " d[187] : <= 1000.0\n", + " d[188] : <= 1000.0\n", + " d[189] : <= -0.0\n", + "Bounds\n", + " x[0] free\n", + " x[1] free\n", + " x[2] free\n", + " x[3] free\n", + " x[4] free\n", + " x[5] free\n", + " x[6] free\n", + " x[7] free\n", + " x[8] free\n", + " x[9] free\n", + " x[10] free\n", + " x[11] free\n", + " x[12] free\n", + " x[13] free\n", + " x[14] free\n", + " x[15] free\n", + " x[16] free\n", + " x[17] free\n", + " x[18] free\n", + " x[19] free\n", + " x[20] free\n", + " x[21] free\n", + " x[22] free\n", + " x[23] free\n", + " x[24] free\n", + " x[25] free\n", + " x[26] free\n", + " x[27] free\n", + " x[28] free\n", + " x[29] free\n", + " x[30] free\n", + " x[31] free\n", + " x[32] free\n", + " x[33] free\n", + " x[34] free\n", + " x[35] free\n", + " x[36] free\n", + " x[37] free\n", + " x[38] free\n", + " x[39] free\n", + " x[40] free\n", + " x[41] free\n", + " x[42] free\n", + " x[43] free\n", + " x[44] free\n", + " x[45] free\n", + " x[46] free\n", + " x[47] free\n", + " x[48] free\n", + " x[49] free\n", + " x[50] free\n", + " x[51] free\n", + " x[52] free\n", + " x[53] free\n", + " x[54] free\n", + " x[55] free\n", + " x[56] free\n", + " x[57] free\n", + " x[58] free\n", + " x[59] free\n", + " x[60] free\n", + " x[61] free\n", + " x[62] free\n", + " x[63] free\n", + " x[64] free\n", + " x[65] free\n", + " x[66] free\n", + " x[67] free\n", + " x[68] free\n", + " x[69] free\n", + " x[70] free\n", + " x[71] free\n", + " x[72] free\n", + " x[73] free\n", + " x[74] free\n", + " x[75] free\n", + " x[76] free\n", + " x[77] free\n", + " x[78] free\n", + " x[79] free\n", + " x[80] free\n", + " x[81] free\n", + " x[82] free\n", + " x[83] free\n", + " x[84] free\n", + " x[85] free\n", + " x[86] free\n", + " x[87] free\n", + " x[88] free\n", + " x[89] free\n", + " x[90] free\n", + " x[91] free\n", + " x[92] free\n", + " x[93] free\n", + " x[94] free\n" + ] + } + ], + "source": [ + "proc = pre_process(A, b, Aeq, beq)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From this, we get the processed A, b, Aeq and beq and we keep them in distinct variables correspodingly." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "A_proc = proc[0]\n", + "b_proc = proc[1]\n", + "Aeq_proc = proc[2]\n", + "beq_proc = proc[3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case you the ```pre_process``` step had already run, you may load its output using the following commands:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "A_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/A_preprocessed.npy')\n", + "b_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/b_preprocessed.npy')\n", + "Aeq_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/Aeq_preprocessed.npy')\n", + "beq_proc = np.load('/home/haris/Documents/GitHub/volesti_fork/volestipy/tests/beq_preprocessed.npy')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Aeq_proc.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Full dimensional (not always required step)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we are able to use the pre processed polytope to get the full dimensional polytope that derives from our initial one. To this end we first build an object for the ```low_dim_HPolytope``` class for the pre-processed polytope. " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "low_hp = low_dim_HPolytope(A_proc, b_proc, Aeq_proc, beq_proc)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then we run the ```full_dimensiolal_polytope``` function of ```volestipy``` to get it. " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "get_fd_hp = low_hp.full_dimensiolal_polytope()\n", + "\n", + "A_fd = get_fd_hp[0].A\n", + "b_fd = get_fd_hp[0].b\n", + "N = get_fd_hp[1]\n", + "N_shift = get_fd_hp[2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once we have the full dimensional polytope, we are able to get the max ball of that." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "max_ball_center_point, max_ball_radius = get_max_ball(A_fd, b_fd)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can use this max ball for rounding the full dimensional polytope. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Rounding" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the A and b of the full dimensional polytope, we build a new HPolytope object." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "hp = HPolytope(A_fd, b_fd)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And we use the max ball to round it." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "rounding_output_max_ellipsoid = hp.rounding(rounding_method = \"max_ellipsoid\", \n", + " inner_point = max_ball_center_point, \n", + " radius = max_ball_radius)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can now get the features or the rounded polytope." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_A = rounding_output_max_ellipsoid[0]\n", + "rounded_b = rounding_output_max_ellipsoid[1]\n", + "rounded_T = rounding_output_max_ellipsoid[2]\n", + "rounded_shift = rounding_output_max_ellipsoid[3]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And use the to get the max ball of this full dimensional, rounded polytope." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_center_point, rounded_radius = get_max_ball(rounded_A, rounded_b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look at that:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[-1.0827203738869838e-08,\n", + " 5.46699607224613e-09,\n", + " -1.9440816473264214e-09,\n", + " 4.202258767454394e-09,\n", + " -5.720196183334541e-09,\n", + " -2.34495800347931e-09,\n", + " 3.4714599880184695e-09,\n", + " -1.0610740112672796e-10,\n", + " 1.5374959601778526e-09,\n", + " 6.363085780165716e-09,\n", + " 7.47879143571297e-09,\n", + " 4.875192491832598e-10,\n", + " -1.5540451275577207e-09,\n", + " 1.8233604962779356e-09,\n", + " -6.1940535936238185e-09,\n", + " -3.027059547527763e-10,\n", + " 5.372701921624584e-09,\n", + " 1.8968608527828443e-09,\n", + " 8.502848362572111e-10,\n", + " 1.4118646354600406e-09,\n", + " -6.156855514982069e-10,\n", + " 8.125766689870477e-10,\n", + " 5.389284100671947e-10,\n", + " -1.7114008103486753e-10]" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rounded_center_point" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1.0000000081541534" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rounded_radius" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sampling" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we build the full dimenionsal rounded polytope. " + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [], + "source": [ + "rounded_polytope = HPolytope(rounded_A, rounded_b)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Keep the dimension of the rounded polytope" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "24" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "d = rounded_polytope.dimensions\n", + "d" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And calculate the value of the L parameter for the sampling function according the following formula:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [], + "source": [ + "L_value = 4 * d * rounded_radius" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And using the latter max ball, we sample on it" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [], + "source": [ + "samples = rounded_polytope.generate_samples(walk_len = 5, \n", + " number_of_points = 10000, \n", + " number_of_points_to_burn = 50, \n", + " radius = rounded_radius, \n", + " inner_point = rounded_center_point,\n", + " L = L_value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And these are the points sampled: " + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[-1.08272037e-08, 5.46699607e-09, -1.94408165e-09, ...,\n", + " -3.83700337e-01, 5.38928410e-10, -1.71140081e-10],\n", + " [-1.08272037e-08, 5.46699607e-09, -1.94408165e-09, ...,\n", + " -3.83700337e-01, 5.38928410e-10, -1.71140081e-10],\n", + " [-1.08272037e-08, 5.46699607e-09, 5.03033014e-01, ...,\n", + " -3.83700337e-01, 1.45401219e-02, -1.71140081e-10],\n", + " ...,\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00],\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00],\n", + " [-7.39181088e-01, 5.91825249e-01, -1.54594975e-01, ...,\n", + " -5.91470135e-01, 8.16609257e-01, -2.23777838e+00]])" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "samples" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, these samples \"live\" in the world of the rounded, full dimensional polytope. Thus, we need to map them back in our initial polyopte. To do that we run one last ```volestipy``` function, using the features returned from the ```rounding``` and the ```full_dimensional``` functions. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [], + "source": [ + "mapped_samples = map_samples_on_initial_polytope(samples, rounded_T, rounded_shift, N, N_shift)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's have a look on our final points and their dimension. " + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(95, 10000)" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "mapped_samples.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Analysis, plots etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will use the ```matplotlib``` library to plot our random samples. First, we download it to our environment." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "collapsed": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting matplotlib\n", + " Using cached matplotlib-3.3.2-cp36-cp36m-manylinux1_x86_64.whl (11.6 MB)\n", + "Collecting kiwisolver>=1.0.1\n", + " Using cached kiwisolver-1.2.0-cp36-cp36m-manylinux1_x86_64.whl (88 kB)\n", + "Collecting cycler>=0.10\n", + " Using cached cycler-0.10.0-py2.py3-none-any.whl (6.5 kB)\n", + "Collecting pillow>=6.2.0\n", + " Using cached Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl (2.2 MB)\n", + "Requirement already satisfied: python-dateutil>=2.1 in /home/haris/.local/lib/python3.6/site-packages (from matplotlib) (2.8.0)\n", + "Requirement already satisfied: pyparsing!=2.0.4,!=2.1.2,!=2.1.6,>=2.0.3 in /home/haris/.local/lib/python3.6/site-packages (from matplotlib) (2.4.0)\n", + "Requirement already satisfied: numpy>=1.15 in /home/haris/anaconda3/envs/py36/lib/python3.6/site-packages (from matplotlib) (1.19.1)\n", + "Collecting certifi>=2020.06.20\n", + " Downloading certifi-2020.6.20-py2.py3-none-any.whl (156 kB)\n", + "\u001b[K |████████████████████████████████| 156 kB 576 kB/s eta 0:00:01\n", + "\u001b[?25hRequirement already satisfied: six in /home/haris/.local/lib/python3.6/site-packages (from cycler>=0.10->matplotlib) (1.12.0)\n", + "Installing collected packages: kiwisolver, cycler, pillow, certifi, matplotlib\n", + " Attempting uninstall: certifi\n", + " Found existing installation: certifi 2019.6.16\n", + " Uninstalling certifi-2019.6.16:\n", + " Successfully uninstalled certifi-2019.6.16\n", + "\u001b[31mERROR: After October 2020 you may experience errors when installing or updating packages. This is because pip will change the way that it resolves dependency conflicts.\n", + "\n", + "We recommend you use --use-feature=2020-resolver to test your packages with the new resolver before it becomes the default.\n", + "\n", + "requests 2.22.0 requires chardet<3.1.0,>=3.0.2, which is not installed.\n", + "cwltool 1.0.20190621234233 requires future, which is not installed.\u001b[0m\n", + "Successfully installed certifi-2020.6.20 cycler-0.10.0 kiwisolver-1.2.0 matplotlib-3.3.2 pillow-7.2.0\n", + "Note: you may need to restart the kernel to use updated packages.\n" + ] + } + ], + "source": [ + "pip install matplotlib" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can import it." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us assume now that we are insteresd in the Ethanol reversible transport via proton symport reaction. This is called ```ETOHt2r```. As you can see, this is the 36th element in our ```reactions``` list." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'PTAr'" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "reactions[22]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We keep all the fluxes' values from the points sampled for this reactions in a variable. And we print its shape to be sure that we have got this right." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(10000,)" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fluxes = mapped_samples[22,:]\n", + "fluxes.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can get the minimum and the maximum value of ETOHt2r flux." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(8.488618241774088, -4.3178112120710377e-14)" + ] + }, + "execution_count": 35, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "maxElement = np.amax(fluxes)\n", + "minElement = np.amin(fluxes)\n", + "maxElement, minElement" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And now we may plot our samples! " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "x = np.array([x for x in range(samples.shape[0])])\n", + "plt.plot(x, fluxes)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And also as an histogram!" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 41, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.hist(fluxes, bins='auto', histtype='bar', rwidth=0.7)\n", + "plt.show" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extras" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In case you need to work with ```.mat``` files you need to implement some further steps that are not in the interest of this tutorial. \n", + "\n", + "To read a ```.mat``` file you need some extra Python libraries, as it is quite a challenging task. If you are more interested in that, you can read this article [here](https://scipy-cookbook.readthedocs.io/items/Reading_mat_files.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the h5py library in case you are working with .mat files of 7.3 release of Matlab and after \n", + "#!sudo -H -S pip install h5py < /home/haris/Desktop/running/metabolic_network_pipeline_volestipy/\\\n", + "#my_project_virtual_env/error.txt\n", + "#print(\"*** The h5py library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the tables library to read .mat files\n", + "#!sudo -H -S pip3 install tables < /home/haris/Desktop/running/metabolic_network_pipeline_volestipy\\\n", + "#/my_project_virtual_env/error.txt\n", + "#print(\"*** The tables library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Matlab up to 7.1 = mat files created with Matlab up to version 7.1 can be read using the mio module part of scipy.io.\n", + "#from scipy.io import loadmat \n", + "#\n", + "## Beginning at release 7.3 of Matlab, mat files are actually saved using the HDF5 format by default (except if you use the -vX flag at save time, see in Matlab). These files can be read in Python using, for instance, the PyTables or h5py package\n", + "#import tables \n", + "#import h5py" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "## Get the ggplot - oriented Python library\n", + "#!sudo -H -S pip3 install -t \"/home/haris/anaconda3/lib/python3.7/site-packages/\" --upgrade pandas plotnine \\\n", + "#< /home/haris/Desktop/running/metabolic_network_pipeline_volestipy/my_project_virtual_env/error.txt\n", + "#print(\"*** The ggplot for Python library has now been installed *** \\n\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#mat_file_with_loadmat = loadmat('/home/haris/Downloads/e_coli_core.mat')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While this one is in case of ```.mat``` files created by releases of Matlab later after the 7.3\n", + "This command will not run in any other case.\n", + "For this demo we will use the ```loadmat``` option." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# mat_file_with_tables = h5py.File('/home/haris/Downloads/e_coli_core.mat')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now you can see your metabolic network. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(mat_file_with_loadmat)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#data_from_mat = mat_file_with_loadmat\n", + "#print(\"the data type of the variable with the network as it was read is: \" + str(type(data_from_mat)))\n", + "\n", + "#s_matrix = data_from_mat.keys()\n", + "#print(\"\\nthe keys of this dictionaries are: \")\n", + "#print(s_matrix)\n", + "\n", + "#e_coli_np_void = data_from_mat['e_coli_core'][0][0]\n", + "#print(\"\\nHowever, if we keep the key:value pair of this dictionary, called 'e_coli_core' where the necessary \\\n", + "#information is located, we can see that its type is: \" + str(type(e_coli_np_void)) + \"\\n\\n\")\n", + "\n", + "#print(\"number of dimensions of the np.void data type equals to:\" + str(e_coli_np_void.ndim) + \"\\n\")\n", + "\n", + "#print(type(e_coli_np_void))\n", + "#print(len(e_coli_np_void))\n", + "\n", + "\n", + "\n", + "## metabolites\n", + "#print(type(e_coli_np_void[0]))\n", + "#print(e_coli_np_void[0].shape)\n", + "\n", + "#print(type(e_coli_np_void[0][0]))\n", + "#print(e_coli_np_void[0][0].shape)\n", + "\n", + "#print(e_coli_np_void[0][:3,])\n", + "#metabolites = [item[0][0] for item in e_coli_np_void[0]]\n", + "#print(metabolites)\n", + "\n", + "## genes\n", + "#print(type(e_coli_np_void[4]))\n", + "#print(e_coli_np_void[4].shape)\n", + "#print(e_coli_np_void[4][:3,])\n", + "\n", + "## reactions\n", + "#print(type(e_coli_np_void[7]))\n", + "#print(e_coli_np_void[7].shape)\n", + "#print(e_coli_np_void[7][:3,])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#for key,value in data_from_mat.items():\n", + "# print(str(key) + \"\\t\" + str(value))\n", + "# print(\"\\n\\n\\n\\n\\n\\n\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.6.12" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/volestipy/tests/test_compute_max_ball.py b/volestipy/tests/test_compute_max_ball.py index 2232ddee2..fd9151f57 100755 --- a/volestipy/tests/test_compute_max_ball.py +++ b/volestipy/tests/test_compute_max_ball.py @@ -5,7 +5,7 @@ import scipy.sparse as sp if __name__ == "__main__": - + m = 2 n = 5 @@ -24,5 +24,3 @@ print(max_ball[0]) print("The radius of max ball equals to:") print(max_ball[1]) - - diff --git a/volestipy/tests/test_ecoli_full_pipeline.py b/volestipy/tests/test_ecoli_full_pipeline.py new file mode 100755 index 000000000..8768d4fcf --- /dev/null +++ b/volestipy/tests/test_ecoli_full_pipeline.py @@ -0,0 +1,89 @@ +#!/usr/bin/python3 + +import numpy as np +import gurobipy as gp +from volestipy import * +import matplotlib.pyplot as plt +import sys + +# Set a variable with the input / metabolic network file +input_file = 'bigg_files/e_coli_core.json' + +# Read json +read_ecoli_core = read_json_file(input_file) + +# Pre-process it +A = read_ecoli_core[0] +b = read_ecoli_core[1] +Aeq = read_ecoli_core[2] +beq = read_ecoli_core[3] + + +# Pre-process it +proc = pre_process(A, b, Aeq, beq) + +A_proc = proc[0] +b_proc = proc[1] +Aeq_proc = proc[2] +beq_proc = proc[3] +min_fluxes = proc[4] +max_fluxes = proc[5] + +# Get an object for the low_dim_HPolytope class for the pre-processed polytope +low_hp = low_dim_HPolytope(A_proc, b_proc, Aeq_proc, beq_proc) +#low_hp = low_dim_HPolytope(A, b, Aeq, beq) + + +## And then get the full dimensional polytope +get_fd_hp = low_hp.full_dimensiolal_polytope() +A_fd = get_fd_hp[0].A +b_fd = get_fd_hp[0].b +N = get_fd_hp[1] +N_shift = get_fd_hp[2] + +# Get the max ball for the full dimensional polytope +max_ball_center_point, max_ball_radius = get_max_ball(A_fd, b_fd) + +### Now we can use the full dimensional polytope; but before sampling on it, we need to round it + +# First, initialize an HPolytope using the full dimensional polytope features we got +hp = HPolytope(A_fd, b_fd) + +## Then use one of the volestipy functions for rounding +rounding_returns = ["new_A","new_b","T_matrix","shift","round_val"] + +# Rounding by making use of max ball and the max_ellipsoid method +rounding_output_max_ellipsoid = hp.rounding(rounding_method = "max_ellipsoid", inner_point = max_ball_center_point, radius = max_ball_radius) +rounded_A = rounding_output_max_ellipsoid[0] +rounded_b = rounding_output_max_ellipsoid[1] +rounded_T = rounding_output_max_ellipsoid[2] +rounded_shift = rounding_output_max_ellipsoid[3] + +## Finally, generate random samples from the rounded full dimensional polytope + +# Get the max ball for the rounded polytope +rounded_center_point, rounded_radius = get_max_ball(rounded_A, rounded_b) + +# Build the rounded polytope +rounded_polytope = HPolytope(rounded_A, rounded_b) + +# and calculate L parameter for sampling +d = rounded_polytope.dimensions +L_value = 4 * d * rounded_radius + +# Then, sample on it +samples = rounded_polytope.generate_samples(walk_len = 5, number_of_points = 10000, number_of_points_to_burn = 50, \ + radius = rounded_radius, inner_point = rounded_center_point, L = L_value) + +# Now map the points retrieved to the initial polytope +mapped_samples = map_samples_on_initial_polytope(samples, rounded_T, rounded_shift, N, N_shift) + +# Plot the distribution of the flux unde study, e.g ATPS4r +fluxes = mapped_samples[21,:] +plt.hist(fluxes, bins='auto', histtype='bar', rwidth=0.7) +plt.savefig('flux_22.png') + +print("minimum values of each flux") +print(min_fluxes) +print("maximum values of each flux") +print(max_fluxes) diff --git a/volestipy/tests/test_full_pipeline.py b/volestipy/tests/test_full_pipeline.py index 3fb3e88a1..b0749daa0 100755 --- a/volestipy/tests/test_full_pipeline.py +++ b/volestipy/tests/test_full_pipeline.py @@ -1,12 +1,12 @@ -#!/usr/bin/python3.6 +#!/usr/bin/python3 import numpy as np import gurobipy as gp from volestipy import * import sys -input_file = 'bigg_files/e_coli_core.json' - +# Set a variable with the input / metabolic network file +input_file = 'bigg_files/iZ_1308.json' # Read json read_ecoli_core = read_json_file(input_file) @@ -15,8 +15,11 @@ A = read_ecoli_core[0] b = read_ecoli_core[1] Aeq = read_ecoli_core[2] +Aeq = np.ascontiguousarray(Aeq) beq = read_ecoli_core[3] + + # Pre-process it proc = pre_process(A, b, Aeq, beq) A_proc = proc[0] @@ -24,19 +27,42 @@ Aeq_proc = proc[2] beq_proc = proc[3] + + + +sys.exit(0) + + + + +#A_proc = np.load('A_preprocessed.npy') +#b_proc = np.load('b_preprocessed.npy') +#Aeq_proc = np.load('Aeq_preprocessed.npy') +#beq_proc = np.load('beq_preprocessed.npy') + + + # Get an object for the low_dim_HPolytope class for the pre-processed polytope -low_hp = low_dim_HPolytope(A_proc, b_proc, Aeq_proc, beq_proc) +low_hp = low_dim_HPolytope(A, b, Aeq, beq) +print("object ok") + -# And then get the full dimensional polytope -get_fd_hp = low_hp.full_dimensiolal_polytope() -A_fd = get_fd_hp[0].A -b_fd = get_fd_hp[0].b +## And then get the full dimensional polytope +#get_fd_hp = low_hp.full_dimensiolal_polytope() +#A_fd = get_fd_hp[0].A +#b_fd = get_fd_hp[0].b +#N = get_fd_hp[1] +#N_shift = get_fd_hp[2] -print("\n\n *** This is the full dimensional polytope ***") -print(A_fd) -print(b_fd) +#print("\n\n *** This is the full dimensional polytope ***") +#print(A_fd) +#print(b_fd) +A_fd = np.load('A_full_dim.npy') +b_fd = np.load('b_full_dim.npy') +N = np.load('N_full_dim.npy') +N_shift = np.load('shift_full_dim.npy') # Get the max ball for the full dimensional polytope print("\n\n\n We are about to calculate max ball") @@ -45,6 +71,11 @@ print(max_ball_center_point) print(max_ball_radius) + + +sys.exit(0) + + ### Now we can use the full dimensional polytope; but before sampling on it, we need to round it # First, initialize an HPolytope using the full dimensional polytope features we got @@ -52,18 +83,41 @@ print("An HP was built out of the full dimensional polytope features") ## Then use one of the volestipy functions for rounding -print("\n\n Rounding is about to start") -rounding_output_min_ellipsoid = hp.rounding(rounding_method = "min_ellipsoid") - rounding_returns = ["new_A","new_b","T_matrix","shift","round_val"] -for i in range(len(rounding_output_min_ellipsoid)): - print("\n" + rounding_returns[i] + ": ") - print(rounding_output_min_ellipsoid[i]) -# Check for the rest rounding methods -rounding_output_max_ellipsoid = hp.rounding(rounding_method = "max_ellipsoid") + +# Rounding by making use of max ball and the max_ellipsoid method +print("Rounding with max ball and max_ellipsoid \n") +rounding_output_max_ellipsoid = hp.rounding(rounding_method = "max_ellipsoid", inner_point = max_ball_center_point, radius = max_ball_radius) +rounded_A = rounding_output_max_ellipsoid[0] +rounded_b = rounding_output_max_ellipsoid[1] +rounded_T = rounding_output_max_ellipsoid[2] +rounded_shift = rounding_output_max_ellipsoid[3] + for i in range(len(rounding_output_max_ellipsoid)): print("\n" + rounding_returns[i] + ": ") print(rounding_output_max_ellipsoid[i]) +## Finally, generate random samples from the rounded full dimensional polytope + +# Get the max ball for the rounded polytope +rounded_center_point, rounded_radius = get_max_ball(rounded_A, rounded_b) + +# Build the rounded polytope +rounded_polytope = HPolytope(rounded_A, rounded_b) + + +# Then, sample on it +samples = rounded_polytope.generate_samples(walk_len = 5, number_of_points = 10000, number_of_points_to_burn = 50, radius = rounded_radius, inner_point = rounded_center_point) +print("\n >> This is the output for random sampling algorithm using max ball on a rounded polytope <<\n") +print("Samples:") +print(samples) +print(type(samples)) + + +# Now map the points retrieved to the initial polytope +print("Points sampled are under mapping") +final_output = map_samples_on_initial_polytope(samples, rounded_T, rounded_shift, N, N_shift) +print("These are the final points") +print(final_output) diff --git a/volestipy/tests/test_read_bigg_files.py b/volestipy/tests/test_read_bigg_files.py index 1fcfe607c..deaa00393 100755 --- a/volestipy/tests/test_read_bigg_files.py +++ b/volestipy/tests/test_read_bigg_files.py @@ -50,6 +50,4 @@ print(met_net[4]) print("-------------------------") print("Reactions are the following " + str(len(met_net[5])) + ":") -print(met_net[5]) - - +print(met_net[5]) diff --git a/volestipy/volestipy/include/bindings.h b/volestipy/volestipy/include/bindings.h index 3dc2e904c..4aabe65b5 100644 --- a/volestipy/volestipy/include/bindings.h +++ b/volestipy/volestipy/include/bindings.h @@ -48,7 +48,6 @@ class HPolytopeCPP{ // regarding the rounding step typedef std::tuple round_result; - // The class and its main specs HPolytopeCPP(); HPolytopeCPP(double *A, double *b, int n_hyperplanes, int n_variables); @@ -61,11 +60,14 @@ class HPolytopeCPP{ double compute_volume(char* vol_method, char* walk_method, int walk_len, double epsilon, int seed); // the generate_samples() function - double generate_samples(int walk_len, int number_of_points, int number_of_points_to_burn, bool boundary, \ - bool cdhr, bool rdhr, bool gaussian, bool set_L, bool billiard, bool ball_walk, double a, double L, double* samples); + double generate_samples(int walk_len, int number_of_points, int number_of_points_to_burn, bool boundary, + bool cdhr, bool rdhr, bool gaussian, bool set_L, bool accelerated_billiard, bool billiard, bool ball_walk, double a, double L, + bool max_ball, double* inner_point, double radius, + double* samples); // the rounding() function - void rounding(char* rounding_method, double* new_A, double* new_b, double* T_matrix, double* shift, double &round_value); + void rounding(char* rounding_method, double* new_A, double* new_b, double* T_matrix, double* shift, double &round_value, + bool max_ball, double* inner_point, double radius); }; diff --git a/volestipy/volestipy/src/bindings.cpp b/volestipy/volestipy/src/bindings.cpp index a07cc0f47..5364e0491 100644 --- a/volestipy/volestipy/src/bindings.cpp +++ b/volestipy/volestipy/src/bindings.cpp @@ -4,9 +4,9 @@ using namespace std; -// >>> This is the main HPolytopeCPP class where the compute_volume(), the rounding() and the sampling() volesti methods are included <<< +// >>> Main HPolytopeCPP class; compute_volume(), rounding() and generate_samples() volesti methods are included <<< -// here is the initialization of the HPolytopeCPP class +// Here is the initialization of the HPolytopeCPP class HPolytopeCPP::HPolytopeCPP() {} HPolytopeCPP::HPolytopeCPP(double *A_np, double *b_np, int n_hyperplanes, int n_variables){ @@ -27,11 +27,12 @@ HPolytopeCPP::HPolytopeCPP(double *A_np, double *b_np, int n_hyperplanes, int n_ HP.init(n_variables, A, b); CheBall = HP.ComputeInnerBall(); } -// after this we need to use a destructor for the HPolytopeCPP object +// Use a destructor for the HPolytopeCPP object HPolytopeCPP::~HPolytopeCPP(){} -////////// start of "compute_volume" ////////// -double HPolytopeCPP::compute_volume(char* vol_method, char* walk_method, int walk_len, double epsilon, int seed){ +////////// Start of "compute_volume" ////////// +double HPolytopeCPP::compute_volume(char* vol_method, char* walk_method, + int walk_len, double epsilon, int seed){ double volume; @@ -65,57 +66,114 @@ double HPolytopeCPP::compute_volume(char* vol_method, char* walk_method, int wal } return volume; } -////////// end of "compute_volume()" ////////// +////////// End of "compute_volume()" ////////// -////////// start of "generate_samples()" ////////// -double HPolytopeCPP::generate_samples(int walk_len, int number_of_points, int number_of_points_to_burn, bool boundary, bool cdhr, bool rdhr, bool gaussian, bool set_L, bool billiard, bool ball_walk, double a, double L, double* samples){ - +////////// Start of "generate_samples()" ////////// +double HPolytopeCPP::generate_samples(int walk_len, int number_of_points, + int number_of_points_to_burn, bool boundary, + bool cdhr, bool rdhr, bool gaussian, bool set_L, + bool accelerated_billiard, bool billiard, + bool ball_walk, double a, double L, bool max_ball, + double* inner_point, double radius, double* samples){ + RNGType rng(HP.dimension()); - std::list rand_points; + HP.normalize(); + + int d = HP.dimension(); + Point starting_point; + + // Check for max ball given + if (max_ball == true){ - //Point default_starting_point = HP.ComputeInnerBall().first; - Point starting_point = HP.ComputeInnerBall().first; + VT inner_vec(d); + for (int i = 0; i < d; i++){ + inner_vec(i) = inner_point[i]; + } + + Point inner_point2(inner_vec); + CheBall = std::pair(inner_point2, radius); + HP.set_InnerBall(CheBall); + starting_point = inner_point2; + + } else { + + //Point default_starting_point = HP.ComputeInnerBall().first; + starting_point = HP.ComputeInnerBall().first; + } + + std::list rand_points; if (boundary == true) { if (cdhr == true) { - uniform_sampling_boundary(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling_boundary(rand_points, HP, rng, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); } else { - uniform_sampling_boundary(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling_boundary(rand_points, HP, rng, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); } } else if (cdhr == true) { if (gaussian == true) { - gaussian_sampling(rand_points, HP, rng, walk_len, number_of_points, a, starting_point, number_of_points_to_burn); + gaussian_sampling(rand_points, HP, rng, walk_len, + number_of_points, a, starting_point, + number_of_points_to_burn); } else { - uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, + starting_point, number_of_points_to_burn); } } else if (rdhr == true){ if (gaussian == true) { - gaussian_sampling(rand_points, HP, rng, walk_len, number_of_points, a, starting_point, number_of_points_to_burn); + gaussian_sampling(rand_points, HP, rng, walk_len, + number_of_points, a, starting_point, + number_of_points_to_burn); } else { - uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, + starting_point, number_of_points_to_burn); } } else if (billiard == true) { if (set_L == true) { BilliardWalk WalkType(L); - uniform_sampling(rand_points, HP, rng, WalkType, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, WalkType, walk_len, number_of_points, + starting_point, number_of_points_to_burn); } else { - uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); + } + } else if (accelerated_billiard == true) { + if (set_L == true) { + AcceleratedBilliardWalk WalkType(L); + uniform_sampling(rand_points, HP, rng, WalkType, walk_len, number_of_points, + starting_point, number_of_points_to_burn); + } else { + uniform_sampling(rand_points, HP, rng, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); } } else { if (set_L == true) { if (gaussian == true) { GaussianBallWalk WalkType(L); - gaussian_sampling(rand_points, HP, rng, WalkType, walk_len, number_of_points, a, starting_point, number_of_points_to_burn); + gaussian_sampling(rand_points, HP, rng, WalkType, walk_len, + number_of_points, a, starting_point, + number_of_points_to_burn); } else { BallWalk WalkType(L); - uniform_sampling(rand_points, HP, rng, WalkType, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, WalkType, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); } } else { if (gaussian == true) { - gaussian_sampling(rand_points, HP, rng, walk_len, number_of_points, a, starting_point, number_of_points_to_burn); + gaussian_sampling(rand_points, HP, rng, walk_len, + number_of_points, a, starting_point, + number_of_points_to_burn); } else { - uniform_sampling(rand_points, HP, rng, walk_len, number_of_points, starting_point, number_of_points_to_burn); + uniform_sampling(rand_points, HP, rng, walk_len, + number_of_points, starting_point, + number_of_points_to_burn); } } } @@ -129,16 +187,37 @@ double HPolytopeCPP::generate_samples(int walk_len, int number_of_points, int nu } } } -////////// end of "generate_samples()" ////////// +////////// End of "generate_samples()" ////////// -////////// start of "rounding()" ////////// -void HPolytopeCPP::rounding(char* rounding_method, double* new_A, double* new_b, double* T_matrix, double* shift, double &round_value){ +////////// Start of "rounding()" ////////// +void HPolytopeCPP::rounding(char* rounding_method, double* new_A, double* new_b, + double* T_matrix, double* shift, double &round_value, + bool max_ball, double* inner_point, double radius){ // make a copy of the initial HP which will be used for the rounding step auto P(HP); RNGType rng(P.dimension()); - CheBall = P.ComputeInnerBall(); + P.normalize(); + + // check for max ball given + if (max_ball == true ){ + + // if yes, then read the inner point provided by the user and the radius + int d = P.dimension(); + VT inner_vec(d); + + for (int i = 0; i < d; i++){ + inner_vec(i) = inner_point[i]; + } + + Point inner_point2(inner_vec); + CheBall = std::pair(inner_point2, radius); + + } else if (max_ball == false ) { + CheBall = P.ComputeInnerBall(); + } + // set the output variable of the rounding step round_result round_res; @@ -148,11 +227,14 @@ void HPolytopeCPP::rounding(char* rounding_method, double* new_A, double* new_b, // run the rounding method if (strcmp(rounding_method,"min_ellipsoid") == 0){ - round_res = min_sampling_covering_ellipsoid_rounding(P, CheBall, walk_len, rng); + round_res = min_sampling_covering_ellipsoid_rounding(P, + CheBall, + walk_len, + rng); } else if (strcmp(rounding_method,"svd") == 0){ round_res = svd_rounding(P, CheBall, walk_len, rng); } else if (strcmp(rounding_method, "max_ellipsoid") == 0){ - round_res = max_inscribed_ellipsoid_rounding(P, CheBall); + round_res = max_inscribed_ellipsoid_rounding(P, CheBall.first); } // create the new_A matrix @@ -192,16 +274,18 @@ void HPolytopeCPP::rounding(char* rounding_method, double* new_A, double* new_b, round_value = get<2>(round_res); } -////////// end of "rounding()" ////////// +////////// End of "rounding()" ////////// -// >>> This is the lowDimHPolytopeCPP class where the pre_processing() and the get_full_dimensional_polytope() volesti methods are included <<< +// >>> The lowDimHPolytopeCPP class; the pre_processing() and the get_full_dimensional_polytope() volesti methods are included <<< lowDimHPolytopeCPP::lowDimHPolytopeCPP() {} -// initialize the low dimensional polytope object -lowDimHPolytopeCPP::lowDimHPolytopeCPP(double *A_np, double *b_np, double *A_aeq_np, double *b_aeq_np, int n_rows_of_A, int n_cols_of_A, int n_row_of_Aeq, int n_cols_of_Aeq){ +// Initialize the low dimensional polytope object +lowDimHPolytopeCPP::lowDimHPolytopeCPP(double *A_np, double *b_np, double *A_aeq_np, + double *b_aeq_np, int n_rows_of_A, int n_cols_of_A, + int n_row_of_Aeq, int n_cols_of_Aeq){ A.resize(n_rows_of_A,n_cols_of_A); b.resize(n_rows_of_A); @@ -227,12 +311,13 @@ lowDimHPolytopeCPP::lowDimHPolytopeCPP(double *A_np, double *b_np, double *A_aeq } } } -// now we need a destructor! - never forget about this! +// Destructor! - never forget about this! lowDimHPolytopeCPP::~lowDimHPolytopeCPP(){} -// here is the class that returns the full dimensional polytope -int lowDimHPolytopeCPP::full_dimensiolal_polytope(double* N_extra_trans, double* shift, double* A_full_extra_trans, double* b_full){ +// Function to get the full dimensional polytope +int lowDimHPolytopeCPP::full_dimensiolal_polytope(double* N_extra_trans, double* shift, + double* A_full_extra_trans, double* b_full){ get_full_dim_pol_result result; @@ -273,7 +358,8 @@ int lowDimHPolytopeCPP::full_dimensiolal_polytope(double* N_extra_trans, double* shift[i] = shift_temp[i]; } - // as we know that N_temp.cols == full_HP_A.cols and likewise for their lines, we may return just one of those vars + // as we know that N_temp.cols == full_HP_A.cols and likewise for their lines, + // we may return just one of those vars return N_temp_trans.rows(); -} +} diff --git a/volestipy/volestipy/volestipy.pyx b/volestipy/volestipy/volestipy.pyx index 58c230d64..6f3b07c85 100644 --- a/volestipy/volestipy/volestipy.pyx +++ b/volestipy/volestipy/volestipy.pyx @@ -28,104 +28,114 @@ def get_time_seed(): return int(time.time()) ## Read a Bigg file and get the necessary A and b -# The .json format case +# The .json format case def read_json_file(input_file): - + with open(input_file, 'r') as f: - + distros_dict = json.load(f) - + reactions_list = distros_dict['reactions'] - + metabolites = [] reactions = [] - + for reaction in reactions_list: - + metabolites_dic = reaction['metabolites'] reaction_name = reaction['id'] reactions.append(reaction_name) - + for metabolite in metabolites_dic.keys(): if metabolite not in metabolites: metabolites.append(metabolite) - + list_of_reaction_lists = [] vector_of_ubs = [] vector_of_lbs = [] - + for reaction in reactions_list: - + ub = float(reaction['upper_bound']) ; vector_of_ubs.append(ub) lb = float(reaction['lower_bound']) ; vector_of_lbs.append(lb) - + metabolites_dic = reaction['metabolites'] reaction_vector = [] - + for term in range(len(metabolites)): - + metabolite = metabolites[term] - + if metabolite in metabolites_dic.keys(): - + reaction_vector.append(metabolites_dic[metabolite]) else: reaction_vector.append(0) - + list_of_reaction_lists.append(reaction_vector) - + f.close() - + # Build function's output; first the A matrix n = len(list_of_reaction_lists) A = np.zeros((2*n, n), dtype=np.float) A[0:n] = np.eye(n) A[n:] -= np.eye(n,n, dtype=np.float) - + # Now, the b vector vector_of_lbs = [-x for x in vector_of_lbs] b = np.asarray(vector_of_ubs + vector_of_lbs) - + # The Aeq matrix Aeq = np.asarray(list_of_reaction_lists) Aeq = np.transpose(Aeq) - + # And the beq vector m = len(metabolites) beq = np.zeros(m) + # Make everything C contigeous + A = np.asarray(A, dtype = 'float') + A = np.ascontiguousarray(A, dtype='float') + b = np.asarray(b, dtype = 'float') + b = np.ascontiguousarray(b, dtype='float') + Aeq = np.asarray(Aeq, dtype = 'float') + Aeq = np.ascontiguousarray(Aeq, dtype='float') + beq = np.asarray(beq, dtype = 'float') + beq = np.ascontiguousarray(beq, dtype='float') + return A, b, Aeq, beq, metabolites, reactions -# The .mat format case +# The .mat format case def read_mat_file(input_file): data_from_mat = scipy.io.loadmat(input_file) - + species_name = '' for key in data_from_mat.keys(): if key[0] != "_": species_name = key - + species = data_from_mat[species_name] list_of_lists = species.tolist() - + counter = 0 - + metabolites = [] - + for element in list_of_lists[0][0]: - + if counter == 0: - + m =len(element) - + for i in element: - + metabolite = i[0][0] - + if metabolite not in metabolites: metabolites.append(metabolite) - + if counter == 7: reactions_list = element.tolist() reactions = [reaction[0][0] for reaction in reactions_list] @@ -136,26 +146,26 @@ def read_mat_file(input_file): ub_tmp = element if counter == 10: Aeq = element - + counter += 1 - + # Build function's output; first the A matrix n = len(ub_tmp) A = np.zeros((2*n, n), dtype=np.float) A[0:n] = np.eye(n) A[n:] -= np.eye(n,n, dtype=np.float) - + # Now, the b vector ub = [i[0] for i in ub_tmp] lb = [-x[0] for x in lb_tmp] b = np.asarray(ub + lb) - + # The Aeq matrix Aeq = np.asarray(Aeq) - + # And the beq vector beq = np.zeros(m) - + return A, b, Aeq, beq, metabolites, reactions # Build a Python functionto pre-process the metabolic network; meaning to remove really "small" facets. @@ -167,6 +177,9 @@ def pre_process(A, b, Aeq, beq): beq_new = beq A_new = np.zeros((0,d)) b_new = [] # this need to be a vector; we do not know its length + + min_fluxes = [] + max_fluxes = [] try: @@ -174,107 +187,118 @@ def pre_process(A, b, Aeq, beq): with gp.Env(empty=True) as env: env.setParam('OutputFlag', 0) env.start() - + with gp.Model(env=env) as model: - + # Create variables x = model.addMVar(shape = d, vtype = GRB.CONTINUOUS , name = "x", lb = -GRB.INFINITY, ub = GRB.INFINITY) - + # Make sparse Aeq + # Aeq = np.array(Aeq, dtype=float) + # Aeq_sparse = sp.csr_matrix(Aeq.astype(np.float)) Aeq_sparse = sp.csr_matrix(Aeq) - + # Make A sparse - A_sparse = sp.csr_matrix(A) - + # A = np.array(A, dtype=float) + # A_sparse = sp.csr_matrix(A.astype(np.float)) + A_sparse = sp.csr_matrix(A) + # Set the b and beq vectors as numpy vectors b = np.array(b) beq = np.array(beq) - + # Add constraints model.addMConstrs(Aeq_sparse, x, '=', beq, name = "c") - + # Update the model to include the constraints added model.update() - + ####################### - # After getting the constraints you need to add the bounds; ObjBound might work: https://www.gurobi.com/documentation/9.0/refman/objbound.html#attr:ObjBound + # After getting the constraints you need to add the bounds; ObjBound might work: + # https://www.gurobi.com/documentation/9.0/refman/objbound.html#attr:ObjBound # to start with, avoid ObjBound and do that the same way as Aeq but with unequalities this time ####################### - + # Add constraints for the uneqalities of A model.addMConstrs(A_sparse, x, '<', b, name = "d") - + # Update the model with the extra constraints and then print it model.update() model.display() - + # Loop through the lines of the A matrix, set objective function for each and run the model for i in range(A.shape[0]): - + # Set the ith row of the A matrix as the objective function objective_function = A[i,] - + # Set the objective function in the model model.setMObjective(None, objective_function, 0.0, None, None, x, GRB.MINIMIZE) model.update() - + # Optimize model model.optimize () - + # If optimized status = model.status if status == GRB.OPTIMAL: - + # Get the max objective value max_objective = model.getObjective().getValue() - + max_fluxes.append(max_objective) + # Likewise, for the minimum objective_function = np.asarray([-x for x in objective_function]) model.setMObjective(None, objective_function, 0.0, None, None, x, GRB.MINIMIZE) model.update() model.optimize() - + # Again if optimized status = model.status if status == GRB.OPTIMAL: - + # Get the max objective value min_objective = model.getObjective().getValue() - + min_fluxes.append(min_objective) + # Calculate the width width = abs(max_objective + min_objective) / np.linalg.norm(A[i,]) - + # Check whether we keep or not the equality if width < 1e-07: Aeq_new = np.vstack((Aeq_new, A[i,])) beq_new = np.append(beq_new, max_objective) - + else: A_new = np.vstack((A_new, A[i,])) b_new = np.append(b_new, b[i]) - - # The np.vstack() creates issues on changing contiguous c orded of np arrays; here we fix this + + # The np.vstack() creates issues on changing contiguous c orded of np arrays; here we fix this Aeq_new = np.ascontiguousarray(Aeq_new, dtype=np.dtype) A_new = np.ascontiguousarray(A_new, dtype=np.dtype) - + # Furthremore, we need to have float64 in all numpy arrays Aeq_new = Aeq_new.astype('float64') A_new = A_new.astype('float64') - + + # Make lists of fluxes numpy arrays + min_fluxes = np.asarray(min_fluxes) ; max_fluxes = np.asarray(max_fluxes) + # And now we export the pre-processed elements on .npy files to load and use them anytime np.save('A_preprocessed.npy', A_new) ; np.save('b_preprocessed.npy', b_new) np.save('Aeq_preprocessed.npy', Aeq_new) ; np.save('beq_preprocessed.npy', beq_new) + np.save('min_fluxes.npy', min_fluxes), np.save('max_fluxes.npy', max_fluxes) # Return a tupple including the new A, b, Aeq and beq - return A_new, b_new, Aeq_new, beq_new - + return A_new, b_new, Aeq_new, beq_new, min_fluxes, max_fluxes + # Print error messages except gp . GurobiError as e : print ("Error code " + str( e . errno ) + ": " + str( e )) except AttributeError : print ("Encountered an attribute error ") -# This is a function to get the maximum ball included in the full dimensional polytope +# This is a function to get the maximum ball included in the full dimensional polytope def get_max_ball(A_full_dim, b_full_dim): extra_column = [] @@ -302,7 +326,8 @@ def get_max_ball(A_full_dim, b_full_dim): model.update() # Make A_full_dim sparse - A_expand_sparse = sp.csr_matrix(A_expand) + # A_expand = np.array(A_expand, dtype=float) + A_expand_sparse = sp.csr_matrix(A_expand.astype(np.float)) # Add constraints model.addMConstrs(A_expand_sparse, x, '<', b_full_dim, name = "c") @@ -332,13 +357,27 @@ def get_max_ball(A_full_dim, b_full_dim): else: value = vars[i].x point.append(value) - + # And check whether its value is negative if r < 0 : print ("The radius calculated has negative value. The polytope is infeasible or something went wrong with the solver") else: return point, r +# Map the points samples on the (rounded) full dimensional polytope, back to the initial one +def map_samples_on_initial_polytope(samples, T, T_shift, N, N_shift): + + samples_T = samples.T + + extra_1 = np.full((samples.shape[0],samples.shape[1]), T_shift) + extra_2 = np.full((samples_T.shape[1], N.shape[0]), N_shift) + + extra_T = extra_1.T + extra_N = extra_2.T + + samples_on_initial_polytope = N.dot(T.dot(samples_T) + extra_T) + extra_N + + return samples_on_initial_polytope ################################################################################ @@ -360,10 +399,12 @@ cdef extern from "bindings.h": # Random sampling double generate_samples(int walk_len, int number_of_points, int number_of_points_to_burn, bool boundary, \ - bool cdhr, bool rdhr, bool gaussian, bool set_L, bool billiard, bool ball_walk, double a, double L, double* samples); + bool cdhr, bool rdhr, bool gaussian, bool set_L, bool accelerated_billiard, bool billiard, bool ball_walk, \ + double a, double L, bool max_ball, double* inner_point, double radius, double* samples); # Rounding H-Polytope - void rounding(char* rounding_method, double* new_A, double* new_b, double* T_matrix, double* shift, double &round_value); + void rounding(char* rounding_method, double* new_A, double* new_b, double* T_matrix, double* shift, double &round_value, \ + bool max_ball, double* inner_point, double radius); # The lowDimPolytopeCPP class along with its functions cdef cppclass lowDimHPolytopeCPP: @@ -375,14 +416,12 @@ cdef extern from "bindings.h": # Get full dimensional polytope int full_dimensiolal_polytope(double* N_extra_trans, double* shift, double* A_full_extra_trans, double* b_full) - # Lists with the methods supported by volesti for volume approximation and random walk volume_methods = ["sequence_of_balls".encode("UTF-8"), "cooling_gaussian".encode("UTF-8"), "cooling_balls".encode("UTF-8")] walk_methods = ["uniform_ball".encode("UTF-8"), "CDHR".encode("UTF-8"), "RDHR".encode("UTF-8"), "gaussian_ball".encode("UTF-8"), \ "gaussian_CDHR".encode("UTF-8"), "gaussian_RDHR".encode("UTF-8"), "uniform_ball".encode("UTF-8"), "billiard".encode("UTF-8")] rounding_methods = ["min_ellipsoid".encode("UTF-8"), "svd".encode("UTF-8"), "max_ellipsoid".encode("UTF-8")] - # Build the HPolytope class cdef class HPolytope: @@ -413,45 +452,68 @@ cdef class HPolytope: raise Exception('"{}" is not implemented to compute volume. Available methods are: {}'.format(vol_method, volume_methods)) # Likewise, the generate_samples() function - def generate_samples(self, walk_len = 1, number_of_points = 1000, number_of_points_to_burn = 100, boundary = False, cdhr=True, \ - rdhr = False, gaussian = False, set_L = False, billiard = False, ball_walk = False, a = 0, L = 0): + def generate_samples(self, walk_len = 1, number_of_points = 1000, number_of_points_to_burn = 0, boundary = False, cdhr=False, \ + rdhr = False, gaussian = False, set_L = False, accelerated_billiard = True, billiard = False, ball_walk = False, a = 0, \ + radius = 0, inner_point = [], L = 0): n_variables = self._A.shape[1] cdef double[:,::1] samples = np.zeros((number_of_points, n_variables), dtype = np.float64, order = "C") - - self.polytope_cpp.generate_samples(walk_len, number_of_points, number_of_points_to_burn, boundary, cdhr, rdhr, gaussian, set_L, billiard, ball_walk, a, L, &samples[0,0]) + cdef double[::1] inner_point_for_c = np.asarray(inner_point) + + # Check whether the user asks for a certai value of radius; this is of higher priority than having a radius from the corresponding function + if radius <= 0: + max_ball = False + else: + max_ball = True + + if L <= 0: + set_L = False + else: + set_L = True + + self.polytope_cpp.generate_samples(walk_len, number_of_points, number_of_points_to_burn, boundary, cdhr, rdhr, gaussian, set_L, \ + accelerated_billiard, billiard, ball_walk, a, L, max_ball, &inner_point_for_c[0], radius, &samples[0,0]) return np.asarray(samples) # we need to build a Python function for getting a starting point depending on the polytope # The rounding() function; like the compute_volume; there are more than one methods for this step - def rounding(self, rounding_method = 'max_ellipsoid'): + def rounding(self, rounding_method = 'max_ellipsoid', inner_point = [], radius = 0): # Get the dimensions of the items about to build n_hyperplanes, n_variables = self._A.shape[0], self._A.shape[1] - # Set the variables of those items; notice that they are all cdef type except of the last one which is about to be used both as a C++ and a Python variable + # Set the variables of those items; notice that they are all cdef type except of the last one which is about to be used + # both as a C++ and a Python variable cdef double[:,::1] new_A = np.zeros((n_hyperplanes, n_variables), dtype=np.float64, order="C") cdef double[::1] new_b = np.zeros(n_hyperplanes, dtype=np.float64, order="C") cdef double[:,::1] T_matrix = np.zeros((n_variables, n_variables), dtype=np.float64, order="C") cdef double[::1] shift = np.zeros((n_variables), dtype=np.float64, order="C") cdef double round_value - + + cdef double[::1] inner_point_for_c = np.asarray(inner_point) + # Transform the rounding_method variable to UTF-8 coding rounding_method = rounding_method.encode("UTF-8") + # Check whether a max ball has been given + if radius > 0: + max_ball = True + else: + max_ball = False + # Check whether the rounding method the user asked for, is actually among those volestipy supports if rounding_method in rounding_methods: - - self.polytope_cpp.rounding(rounding_method, &new_A[0,0], &new_b[0], &T_matrix[0,0], &shift[0], round_value) - + + self.polytope_cpp.rounding(rounding_method, &new_A[0,0], &new_b[0], &T_matrix[0,0], &shift[0], round_value, max_ball, &inner_point_for_c[0], radius) + np.save('A_rounded.npy', new_A) ; np.save('b_rounded.npy', new_b) np.save('T_rounded.npy', T_matrix) ; np.save('shift_rounded.npy', shift) np.save('round_value.npy', np.asarray(round_value)) - + return np.asarray(new_A),np.asarray(new_b),np.asarray(T_matrix),np.asarray(shift),np.asarray(round_value) - + else: - + raise Exception('"{}" is not implemented to walk types. Available methods are: {}'.format(rounding_method, rounding_methods)) @property @@ -464,7 +526,6 @@ cdef class HPolytope: def dimensions(self): return self._A.shape[1] - # Build the low_dim_polytope_cpp class cdef class low_dim_HPolytope: @@ -476,7 +537,7 @@ cdef class low_dim_HPolytope: # Set the specs of the class def __cinit__(self, double[:,::1] A, double[::1] b, double[:,::1] Aeq, double[::1] beq): - + self._A = A self._b = b self._Aeq = Aeq @@ -495,11 +556,14 @@ cdef class low_dim_HPolytope: self.low_dim_polytope_cpp = lowDimHPolytopeCPP(&A[0,0], &b[0], &Aeq[0,0], &beq[0], n_rows_of_A, n_cols_of_A, n_row_of_Aeq, n_cols_of_Aeq) else: - raise Exception('The number of columns of A equals to "{}" while those of Aeq {}. A and Aeq need to have the same number of columns'.format(n_cols_of_A, n_cols_of_Aeq)) + raise Exception('The number of columns of A equals to "{}" while those of Aeq {}. \ + A and Aeq need to have the same number of columns'.format(n_cols_of_A, n_cols_of_Aeq)) else: - raise Exception('The number of rows of Aeq equals to "{}" while the elements of the beq vector are {}. The beq vector needs to have length equal to the number of rows of Aeq.'.format(n_row_of_Aeq, beq.shape[0])) + raise Exception('The number of rows of Aeq equals to "{}" while the elements of the beq vector are {}. \ + The beq vector needs to have length equal to the number of rows of Aeq.'.format(n_row_of_Aeq, beq.shape[0])) else: - raise Exception('The number of rows of A equals to "{}" while the elements of b are {}. The b vector needs to have length equal to the number of rows of A.'.format(n_rows_of_A, b.shape[0])) + raise Exception('The number of rows of A equals to "{}" while the elements of b are {}. \ + The b vector needs to have length equal to the number of rows of A.'.format(n_rows_of_A, b.shape[0])) # The get_full_dimensional_polytope() function(); that needs to run in case the user does not provide volestipy with a full dimensional polytope def full_dimensiolal_polytope(self): @@ -568,5 +632,4 @@ cdef class low_dim_HPolytope: @property def dimensions(self): return self._A.shape[1] - - +