<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3252642569764035520</id><updated>2024-10-24T21:47:32.613+02:00</updated><category term="algorithms"/><category term="optimization"/><category term="web scraping"/><category term="AMPL"/><category term="C/C++"/><category term="algebra"/><category term="data visualization"/><category term="excel"/><category term="graphs"/><category term="numerical methods"/><category term="statistics"/><title type='text'>ComputSimu</title><subtitle type='html'>Computational simulations, statistics, finance, numerical methods...</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>10</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-3271960601732988928</id><published>2016-11-07T09:50:00.000+01:00</published><updated>2017-02-05T00:10:05.032+01:00</updated><title type='text'>Computing the Goodwin-Staton integral</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  In this post we will explore different approaches for the evaluation of
  the Goodwin-Staton integral, which is one of the generalizations of the
  complementary error function. The Goodwin-Staton integral is defined as
  $$\begin{equation}G(z) = \int_0^{\infty} \frac{e^{-t^2}}{t+z} \; dt \quad
  |\mathrm{arg}\, z| &lt; \pi \end{equation}$$

  From now on, we consider the case where $z$ is real positive number. Note
  that this special functions can be expressed in terms of other elementary
  special functions; the error function and the exponential integral. Thus,

  $$\begin{equation}G(x) = -\frac{e^{-x^2}}{2}(\pi i \mathrm{erf}(ix) + E_i(x^2))
  \end{equation}$$
  Additionally, the previous representation can be slightly simplified by
  considering the following connection formulas: $E_i(x) = -E_1(-x)$ and
  $\mathrm{erfi}(x) = -i\mathrm{erf}(ix)$, where $\mathrm{erfi}(x)$ is the
  imaginary error function, both valid when $x &gt; 0$. In particular, $E_1(x)$
  for real negative argument is not currently supported in Scipy, which will
  be used for implemented each of the proposed methods.

&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;
  from scipy.special import expi, erfi
  from scipy import exp, pi


  def goodwin_staton_1(x):
      mx2 = -x*x
      ans = 0.5 * exp(mx2) * (pi * erfi(x) - expi(-mx2))
      return ans
&lt;/pre&gt;

  When $x$ is small the previous equation can be safely evaluated, but for
  $x \gtrsim 20$ the computation will overflow. This problem is avoidable if we
  consider some different approaches. A sensible approach consists
  of substituting the first term using a well-known relation between the
  imaginary error function and Dawson integral $F(x)$,
  $$\begin{equation}\frac{\pi \mathrm{erfi}(x)}{2e^{x^2}} = \sqrt{\pi}F(x) \end{equation}$$

  On the other hand, the second term involving the exponential integral $E_1(-x^2)$
  can be replaced by its asymptotic expansion as follows,
  $$\begin{equation} \frac{e^{-x^2} E_1(-x^2)}{2} \sim -\frac{1}{2x^2}
  \sum_{k=0}^{\infty} \frac{k!}{x^{2k}},\quad x \to \infty \end{equation}$$
  Therefore, for large argument the Goodwin-Staton integral can be computed as
  $$\begin{equation} G(x) \sim \sqrt{\pi} F(x) -\frac{1}{2x^2}
  \sum_{k=0}^{\infty} \frac{k!}{x^{2k}},\quad x \to \infty \end{equation}$$

&lt;pre class=&quot;brush: py&quot;&gt;
  from scipy.special import dawsn
  from scipy import pi, exp, sqrt


  def goodwin_staton_2(x):
      # compute Dawson&#39;s integral
      term1 = sqrt(pi) * dawsn(x)

      # compute series
      maxiter = 1000
      eps = 2.2e-16
      acc = False
      s = 1.0
      sp = s
      n = 1
      d = 1
      x2 = x*x

      for k in range(1, maxiter):
          n *= k
          d *= x2
          s += n / d
          if abs((s - sp) / sp) &lt; eps:
              if acc:
                  break
              else:
                  acc = True
          else:
              sp = s

      ans = term1 - 0.5 * s / x2
      return ans
&lt;/pre&gt;

  Another alternative is representing the second term as definite integral,
  $$\begin{equation} \frac{e^{-x^2} E_1(-x^2)}{2} = - \frac{1}{2}\int_0^1
  \frac{dt}{x^2 + \log(t)}
  \end{equation}$$
  Therefore, the Goodwin-Station is represented as follows,
  $$\begin{equation} G(x) = \sqrt{\pi}F(x) - \frac{1}{2}\int_0^1 \frac{dt}
  {x^2 + \log(t)}  \end{equation}$$

&lt;pre class=&quot;brush: py&quot;&gt;
from scipy.integrate import quad
from scipy.special import dawsn
from scipy import log, inf, sqrt, pi


def integrand(t, x):
    return 1 / (x * x + log(t))


def term2_integral(x):
    eps = 2.2e-16
    return quad(integrand, 0, 1, args=x, epsabs=eps, epsrel=eps, limit=100)


def goodwin_staton_3(x):
    # compute Dawson&#39;s integral
    term1 = sqrt(pi) * dawsn(x)

    # compute integral
    term2, err = term2_integral(x)

    return term1 - 0.5 * term2, err
&lt;/pre&gt;

Finally, we can evaluate the integral using an adaptive quadrature algorithm
implemented in scipy.integrate.quad, based on the Fortran library QUADPACK.

&lt;pre class=&quot;brush: py&quot;&gt;
from scipy.integrate import quad
from scipy import exp, inf


def integrand(t, x):
    return exp(-t**2) / (t + x)


def goodwin_staton_4(x):
    eps = 2.2e-16
    return quad(integrand, 0, inf, args=x, epsabs=eps, epsrel=eps, limit=100)
&lt;/pre&gt;

In order to perform a check of correctness, we evaluate the integral definition
using the tanh-sinh or double exponential integration algorithm implemented in
mpmath with 20 digits of precision. For example,

&lt;pre class=&quot;brush: py&quot;&gt;
&gt;&gt;&gt; from mpmath import *
&gt;&gt;&gt; mp.dps = 20
&gt;&gt;&gt; z = 10
&gt;&gt;&gt; quad(lambda t: exp(-t*t)/(t + z), [0, inf])
mpf(&#39;0.084021593706602168771586&#39;)
&lt;/pre&gt;

&lt;/span&gt;
&lt;/span&gt;

&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/3271960601732988928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2016/11/computing-goodwin-staton-integral.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/3271960601732988928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/3271960601732988928'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2016/11/computing-goodwin-staton-integral.html' title='Computing the Goodwin-Staton integral'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-2647499816585459921</id><published>2015-07-01T12:44:00.003+02:00</published><updated>2015-07-01T12:47:37.635+02:00</updated><title type='text'>Interior Point Method: Primal Affine scaling algorithm in Python</title><content type='html'>&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJIr5zrvlIT1tqxaBKhA-F7EeiUCtDJtntygzd4fwS89bjQukun1V_KxJ5QE4p8HzFBoeHzPWg_wORXexouDqi1DgM_koCt0ICYM8OtAglvxfdk7vtzfynA1in8Q2uTJjItmzEFeekLlgU/s1600/figure_1.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;/a&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;On this post we implement The Primal Affine scaling algorithm, one of the Interior Point Methods. Let us start by the Problem Formulation:&lt;br /&gt;
        &lt;br /&gt;
        &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;center&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;$\begin{equation*}\label{a}
        \begin{aligned} 
        &amp;amp; {\underset{x} min}
        &amp;amp; &amp;amp; c^T x\\
        &amp;amp; \text{subject to} 
        &amp;amp; &amp;amp; Ax= b \quad \quad \quad (P)\\
        &amp;amp;&amp;amp;&amp;amp; x \ge 0\\
        \end{aligned}
        \end{equation*}$&lt;/span&gt;&lt;/span&gt;&lt;/center&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;

        &lt;br /&gt;
        where $x\in \mathbb{R}^n$ is the vector of variables, $c \in \mathbb{R}^n$ is the vector of linear costs, $A \in \mathbb{R}^{m\times n}$ is the matrix of constraint and $b \in \mathbb{R}^m$ is the right-hand-side vector. In general, two main hypothesis are considered: Matrix $A$ is full row rank and $P$  is nondegenerate. However, as shown later, some techniques are available to deal with problems where $A$ is not full rank.&lt;br /&gt;
        &lt;br /&gt;        
        This algorithm includes a Big-M formulation and therefore the Big-M value must be chosen in advance, several approaches are possible:&lt;br /&gt;
        A first approach is start $M$ with a large value, $10^{30}$, for instance. However, if $M$ is too large it can causes numerical problems, since it is known that the presence of coefficients larger than the rest of variables by many orders of magnitude have potentially undesirable numerical aspects. Therefore, ideally we should search for a $\textit{&quot;sufficiently large&quot;}$ $M$. 
        A standard decision is choose a $M$ value which is at least $n$ times larger than the largest value of any of the variables in the specific Linear programming problem.
        &lt;br /&gt;
        For this implementation, the second approach with $n=100$ was chosen. Nevertheless, the first approach has been also tested, obtaining bad results in several problems, with numerical instability when approaching to the optimal value, hence,&lt;br /&gt;&lt;br /&gt;
        
        &lt;/span&gt;&lt;/span&gt;
&lt;center&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
$\begin{equation}\label{big-m}
        M = n \cdot \mathrm{max}_{1 \le i \le n}\;|c_i|
        \end{equation}$&lt;/span&gt;&lt;/span&gt;&lt;/center&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;br /&gt;
        where $c$ is the cost vector and $n$ the number of variables. In any case, the presented implementation provides the option of supplying a custom $M$ in case the user previously knows an upper or lower bound on some quantity (e.g. a capacity limit). &lt;br /&gt;&lt;br /&gt;

        We focus now on the algorithm implementation. The primal affine scaling algorithm has been implemented in a class called PrimalAffine() with several arguments. Furthermore, a function called _pre_check checks the input of the class: If the matrix and vectors are of the class ndarray. A relevant function is _check: This function validates that the vector $b$ and $c$ are column vectors and checks if  the matrix $A$ is a full matrix, otherwise throw an exception and do not continue solving the problem. This check can be removed if the Cholesky decomposition for semidefinite matrices is implemented (we implement it later).&lt;br /&gt;&lt;br /&gt;

        The following code is the main routine in the algorithm, where two functions $({\tt \_dual\_gap}$ and ${\tt \_compute\_y})$ are included. Basically, these two separated functions aim to improve readability.



&lt;pre class=&quot;brush: py&quot;&gt;import numpy as np
import scipy.io
from scipy.sparse import csr_matrix
import scipy
import pandas as pd
import time
import matplotlib.pyplot as plt
import math
import numba


class PrimalAffine(object):
    def __init__(self, c, a, b, opt_gap=1.0e-6, eps=1.0e-12, rho=0.95, m=None):
        self.c = c
        self.a = a
        self.b = b
        self.opt_gap = opt_gap
        self.eps = eps
        self.rho = rho
        self._alphas = []
        self._f_values = []
        self._gaps = []
        self._iter = []
        self._pre_check()

        if m is None:
            self.m = 100 * np.max(abs(self.c))
        else:
            self.m = m
        print(&quot;Max value = {}&quot;.format(np.max(abs(self.c))))
        print(&quot;Big-M = {}&quot;.format(self.m))

        self._optimize_primal()

    def _pre_check(self):
        if not (isinstance(self.a, np.ndarray) or isinstance(self.b, np.ndarray) or isinstance(self.c, np.ndarray)):
            raise Exception(&#39;Inputs must be a numpy arrays&#39;)

    def _check(self, ra, ca, rb, rc):
        if np.linalg.matrix_rank(self.a) != ra:
            raise Exception(&#39;Matrix A is not full rank&#39;)

        if rb != ra:
            if np.size(self.b) == ra:
                self.b = np.transpose(self.b)
            else:
                raise AttributeError(&#39;dimension of vector b is not correct&#39;)

        if rc != ca:
            if np.size(self.c) == ca:
                self.c = np.transpose(self.c)
            else:
                raise AttributeError(&#39;dimension of vector b is not correct&#39;)

    def _optimize_primal(self):

        r_a, c_a = np.shape(self.a)
        r_b = np.shape(self.b)[0]
        r_c = np.shape(self.c)[0]

        self._check(r_a, c_a, r_b, r_c)

        x = np.ones((c_a, 1))
        a = np.c_[self.a, self.b - np.dot(self.a, x)]
        x = np.ones((c_a + 1, 1))
        c = np.vstack([self.c, self.m])
        d = np.eye(c_a + 1)
        y = self._compute_y(a, d, c)

        i = 0
        while self._dual_gap(c, x, self.b, y) &amp;gt; self.opt_gap:
            z = c - np.dot(np.transpose(a), y)
            dx = np.dot(-d, z)
            if np.all(dx &amp;gt;= 0):
                print(&#39;Unbounded problem&#39;)
                break
            alpha = self.rho * np.min(-x[dx &amp;lt; self.eps] / dx[dx &amp;lt; self.eps].ravel())
            x += alpha*dx
            d = np.diag(x.ravel())**2
            y = self._compute_y(a, d, c)
            i += 1

            f_obj = np.dot(np.transpose(c), x)
            self._f_values.append(f_obj.ravel()[0])
            self._alphas.append(alpha.ravel()[0])
            self._gaps.append(self._dual_gap(c, x, self.b, y).ravel()[0])

        if x[c_a] &amp;gt; 1e-5:
            print(&#39;Infeasible problem. x[n+1] = {}&#39;.format(x[c_a]))
        else:
            pass
            print(&#39;\n&#39;, x[0:c_a])

    def _compute_y(self, aa, dd, cc):
        term1 = np.dot(np.dot(aa, dd), np.transpose(aa))
        term2 = np.dot(np.dot(aa, dd), cc)
        L = self._chol_semidefinite(term1)
        sol = self._chol_solve(L, term2)
        return sol

    @staticmethod
    def _dual_gap(cc, xx, bb, yy):
        term1 = np.dot(np.transpose(cc), xx)
        term2 = term1 - np.dot(np.transpose(bb), yy)
        term3 = 1.0 + abs(term1)
        return abs(term2)/term3

    @staticmethod
    @numba.autojit
    def _chol_semidefinite(A):
        n = len(A)

        # create zero matrix for L
        L = np.zeros((n, n))

        # Perform the Cholesky decomposition
        for i in range(n):
            for k in range(i+1):
                tmp_sum = 0
                for j in range(k):
                    tmp_sum += L[i, j] * L[k, j]

                if i == k:  # diagonal
                    L[i, k] = math.sqrt(A[i, i] - tmp_sum)
                    if L[i, k] &amp;lt;= 0:
                        L[i, k] = 10**10

                else:
                    L[i, k] = (1.0 / L[k, k] * (A[i, k] - tmp_sum))
        return L

    @staticmethod
    def _chol_solve(L, b):
        L_inv = np.linalg.inv(L)
        z = np.dot(L_inv, b)
        y = np.dot(np.transpose(L_inv), z)
        return y


    def results(self):
        d = {&#39;gap&#39;: self._gaps, &#39;fobj&#39;: self._f_values, &#39;alpha&#39;: self._alphas}
        df = pd.DataFrame(d)
        print(df)
&lt;/pre&gt;
A few comments about the above code: 
&lt;ul&gt;
&lt;li&gt;An important point is to check whether the problem is infeasible or not. Therefore, if $x_{n+1}^* &amp;gt; \epsilon_{inf}$ then problem $(P)$ is infeasible, due to $M \gg 0$ in the optimal solution and hence, $x_{n+1}^* \approx 0$. We set $\epsilon_{inf}$ to $1{e-}5$.&lt;/li&gt;
&lt;li&gt;We included the function to compute the Cholesky decomposition in a positive semidefinite matrix. Unfortunately, this implementation is not very efficient, even using good libraries like ${\tt Numpy}$, so in order to speed up the computation we use the library ${\tt Numba}$ so that the code can be just-in-time compiled by using the LLVM compiler. The ${\tt @numba.autojit}$ decorator tells ${\tt Numba}$ to compile the function. In average, by using a JIT compiler, it is possible to achieve $\times 3$ speed up. This function is based on the Cholesky-Banachiewicz algorithm applying a modification, so that if a value of the diagonal is 0 (zero pivot), it is replaced by a large value $L_{ik} = 10^{64}$ that is in a sense surrogates for $\infty$.&lt;/li&gt;
&lt;/ul&gt;
Furthermore, we can test our algorithm solving problems of the Netlib collection. The Netlib problems in format ${\tt .mat}$ have been downloaded from 
&lt;a href=&quot;http://www.cise.ufl.edu/research/sparse/mat/LPnetlib/&quot;&gt;NETLIB problems&lt;/a&gt;. As the algorithm was implemented in Python a function has been included to read .mat files. 
&lt;pre class=&quot;brush: py&quot;&gt;def mat_parse(file):
    mat_content = scipy.io.loadmat(file)
    mat_struct = mat_content[&#39;Problem&#39;]
    val = mat_struct[0, 0]
    A = csr_matrix(val[&#39;A&#39;]).todense()
    b = val[&#39;b&#39;]
    c = val[&#39;aux&#39;][0][0][0]
    return A, b, c


if __name__ == &#39;__main__&#39;:
    # http://www.cise.ufl.edu/research/sparse/mat/LPnetlib/
    A, b, c = mat_parse(&#39;lp_sctap3.mat&#39;)

    print(np.shape(A))
    print(np.shape(b))
    print(np.shape(c))

    t1 = time.perf_counter()
    primal = PrimalAffine(c, A, b, opt_gap=1e-6)
    elapsed = (time.perf_counter() - t1)
    print(elapsed)
    primal.results()
&lt;/pre&gt;
Finally, this is a small example that shows the behaviour of this algorithm:

&lt;center&gt;
$\begin{equation}
A = \begin{pmatrix}
2 &amp;amp; 1 &amp;amp; -1 &amp;amp; 0\\ 3&amp;amp; 4&amp;amp; 0 &amp;amp; 1\\
\end{pmatrix} \quad b = \begin{pmatrix}
2 \\ 12
\end{pmatrix} \quad c=\begin{pmatrix}
3 \\ 1 \\ 0 \\ 0
\end{pmatrix}
\end{equation}$&lt;/center&gt;
And the following table and plot summarize the steps towards the optimal solution of the problem:&lt;br /&gt;&lt;br /&gt;


&amp;nbsp;&lt;table style=&quot;width: 100%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
    &lt;th&gt;Iter&lt;/th&gt;
    &lt;th&gt;alpha&lt;/th&gt;
    &lt;th&gt;fobj&lt;/th&gt;       
    &lt;th&gt;gap&lt;/th&gt;
    &lt;th&gt;x1&lt;/th&gt;
    &lt;th&gt;x2&lt;/th&gt;
    &lt;th&gt;x3&lt;/th&gt;
    &lt;th&gt;x4&lt;/th&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;0.0086&lt;/td&gt;
    &lt;td&gt;19.52871&lt;/td&gt;
    &lt;td&gt;0.76302&lt;/td&gt;
    &lt;td&gt;0.85813&lt;/td&gt;
    &lt;td&gt;1.95431&lt;/td&gt;
    &lt;td&gt;1.67057&lt;/td&gt;
    &lt;td&gt;1.40837&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;
    &lt;td&gt;0.0636&lt;/td&gt;
    &lt;td&gt;5.15115&lt;/td&gt;
    &lt;td&gt;0.35592&lt;/td&gt;
    &lt;td&gt;0.78414&lt;/td&gt;
    &lt;td&gt;2.04874&lt;/td&gt;
    &lt;td&gt;1.61701&lt;/td&gt;
    &lt;td&gt;1.44264&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;0.7896&lt;/td&gt;
    &lt;td&gt;2.96509&lt;/td&gt;
    &lt;td&gt;0.08685&lt;/td&gt;
    &lt;td&gt;0.03921&lt;/td&gt;
    &lt;td&gt;2.54061&lt;/td&gt;
    &lt;td&gt;0.61903&lt;/td&gt;
    &lt;td&gt;1.71583&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;3&lt;/td&gt;
    &lt;td&gt;3.1027&lt;/td&gt;
    &lt;td&gt;2.27926&lt;/td&gt;
    &lt;td&gt;0.06842&lt;/td&gt;
    &lt;td&gt;0.03034&lt;/td&gt;
    &lt;td&gt;2.17289&lt;/td&gt;
    &lt;td&gt;0.23358&lt;/td&gt;
    &lt;td&gt;3.2172&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;4&lt;/td&gt;
    &lt;td&gt;4.4464&lt;/td&gt;
    &lt;td&gt;2.05176&lt;/td&gt;
    &lt;td&gt;0.01697&lt;/td&gt;
    &lt;td&gt;0.02578&lt;/td&gt;
    &lt;td&gt;1.96012&lt;/td&gt;
    &lt;td&gt;0.01168&lt;/td&gt;
    &lt;td&gt;4.082&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;5&lt;/td&gt;
    &lt;td&gt;36.9018&lt;/td&gt;
    &lt;td&gt;2.01468&lt;/td&gt;
    &lt;td&gt;0.00486&lt;/td&gt;
    &lt;td&gt;0.00129&lt;/td&gt;
    &lt;td&gt;2.00406&lt;/td&gt;
    &lt;td&gt;0.00664&lt;/td&gt;
    &lt;td&gt;3.97979&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;6&lt;/td&gt;
    &lt;td&gt;140.6546&lt;/td&gt;
    &lt;td&gt;2.00183&lt;/td&gt;
    &lt;td&gt;0.00061&lt;/td&gt;
    &lt;td&gt;0.00106&lt;/td&gt;
    &lt;td&gt;1.99833&lt;/td&gt;
    &lt;td&gt;0.00044&lt;/td&gt;
    &lt;td&gt;4.00352&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;7&lt;/td&gt;
    &lt;td&gt;900.1966&lt;/td&gt;
    &lt;td&gt;2.00055&lt;/td&gt;
    &lt;td&gt;0.00018&lt;/td&gt;
    &lt;td&gt;0.00005&lt;/td&gt;
    &lt;td&gt;2.00016&lt;/td&gt;
    &lt;td&gt;0.00027&lt;/td&gt;
    &lt;td&gt;3.9992&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;8&lt;/td&gt;
    &lt;td&gt;3579.9455&lt;/td&gt;
    &lt;td&gt;2.00009&lt;/td&gt;
    &lt;td&gt;0.00003&lt;/td&gt;
    &lt;td&gt;0.00004&lt;/td&gt;
    &lt;td&gt;1.99993&lt;/td&gt;
    &lt;td&gt;0.00001&lt;/td&gt;
    &lt;td&gt;4.00016&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;9&lt;/td&gt;
    &lt;td&gt;22196.8995&lt;/td&gt;
    &lt;td&gt;2.00002&lt;/td&gt;
    &lt;td&gt;0.00001&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;2.00001&lt;/td&gt;
    &lt;td&gt;0.00001&lt;/td&gt;
    &lt;td&gt;3.99997&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;10&lt;/td&gt;
    &lt;td&gt;101489.1179&lt;/td&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;4.00001&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;11&lt;/td&gt;
    &lt;td&gt;425757.3225&lt;/td&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;2&lt;/td&gt;
    &lt;td&gt;0&lt;/td&gt;
    &lt;td&gt;4&lt;/td&gt;
  &lt;/tr&gt;
&lt;tr&gt;

  &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&amp;nbsp;&lt;table style=&quot;width: 100%;&quot;&gt;&lt;tbody&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJIr5zrvlIT1tqxaBKhA-F7EeiUCtDJtntygzd4fwS89bjQukun1V_KxJ5QE4p8HzFBoeHzPWg_wORXexouDqi1DgM_koCt0ICYM8OtAglvxfdk7vtzfynA1in8Q2uTJjItmzEFeekLlgU/s1600/figure_1.png&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;476&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJIr5zrvlIT1tqxaBKhA-F7EeiUCtDJtntygzd4fwS89bjQukun1V_KxJ5QE4p8HzFBoeHzPWg_wORXexouDqi1DgM_koCt0ICYM8OtAglvxfdk7vtzfynA1in8Q2uTJjItmzEFeekLlgU/s640/figure_1.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Figure 1&lt;span style=&quot;font-family: inherit;&quot;&gt;: Steps towards the opti&lt;span style=&quot;font-family: inherit;&quot;&gt;mal solution.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; Optimal solution = 2. x1 = 0&lt;span style=&quot;font-family: inherit;&quot;&gt; and x2 = 2. Total &lt;span style=&quot;font-family: inherit;&quot;&gt;number of iterations = 12.&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class=&quot;separator&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJIr5zrvlIT1tqxaBKhA-F7EeiUCtDJtntygzd4fwS89bjQukun1V_KxJ5QE4p8HzFBoeHzPWg_wORXexouDqi1DgM_koCt0ICYM8OtAglvxfdk7vtzfynA1in8Q2uTJjItmzEFeekLlgU/s1600/figure_1.png&quot;&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/span&gt;

&lt;/span&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/2647499816585459921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2015/07/interior-point-method-primal-affine.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2647499816585459921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2647499816585459921'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2015/07/interior-point-method-primal-affine.html' title='Interior Point Method: Primal Affine scaling algorithm in Python'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJIr5zrvlIT1tqxaBKhA-F7EeiUCtDJtntygzd4fwS89bjQukun1V_KxJ5QE4p8HzFBoeHzPWg_wORXexouDqi1DgM_koCt0ICYM8OtAglvxfdk7vtzfynA1in8Q2uTJjItmzEFeekLlgU/s72-c/figure_1.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-5992318996961398341</id><published>2015-04-24T03:25:00.000+02:00</published><updated>2015-04-24T03:37:40.226+02:00</updated><title type='text'>AMPL reporting solver statistics</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;
        This a simple script that I have been working on, which provides some Solver statistics to AMPL. At this moment, the script can handle the MINOS 
  solver output and generate cool charts to summarize the process till the solver reaches a solution.&lt;br /&gt;
        As usual, I have written a python script that is called by the shell command in AMPL.&lt;br /&gt;
  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: c&quot;&gt;option solver minos;
option minos_options &quot;Superbasics_limit=100 summary_file=1 1=summary.txt summary_level = 1 summary_frequency=1&quot;;
  
printf &quot;MINOS_report: generating AMPL results...\n&quot;;
shell &#39;C:\Python27\python.exe &quot;MINOS_report.py&quot; summary.txt&#39;;
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
  As said, this script was written to work with MINOS, so after choosing MINOS as solver,
  we must provide to MINOS the output file which will contain the solver&#39;s statistics. The python script just parse the output file, clean it and 
  generate the chart shown below. This code is just an example and does not aim to be very fast or optimum in terms of computational efficiency since is just a first test.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;
import pandas as pd
import matplotlib.pyplot as plt
import sys
import os


class Generate(object):
    def __init__(self, i_file):
        self.f_input = i_file
        self.f_output = &quot;results_clean.csv&quot;
        self.data = []
        self.output = []

    def clean_file(self):
        with open(self.f_input, &quot;r&quot;) as f:
            it = 0
            for line in f:
                if &quot;EXIT&quot; in line:
                    break
                elif line[:7].strip().isdigit() and int(line[:7].strip()) &gt; it \
                        and not &quot;T&quot; in line:
                    if len(line) &gt; 10:
                        #print line
                        it += 1
                        self.output.append(line)
        f.close()
        w = open(self.f_output, &quot;w&quot;)
        w.writelines(self.output)
        w.close()
        print &quot;MINOS_report: new file &gt; {0}&quot;.format(self.f_output)

    def get_data(self):
        cols = [(1, 7), (8, 16), (17, 22), (23, 32), (33, 48), (49, 54), (55, 60), (61, 65)]
        self.data = pd.read_fwf(self.f_output, colspecs=cols, header=None)

    def plots(self):

        itn = len(self.data)
        rgradient = self.data[1]
        ninf = self.data[2]
        sinf = self.data[3]
        objective = self.data[4]
        nobj = self.data[5]
        ncon = self.data[6]
        nsb = self.data[7]

        it = list(range(1, itn + 1))

        _min_obj = objective[itn - 1]
        _max_nsb = nsb[itn - 1]
        _max_nobj = nobj[itn - 1]
        _sinf = sinf[itn - 1]
        _ninf = ninf[itn - 1]
        _ncon = ncon[itn - 1]

        plt.figure(&quot;AMPL results&quot;)

        # plot 1
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ax1 = plt.subplot(211)
        ax1.set_title(&#39;Iterations={0}. Objective (optimal solution)={1}&#39;
                      .format(itn, _min_obj), size=10)

        ax1.set_xlabel(&#39;iterations&#39;)
        ax1.set_ylabel(&#39;objective function&#39;)
        l_obj = ax1.plot(it, objective, &#39;.-&#39;, color=&quot;#0E3EEB&quot;, label=&quot;obj&quot;)
        ax2 = ax1.twinx()
        ax2.set_ylabel(&#39;reduced gradient&#39;)
        l_rg = ax2.plot(it, rgradient, &#39;.-&#39;, color=&quot;#EB710E&quot;, label=&quot;rg&quot;)

        lns = l_obj + l_rg
        labs = [l.get_label() for l in lns]

        ax1.grid()
        ax1.legend(lns, labs, loc=0)

        # plot 2
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ax3 = plt.subplot(223)
        ax3.set_title(&#39;number of superbasics={0}\n # objective and gradient calculations={1}&#39;
                      .format(_max_nsb, _max_nobj), size=10)

        l_sb = ax3.plot(it, nsb, &#39;.-&#39;, color=&quot;#0E3EEB&quot;, label=&quot;nsb&quot;)
        ax3.set_xlabel(&#39;iterations&#39;)
        ax3.set_ylabel(&#39;no.superbasics&#39;)
        ax4 = ax3.twinx()
        l_nobj = ax4.plot(it, nobj, &#39;.-&#39;, color=&quot;#EB710E&quot;, label=&quot;nobj&quot;)
        ax4.set_ylabel(&#39;calculations obj. &amp; gradient&#39;)

        lns = l_sb + l_nobj
        labs = [l.get_label() for l in lns]

        ax3.grid()
        ax3.legend(lns, labs, loc=4)

        # plot 3
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        plt.subplot(224)
        plt.title(&#39;no. of infeasibilities={0}\n sum of infeasibilities={1}\n &#39;
        &#39;# nonlinear constraints evaluations={2}&#39;.format(_ninf, _sinf, _ncon), size=10)
        plt.plot(it, ncon, &#39;g-&#39;, label=&quot;ncon&quot;)
        plt.plot(it, ninf, &#39;y-&#39;, label=&quot;ninf&quot;)
        plt.plot(it, sinf, &#39;m-&#39;, label=&quot;sinf&quot;)
        plt.xlabel(&#39;iterations&#39;)
        plt.grid()
        plt.legend()

        plt.tight_layout()
        plt.show()


if __name__ == &quot;__main__&quot;:
    summary_file = sys.argv[1]
    #summary_file = &quot;C:/Users/Guillermo Navas/Desktop/MSc Statistics and Operations research/Continuous optimization/&quot; \
    #                   &quot;Modelling and solving optimization problems/Lab assignment 2 _ Network flow problems/solver_summary.txt&quot;
    report = Generate(summary_file)
    report.clean_file()
    report.get_data()
    report.plots()
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheRoyz-7EsYbx-D5ay4hv1PV4Ln2izSm2xVN8q-rNx0SS4nCfA3y5qsbXpkVWjazISc6zZbbn609LyxErxZQyy_gcfLKJfLaf23AegHDxjxVZZB75v4IP-5m7EDOwXBBCmQxiWVMNN90S3/s1600/ampl_results.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheRoyz-7EsYbx-D5ay4hv1PV4Ln2izSm2xVN8q-rNx0SS4nCfA3y5qsbXpkVWjazISc6zZbbn609LyxErxZQyy_gcfLKJfLaf23AegHDxjxVZZB75v4IP-5m7EDOwXBBCmQxiWVMNN90S3/s1600/ampl_results.png&quot; height=&quot;390&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/5992318996961398341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2015/04/ampl-reporting-solver-statistics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/5992318996961398341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/5992318996961398341'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2015/04/ampl-reporting-solver-statistics.html' title='AMPL reporting solver statistics'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheRoyz-7EsYbx-D5ay4hv1PV4Ln2izSm2xVN8q-rNx0SS4nCfA3y5qsbXpkVWjazISc6zZbbn609LyxErxZQyy_gcfLKJfLaf23AegHDxjxVZZB75v4IP-5m7EDOwXBBCmQxiWVMNN90S3/s72-c/ampl_results.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-2922798458847906685</id><published>2014-10-31T11:45:00.001+01:00</published><updated>2015-04-24T03:19:08.368+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="AMPL"/><category scheme="http://www.blogger.com/atom/ns#" term="C/C++"/><category scheme="http://www.blogger.com/atom/ns#" term="optimization"/><title type='text'>creating shared library AMPL</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
        &lt;span style=&quot;font-size: small;&quot;&gt;
        On this post I will try to explain in detail how create a shared library f&lt;span style=&quot;font-family: inherit;&quot;&gt;or&lt;/span&gt; AMPL. At this moment the &lt;a href=&quot;http://ampl.com/resources/extended-function-library/&quot;&gt;Extended Function Library&lt;/a&gt; extends AMPL with over 300 functions, all of them 
        available on the GNU Scientific library. Hence, before creating your own library you should check if your function is already
        included in that library.&lt;br /&gt;
        &lt;br /&gt;
        I started my custom library because I needed the sigmoid function for one project and that function was not available in the Extended Function Library.&lt;br /&gt;&lt;br /&gt;This process has the next steps:&lt;/span&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;li&gt;Download headers: funcadd.h and stdio.1.h&lt;/li&gt;
&lt;li&gt;Visual Studio: create a new Win32 project -&amp;gt; DLL.&lt;/li&gt;
&lt;li&gt;Build DLL and testing.&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;
        
        The headers can be downloaded from the pages below:
        &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;li&gt;funcadd.h: &lt;a href=&quot;ftp://ftp.mirrorservice.org/sites/ftp.netlib.org/ampl/solvers/funcadd.h&quot;&gt;download file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;stdio1.h: &lt;a href=&quot;http://www.netlib.org/ampl/solvers/stdio1.h0&quot;&gt;download file&lt;/a&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
Once this is done, create a new project -&amp;gt; Win32 project in Visual Studio and select application type DLL. Add both headers to Header Files and create a new file for your functions (e.g mathFuncs.c). Now your solution explorer should look like this:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPvm9Xe9IrUKhz2-1TiwWAsHqbdCtdWwqUx_V7pz__OCg6Sxs73eabgUiB_iE78oBXc8YoZ3YryNdFuwTNUwz5U3iQQ3d-UFW3ax74Wcf7COpJY6Usz_wshLbnz2aMT_u2CUHVHQmi1_R/s1600/solution+explorer.bmp&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPvm9Xe9IrUKhz2-1TiwWAsHqbdCtdWwqUx_V7pz__OCg6Sxs73eabgUiB_iE78oBXc8YoZ3YryNdFuwTNUwz5U3iQQ3d-UFW3ax74Wcf7COpJY6Usz_wshLbnz2aMT_u2CUHVHQmi1_R/s1600/solution+explorer.bmp&quot; height=&quot;295&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1. Solution Explorer - Visual Studio&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;As said, we will create the sigmoid function and an approximation, the C code below shows one possible implementation, surely can be improved to gain efficiency. But before getting into the code, let&#39;s explain some general concepts about solvers and sigmoid functions. In general, the solvers need the first and second order derivatives of the function, depending on the method implemented by the solver (quasi-newton, newton&#39;s method, etc.), they may require the first derivative or both, as example &lt;a href=&quot;http://ampl.com/products/solvers/solvers-we-sell/minos/&quot;&gt;MINOS&lt;/a&gt; requires just the first order derivative since it approximates the second one. In this .dll we will provide both derivatives of the functions.
        &lt;br /&gt;&lt;br /&gt;
        Sigmoid function: $\frac{1}{(1 +\exp(-x))}$&lt;br /&gt;&lt;br /&gt;
        First order derivative: $\frac{1}{(1 +\exp(-x))} (1 - \frac{1}{(1 +\exp(-x))}) = sigmoid(x)(1-sigmoid(x))$&lt;br /&gt;&lt;br /&gt;
        Second order derivative: $\frac{-(\exp(x)(\exp(x) - 1))}{(\exp(x) + 1)^3}$&lt;br /&gt;
        &lt;br /&gt;
        A possible sigmoid function approximation ,computationally faster, is the &quot;fast sigmoid&quot; function. The evaluation of the exponential function has a relevant cost and in many situations the exact sigmoid function may not be needed. This post is an interesting resource about the topic with a good benchmarking between methods &lt;a href=&quot;http://txt.arboreus.com/2013/03/29/fast-sigmoid.html&quot;&gt;link&lt;/a&gt;.
        &lt;br /&gt;&lt;br /&gt;
        Fast sigmoid function: $\frac{x}{(1 + |x|)}$&lt;br /&gt;&lt;br /&gt;
        First order derivative: $\frac{(-\frac{x^2}{|x|} + |x| + 1)}{|x|(1 + |x|)^2}$&lt;br /&gt;&lt;br /&gt;
        Second order derivative: $\frac{3x^2|x| - 3|x|^3 - 3|x|^2 + x^2}{|x|^3(|x| + 1)^3}$&lt;br /&gt;

        &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: c&quot;&gt;
#include &quot;stdlib.h&quot;
#include &quot;math.h&quot;
#include &quot;funcadd.h&quot;    /* includes &quot;stdio1.h&quot; */

#define MAX_VAL 1.0e+300

#ifdef __cplusplus
/* The #ifdef __cplusplus lines allow this to be compiled
 * either by an ANSI C compiler or by a C++ compiler.
 */
extern &quot;C&quot; {
#endif

 static real
sigmoid(arglist *al)
 {
     /*  Sigmoid function: sigmoid(x) = 1/(1 + exp(-x)) */
     
     real x = al-&amp;gt;ra[0];
     AmplExports *ae = al-&amp;gt;AE;

     if (x &amp;gt; MAX_VAL || x &amp;lt; -MAX_VAL) 
     {
         fprintf(Stderr, &quot;x = %d exceeded the maximum allowed value.&quot;, x);
         return -1;
     }
     else
     {
        if (al-&amp;gt;derivs)
        {
            //first derivative: sigmoid gradient
            //  domain: R (all real numbers)
            //  range: {y c R: 0 &amp;lt;= y &amp;lt;= 0.25}

            *al-&amp;gt;derivs = (1.0f/(1.0f + exp(-x)))*(1.0f -1.0f/(1.0f + exp(-x)));
            if (al -&amp;gt; hes)
            {
                //second derivative (hessian)
                //  domain: R (all real numbers)
                //  range: {y c R: -1/(6*sqrt(3)) &amp;lt;= 1/(6*sqrt(3))}

                *al-&amp;gt;hes = -(exp(x) * (exp(x) - 1.0f)/ (pow(exp(x) + 1.0f, 3)));
            }
        }
        return 1.0f/(1.0f + exp(-x));
     }   
 }
 
 static real
fast_sigmoid(arglist * al)
 {
    /* fast sigmoid: sigmoid function approximation.
       fast_sigmoid(x) = x/(1 + abs(x))

       Domain {x c R: x != 0} -&amp;gt; derivative discontinuity at x = 0
     */
     
     real x = al-&amp;gt;ra[0];
     if (al-&amp;gt;derivs)
     {
         // first derivative (gradient)
         *al-&amp;gt;derivs = (-pow(x,2)/fabs(x) + fabs(x) + 1) /(fabs(x) * pow(1 + fabs(x), 2));
         
         if (al -&amp;gt; hes)
         {
             // second derivative (hessian)
             real d = 3 * pow(x,2) * fabs(x) - 3 * pow(fabs(x), 3);
             real d1 = 3 * pow(fabs(x),2) + pow(x,2);
             *al-&amp;gt;hes = (d  - d1) / (pow(fabs(x), 3) * pow(fabs(x) + 1, 3));
         }
     }
     return x / (1 + fabs(x));  
 }

 void
funcadd(AmplExports *ae){
/* Insert calls on addfunc here... */

/* Arg 3, called type, must satisfy 0 &amp;lt;= type &amp;lt;= 6:
 * type&amp;amp;1 == 0: 0,2,4,6 ==&amp;gt; force all arguments to be numeric.
 * type&amp;amp;1 == 1: 1,3,5   ==&amp;gt; pass both symbolic and numeric arguments.
 * type&amp;amp;6 == 0: 0,1 ==&amp;gt; the function is real valued.
 * type&amp;amp;6 == 2: 2,3 ==&amp;gt; the function is char * valued; static storage
                suffices: AMPL copies the return value.
 * type&amp;amp;6 == 4: 4,5 ==&amp;gt; the function is random (real valued).
 * type&amp;amp;6 == 6: 6   ==&amp;gt; random, real valued, pass nargs real args,
 *              0 &amp;lt;= nargs &amp;lt;= 2.
 *
 * Arg 4, called nargs, is interpretted as follows:
 *  &amp;gt;=  0 ==&amp;gt; the function has exactly nargs arguments
 *  &amp;lt;= -1 ==&amp;gt; the function has &amp;gt;= -(nargs+1) arguments.
 */

    addfunc(&quot;sigmoid&quot;, (rfunc) sigmoid, 0, 1, 0);
    addfunc(&quot;f_sigmoid&quot;, (rfunc) fast_sigmoid, 0, 1, 0);
}

#ifdef __cplusplus
    }
#endif

&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
When creating a custom functions there are two important points, write the first order derivative (*al -&amp;gt;derivs) and if there is second derivative (if the solver&#39;s method requires the second order derivative for computing the Hessian ; al -&amp;gt; hes) then (*al-&amp;gt;hes).&lt;br /&gt;&lt;br /&gt;
    A last comment regarding funcadd(); It is important to define appropiate names to call your function (first argument in addfunc()), in this case I chose &quot;sigmoid&quot; and &quot;f_sigmoid&quot;, keep in mind this, because otherwise AMPL will not recognize your functions.&lt;br /&gt;&lt;br /&gt;

    Now it is time to build the .dll and do some testing with AMPL. Paste your .dll into your AMPL directory:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJV7zbYfdLJj1jcFK2L4xkTRGGd4GZZThH1VQ-t7n4s1BTERDQi2bnAXAk3V0HrXkLrxmJX5eLW50qYPD9hMBHmtJPmcgRQ0R79PPjwbQN3_-asxAZZ3C7Uw_8TOphfXdUGW272L1Xfn7b/s1600/ampl_dir.bmp&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJV7zbYfdLJj1jcFK2L4xkTRGGd4GZZThH1VQ-t7n4s1BTERDQi2bnAXAk3V0HrXkLrxmJX5eLW50qYPD9hMBHmtJPmcgRQ0R79PPjwbQN3_-asxAZZ3C7Uw_8TOphfXdUGW272L1Xfn7b/s1600/ampl_dir.bmp&quot; height=&quot;278&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2. AMPL directory (student-edition)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Open ampl.exe or amplide.exe and type the instructions below to test your functions; if you followed these steps your output should be identical.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi96uFHUQzGARb3hNGEfFCb-NTSOjDBCQaR58tAPJ1txsw7YIGvutmtVoy3yDBRSjaTTJZst7jLKAbcPG5iSbPLGbABEB97oTYd_R5_zrFo5T-ZcPaYNKFnfLEIMfS4PPmE3T5Tz34gFbgL/s1600/ampl_c.bmp&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi96uFHUQzGARb3hNGEfFCb-NTSOjDBCQaR58tAPJ1txsw7YIGvutmtVoy3yDBRSjaTTJZst7jLKAbcPG5iSbPLGbABEB97oTYd_R5_zrFo5T-ZcPaYNKFnfLEIMfS4PPmE3T5Tz34gFbgL/s1600/ampl_c.bmp&quot; height=&quot;231&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 3. AMPL console&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;

    That&#39;s all from my side, I hope you find it useful.
    &lt;/span&gt;

&lt;/span&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/2922798458847906685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/10/creating-shared-library-ampl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2922798458847906685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2922798458847906685'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/10/creating-shared-library-ampl.html' title='creating shared library AMPL'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnPvm9Xe9IrUKhz2-1TiwWAsHqbdCtdWwqUx_V7pz__OCg6Sxs73eabgUiB_iE78oBXc8YoZ3YryNdFuwTNUwz5U3iQQ3d-UFW3ax74Wcf7COpJY6Usz_wshLbnz2aMT_u2CUHVHQmi1_R/s72-c/solution+explorer.bmp" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Barcelona, Spain</georss:featurename><georss:point>41.3850639 2.1734034999999494</georss:point><georss:box>41.1944764 1.8506799999999495 41.5756514 2.4961269999999494</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-8226893116117802210</id><published>2014-08-14T00:01:00.000+02:00</published><updated>2014-08-26T12:38:56.963+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algebra"/><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>Sparse matrix: from categorical matrix to binary matrix</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
      &lt;span style=&quot;font-size: small;&quot;&gt;
      On this post I will show a mini project I have been working on for the last few days. The goal is generate boolean or binary data from 
      categorical data. For doing so, I will primarly use &lt;a href=&quot;http://pandas.pydata.org/&quot;&gt;Pandas&lt;/a&gt; and &lt;a href=&quot;http://www.numpy.org/&quot;&gt;Numpy&lt;/a&gt; libraries. This class was created for testing purposes, so performance has not been taken into account and therefore is not relevant at this moment, however I am convinced that the code can be much more optimized.&lt;br /&gt;
      &lt;br /&gt;
      Firstly, a short explanation about what this code is doing:&lt;br /&gt;
      &lt;br /&gt;
      The next table represents the input data, as shown, fields p1, p2, p3 and p4 store categorical data, in this case a product code. Each module consists of four products (p) at most. &lt;i&gt;Note: field &quot;modules&quot; is the index (row names).&lt;/i&gt;&lt;br /&gt;
      &lt;br /&gt;
      &lt;table align=&quot;center&quot; style=&quot;width: 300px;&quot;&gt;
       &lt;tbody&gt;
&lt;tr&gt;
         &lt;th&gt;modules&lt;/th&gt;
         &lt;th&gt;p1&lt;/th&gt;
         &lt;th&gt;p2&lt;/th&gt;
         &lt;th&gt;p3&lt;/th&gt;
         &lt;th&gt;p4&lt;/th&gt;  
         &lt;th&gt;price&lt;/th&gt;
       &lt;/tr&gt;
&lt;tr&gt;
         &lt;td&gt;m_1&lt;/td&gt;
         &lt;td&gt;A1&lt;/td&gt;  
         &lt;td&gt;A2&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;9.90&lt;/td&gt; 
       &lt;/tr&gt;
&lt;tr&gt;
         &lt;td&gt;m_2&lt;/td&gt;
         &lt;td&gt;A1&lt;/td&gt;  
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;A3&lt;/td&gt;
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;10.50&lt;/td&gt; 
       &lt;/tr&gt;
&lt;tr&gt;
         &lt;td&gt;m_3&lt;/td&gt;
         &lt;td&gt;B1&lt;/td&gt;  
         &lt;td&gt;B2&lt;/td&gt;
         &lt;td&gt;A4&lt;/td&gt;
         &lt;td&gt;C1&lt;/td&gt;
         &lt;td&gt;20.30&lt;/td&gt; 
       &lt;/tr&gt;
&lt;tr&gt;
         &lt;td&gt;m_4&lt;/td&gt;
         &lt;td&gt;B1&lt;/td&gt;  
         &lt;td&gt;&lt;/td&gt;
         &lt;td&gt;A1&lt;/td&gt;
         &lt;td&gt;C1&lt;/td&gt;
         &lt;td&gt;22.10&lt;/td&gt; 
       &lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
      Now, let&#39;s imagine we want to solve a linear equation system (Ax = b) composed by field p1, p2, p3 and p4 as matrix &quot;A&quot; , unknows (A1, A2, A3, A4, B1, B2, C1) and  price as vector &quot;b&quot;:&lt;br /&gt;&lt;br /&gt;

            $A=\begin{bmatrix}a_{11} &amp;amp; a_{12} &amp;amp; \cdots &amp;amp; a_{1n} \\a_{21} &amp;amp; a_{22} &amp;amp; \cdots &amp;amp; a_{2n} \\\vdots &amp;amp; \vdots &amp;amp; \ddots &amp;amp; \vdots \\a_{m1} &amp;amp; a_{m2} &amp;amp; \cdots &amp;amp; a_{mn}\end{bmatrix}, \quad x=\begin{bmatrix}x_1 \\x_2 \\\vdots \\x_n\end{bmatrix}, \quad b=\begin{bmatrix}b_1 \\b_2 \\\vdots \\b_m\end{bmatrix}$
      &lt;br /&gt;&lt;br /&gt;
            The matrix equations shows that &lt;b&gt;size(A) = m x n&lt;/b&gt;, &lt;b&gt;size(x) = n&lt;/b&gt; and &lt;b&gt;size(b) = m&lt;/b&gt;. On the above example columns(A) is not equal to size(x). Hence, we need a new matrix &lt;b&gt;A&lt;/b&gt; with the correct shape, see below.&lt;br /&gt;&lt;br /&gt;

            $A=\begin{bmatrix}1 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 
                            \\1 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0
                            \\0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1 &amp;amp; 1
                            \\1 &amp;amp; 0 &amp;amp; 0 &amp;amp; 0 &amp;amp; 1 &amp;amp; 0 &amp;amp; 1
                \end{bmatrix}, 
                \quad x=\begin{bmatrix}A1 \\A2 \\A3 \\A4 \\B1 \\B2 \\C1 \end{bmatrix}, 
                \quad b=\begin{bmatrix}9.90 \\10.50 \\20.30 \\22.10 \end{bmatrix}$
            &lt;br /&gt;&lt;br /&gt;
            If we get a matrix &quot;A&quot; like the previous one, then we can solve the system easier. &lt;br /&gt;
            Using vectorial notation, &lt;b&gt;m_1 = A(1, :).x&lt;/b&gt;  &lt;i&gt;(e.g. Matlab indexing)&lt;/i&gt;
            &lt;br /&gt;&lt;br /&gt;
            Before we continue, I would like to remark that the above system can be easily solvead by isolating x from the equation or by using LU decomposition, especially for square matrices. When dealing with non square matrices ($m \neq n$) the next methods are normaly used:&lt;br /&gt;
            &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;li&gt;Normal equation: $x = (A^{T} A)^{-1} A^{T} b $&lt;/li&gt;
&lt;li&gt;QR factorization&lt;/li&gt;
&lt;li&gt;SVD decomposition&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
            &lt;br /&gt;
      &lt;/span&gt;
            &lt;b&gt;&lt;u&gt;Code:&lt;/u&gt;&lt;/b&gt;
     &lt;/span&gt;
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    import numpy as np
    import pandas as pd
    import warnings
    import matplotlib.pyplot as plt


    class CatBin(object):
        def __init__(self, i_file, o_file=False, cat_cols=&quot;all&quot;, other_cols=None, op_nan=True):
            &quot;&quot;&quot;
            Class to convert a matrix with categorical data into a matrix with binary data.

            Example: Convert the below matrix into a binary matrix

                initial_data =
                modules   p1    p2      p3      p4     price
                m_1       A1    A2      nan     nan    9.90
                m_2       A1    nan     A3      nan    10.50
                m_3       B1    B2      A4      C1     20.30
                m_4       B1    nan     A1      C1     22.10

                binary_data =
                modules   A1  A2  A3  A4  B1  B2  C1    price
                m_1       1   1   0   0   0   0   0     9.90
                m_2       1   0   1   0   0   0   0     10.50
                m_3       0   0   0   1   1   1   1     20.30
                m_4       1   0   0   0   1   0   1     22.10

            Uses:
            Solve a linear equation system: Ax = b
                A = matrix[0,1]
                x = [A1, A2, A3, A4, B1, B2, C1]
                b = price

                Note:
                if non-square matrix, we can solve the system by using some 
                of the well-known methods:

                    Normal equation
                    QR factorization
                    SVD decomposition

            Graphs - adjacency matrix - connectivity
            ...

            :param i_file: input_file in csv format
            :param o_file: if True a csv is generated. The path must be provided.
            :param cat_cols: slicing - e.g [1, 10] -&amp;gt; from column 1 to 10(not included - pandas)
            :param other_cols:

            if the new data frame must preserve others columns besides those
            with categorical data, position and name should be provided in a dictionary.
                e.g
                others = {&#39;i&#39; : &#39;modules&#39;, &#39;e&#39;, &#39;prices&#39;}
                if &#39;i&#39;, that column will be inserted on the first position in the new data frame
                    data.insert(0, &#39;name&#39;, column_data)
                if &#39;e&#39;, that column will be inserted after the rest of columns
                    data[&#39;name&#39;] = column_data

            :param op_nan: if true all NaN values will be removed.
            &quot;&quot;&quot;

            self.o_file = o_file
            self.cat_cols = cat_cols
            self.other_cols = other_cols
            self.nan = op_nan
            self.list = []

            self.rows = None
            self.columns = None
            self.p_sparsity = -1

            self.input_data = pd.read_csv(i_file)
            self.boolean_m = None
            self.boolean_a = None

            if self.cat_cols is &quot;all&quot;:
                if self.nan is True:
                    # if all data is categorical data to be converted, automatically 
                    # others_cols must be false to avoid inconsistencies.
                    
                    self.data = self.input_data.fillna(value=&#39;nan&#39;)
                else:
                    self.data = self.input_data
                if other_cols is not None:
                    other_cols = None
                    warnings.warn(&quot;other_cols has been set to False to avoid inconsistencies&quot;)
            else:
                # cat_cols is an array [start, end]
                if isinstance(self.cat_cols, list):
                    if len(self.cat_cols) == 2:
                        _start = self.cat_cols[0]
                        _end = self.cat_cols[1]
                        if self.nan is True:
                            self.data = self.input_data.fillna(value=&#39;nan&#39;).iloc[:, _start: _end]
                        else:
                            self.data = self.input_data.iloc[:, _start, _end]
                    else:
                        raise ValueError(&quot;&#39;start&#39;and &#39;end&#39; position must be provided&quot;)
                else:
                    raise TypeError(&quot;cat_cols is not a list&quot;)

            if not self.data.empty:
                # extract unique values:
                self.list = self.unique_values()
            else:
                raise ImportError(&quot;errors or empty csv file. Check input file&quot;)

        def unique_values(self):
            &quot;&quot;&quot; return sorted list of unique values &quot;&quot;&quot;

            u_values = pd.Series(self.data.values.ravel()).unique()
            if self.nan is True:
                return np.sort(u_values[u_values != &#39;nan&#39;])
            else:
                return np.sort(u_values)

        def boolean_matrix(self):
            matrix = []
            for i in range(len(self.data)):
                v = self.data.iloc[i, :].values
                # avoid worrying about the argument op_nan
                intersect = set(v).intersection(self.list)

                ea = np.zeros(len(self.list))
                for n in intersect:
                    for index, v in enumerate(self.list):
                        if n == v:
                            ea[index] = 1
                matrix.append(ea)

            self.rows = len(matrix)
            self.columns = len(matrix[0])
            self.boolean_m = pd.DataFrame(matrix, columns=self.list)

            return self.boolean_m

        def boolean_augmented_matrix(self):
            &quot;&quot;&quot;
            The goal of this function is create the augmented matrix:
            Ax = b --&amp;gt; augmented_matrix = [A|b]

            However, this function allows the option of inserting at least 
            one first column and many others columns after the boolean data, 
            in case that was required to suit your necessities.
            &quot;&quot;&quot;
            if self.cat_cols is not &#39;all&#39;:
                if self.boolean_m is None:
                    self.boolean_a = self.boolean_matrix()
                else:
                    self.boolean_a = self.boolean_m.copy()

                if self.other_cols is not None and isinstance(self.other_cols, dict):
                    for key, value in self.other_cols.items():
                        if key[0] is &#39;i&#39;:
                            self.boolean_a.insert(0, value, self.input_data[value])
                        elif key[0] is &#39;e&#39;:
                            self.boolean_a[value] = self.input_data[value]
                        else:
                            raise ValueError(&quot;Incorrect key format&quot;)
                else:
                    warnings.warn(&quot;insufficient arguments&quot;)
                return self.boolean_a
            else:
                raise ValueError(&quot;cat_cols = &#39;all&#39; the aug. matrix is not possible&quot;)

        def sparsity(self):
            &quot;&quot;&quot;
            The sparsity or density is the fraction of non-zero elements in a matrix.
            :return: ratio non-zero/total
            &quot;&quot;&quot;
            if self.rows and self.columns and self.boolean_m is not None:
                total = self.rows * self.columns
                non_zeros = sum(self.boolean_m[self.boolean_m == 1].count())
                self.p_sparsity = non_zeros / total
                return &quot;sparsity = {0:.4}%&quot;.format(self.p_sparsity * 100)
            else:
                raise ValueError(&quot;incorrect data shape. A boolean transformation is required&quot;)

        def generate_csv(self, matrix_type=&#39;normal&#39;):
            &quot;&quot;&quot;
            generate a csv file with boolean matrix or augmented matrix
            note: removes first column (index)
            &quot;&quot;&quot;
            if matrix_type in [&#39;normal&#39;, &#39;augmented&#39;]:
                if matrix_type is &#39;normal&#39;:
                    if self.boolean_m is not None:
                        self.boolean_m.to_csv(self.o_file, index=False)
                else:
                    if self.boolean_a is not None:
                        self.boolean_a.to_csv(self.o_file, index=False)
            else:
                raise ValueError(&quot;select: normal or augmented&quot;)

        @property
        def clean_data(self):
            return self.data

        @property
        def raw_data(self):
            return self.input_data

        @property
        def initial_size(self):
            &quot;&quot;&quot; Only includes those fields with categorical data&quot;&quot;&quot;
            rows = self.data.shape[0]
            columns = self.data.shape[1]
            return &quot;rows={0}, columns={1}, total={2} elements&quot;.\
                format(rows, columns, rows * columns)

        @property
        def final_size(self):
            rows = self.boolean_m.shape[0]
            columns = self.boolean_m.shape[1]
            return &quot;rows={0}, columns={1}, total={2} elements&quot;.\
                format(rows, columns, rows * columns)
    &lt;/pre&gt;
&lt;br /&gt;
The code tries to be self-explanatory, however I consider that three functions need more details:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;boolean_matrix:&lt;/b&gt; This function contains the basic code to convert the input data. Basically, it compares each row from the initial data &quot;A&quot; with its unique values and inserts one on those positions where matching. As example, this task can be done in Matlab much easier, Matlab can compare two arrays with different length by using the function &lt;b&gt;&lt;i&gt;&quot;ismember()&lt;/i&gt;&lt;/b&gt;&quot;:
        &lt;pre class=&quot;brush: text&quot;&gt;        
          p = {&#39;A1&#39;, &#39;A2&#39;, &#39;A3&#39;, &#39;A4&#39;, &#39;B1&#39;, &#39;B2&#39;, &#39;C1&#39;}; % character arrays or cell arrays
          p_test = {&#39;A1&#39;, &#39;B1&#39;,&#39;C1&#39;};
          ismember(p, p_test)

          ans =

             1     0     0     0     1     0     1
        &lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;boolean_augmented_matrix:&lt;/b&gt; The augmented matrix is that obtained by appending the solution vector &quot;b&quot; to matrix &quot;A&quot;, usually denoted as &lt;b&gt;[A b]&lt;/b&gt; or &lt;b&gt;(A|b)&lt;/b&gt;. Having a solvable linear equation system, then the augmented matrix [A b] has the same rank as A. Besides of creating the augmented matrix, this function allows the possibility to append other columns if needed.&lt;/li&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Sparsity:&lt;/b&gt; The sparsity or density is the fraction of non-zero elements in matrix. A typical example of sparse matrix is the adjacency matrix of an undirected graph.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Below a short example using the class CatBin:
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    from others.catbin import CatBin
    import time

    file = &quot;test data/i_simple.csv&quot;
    output_file = &quot;test data/clean_matrix.csv&quot;

    others = {&#39;i&#39;: &#39;modules&#39;, &#39;e&#39;: &#39;price&#39;}

    t1 = time.time()
    ct = CatBin(i_file=file, o_file=output_file, cat_cols=[1, 5], other_cols=others, op_nan=True)
    
    unique_v = ct.unique_values()
    boolean_m = ct.boolean_matrix()
    boolean_a = ct.boolean_augmented_matrix()
    sparsity = ct.sparsity()
    t = time.time() - t1
    
    print(t)
    print(ct.initial_size)
    print(ct.final_size)

    ct.generate_csv()
    &lt;/pre&gt;
The file &quot;i_simple.csv&quot; is exactly the first table on this post. This code uses all features of the class, producing both boolean matrix and boolean augmented matrix and calculates the sparsity ratio. The most simple example needs 5 lines (without verbose). 
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    from others.catbin import CatBin
    
    file = &quot;test data/i_simple.csv&quot;
    output_file = &quot;test data/clean_matrix.csv&quot;

    ct = CatBin(i_file=file, o_file=output_file, cat_cols=[1, 5], 
                other_cols={&#39;i&#39;: &#39;modules&#39;, &#39;e&#39;: &#39;price&#39;}, op_nan=True)

    boolean_a = ct.boolean_augmented_matrix()
    &lt;/pre&gt;
&lt;b&gt;&lt;u&gt;Results:&lt;/u&gt;&lt;/b&gt;
    &lt;br /&gt;
&lt;pre&gt;    
      modules  A1  A2  A3  A4  B1  B2  C1  price
    0     m_1   1   1   0   0   0   0   0    9.9
    1     m_2   1   0   1   0   0   0   0   10.5
    2     m_3   0   0   0   1   1   1   1   20.3
    3     m_4   1   0   0   0   1   0   1   22.1

    0.010005950927734375
    rows=4, columns=4, total=16 elements
    rows=4, columns=7, total=28 elements
    &lt;/pre&gt;
In my laptop(4GB, i5) the process took 0.01 seconds. The next step will be to test  something bigger. The dimensiones of the new data is 2194 x 11:
    &lt;br /&gt;
&lt;pre&gt;    1.1577680110931396
    rows=2194, columns=9, total=19746 elements
    rows=2194, columns=294, total=645036 elements
    &lt;/pre&gt;
Due to the number of unique values is much higher, the number of elements is almost 650.000 and the process now took 1.15 seconds, surely this can be improved, but for now it works for my purposes. As shown, the new dimensiones will be multiplied by a factor &lt;b&gt;X(unique values / initial columns)&lt;/b&gt;.&lt;br /&gt;
&lt;br /&gt;
Hence, having large amount of binary data in a database can also have an impact on performance, so I will not recommend to store the new dataset in a DB better create a system file. There are other options of storing a sparse matrix much more efficient that save the complete data in a DB (CSR or CSC, for instance).&lt;br /&gt;
&lt;br /&gt;
One more example: This dataset includes extra columns before and after the fields with categorical data (2194 x 13). If the order of the extra columns matters is convenient to use ordered dictionaries.
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    from others.catbin import CatBin
    from collections import OrderedDict
    import time

    file = &quot;test data/i_data_2.csv&quot;
    output_file = &quot;test data/clean_matrix.csv&quot;

    others = {&#39;i1&#39;: &#39;modules&#39;, &#39;i2&#39;: &#39;modules2&#39;, &#39;e1&#39;: &#39;price&#39;, &#39;e2&#39;: &#39;price2&#39;}
    ordered_others = OrderedDict(sorted(others.items(), key=lambda t: t[0]))

    t1 = time.time()
    
    ct = CatBin(i_file=file, o_file=output_file, cat_cols=[2, 11],
                other_cols=others, op_nan=True)
    
    boolean_m = ct.boolean_matrix()
    boolean_a = ct.boolean_augmented_matrix()
    
    t = time.time() - t1
    
    sparsity = ct.sparsity()
    print(t)
    print(ct.initial_size)
    print(ct.final_size)
    print(boolean_a)
    &lt;/pre&gt;
Finally, a function for plotting:
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    def plot_sparse(self, ticks=False, x_ticks=False, y_ticks=False, y_label=None,
                    sparsity=False):
        &quot;&quot;&quot;
        Notes: 
            if sparsity was previously calculated - this figure can be included.
            if data is extraordinarily large might be convenient to hide ticks.
        &quot;&quot;&quot;
        if sparsity and self.p_sparsity &amp;gt;= 0:
            plt.title(&quot;sparsity ratio = {0:.4}%&quot;.format(self.p_sparsity * 100), fontsize=10)
            plt.suptitle(&quot;boolean matrix&quot;, fontsize=14, fontweight=&#39;bold&#39;)
        else:
            plt.title(&quot;boolean matrix&quot;, fontsize=14, fontweight=&#39;bold&#39;)
        plt.imshow(self.boolean_m, interpolation=&#39;nearest&#39;, cmap=&#39;gist_yarg&#39;)

        if ticks is True:
            plt.yticks(range(self.boolean_m.shape[0]))
            if x_ticks is True:
                plt.xticks(np.arange(len(self.list)), self.list)
            if y_label is not None and y_ticks is True:
                plt.yticks(np.arange(len(self.input_data[y_label])), self.input_data[y_label])
        else:
            plt.axis(&#39;off&#39;)

        plt.show()
    &lt;/pre&gt;
Let&#39;s plot both matrices used on the previous examples:
    &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    ct.plot_sparse(ticks=True, x_ticks=True, sparsity=True)
    &lt;/pre&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVMB3-5O7V9SwrO7pIwMPX5-ZZVc4sOQgxbBRVtXM9iXgUUWG3ROrHB0kk8dWvBR6MDvDhUM23CVip6reKxodR-i_ief235kwtOwrlcFdF5fBVhM1K6OKWkuhS47kfMtRNN2j_mdunNLkV/s1600/simple.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVMB3-5O7V9SwrO7pIwMPX5-ZZVc4sOQgxbBRVtXM9iXgUUWG3ROrHB0kk8dWvBR6MDvDhUM23CVip6reKxodR-i_ief235kwtOwrlcFdF5fBVhM1K6OKWkuhS47kfMtRNN2j_mdunNLkV/s320/simple.png&quot; height=&quot;298&quot; title=&quot;&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;fig.1: small matrix&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    ct.plot_sparse(ticks=False, sparsity=True)
    &lt;/pre&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBQV8-O6xij9CmjoUauXOgUUBEjDqjQKK6caBeU8BzbwgVM4PhWmcUvmMqBkK3vykLfzfLKWvgBLoyoVyX_t6CN7yeZorbNu-YwYjbj5tLB3IBQHAEAxU8CHRRoMNY_HlrKGwWSTGaHhGg/s1600/data2.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBQV8-O6xij9CmjoUauXOgUUBEjDqjQKK6caBeU8BzbwgVM4PhWmcUvmMqBkK3vykLfzfLKWvgBLoyoVyX_t6CN7yeZorbNu-YwYjbj5tLB3IBQHAEAxU8CHRRoMNY_HlrKGwWSTGaHhGg/s320/data2.png&quot; height=&quot;400&quot; width=&quot;177&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;fig.2: medium matrix&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;pre class=&quot;brush: py&quot;&gt;    ct.plot_sparse(ticks=True, x_ticks=True, sparsity=True)
    &lt;/pre&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOu3IIRFoYqTrzdcNYdu35EuTWK3JB8N__kWF2KIVkeJ17KXHQrlpiIF7sfqOKPmOBP_kP-VXNqGDV_XpO55hGFTKI2poDVSh3bsVUGSZejflbV43A9MO_xBvwMRzM5s7IWdO2yTltFCFl/s1600/data_detail.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOu3IIRFoYqTrzdcNYdu35EuTWK3JB8N__kWF2KIVkeJ17KXHQrlpiIF7sfqOKPmOBP_kP-VXNqGDV_XpO55hGFTKI2poDVSh3bsVUGSZejflbV43A9MO_xBvwMRzM5s7IWdO2yTltFCFl/s400/data_detail.png&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;fig.3: medium matrix - detail&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
That&#39;s all for this post, I hope you find it useful.
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/8226893116117802210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/08/sparse-matrix-from-categorical-matrix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/8226893116117802210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/8226893116117802210'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/08/sparse-matrix-from-categorical-matrix.html' title='Sparse matrix: from categorical matrix to binary matrix'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVMB3-5O7V9SwrO7pIwMPX5-ZZVc4sOQgxbBRVtXM9iXgUUWG3ROrHB0kk8dWvBR6MDvDhUM23CVip6reKxodR-i_ief235kwtOwrlcFdF5fBVhM1K6OKWkuhS47kfMtRNN2j_mdunNLkV/s72-c/simple.png" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Barcelona, Spain</georss:featurename><georss:point>41.3850639 2.1734034999999494</georss:point><georss:box>41.1944764 1.8506799999999495 41.5756514 2.4961269999999494</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-6821496272988065830</id><published>2014-03-29T20:17:00.000+01:00</published><updated>2015-04-06T13:03:35.767+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="optimization"/><title type='text'>TSP / ATSP algorithm.</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  This post will be dedicated to the Travelling salesman problem (TSP), one of the most known combinatorial optimization problem.
  The goal of this problem is simple: A salesman has to visit a number of places (nodes). Which route would visits them all in the shortest total 
  distance (time, cost, etc...)&lt;br /&gt;
  The simplest way to solve the problem is list and try all possible routes and them select the shortest one. The problem here is the computational
  time which will grow faster than exponential (Stirling&#39;s formula: $n! \approx \sqrt{2\pi n}(\frac{n}{e})^n$)
  &lt;br /&gt;
  &lt;br /&gt;
  There are other solutions which can reduce this computational time, for example &lt;b&gt;dynamic programming&lt;/b&gt; which solves the problem in
  exponential time E. The first implemented method using that more efficient method was the &lt;b&gt;Held-Karp algorithm&lt;/b&gt; which finds the 
  shortest route in $2^n n^2$&lt;br /&gt;
  Other methods are: k-opt, Greedy algorithm, Greedy k-opt, Genetic algorithm, Simulating annealing, neuronal network approach among others.&lt;br /&gt;
  &lt;/span&gt;&lt;/span&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;
  On this post I will show an implementation for the simplest and naive method, an implementation for dealing with asymmetric input matrices 
  and finally we will compare these methods with the genetic algorithm(this implementation has too many lines of code for one post)&lt;br /&gt;
  &lt;/span&gt;

&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import itertools
import numpy as np

INF = 1000000


class TSPExact:
    def __init__(self, matrix, redundant=False):
        &quot;&quot;&quot;
        input: Adjacency matrix N x N
        len(nodes) = shape(input)
        @param matrix: N x N matrix
        @param redundant: false by default (n-1)!
        &quot;&quot;&quot;
        # 1: Check if the adjacency matrix is symmetric
        self.cost_matrix = np.array(matrix)
        self.symmetry = None
        if self.symmetric() is False:
            self.symmetry = False
            self.as_symmetric()

        self.size = len(self.cost_matrix)
        self.nodes = range(self.size)
        self.all_tours = itertools.permutations

        if redundant is False:
            self.tours = self.non_redundant()
        else:
            self.tours = list(self.all_tours(self.nodes))

    def as_symmetric(self):
        &quot;&quot;&quot;
        Reformulate an asymmetric TSP as a symmetric TSP: 
        &quot;Jonker and Volgenant 1983&quot;
        This is possible by doubling the number of nodes. For each city a dummy 
        node is added: (a, b, c) =&amp;gt; (a, a&#39;, b, b&#39;, c, c&#39;)

        distance = &quot;value&quot;
        distance (for each pair of dummy nodes and pair of nodes is INF)
        distance (for each pair node and its dummy node is -INF)
        ------------------------------------------------------------------------
          |A&#39;   |B&#39;   |C&#39;   |A    |B    |C    |
        A&#39;|0    |INF  |INF  |-INF |dBA  |dCA  |
        B&#39;|INF  |0    |INF  |dAB  |-INF |dCB  |
        C&#39;|INF  |INF  |0    |dAC  |dBC  |-INF |
        A |-INF |dAB  |dAC  |0    |INF  |INF  |
        B |dBA  |-INF |dBC  |INF  |0    |INF  |
        C |dCA  |dCB  |-INF |INF  |INF  |0    |

        For large matrix an exact solution is infeasible
        if N &amp;gt; 5 (N = N*2 &amp;gt; 10) then use other techniques: 
        Heuristics and relaxation methods
        @return: new symmetric matrix

        [INF][A.T]
        [A  ][INF]
        &quot;&quot;&quot;

        shape = len(self.cost_matrix)
        mat = np.identity(shape) * - INF + self.cost_matrix

        new_shape = shape * 2
        new_matrix = np.ones((new_shape, new_shape)) * INF
        np.fill_diagonal(new_matrix, 0)

        # insert new matrices
        new_matrix[shape:new_shape, :shape] = mat
        new_matrix[:shape, shape:new_shape] = mat.T
        # new cost matrix after transformation
        self.cost_matrix = new_matrix

    def total_tour(self, tour):
        total = sum(self.cost_matrix[tour[node], tour[(node + 1) % self.size]] for node in self.nodes)
        return total, tour

    def shortest(self):
        min_tour = min(self.total_tour(tour) for tour in self.tours)
        if self.symmetry is False:
            min_tour_real = min_tour[0] + self.size / 2 * INF
            min_cycle_real = min_tour[1][0::2]
            return min_tour_real, min_cycle_real
        else:
            return min_tour

    def non_redundant(self):
        start_node = self.nodes[0]
        new_set = list(self.nodes)[1:]
        return [list(np.append(start_node, tour)) for tour in self.all_tours(new_set)]

    def symmetric(self):
        #@return: boolean symmetric | asymmetric
        mat = [tuple(row) for row in self.cost_matrix]
        return mat == zip(*mat)

    @property
    def tour_iterations(self):
        return list(self.tours)

    @property
    def tour_size(self):
        return self.size
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  The code above tried to be self explanatory, but it might be some points unclear. The trickiest part is the transformation from 
  asymmetric matrix to symmetric matrix. As shown in the code, we are using the implementation suggested by &lt;b&gt;Jonker R, Volgenant T (1983)&lt;/b&gt;
  (“Transforming asymmetric into symmetric traveling salesman problems.” Operations Research Letters, 2, 161–163). The process behind
  is simple, doubling the number of nodes and transposing the original matrix it is possible get a symmetric matrix which can be
  solvable applying the current known methods. Finally this algorithm requires the removal of all the dummy nodes and a subtle operation
  in order to get the real shortest tour value.
  &lt;br /&gt;
  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;$shortestRoute (real) = shortestRoute + \frac{Size(InputMatrix)}{2} \times INF.Value $&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
  We can use slicing in Numpy for removing dummy nodes.&lt;br /&gt;

&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;
min_tour_real = min_tour[0] + self.size / 2 * INF
min_cycle_real = min_tour[1][0::2]
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;br /&gt;
  &lt;u&gt;&lt;b&gt;Unit testing&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
  &lt;br /&gt;
  Now it&#39;s time to compare some algorithms. I have hard coded three different matrices for testing purpose. We must keep in mind that
  the matrix size will be multiplied by two if input matrix is asymmetric. In addition, one must point out that the basic algorithm 
  becomes infeasible when the number of nodes is higher than 12 (6 - asymmetric matrix) 
  &lt;/span&gt;
 &lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;from Algorithms.scripts.TSP_Algorithm import *
import unittest
import time

MATRIX = [[0, 750, 43, 402], [750, 0, 736, 671], [43, 736, 0, 117], [402, 671, 117, 0]]
MATRIX5 = [[0, 750, 43, 402, 133], [750, 0, 736, 671, 85], [43, 736, 0, 117, 934], 
     [402, 671, 117, 0, 982], [133, 85, 934, 982, 0]]

MATRIX8 = [[0, 750, 431, 402, 133, 489, 310, 566], [750, 0, 736, 671, 85, 174, 870, 927],
           [431, 736, 0, 117, 934, 65, 939, 305], [402, 671, 117, 0, 982, 727, 911, 870],
           [133, 85, 934, 982, 0, 956, 834, 118], [489, 174, 65, 727, 956, 0, 322, 397],
           [310, 870, 939, 911, 834, 322, 0, 127], [566, 927, 305, 870, 118, 397, 127, 0]]


class TestAlgorithms(unittest.TestCase):
    @staticmethod
    def test_exact():
        start_time = time.time()
        tsp = TSPExact(MATRIX5)
        total_value, tour = tsp.shortest()
        print &quot;__exact__&quot;
        print total_value
        print tour
        print &quot;Time (s)&quot;, time.time() - start_time
  
    @staticmethod
    def test_genetic():
        start_time = time.time()
        tsp = TSPGenetic(MATRIX5)
        total, route = tsp.calculate()
        print &quot;__genetic__&quot;
        print total
        print route
        print &quot;Time (s)&quot;, time.time() - start_time
&lt;/pre&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;Some results&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
MATRIX(Asymmetric)&lt;br /&gt;
__exact__&lt;br /&gt;
1580.0&lt;br /&gt;
[0, 2, 3, 1]&lt;br /&gt;
Time (s) 0.130000114441&lt;br /&gt;
__genetic__&lt;br /&gt;
1580&lt;br /&gt;
[0, 2, 3, 1]&lt;br /&gt;
Time (s) 0.00100016593933&lt;br /&gt;
&lt;br /&gt;
MATRIX5(Asymmetric)&lt;br /&gt;
__exact__&lt;br /&gt;
1049.0&lt;br /&gt;
[0, 2, 3, 1, 4]&lt;br /&gt;
Time (s) 10.1160001755&lt;br /&gt;
__genetic__&lt;br /&gt;
1049&lt;br /&gt;
[0, 2, 3, 1, 4]&lt;br /&gt;
Time (s) 0.000999927520752&lt;br /&gt;
&lt;br /&gt;
MATRIX8(Asymmetric)&lt;br /&gt;
__exact__&lt;br /&gt;
16 nodes - time...&lt;br /&gt;
__genetic__&lt;br /&gt;
1398&lt;br /&gt;
[0, 3, 2, 5, 1, 4, 7, 6]&lt;br /&gt;
Time (s) 0.00399994850159&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;Comments&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
As shown on the previous tests, the problem becomes intractable for the Exact algorithm as the number of nodes increases.
Using the Genetic algorithm we got the same results, however this algorithm might not obtain the exact solution in large
graphs. 
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/6821496272988065830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/03/tsp-atsp-algorithm-basic-python.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/6821496272988065830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/6821496272988065830'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/03/tsp-atsp-algorithm-basic-python.html' title='TSP / ATSP algorithm.'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total><georss:featurename>Frankfurt, Germany</georss:featurename><georss:point>50.1109221 8.6821267000000262</georss:point><georss:box>49.7851336 8.0366797000000254 50.436710600000005 9.3275737000000269</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-4453364745851344067</id><published>2014-02-23T19:39:00.001+01:00</published><updated>2014-08-21T11:41:01.779+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="excel"/><category scheme="http://www.blogger.com/atom/ns#" term="web scraping"/><title type='text'>Python and Excel/VBA</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  Today we are going to talk about how easy it could be run Python&#39;s scripts from Excel, which might be considered pretty interesting.
  Basically we will create a VBA code which launches a console running the selected script. This script creates an output which must be printed 
  on the same excel file from where it was launched.
  &lt;br /&gt;
  &lt;br /&gt;
  Continuing with the previous post, we will use the scraping script to print the extracted data into excel. First we will change a bit the 
  previous code and we will create a class called &quot;collect&quot;. &lt;b&gt;UPDATE:&lt;/b&gt; The website has changed and the previous code doesn&#39;t work any more! 
  &lt;/span&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import numpy as np
import urllib2
import urlparse
import re
from bs4 import BeautifulSoup


class collect:

    def __init__(self, mainSites):
        self.sites = mainSites

    def connect(self, site):
        hdr = {&#39;User-Agent&#39;: &#39;Mozilla/5.0 (X11; Linux x86_64)&#39;,
                &#39;Accept&#39;: &#39;text/html,application/xhtml+xml,application/xml&#39;
                &#39;;q=0.9,*/*;q=0.8&#39;,
               &#39;Accept-Charset&#39;: &#39;ISO-8859-1,utf-8;q=0.7,*;q=0.3&#39;,
               &#39;Accept-Encoding&#39;: &#39;none&#39;,
               &#39;Accept-Language&#39;: &#39;en-US,en;q=0.8&#39;,
               &#39;Connection&#39;: &#39;keep-alive&#39;}
        req = urllib2.Request(site, headers=hdr)
        page = urllib2.urlopen(req).read()
        soup = BeautifulSoup(page)
        return soup

    def extractUrls(self):
        FxUrls = []
        C1 = []
        C2 = []
        for mainSite in self.sites:
            soup = self.connect(mainSite)
            for link in soup.find_all(&#39;td&#39;, {&#39;class&#39;: &#39;bold left noWrap&#39;}):
                path = &#39;http://www.investing.com/currencies/&#39;
                url = link.find(href=re.compile(path)).get(&#39;href&#39;)
                FxUrls.append(url)
                curr = urlparse.urlparse(url).path.split(&quot;/&quot;)[2].split(&quot;-&quot;)
                C1.append(curr[0])
                C2.append(curr[1])
        return np.vstack((FxUrls, C1, C2))

    def extractData(self):
        Value = []
        Data = self.extractUrls()
        for link in Data[0, :]:
            soup = self.connect(link)
            for span in soup.find_all(&#39;span&#39;, {&#39;id&#39;: &#39;last_last&#39;}):
                value = (span.text).replace(&#39;,&#39;, &#39;&#39;)
                Value.append(value)
        return np.vstack((Data, Value))
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  Once we have the script is time to create the interaction with Excel. In order to do this operation we will use an excellent module: 
  &lt;a href=&quot;http://pythonhosted.org/Pyvot/index.html&quot;&gt;pyvot&lt;/a&gt;. I have previously prepared some special ranges for printing the data 
  (I recommend Name ranges as a good Excel/VBA practice). The script below will create a connection with Excel, just selecting the desired 
  ranges and sending the values. This script will also need some arguments, the workbook name from where the script is launched and our links. 
  &lt;br /&gt;
  &lt;/span&gt;
 &lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import sys
import scraping
import xl

#arguments:
excelWb = sys.argv[1]
print &quot;Excel workbook: &quot;, excelWb

mainSites = []
for i in range(len(sys.argv) - 2):
    mainSites.append(str(sys.argv[i + 2]))
print &quot;urls: &quot;, mainSites

scr = scraping.collect(mainSites)
data = scr.extractData()

rngCurr1 = data[1, :]
rngCurr2 = data[2, :]
rngValue = data[3, :]

&quot;&quot;&quot;Excel connection&quot;&quot;&quot;
wb = xl.Workbook(excelWb)
wb.range(&quot;rngCurr1&quot;).set(rngCurr1)
wb.range(&quot;rngCurr2&quot;).set(rngCurr2)
wb.range(&quot;rngRate&quot;).set(rngValue)
&lt;/pre&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm8shTnqoFdSyrl1HJ91b63s40OQDqOvWuUFz98-FurK5nuHBgZArHcE9KWEdUfrMnl9Jy_gdnfj5-ZCKcQc6stG_mqgN6p-Xuh767eqOxO3jONxhLuifRRxUoXHD-66j4yXeCEaYZlTYU/s1600/template.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm8shTnqoFdSyrl1HJ91b63s40OQDqOvWuUFz98-FurK5nuHBgZArHcE9KWEdUfrMnl9Jy_gdnfj5-ZCKcQc6stG_mqgN6p-Xuh767eqOxO3jONxhLuifRRxUoXHD-66j4yXeCEaYZlTYU/s1600/template.png&quot; height=&quot;476&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Excel template&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxFs66ptEFWEKDdPMiLUBJQsCorxOGDzFbHFoCZq5R8d0i0Bu6g2c9wK2iJMnunMFvu0aECrYq8nVImF1yrj9Uw45fj68eHGatl883C2CThQv-J-yI0B9h66fNBGcnwyT6Ugz3Z3oJJnm5/s1600/ranges.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxFs66ptEFWEKDdPMiLUBJQsCorxOGDzFbHFoCZq5R8d0i0Bu6g2c9wK2iJMnunMFvu0aECrYq8nVImF1yrj9Uw45fj68eHGatl883C2CThQv-J-yI0B9h66fNBGcnwyT6Ugz3Z3oJJnm5/s1600/ranges.png&quot; height=&quot;307&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Ranges&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  Finally, we need a VBA code which can run a script through the Windows console. 
  First we will be calling a function to clear ranges contents and the main function afterwards. The main function, called runScript, 
  creates an object Shell and runs the script with its arguments, which are: workbook name and array of urls.
  &lt;br /&gt;
  &lt;/span&gt;
 &lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: vb&quot;&gt;Option Explicit

Sub clean()

Dim rngForex As Range
Set rngForex = Sheet1.Range(&quot;rngForex&quot;)
rngForex.ClearContents

End Sub

Sub runScript()

Dim oShell As Object
Dim sScript As String, sScriptName As String, sWbName As String
Dim sArguments As String
Dim iRegions As Integer, i As Integer
Dim aRegion() As String, sLink As String

Call clean

Set oShell = CreateObject(&quot;WScript.Shell&quot;)

sWbName = ThisWorkbook.Name
sScriptName = &quot;scrapingtest.py&quot;
sLink = &quot;http://www.investing.com/currencies/&quot;

iRegions = Application.WorksheetFunction.CountA(Sheet1.Range(&quot;rngRegions&quot;))
ReDim aRegion(iRegions - 1)
For i = 1 To iRegions
    aRegion(i - 1) = sLink &amp;amp; CStr(Sheet1.Range(&quot;rngRegions&quot;).Cells(i, 1).Value)
    sArguments = sArguments &amp;amp; aRegion(i - 1) &amp;amp; &quot; &quot;
Next i

sScript = sScriptName &amp;amp; &quot; &quot; &amp;amp; sWbName &amp;amp; &quot; &quot; &amp;amp; sArguments
oShell.Run (&quot;cmd.exe /S /C &quot; &amp;amp; sScript)

End Sub&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  Now, if you click &quot;RUN&quot; a console will appear showing a message similar to this one: 
  &lt;br /&gt;
  &lt;/span&gt;
 &lt;/span&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha9SbRliY16_bWuVhNE2XkCyaVQtWFRjUvxZcoPd7jCBvH1_hiOehc2S9-R8bCBV3J60-TAuME31rJdq9ML1mHAS7St0fKGWwBQXmu2WRGzVeWGjpVpUwh-_IQRIYH43fWVNdPWU8gQ-lS/s1600/cmd.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha9SbRliY16_bWuVhNE2XkCyaVQtWFRjUvxZcoPd7jCBvH1_hiOehc2S9-R8bCBV3J60-TAuME31rJdq9ML1mHAS7St0fKGWwBQXmu2WRGzVeWGjpVpUwh-_IQRIYH43fWVNdPWU8gQ-lS/s1600/cmd.png&quot; height=&quot;323&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  &lt;b&gt;&lt;u&gt;Conclusion:&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;
  My personal opinion is that at this moment there are not real alternatives to Excel. Is true that there 
  are open source tools like LibreOffice or Apache OpenOffice but these are not even comparable to Excel. It is quite common create scripts in C# 
  to automate processes which are not so fast in VBA. VS languages (VB /C#) are chosen because they are much more integrated with Excel and 
  generally speaking with most of the Microsoft applications.&lt;br /&gt;&lt;br /&gt;
  The aim of this post was show that we can use Python to accelerate the code and simply use Excel as a template where print our results, creating 
  dashboards, reports and so on. Thus, for me Python and Excel/VBA is a good association and I will use it going forward.
  &lt;br /&gt;
  &lt;/span&gt;
 &lt;/span&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/4453364745851344067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/02/python-and-excelvba.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/4453364745851344067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/4453364745851344067'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/02/python-and-excelvba.html' title='Python and Excel/VBA'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhm8shTnqoFdSyrl1HJ91b63s40OQDqOvWuUFz98-FurK5nuHBgZArHcE9KWEdUfrMnl9Jy_gdnfj5-ZCKcQc6stG_mqgN6p-Xuh767eqOxO3jONxhLuifRRxUoXHD-66j4yXeCEaYZlTYU/s72-c/template.png" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Frankfurt, Germany</georss:featurename><georss:point>50.1109221 8.6821267000000262</georss:point><georss:box>49.7851336 8.0366797000000254 50.436710600000005 9.3275737000000269</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-2326957033294007451</id><published>2014-01-25T00:54:00.000+01:00</published><updated>2014-08-21T11:42:17.130+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="data visualization"/><category scheme="http://www.blogger.com/atom/ns#" term="graphs"/><category scheme="http://www.blogger.com/atom/ns#" term="web scraping"/><title type='text'>Networks 1: Scraping + Data visualization + Graph stats</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  &lt;!--intro--&gt;
  These last weeks I have been reading about networks and optimization algorithms, I think is an interesting field with many applications, 
  so my idea was write a new article (or series of articles) showing roughly how use some interesting python libraries like Networkx, for instance. 
  In this article I also like to make a brief introduction to Scraping (a very good way to get data for your graphs).
  &lt;br /&gt;&lt;br /&gt;
  And only to whet your appetite: 
  &lt;br /&gt;&lt;br /&gt;
  
  &lt;!--images--&gt;
  &lt;!--undirected graph--&gt;
  &lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZjILEKb-_YIOLaMV0Q8Tov0k4NCKbYXkRHKIBD7nIf7dVFeQEa82bCZHEWQbyHcMklf-Toaj63hp85W8C74oV2vH2vJO5scs6DsjdZ71uBkpUDDgmALJscqe7IBnG-7Uh2KLEq-gwWrd5/s1600/undirectedgraph.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZjILEKb-_YIOLaMV0Q8Tov0k4NCKbYXkRHKIBD7nIf7dVFeQEa82bCZHEWQbyHcMklf-Toaj63hp85W8C74oV2vH2vJO5scs6DsjdZ71uBkpUDDgmALJscqe7IBnG-7Uh2KLEq-gwWrd5/s1600/undirectedgraph.png&quot; height=&quot;544&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1. Undirected graph.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;Web Scraping:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
  &lt;br /&gt;
  The first step to construct graphs like the previous one is get the data. As example, I wanted to visualize the whole foreign exchange market
  and the connections between each currency (Foreign exchange cross rates), but there are another good examples like user connections in social networks (Twitter, Facebook etc). &lt;br /&gt;
  For this case study(Forex), there are several available websites where you can find financial data for free, nonetheless this data will
  be restricted to certain time periods, so do not expect 10 or 30 seconds candles for free. 
  &lt;br /&gt;&lt;br /&gt;
  &lt;u&gt;List of Forex websites:&lt;/u&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;https://www.google.com/finance&quot;&gt;Google Finance&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://finance.yahoo.com/&quot;&gt;Yahoo Finance&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://www.dukascopy.com/swiss/english/home/&quot;&gt;Dukascopy&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://www.investing.com/&quot;&gt;Investing&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
  &lt;br /&gt;
  Once we have selected our source, we can think about how extract the info. Some websites like Yahoo Finance allow downloading end-of-day equities
  or forex data, normally in csv format. But let&#39;s image that our intention is to obtain the most possible current data. Here Scraping is the appropriate
  technique. Web scraping is the process of automatically collecting information from websites, usually simulating human interaction through a 
  full-fledged web browser. Note: web scraping may be against the terms of use of several websites.&lt;br /&gt;&lt;br /&gt;
  For this purpose, I used the next python modules:
  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ol&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://docs.python.org/2/library/urllib2.html&quot;&gt;urllib2&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://docs.python.org/2/library/urlparse.html&quot;&gt;urlparse&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://docs.python.org/2/library/re.html&quot;&gt;re&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;a href=&quot;http://www.crummy.com/software/BeautifulSoup/bs4/doc/&quot;&gt;BeautifulSoup&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;br /&gt;
  The goal then is extract all the foreign exchange cross rates. This data will be collected in three numpy arrays and finally 
  we will create a dataframe with pandas to export a csv file. The tricky part of all this is parse the html file, however BeautifulSoup allows using 
  regular expressions, which combined with urlparse creates a powerful and simple tool. So let&#39;s take a look at the script.&lt;br /&gt;
  &lt;!--scraping python--&gt;
&lt;br /&gt;&lt;u&gt;Script:&lt;/u&gt; &lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;import numpy as np
import pandas as pd
import urllib2
import urlparse
import re
from bs4 import BeautifulSoup

#------------------------------------------------------------------------------
#Functions:
#------------------------------------------------------------------------------


def add_exchange(Data):
    Value = []
    for link in Data[0, :]:
        soup = connect(link)
        for span in soup.find_all(&#39;span&#39;, {&#39;id&#39;: &#39;last_last&#39;}):
            #remove thousands (&quot;,&quot;)
            value = (span.text).replace(&#39;,&#39;, &#39;&#39;)
            Value.append(value)
    return np.vstack((Data, Value))


def connect(site):
    hdr = {&#39;User-Agent&#39;: &#39;Mozilla/5.0 (X11; Linux x86_64)&#39;,
       &#39;Accept&#39;: &#39;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&#39;,
       &#39;Accept-Charset&#39;: &#39;ISO-8859-1,utf-8;q=0.7,*;q=0.3&#39;,
       &#39;Accept-Encoding&#39;: &#39;none&#39;,
       &#39;Accept-Language&#39;: &#39;en-US,en;q=0.8&#39;,
       &#39;Connection&#39;: &#39;keep-alive&#39;}
    req = urllib2.Request(site, headers=hdr)
    page = urllib2.urlopen(req).read()
    soup = BeautifulSoup(page)
    return soup

#------------------------------------------------------------------------------
#Extract list of currencies + Matrix
#------------------------------------------------------------------------------
mainSites = {&#39;http://www.investing.com/currencies/middle-east&#39;,
    &#39;http://www.investing.com/currencies/north-america&#39;,
    &#39;http://www.investing.com/currencies/central-america&#39;,
    &#39;http://www.investing.com/currencies/south-america&#39;,
    &#39;http://www.investing.com/currencies/asia&#39;,
    &#39;http://www.investing.com/currencies/pacific&#39;,
    &#39;http://www.investing.com/currencies/europe&#39;,
    &#39;http://www.investing.com/currencies/middle-east&#39;,
    &#39;http://www.investing.com/currencies/africa&#39;,
    &#39;http://www.investing.com/currencies/caribbean&#39;}

FxUrls = []
C1 = []
C2 = []
for mainSite in mainSites:
    soup = connect(mainSite)
    for link in soup.find_all(href=re.compile(&quot;www.investing.com/currencies/&quot;)):
        #extract currencies:
        url = link.get(&#39;href&#39;)
        FxUrls.append(url)
        currencies = urlparse.urlparse(url).path.split(&quot;/&quot;)[2].split(&quot;-&quot;)
        C1.append(currencies[0])
        C2.append(currencies[1])

#Create Matrix
Forex = np.vstack((FxUrls, C1, C2))
#------------------------------------------------------------------------------

#Extract all foreign exchange cross rates:
Import = add_exchange(Forex)

#Pandas dataframe
data = {&#39;currency_1&#39;: Import[1, :],
    &#39;currency_2&#39;: Import[2, :],
    &#39;value&#39;: Import[3, :]}

df = pd.DataFrame(data)
df.to_csv(&#39;Forex.csv&#39;, index=False, cols=[&#39;currency_1&#39;, &#39;currency_2&#39;, &#39;value&#39;])

&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
Summarizing what we have done in this script: &lt;br /&gt;&lt;br /&gt;
  
  I wrote two functions, one in order to connect with website and capture the html page, and the other one to parse this html and select
  the required information. There are different ways to extract the data, select the one that best suits the structure of your html file. 
  Run the script, just take into account that this script may take a while depending on your internet connection.
  &lt;br /&gt;
  With this tool, you might consider a dynamic system to obtain frequently data. Well, that would be complicated and unlikely, your 
  IP address would be blocked if the number of requests is considerable.
  &lt;br /&gt;&lt;br /&gt;
  &lt;br /&gt;&lt;u&gt;&lt;b&gt;Networkx - Graphs:&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
  &lt;br /&gt;
  Now we have collected the data, it&#39;s time to show what we got. For the creation and study of the graphs we will use the python package 
  called &lt;a href=&quot;http://networkx.github.io/&quot;&gt;Networkx&lt;/a&gt;. This is a pretty helpful package which provides many functions and algorithm 
  that facilitate the study of complex networks. However, this may be not the best package to draw your graph, although we can use it as an 
  interface to use &lt;a href=&quot;http://www.graphviz.org/&quot;&gt;Graphviz&lt;/a&gt;.
  &lt;br /&gt;&lt;br /&gt;
  The first thing I did was write a new module, called &quot;graphs&quot;, with the Networkx&#39;s functionalities I needed. This includes two classes, 
  &quot;create_graph&quot;and &quot;graphStats&quot;. The first one reads the produced csv file and creates the two elements that form a graph, nodes and edges.
  In this case we also have weights, the exchange rates (third column), so we need a list in order to create the labels, which looks like this:
  &lt;br /&gt;&lt;br /&gt;
  example: {(&#39;D&#39;, &#39;E&#39;):9.0, (&#39;F&#39;, &#39;N&#39;):6.0}...
  &lt;br /&gt;&lt;br /&gt;
  The class &quot;graphStats&quot; includes two functions in order to calculate the degree centrality and betweenness centrality, we will talk about this
  in more detail later on.
  &lt;br /&gt;
  &lt;!--Graph class--&gt;
&lt;br /&gt;&lt;u&gt;Graph class:&lt;/u&gt; &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import networkx as nx
from operator import itemgetters
import pandas as pd
import numpy as np


class create_graph:

    def __init__(self):
        data = &#39;csv/Forex.csv&#39;
        headers = [&#39;start&#39;, &#39;end&#39;, &#39;weights&#39;]
        self.Network = pd.read_csv(data, skiprows=1, names=headers)
        self.graph = np.asarray(self.Network[[&#39;start&#39;, &#39;end&#39;]])
        self.nodes = np.unique(self.graph)
        self.weights = list(map(float, self.Network[&#39;weights&#39;]))

    def networkList(self):
        G = nx.DiGraph()
        for node in self.nodes:
            G.add_node(node)

        self.graph_l = []
        for edge in self.graph:
            G.add_edge(edge[0], edge[1])
            self.graph_l.append((edge[0], edge[1]))

        labels = dict(list(zip(self.graph_l, self.weights)))
        return G, labels


class graphStats:

    def calculate_degree_centrality(self, graph):
        dgc_key = []
        dgc_value = []
        g = graph
        dc = nx.degree_centrality(g)
        nx.set_node_attributes(g, &#39;degree_cent&#39;, dc)
        degcent_sorted = sorted(dc.items(), key=itemgetter(1), reverse=True)
        for key, value in degcent_sorted:
            dgc_key.append(str(key))
            dgc_value.append(value)
        return dgc_key, dgc_value

    def calculate_betweenness_centrality(self, graph):
        btc_key = []
        btc_value = []
        g = graph
        bc = nx.betweenness_centrality(g)
        betcent_sorted = sorted(bc.items(), key=itemgetter(1), reverse=True)
        for key, value in betcent_sorted:
            btc_key.append(str(key))
            btc_value.append(value)
        return btc_key, btc_value

&lt;/pre&gt;
&lt;br /&gt;
  Now we have prepared the module, we will use matplotlib to draw the graph. Actually, this is not a huge network, it has only 133 nodes and 
  1918 edges, but it is difficult get a good resolution if your output file is .jpg or png, so I recommend a pdf file and some adjustments 
  in the figure size.
  &lt;br /&gt;

&lt;!--Graph--&gt;
&lt;br /&gt;&lt;u&gt;Graph - plot:&lt;/u&gt; &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import networkx as nx
import matplotlib.pyplot as plt
import graphs

#------------------------------------------------------------------------------
# Read data + create graph
#------------------------------------------------------------------------------
gr = graphs.create_graph()
graph = gr.graph
G, labels = gr.networkList()

#------------------------------------------------------------------------------
# Graph plot:
#------------------------------------------------------------------------------
fig = plt.figure()
#fig = plt.figure(figsize=(8,8), dpi=1000) - pdf file
pos = nx.graphviz_layout(G, prog=&#39;neato&#39;)
node_color = [float(G.degree(v)) for v in G]
nx.draw_networkx_nodes(G, pos, node_size=[float(G.degree(v)) * 2.5 for v in G],
             alpha=0.6, node_color=node_color)
nx.draw_networkx_edges(G, pos, alpha=0.25, edge_color=&#39;blue&#39;, width=0.5,
arrows=False)
nx.draw_networkx_labels(G, pos, font_size=2.5)

plt.axis(&#39;off&#39;)
plt.show()
#plt.savefig(&quot;directedGraph.pdf&quot;)

&lt;/pre&gt;
&lt;!--undirected graph / detail--&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgpSxlG3xXl66EIj2bpkb-PR0vHAqO_oiYcLNgU29ejVrZ7eqCtfCYQs7blfFQ7sSBQw5ibmQ-H7KUhAkiWS_RtVOV__VcEXJyz7NVy-Nj3NZc2_aggTW7gIMwaQXdmUGrPZORPB8G8ys7/s1600/detail_center.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgpSxlG3xXl66EIj2bpkb-PR0vHAqO_oiYcLNgU29ejVrZ7eqCtfCYQs7blfFQ7sSBQw5ibmQ-H7KUhAkiWS_RtVOV__VcEXJyz7NVy-Nj3NZc2_aggTW7gIMwaQXdmUGrPZORPB8G8ys7/s1600/detail_center.png&quot; height=&quot;364&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 1.1. Undirected graph (detail).&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;!--directed graph--&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU-jz_cw2vTWo7lsltWryYg_h20zRITIWafzMnkG9YV1t-OnpCPklH9-W-IMPmOl1luWsYc3O9c2YRY2GDYIHd8lU5yTllJwdidfM5gwDRHTDixj7wOoVemQqi4UjbJdgCm1lVkjVkbe2r/s1600/directedgraph.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhU-jz_cw2vTWo7lsltWryYg_h20zRITIWafzMnkG9YV1t-OnpCPklH9-W-IMPmOl1luWsYc3O9c2YRY2GDYIHd8lU5yTllJwdidfM5gwDRHTDixj7wOoVemQqi4UjbJdgCm1lVkjVkbe2r/s1600/directedgraph.png&quot; height=&quot;537&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;Figure 2. Directed graph.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
   The second graph is which shows the real Forex network. The Forex network is a directed graph, a graph where its edges have a direction
   associated with them. This digraph  is strongly connected due to it contains several pairs of vertices with both paths, 
   (euro -&amp;gt; dolar and dolar -&amp;gt; euro, for instance).
   &lt;br /&gt;
  &lt;!--Graph stats--&gt;
&lt;br /&gt;&lt;u&gt;Graph - stats:&lt;/u&gt; &lt;br /&gt;
   &lt;br /&gt;
   Networkx is a great python package to study graphs, its main purpose. In this point we are going to look into some statistics which 
   will help us to extract real information from our graphs with the aim of interpret the results properly.
   &lt;br /&gt;&lt;br /&gt;
   1) Betweenness centrality:&lt;br /&gt;&lt;br /&gt;
   Betweenness centrality quantifies the number of times a node acts as bridge along the shortest path between two other nodes. It is 
   basically a measure of connectedness between components of the graph.
   &lt;br /&gt;&lt;br /&gt;
   2) Degree centrality:&lt;br /&gt;&lt;br /&gt;
   The centrality for a node measures its relative importance within the graph. The degree centrality for a node (n) is the number of nodes 
   it is connected. The degree centrality values are normalized by the maximum degree in the graph. For a graph with self loops
   (a digraph) the maximum degree might be higher than 1 and the degree centrality as well.
   &lt;br /&gt;&lt;br /&gt;
   In this article I will not expand the theory behind these measures.
   &lt;br /&gt;
     
   
&lt;pre class=&quot;brush: py&quot;&gt;import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
import graphs


def topTable(field1, field2, n_top):
    topM = max(field2) * 0.9
    right = len(field1) * 0.75
    plt.text(right, topM * 1.08, &#39;Top %s&#39; % n_top, fontsize=12)
    for i in range(n_top):
        curr = field1[i]
        val = field2[i]
        plt.text(right, topM - i * topM / 20, &#39;{}) {} = {}&#39;.format(i + 1,
        curr.upper(), round(val, 3)), fontsize=8)

#------------------------------------------------------------------------------
# Read data + create graph
#------------------------------------------------------------------------------
gr = graphs.create_graph()
G, labels = gr.networkList()

#------------------------------------------------------------------------------
# Stats + plots:
#------------------------------------------------------------------------------
stats = graphs.graphStats()
betc_key, betc_value = stats.calculate_betweenness_centrality(G)
degc_key, degc_value = stats.calculate_degree_centrality(G)

#Average degree
N = G.order()
K = G.size()
avg_d = float(N) / K
avg_degree = &#39;Average degree: %.4f &#39; % (avg_d)


# Plot: Degree_centrality
plt.figure()

ax1 = plt.subplot(211)
plt.title(&#39;Degree centrality for nodes&#39;, fontsize=12)
a_lenght = np.arange(len(degc_value))
plt.bar(a_lenght, degc_value, color=cm.jet(degc_value), align=&#39;center&#39;)
plt.xticks(a_lenght, degc_key, size=&#39;small&#39;, rotation=&#39;vertical&#39;)
plt.tick_params(axis=&#39;x&#39;, labelsize=4)
plt.tick_params(axis=&#39;y&#39;, labelsize=8)
plt.autoscale(enable=True, axis=&#39;both&#39;, tight=None)

#Top degree centrality:
topTable(degc_key, degc_value, 10)
plt.text(len(degc_value) * 0.75, max(degc_value) * 0.4, avg_degree,
bbox={&#39;facecolor&#39;: &#39;blue&#39;, &#39;alpha&#39;: 0.25, &#39;pad&#39;: 10}, fontsize=7)

# Plot: Betweenness_centrality
plt.subplot(212)
plt.title(&#39;Betweenness centrality for nodes&#39;, fontsize=12)
a_lenght = np.arange(len(betc_value))
plt.bar(a_lenght, betc_value, color=cm.jet(betc_value), align=&#39;center&#39;)
plt.xticks(a_lenght, betc_key, size=&#39;small&#39;, rotation=&#39;vertical&#39;)
plt.tick_params(axis=&#39;x&#39;, labelsize=4)
plt.tick_params(axis=&#39;y&#39;, labelsize=8)
plt.autoscale(enable=True, axis=&#39;both&#39;, tight=None)
plt.ylim(0, max(betc_value) * 1.1)
plt.plot(betc_value, &#39;--b&#39;)

#Top degree betweenness:
topTable(betc_key, betc_value, 10)

plt.show()

&lt;/pre&gt;
&lt;!--stats--&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMPPxoQy64VcPHVSXKACxbpHC9vLqrGZzUO92-UzL4OVnU279IsJ45j3PM_VZSREq-jHgvHH-DEtBieyCJnPjPNsMj-4nNQp8yxa2l2ZkTcSAQ4xMNXeuh2r2DEa3qz2j-pS8U-zTarMM3/s1600/DegreeBetwCentr.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMPPxoQy64VcPHVSXKACxbpHC9vLqrGZzUO92-UzL4OVnU279IsJ45j3PM_VZSREq-jHgvHH-DEtBieyCJnPjPNsMj-4nNQp8yxa2l2ZkTcSAQ4xMNXeuh2r2DEa3qz2j-pS8U-zTarMM3/s1600/DegreeBetwCentr.png&quot; height=&quot;436&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The above plot shows the currencies which have more relevance into the network, and as we suspected these are: USD dolar, Euro and the pound sterling. 
We can make at least two significant considerations; The average degree centrality is quite low, what shows that there are currencies with a notable grade 
of popularity(Degree centrality : in-degree) and these same currencies play a broker role in the network due to cumulate most of trajectories for 
the shortest paths. For this particular example,this might mean that we can create a more simplistic network, which would represent pretty faithfully 
the Forex market, excluding those currencies with fewer number of connections.
 &lt;br /&gt;&lt;br /&gt;
 
  &lt;!--Graph matrix--&gt;
&lt;br /&gt;&lt;u&gt;&lt;b&gt;Adjacency Matrix:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
  &lt;br /&gt;
  The adjacency matrix is a N x N matrix where the cells constitute edges. In this example the fields are coloured according
  the degree centrality and as the graph is directed, the matrix is not symmetric. 
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import numpy as np
import matplotlib.pyplot as plt
import graphs


gr = graphs.create_graph()
G = gr.networkList()[0]

n = len(gr.nodes)
oMapp = dict(list(zip(gr.nodes, np.arange(n))))

Mtx_w = (np.ones((n, n))) * np.inf
for i in range(len(gr.graph)):
    start = oMapp.get(gr.Network[&#39;start&#39;][i])
    end = oMapp.get(gr.Network[&#39;end&#39;][i])
    w = gr.Network[&#39;weights&#39;][i]
    Mtx_w[start, end] = w

Mtx_nodes = []
Mtx_nodes = np.array([np.concatenate([Mtx_nodes, gr.nodes]) for _ in range(n)])
#-----------------------------------------------------------------------------

# Show matrix by colour:
Mtx_Image = Mtx_w.copy()
for i in range(n):
    count = ((Mtx_Image[i, :] != np.inf) &amp;amp; (Mtx_Image[i, :] != np.nan)).sum()
    Mtx_Image[i, :][Mtx_Image[i, :] != np.inf] = count

# Gradient based on degrees
plt.figure()
plt.title(&#39;Foreign Exchange cross rates&#39;, fontsize=16)
plt.imshow(Mtx_Image, interpolation=&#39;nearest&#39;)
plt.xticks(np.arange(len(gr.nodes)), gr.nodes, rotation=90)
plt.yticks(np.arange(len(gr.nodes)), gr.nodes)
plt.tick_params(axis=&#39;both&#39;, labelsize=4)

plt.tight_layout()
plt.show()
#plt.savefig(&quot;Forex_Matrix.pdf&quot;)

&lt;/pre&gt;
&lt;/span&gt;&lt;br /&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMbXB-F0vKr4ehVr6qCpvYIWV2skCbRhrK_4FXEyAJ9rDJT2rleKIax_H92vGG65J9NAOryWID9-O3h3ZSx78wiX_LVdPHG_breP5IstevB85Z_nExj3uDwOfWM4Tal49xtJaccEgbycID/s1600/ForexMatrix.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMbXB-F0vKr4ehVr6qCpvYIWV2skCbRhrK_4FXEyAJ9rDJT2rleKIax_H92vGG65J9NAOryWID9-O3h3ZSx78wiX_LVdPHG_breP5IstevB85Z_nExj3uDwOfWM4Tal49xtJaccEgbycID/s1600/ForexMatrix.png&quot; height=&quot;370&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;
&lt;br /&gt;&lt;br /&gt;
&lt;!--conclusion--&gt;
  This first article related to networks has been just a brief introduction on this field. We will continue exploring graphs and graph algorithms in 
  next posts. Finally, I would like to make some notes regarding the network images, these images have been modified reversing the RGB output 
  (I preferred a black background), I used GIMP for that task.
 
  &lt;/span&gt;
&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/2326957033294007451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/01/networks-1-scraping-data-visualization.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2326957033294007451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/2326957033294007451'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/01/networks-1-scraping-data-visualization.html' title='Networks 1: Scraping + Data visualization + Graph stats'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZjILEKb-_YIOLaMV0Q8Tov0k4NCKbYXkRHKIBD7nIf7dVFeQEa82bCZHEWQbyHcMklf-Toaj63hp85W8C74oV2vH2vJO5scs6DsjdZ71uBkpUDDgmALJscqe7IBnG-7Uh2KLEq-gwWrd5/s72-c/undirectedgraph.png" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Frankfurt, Germany</georss:featurename><georss:point>50.1109221 8.6821267000000262</georss:point><georss:box>49.7851336 8.0366797000000254 50.436710600000005 9.3275737000000269</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-8994754009234855698</id><published>2014-01-05T02:02:00.000+01:00</published><updated>2014-08-21T11:46:51.517+02:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="numerical methods"/><title type='text'>Numerical methods: ODE and Finite difference method</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
  &lt;span style=&quot;font-size: small;&quot;&gt;
  The goal of this post is show how solve an ordinary differential equation, numerically and using the finite difference method and compare the result with the analytic solution.
  The problem statement is as follow:&lt;br /&gt;&lt;br /&gt;
  Numerically solve the ODE:  $m\frac{\partial^{2}y}{\partial t^{2}} = -b\frac{\partial y}{\partial t} $ that represents an object whose velocity at $t=0$ is equal to $v_0$ and it is slowing due to a retardant force, which is proportional to its velocity.&lt;br /&gt;&lt;br /&gt;
  The integration interval is $0 \leq t \leq 5$ seconds. For simplicity, we take $m = b = 1$. &lt;br /&gt;
  Boundary conditions: &lt;br /&gt;
  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;
   $y(0) = 0 m$ &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;
    $y(5) = 1 m$ &lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: small;&quot;&gt;Analytic solution: &lt;br /&gt;
  $Y(t) = \frac{m v_0}{b} (1 - e^{-\frac{b}{m}t})$ where $v_0 = 1$
  &lt;br /&gt;&lt;br /&gt;
  &lt;u&gt;&lt;b&gt;Ordinary differential equation:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
  We will start solving the ordinary differential equation of second grade . I will explain the resolution step by step:&lt;br /&gt;
  &lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Step 1: Characteristic equation&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;Step 2: Finding constants of integration&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
$m\frac{\partial^{2}y}{\partial t^{2}} = -b\frac{\partial y}{\partial t} \Rightarrow mD^{2} = -bD \Rightarrow D(mD + b) = 0 $&lt;br /&gt;

  Thus, we have two possible solutions: $s1 = 0; s2 = -\frac{b}{m}$. As these two roots are real and distinct ($s1 \ne s2$)  we can use the general solution for this specific case:
  &lt;br /&gt;
  &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;$Y(x) = C1 e^{s_1 x} + C2 e^{s_2 x}  \Rightarrow Y(t) = C1 e^{0 t} + C2 e^{-\frac{b}{m} t} = C1+C2 e^{-\frac{b}{m} t}$&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
&lt;br /&gt;  
  Using the boundary conditions we can obtain the constants of integration C1 and C2:&lt;br /&gt;
  $Y(t=0) \Rightarrow C1 = -C2$ &lt;br /&gt;
  $Y(t=5) \Rightarrow -C2 + C2e^{-\frac{b}{m} 5 }  = 1 \Rightarrow (-1 + e^{-\frac{b}{m} 5 } ) C2 = 1 \Rightarrow C2 = \frac{1}{(-1 + e^{-\frac{b}{m} 5 } ) } $ &lt;br /&gt;
  Solution: 
  &lt;br /&gt;$Y(t) = -\frac{1}{(-1 + e^{-\frac{b}{m} 5 } ) }  + \frac{1}{(-1 + e^{-\frac{b}{m} 5 } ) } e^{-\frac{b}{m} t}$ &lt;br /&gt;
  &lt;br /&gt; $m = b = 1 \Rightarrow  Y(t) = 1.00678  - 1.00678 e^{-t}$&lt;br /&gt;&lt;br /&gt;
  
  &lt;u&gt;&lt;b&gt;Finite difference method:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
  We use the centered difference at time t to obtain the central difference approximation in both equation sides.&lt;br /&gt;
  \[y&quot; = \frac{\partial^{2}y}{\partial t^{2}}  = \frac{U_{i+1} - 2U_i + U_ {i-1}}{h^{2}}  \enspace y&#39; = \frac{\partial y}{\partial t} = \frac{U_{i+1}-U_{i-1}}{2h} \]&lt;br /&gt;
  Now we can sustitude these above approximations in the initial expression: &lt;br /&gt;
  \[\frac{m}{h^{2}}(U_{i+1} - 2U_i + U_ {i-1}) = -\frac{b}{2h}(U_{i+1}-U_{i-1})\]
  Isolate $U_i$: &lt;br /&gt;
  $U_{i+1} - 2U_i + U_ {i-1} = -\frac{b}{2h}(U_{i+1}-U_{i-1})\frac{h^{2}}{m} \Rightarrow [-\frac{bh}{2m}(U_{i+1}-U_{i-1})-(U_{i+1}+U_{i-1})] \frac{1}{-2} = U_i$ 
  &lt;br /&gt;&lt;br /&gt;
  &lt;u&gt;&lt;b&gt;Implementation:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
  For this simple example, we create a Python class called &quot;ODE&quot;, which includes the analytic solution and the basic methodology based on the iterative scheme.&lt;br /&gt;
  &lt;br /&gt;
  Iterations:
&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;def solve(self, n, steps, m, b, h):
    v = np.zeros(n)
    #Boundary conditions
    #y(t = 0) = 0
    v[0] = 0
    #y(t = 5) = 1
    v[n - 1] = 1

    #Iterations
    for i in range(steps):
        for i in range(1, n - 1):
            a1 = (v[i - 1] - v[i + 1]) * (b * h / (2 * m))
            a2 = v[i + 1] + v[i - 1]
            v[i] = (a1 - a2) / (-2)
    return v
&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;
As shown, the first value in the array $= 0$, first boundary condition (we start the loop in the position 1) and the last value = 1 (position n - 1). 
  Finally, the function returns the complete array. &lt;br /&gt;&lt;br /&gt;
  The attached chart shows how the result is approximated by finite difference as the number of iterations increases.

  &lt;br /&gt;&lt;br /&gt;
  &lt;/span&gt;
 &lt;/span&gt;


  &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoVFAbJNvKTKSO0C_aXowjanpvXYNQX9ybokRkh3p_aj2ufkteJLbrYt8sVpmil-BKbxlZnN5Xv81eiUgyBdw9Ll33OLKgOBYk5Wr1iuYHu0O0eSdSuNC1YQb92XLU-se5_hkBrtmXRkcC/s1600/results.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoVFAbJNvKTKSO0C_aXowjanpvXYNQX9ybokRkh3p_aj2ufkteJLbrYt8sVpmil-BKbxlZnN5Xv81eiUgyBdw9Ll33OLKgOBYk5Wr1iuYHu0O0eSdSuNC1YQb92XLU-se5_hkBrtmXRkcC/s640/results.png&quot; height=&quot;368&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;Code:&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import numpy as np
import matplotlib.pyplot as plt


class ODE(object):

    def __init__(self, m, b, v0, t_min, t_max, n):
        self.t = np.linspace(t_min, t_max, n)
        #Analytic solution
        self.s = m * v0 / b * (1 - np.exp(- b / m * self.t))
        #ODE
        C2 = 1 / (- 1 + np.exp(- b / m * t_max))
        C1 = -C2
        self.f = C1 + C2 * np.exp(- b / m * self.t)

    def solve(self, n, steps, m, b, h):
        v = np.zeros(n)
        #Boundary conditions
        #y(t = 0) = 0
        v[0] = 0
        #y(t = 5) = 1
        v[n - 1] = 1

        #Iterations
        for i in range(steps):
            for i in range(1, n - 1):
                a1 = (v[i - 1] - v[i + 1]) * (b * h / (2 * m))
                a2 = v[i + 1] + v[i - 1]
                v[i] = (a1 - a2) / (-2)
        return v

#inputs and solution:
m = 1
b = 1
v0 = b / m
t_min = 0.0
t_max = 5.0
n = 100
h = t_max / n

vel = ODE(m, b, v0, t_min, t_max, n)
plt.plot(vel.t, vel.f, &#39;b.-&#39;, label=&#39;ODE&#39;)
plt.plot(vel.t, vel.s, &#39;g.-&#39;, label=&#39;Analytic solution&#39;)

for i in range(250, 3000, 500):
    sol_i = vel.solve(n, i, m, b, h)
    plt.plot(vel.t, sol_i, &#39;-.&#39;, label=r&#39;Iteration = %i&#39; % i)

plt.ylabel(&#39;Distance (m)&#39;)
plt.xlabel(&#39;Time (s)&#39;)

plt.legend(loc=2, prop={&#39;size&#39;: 9})
plt.show()
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/8994754009234855698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2014/01/numerical-methods-ode-and-finite.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/8994754009234855698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/8994754009234855698'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2014/01/numerical-methods-ode-and-finite.html' title='Numerical methods: ODE and Finite difference method'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoVFAbJNvKTKSO0C_aXowjanpvXYNQX9ybokRkh3p_aj2ufkteJLbrYt8sVpmil-BKbxlZnN5Xv81eiUgyBdw9Ll33OLKgOBYk5Wr1iuYHu0O0eSdSuNC1YQb92XLU-se5_hkBrtmXRkcC/s72-c/results.png" height="72" width="72"/><thr:total>0</thr:total><georss:featurename>Frankfurt, Germany</georss:featurename><georss:point>50.1109221 8.6821267000000262</georss:point><georss:box>49.7851336 8.0366797000000254 50.436710600000005 9.3275737000000269</georss:box></entry><entry><id>tag:blogger.com,1999:blog-3252642569764035520.post-3263471943282485519</id><published>2013-11-30T00:46:00.000+01:00</published><updated>2014-11-14T13:05:55.910+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="statistics"/><title type='text'>Weibull analysis</title><content type='html'>&lt;div style=&quot;text-align: justify;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;This first post in &lt;b&gt;ComputSimu&lt;/b&gt; will explain the basic methodology to calculate Weibull distribution given a data set, in this case a data set provided by a three point bending test for specimens with circular cross section. The Weibull distribution is one of the most used distributions to model life data, due to its extreme flexibility to fit a wide range of data (Normal distribution or logarithmic distribution, for instance) and its applicability modelling different problems (weather forecasting, failure analysis, delivery times, etc...) &lt;br /&gt;&lt;br /&gt;For creating the plot and calculate the Weibull distribution parameters we will use a python script (&lt;a href=&quot;http://www.python.org/&quot;&gt;www.python.org&lt;/a&gt;). Python is widely extended as scripting language in computational science with an impressive support, which guarantees a constant number of new modules and improvements. &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;u&gt;&lt;b&gt;Schema:&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;
&lt;ol&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Three point bending test&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Weibull distribution&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Characteristic life&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Weibull distribution characteristics&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Extra: Gamma function&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;/span&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Code&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;&lt;u&gt;&lt;b&gt;1) Three point bending test&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;This test consists in an applied force (F) acting at the center of a beam to assess the fracture resistance. Required formulas: &lt;br /&gt;&lt;br /&gt;&lt;u&gt;Beam deflection (double pinned contact):&lt;/u&gt; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;$Moment(max) =\dfrac{F}{2}\dfrac{L}{2} = \dfrac{FL}{4}$ where \(L = span\) (mm) and \(F = load\) (N)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;$Stress(max) = \dfrac{M_t}{\dfrac{I_p}{r}} = \dfrac{M_t}{W_p}$ where \(r = radius\) (mm); \(W_p = W_y = W_z = \dfrac{I_y}{r} = \dfrac{\dfrac{\pi r^4}{4}}{r} = \dfrac{\pi r^3}{4}\)&lt;br /&gt;$Stress(max) = \dfrac{Moment(max)}{Resisting Bending Moment} = \dfrac{\dfrac{FL}{4}}{\dfrac{\pi r^3}{4}} = \dfrac{FL}{\pi r^3}$ (MPa)&lt;br /&gt;We will use &lt;a href=&quot;http://www.numpy.org/&quot;&gt;Numpy&lt;/a&gt; to import the data (there are many options, but this works pretty well). The completed code is on the bottom of the post, but I will explain quickly the most important parts. The first step is import the data into an array. These values are ordered ascendant, which is a must in order to calculate the failure probability, but you can also order your array once the values are imported. Example: &lt;br /&gt;&lt;br /&gt;&lt;u&gt;&lt;b&gt;F(N)&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;333&lt;br /&gt;440&lt;br /&gt;440&lt;br /&gt;... &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt; path = &#39;../Data_Test.csv&#39;
 aSamples = np.genfromtxt(path, delimiter=&#39;,&#39;, skip_header=1, dtype=&#39;f&#39;)
 &lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;Now, we need two functions to create two new arrays with failure probabilities and the failure stresses. To calculate the probability we can choose one of the two methods below depending on the number of samples. &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;/span&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;
def FailureProb(n, N):
    if(N &amp;lt; 100):
        #Bernard&#39;s approximation
        return (n - 0.3) / (N + 0.4)
    else:
        #Mean Ranks
        return n / (N + 1)


def MaxStress(F, L, r):
    # Maximum Stress (cylinder 3 points)
    return (F * L) / (math.pi * r ** 3)

aSamples = np.genfromtxt(path, delimiter=&#39;,&#39;, skip_header=1, dtype=&#39;f&#39;)

aFailureProb = aSamples.copy()
aFailureStress = aSamples.copy()

for i in range(len(aFailureProb)):
    aFailureProb[i] = FailureProb((i + 1), float(len(aSamples) + 1))
    aFailureStress[i] = MaxStress(aSamples[i], L, r) 
&lt;/pre&gt;
&lt;/div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;br /&gt;&lt;u&gt;&lt;b&gt;2) Weibull distribution&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;The probability density function of a random variable is: \[f(x; \alpha, \beta) = \begin{cases} \frac{\alpha}{\beta} (\frac{x}{\alpha})^{(\alpha - 1)} e^{-(\frac{x}{\beta})^{\alpha}} &amp;amp; \text{if } x \geq 0 \\ 0 &amp;amp; \text{if } x &amp;lt; 0 \end{cases}\]&lt;br /&gt;and the cumulative distribution function is: \[F(x; \alpha, \beta) = \begin{cases} 1-e^{-(\frac{x}{\beta})^{\alpha}} &amp;amp; \text{if } x \geq 0 \\ 0 &amp;amp; \text{if } x &amp;lt; 0 \end{cases}\]&lt;br /&gt;&lt;u&gt;Shape parameter ($\alpha$):&lt;/u&gt;&lt;br /&gt;$\alpha$ shows how the failure rate develops in time. We can describe three different situations for the parameter $\alpha$: 
&lt;/span&gt;&lt;br /&gt;
&lt;ul&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\alpha$ &amp;lt; 1: This first situation is characterized by a decreasing failure rate or hazard function. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\alpha$ = 1: The second situation is characterized by a constant failure rate (independent of time), this is called &lt;i&gt;lack of memory&lt;/i&gt;. In this situation Weibull distribution is identical to the exponential distribution. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\alpha$ &amp;gt; 1: The third situation is characterized by an increasing failure rate. This represents that the more older is the &quot;element&quot; the more likely it is to fail.&lt;/span&gt;&lt;/li&gt;
&lt;/span&gt;&lt;/ul&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;u&gt;Scale parameter or characteristic life ($\beta$):&lt;/u&gt;&lt;br /&gt;$\beta$ is the time/cycle/sample at which &lt;span style=&quot;color: purple;&quot;&gt;63,2%&lt;/span&gt; are expected to fail. This is a constant for all Weibull distribution, regardless the shape parameter. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Plot:&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8FD5hj0Zj2XDUntJwxTOLRY_FIxcYnHM6nUajF7CqiGtya_SFNuWQPHmkBSoWj15IlLN_3wtuCtmDRmD-jmjyzsWo-1Wcsvqg3kha9QJJTPkdKEhltKwfoBcO5QG6YucXtdqtKfvvmpLM/s1600/WeibullDistr.png&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8FD5hj0Zj2XDUntJwxTOLRY_FIxcYnHM6nUajF7CqiGtya_SFNuWQPHmkBSoWj15IlLN_3wtuCtmDRmD-jmjyzsWo-1Wcsvqg3kha9QJJTPkdKEhltKwfoBcO5QG6YucXtdqtKfvvmpLM/s640/WeibullDistr.png&quot; height=&quot;499&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;b&gt;Script:&lt;/b&gt; &lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;
&quot;&quot;&quot;
Weibull:
    1) Probability density function
    2) Cumulative distribution function
&quot;&quot;&quot;

import numpy as np
import matplotlib.pyplot as plt
from weibull import weibProbDist, weibCumDist

x = np.linspace(0, 5, 100)
a_alpha = np.array([0.5, 1, 2, 5])
label = r&#39;${\alpha} = %s, {\beta} = %s$&#39;

fig = plt.figure(&#39;Weibull&#39;)
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
for i in a_alpha:
    ax1.plot(x, weibProbDist(x, i, 1), label=label % (i, 1))
    ax2.plot(x, weibCumDist(x, i, 1), label=label % (i, 1))
ax1.set_title(&#39;Probability density function&#39;, size=12)
ax2.set_title(&#39;Cumulative distribution function&#39;, size=12)
ax1.legend(loc=1, prop={&#39;size&#39;: 10})
ax2.legend(loc=7, prop={&#39;size&#39;: 10})

fig.subplots_adjust(hspace=0.5)
plt.show()
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;
&lt;br /&gt;&lt;u&gt;&lt;b&gt;3) Characteristic life &lt;/b&gt;&lt;/u&gt;&lt;br /&gt;To obtain the Weibull parameters the first step is linearise the cumulative distribution functions: $F(x) = 1-e^{-(\frac{x}{\beta})^{\alpha}} \Rightarrow P_f = 1-e^{-(\frac{\sigma}{\sigma_0})^{m}}$ where m = slope and \(\sigma\) = scale (characteristic stress)&lt;br /&gt;&lt;br /&gt;$P_s = 1-P_f$&lt;br /&gt;$ln(P_s^{-1}) = ln(e^{(\frac{\sigma}{\sigma_0})^{m}}) \Rightarrow ln[ln(P_s^{-1})] = m \enspace ln(\frac{\sigma}{\sigma_0}) \Rightarrow ln[ln(P_s^{-1})] = m \enspace ln(\sigma) - m \enspace ln(\sigma_0)$&lt;br /&gt;&lt;br /&gt;Linear expression:&lt;br /&gt;$\underbrace{ln[ln(P_s^{-1})]}_\text{f(x)} = \underbrace{ m \enspace ln(\sigma)}_\text{mx} - \underbrace{ m \enspace ln(\sigma_0)}_\text{b}$&lt;br /&gt;Maximum likelihood estimation (MLE) - Linear regression: &lt;br /&gt;$m (slope)= \dfrac{Cov(ln(\sigma), ln[ln(P_s^{-1})])}{Var(ln(\sigma))} = \dfrac{\dfrac{1}{n} \sum_{i=1}^{n}(ln(\sigma) - \overline{ln(\sigma)}) (ln[ln(P_s^{-1})] - \overline{ln[ln(P_s^{-1})])}}{\dfrac{1}{n} \sum_{i=1}^{n}(ln(\sigma) - \overline{ln(\sigma)})^2}$&lt;br /&gt;$b (intercept)= \overline{ln[ln(P_s^{-1})])} - m \enspace \overline{ln(\sigma)}$&lt;/span&gt;In order to solve this simple equation we use &lt;a href=&quot;http://www.scipy.org/&quot;&gt;Scipy&lt;/a&gt; and its module called stats which apply the described methodology above. 
&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt; #Survival probability = 1 - Failure Probability
 aSurvivalProb = 1 - aFailureProb

 #Linear regression: parameters (m, b)
 aLnPs = np.log(- np.log(aSurvivalProb))
 aLnFS = np.log(aFailureStress / 1000)

 slope, intercept, r_square, s, std_error = stats.linregress(aLnFS, aLnPs)
 regressLine = slope * aLnPs + intercept

 #Characteristic life : Stress
 Stress = np.exp(- (intercept / slope)) * 1000
 Pr_Stress = weibCumDist(Stress, slope, Stress)
 &lt;/pre&gt;
Finally, we can calculate the parameter $\beta$ with the next expression: &lt;br /&gt;
$\beta, \sigma = e^{-(\frac{intercept(b)}{slope(m)})}$&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Plotting analysis results:&lt;/b&gt;&lt;br /&gt;
As described above, the final plot shows how a stress = 125,08 MPa is the characteristic stress whereby the failure probability is equal to 63,2%. The plots below try to be self-explanatory. &lt;br /&gt;
&lt;br /&gt;
&lt;table align=&quot;center&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;tr-caption-container&quot; style=&quot;margin-left: auto; margin-right: auto; text-align: center;&quot;&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEita8bHUPyeIUztW8ISO9FoNNfFCMzgJa54u9gSJ88tBsUaKKvJuOONocBtcTmF0gAWcV61pvuK1MiLbxiRJMzsaM_zE0Rwqo8AGLgHg2TmjPDvb6br554tKSlsAXk8GvgF8nKhbfGeIVle/s1600/FinalResults.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: auto; margin-right: auto;&quot;&gt;&lt;img border=&quot;0&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEita8bHUPyeIUztW8ISO9FoNNfFCMzgJa54u9gSJ88tBsUaKKvJuOONocBtcTmF0gAWcV61pvuK1MiLbxiRJMzsaM_zE0Rwqo8AGLgHg2TmjPDvb6br554tKSlsAXk8GvgF8nKhbfGeIVle/s640/FinalResults.png&quot; height=&quot;480&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;tr-caption&quot; style=&quot;text-align: center;&quot;&gt;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;4) Weibull distribution characteristics&lt;/b&gt;&lt;/u&gt; &lt;br /&gt;
You will find all characteristic parameters in the Weibull module. These parameters are exported into a .csv file. &lt;br /&gt;
$Mean = \beta \enspace \Gamma(1+\dfrac{1}{\alpha})$ &lt;br /&gt;
$Median = \beta \enspace \ln(2)^{(\frac{1}{\alpha})}$ &lt;br /&gt;
$Mode = \begin{cases} \beta \enspace (\frac{\alpha - 1}{\alpha})^{\frac{1}{\alpha}} &amp;amp; \text{if } \alpha &amp;gt; 1 \\ 0 &amp;amp; \text{if } \alpha = 1 \end{cases}$&lt;br /&gt;
$Variance = \beta^2 \enspace \Gamma(1+\dfrac{2}{\alpha}) - \mu^2$&lt;br /&gt;
$Skewness = \beta^2[\Gamma(1+\dfrac{3}{\alpha})+2(\Gamma(1+\dfrac{1}{\alpha}))^3 - 3[\Gamma(1+\dfrac{2}{\beta})][\Gamma(1+\dfrac{1}{\beta})]]$&lt;br /&gt;
&lt;u&gt;Skewness&lt;/u&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\text{if } \alpha &amp;lt; 3.6: Skewness &amp;gt; 0 $&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\text{if }\alpha = 3.6: Skewness = 0 $&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: inherit;&quot;&gt;$\text{if }\alpha &amp;gt; 3.6: Skewness &amp;lt; 0 $&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;5) Extra: Gamma function&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
&lt;br /&gt;
The Weibull module also include one of the possible approximations for the Gamma function, Lanczos approximation. You can find more information about different implementations on the links below: &lt;br /&gt;
&lt;a href=&quot;http://www.boost.org/doc/libs/1_35_0/libs/math/doc/sf_and_dist/html/math_toolkit/backgrounders/lanczos.html&quot;&gt;C++ library + pseudocode&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.rskey.org/CMS/index.php/the-library/11&quot;&gt;&quot;Calculators and the Gamma Function&quot;, Viktor T. Toth &lt;/a&gt;(Recommended)&lt;br /&gt;
&lt;br /&gt;
&lt;u&gt;&lt;b&gt;6) Code&lt;/b&gt;&lt;/u&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;import numpy as np
import matplotlib.pyplot as plt
import math
from scipy import stats
from weibull import *
import csv

#inputs:
L, r = float(40), float(4)
path = &#39;../Data_Test.csv&#39;
pathReport = &#39;../WeibullReport.csv&#39;


def FailureProb(n, N):
    if(N &amp;lt; 100):
        #Bernard&#39;s approximation
        return (n - 0.3) / (N + 0.4)
    else:
        #Mean Ranks
        return n / (N + 1)


def MaxStress(F, L, r):
    # Maximum Stress (cylinder 3 points)
    return (F * L) / (math.pi * r ** 3)

aSamples = np.genfromtxt(path, delimiter=&#39;,&#39;, skip_header=1, dtype=&#39;f&#39;)

aFailureProb = aSamples.copy()
aFailureStress = aSamples.copy()

for i in range(len(aFailureProb)):
    aFailureProb[i] = FailureProb((i + 1), float(len(aSamples) + 1))
    aFailureStress[i] = MaxStress(aSamples[i], L, r)

MeanForces = np.mean(aSamples)
MeanStress = np.mean(aFailureStress)

#Survival probability = 1 - Failure Probability
aSurvivalProb = 1 - aFailureProb

#Linear regression: parameters (m, b)
aLnPs = np.log(- np.log(aSurvivalProb))
aLnFS = np.log(aFailureStress / 1000)

slope, intercept, r_square, s, std_error = stats.linregress(aLnFS, aLnPs)
regressLine = slope * aLnPs + intercept

m = slope
b = intercept

#Characteristic life : Stress
Stress = np.exp(- (intercept / slope)) * 1000
Pr_Stress = weibCumDist(Stress, slope, Stress)

# export results to .csv
Results = [
            [&#39;Parameters&#39;, &#39;Value&#39;, &#39;Units&#39;],
            [&#39;shape (alpha)&#39;, slope],
            [&#39;scale (beta)&#39;, Stress, &#39;MPa&#39;],
            [&#39;Mean&#39;, weibMean(slope, Stress), &#39;MPa&#39;],
            [&#39;Median&#39;, weibMean(slope, Stress), &#39;MPa&#39;],
            [&#39;Mode&#39;, weibMode(slope, Stress), &#39;MPa&#39;],
            [&#39;Variance&#39;, weibVar(slope, Stress), &#39;MPa^2&#39;],
            [&#39;Standard Deviation&#39;, np.sqrt(weibVar(slope, Stress)), &#39;MPa&#39;],
            [&#39;Skewness&#39;, weibSkew(slope, Stress)]
          ]

with open(pathReport, &#39;wb&#39;) as f:
    writer = csv.writer(f)
    writer.writerows(Results)

#Plots:
fig = plt.figure(&#39;Weibull&#39;)
ax1 = fig.add_subplot(211)
scatt = ax1.scatter(aLnFS, aLnPs, label=&#39;samples&#39;, c=&#39;DarkTurquoise&#39;, s=15)
regres = ax1.plot(aLnPs, regressLine, &#39;b-&#39;, label=&#39;Linear regression (MLE)&#39;)
ax1.set_ylabel(&#39;$Ln[-Ln(Ps)]$&#39;)
ax1.set_xlabel(&#39;$Ln(\sigma) : Ln(GPa)$&#39;)
ax1.set_title(&#39;Weibull analysis&#39;)
ax1.set_ylim(min(aLnPs) * 1.1, max(aLnPs) * 1.25)
ax1.set_xlim(min(aLnFS) * 1.1, max(aLnFS) * 0.9)
ax1.legend(loc=2, prop={&#39;size&#39;: 10})
ax1.text(min(aLnFS) * 1.05, -1, r&#39;$y=%.4f m + %.4f$&#39; % (m, b))
ax1.text(min(aLnFS) * 1.05, -1.5, r&#39;$R^2=%.4f$&#39; % r_square)

x = np.linspace(0, round(Stress * 2, 0), 100)
ax2 = fig.add_subplot(212)
ax2.set_title(&#39;Weibull distribution&#39;)
ax2.plot(x, weibProbDist(x, slope, Stress), label=&#39;Prob. Density function&#39;)
ax2.fill_between(x, weibProbDist(x, slope, Stress), 0, color=&#39;0.90&#39;)
ax2.set_ylabel(r&#39;$f(x, {\alpha}, {\beta})$&#39;)
ax2.set_xlabel(r&#39;${\sigma} (MPa)$&#39;)
ax3 = ax2.twinx()
ax3.plot(x, weibCumDist(x, slope, Stress), &#39;r&#39;, label=&#39;Cum. distr. function&#39;)
ax3.fill_between(x, weibCumDist(x, slope, Stress), alpha=0.15, color=&#39;r&#39;)
ax3.set_ylim(0, 1)
ax3.set_ylabel(r&#39;$F(x) = 1-exp(-(x/{\beta})^{\alpha})$&#39;)
ax3.legend(loc=7, prop={&#39;size&#39;: 10})
ax2.legend(loc=2, prop={&#39;size&#39;: 10})

#Text:
ax3.text(5, 0.7, r&#39;${\alpha} = %.4f, {\beta} = %.4f$&#39; % (m, Stress))
ax3.text(5, 0.6, r&#39;$F(%s) = %s$&#39; % (round(Stress, 3), round(Pr_Stress, 3)),
color=&#39;m&#39;)

#Arrows:
ax3.arrow(Stress, 0, 0, Pr_Stress - 0.1, head_width=2, head_length=0.1,
ec=&#39;m&#39;, fc=&#39;m&#39;)
ax3.arrow(Stress, Pr_Stress, round(Stress * 2, 0) - Stress - 10, 0,
head_width=0.02, head_length=10, ec=&#39;m&#39;, fc=&#39;m&#39;)

fig.subplots_adjust(hspace=0.5)
plt.show()
&lt;/pre&gt;
&lt;span style=&quot;font-family: inherit;&quot;&gt;&lt;span style=&quot;font-size: small;&quot;&gt;Weibull module: &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class=&quot;brush: py&quot;&gt;&quot;&quot;&quot;
Weibull distribution:
    1) Probability density function
    2) Cumulative distribution function
    3) Mean
    4) Median
    5) Mode
    6) Variance - Standard deviation
    7) Skewness
    8) Gamma function (Lanczos approximation)
&quot;&quot;&quot;

import numpy as np
import cmath as cm


def weibProbDist(x, a, b):
    return (a / b) * (x / b) ** (a - 1) * np.exp(-(x / b) ** a)


def weibCumDist(x, a, b):
    return 1 - np.exp(-(x / b) ** a)


def weibMean(a, b):
    return b * gamma(1 + 1 / a)


def weibMedian(a, b):
    return b * np.log(2) ** (1 / a)


def weibMode(a, b):
    if a &amp;gt; 1:
        return b * ((a - 1) / a) ** (1 / a)
    else:
        return 0


def weibVar(a, b):
    return (b ** 2) * gamma(1 + 2 / a) - weibMean(a, b) ** 2


def weibSkew(a, b):
    ax_1 = gamma(1 + 3 / a) + 2 * (gamma(1 + 1 / a) ** 3)
    ax_2 = 3 * (gamma(1 + 2 / a) * gamma(1 + 1 / a))
    return (b ** 3) * (ax_1 - ax_2)

&quot;&quot;&quot;
Gamma function:

Lanczos approximation implementation.
Numerical Recipes in C (2nd ed. Cambridge University Press 1992)

&quot;&quot;&quot;
g = 5

p0 = float(1.000000000190015)
p1 = float(76.18009172947146)
p2 = float(-86.50532032941677)
p3 = float(24.01409824083091)
p4 = float(-1.231739572450155)
p5 = float(1.208650973866179e-3)
p6 = float(-5.395239384953e-6)

Pn_Coef = np.array([p0, p1, p2, p3, p4, p5, p6])


def gamma(z):
    z = complex(z)
    if z.real &amp;lt; 0.5:
        #Recursion method:
        return cm.pi / (cm.sin(cm.pi * z) * gamma(1 - z))
    else:
        ax_1 = cm.sqrt(cm.pi * 2) / z
        ax2_sum = Pn_Coef[0]
        for i in range(1, g + 2):
            ax2_sum += Pn_Coef[i] / (z + i)
        t = z + g + 0.5
        ax_3 = (t ** (z + 0.5)) * cm.exp(-t)
        return ((ax_1 * ax2_sum) * ax_3).real
 &lt;/pre&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://computsimu.blogspot.com/feeds/3263471943282485519/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://computsimu.blogspot.com/2013/11/weibull-analysis.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/3263471943282485519'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3252642569764035520/posts/default/3263471943282485519'/><link rel='alternate' type='text/html' href='http://computsimu.blogspot.com/2013/11/weibull-analysis.html' title='Weibull analysis'/><author><name>Guillermo Navas-Palencia</name><uri>http://www.blogger.com/profile/15645423728499196020</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8FD5hj0Zj2XDUntJwxTOLRY_FIxcYnHM6nUajF7CqiGtya_SFNuWQPHmkBSoWj15IlLN_3wtuCtmDRmD-jmjyzsWo-1Wcsvqg3kha9QJJTPkdKEhltKwfoBcO5QG6YucXtdqtKfvvmpLM/s72-c/WeibullDistr.png" height="72" width="72"/><thr:total>1</thr:total><georss:featurename>Frankfurt, Germany</georss:featurename><georss:point>50.1109221 8.6821267000000262</georss:point><georss:box>49.7851336 8.0366797000000254 50.436710600000005 9.3275737000000269</georss:box></entry></feed>