Blog con Nikola, Jupyter, Matlab y GitHub pages

Introducción

Nikola es un buena forma de crear un sitio web/blog estático. Es versátil, potente y de código abierto. Existen otras alternativas como, Hugo, Pelican, y Sphinx. Después de revisar los pros y contras, decidí usar Nikola principalmente por su integración con Jupyter Notebook y el Matlab-kernel.

Hay buen material en internet sobre la instalación y uso de Nikola, pero pensé que sería útil mostrar mi metodología desde la perspectiva de alguién que nunca usó Anaconda, Jupyter y Nikola.

Sin embargo, acá la lista de la documentación oficial y algunos tutoriales (inglés) que recomiendo:

Pre-requisitos

Configurar VSCode

  • Instalar Python extension.
  • Asegúrate que esté habilitado Python › Data Science: Allow Import From Notebook en configuración de la extensión.

Crea un nuevo entorno con Anaconda o Conda

  • Descarga e instala Anaconda o Miniconda. Es tu decisión.
  • Asegúrate que C:\ProgramData\Anaconda3 y C:\ProgramData\Anaconda3\Scripts estén listado path variables de Windows.
  • En el navegador de Anaconda, crea un entorno llamado jmatlabNikola con Python 3.6.
  • O abre la terminal y corre,
      conda create -n jmatlabNikola python=3.6
  • Una nueva carpeta se creará en C:\Users\<user_name>\.conda\envs\

¿Por qué Python 3.6?

Porque el Matlab engine es compatible solo con Python 2.7, 3.6, y 3.7. La versión 3.7 es para Matlab 2019+, y la versión 3.6 es para Matlab 2018+. También, Python 3.6 es conocido como la versión más estable.

¿Por qué un entorno?

Anaconda (conda) es una potente plataforma de administración de paquetes que te permite instalar espacio de trabajo auto-contenidos (entorno) con diferentes kernels y librerías. Por ejemplo, digamos que tengo dos entornos:

  • jmatlabNikola: compuesto por Python 3.6, Jupyter Notebook, jmatlab, y Nikola.
  • openCV_TF: compuesto por Python 3.7, OpenCV, y TensorFlow.

Entonces, si quiero escribir un post:

  • Corro activate jmatlabNikola → cambia a Python 3.6 (puedes verificar con python --version).
    (jmatlabNikola) C:\Users\<user_name>\blog>python --version
    Python 3.6.10 :: Anaconda, Inc.
    Cualquier post que escriba será compilado solamente en este entorno. Ninguna de las librerías del otro entorno(s) estará disponible.

Si quiero trabajar con OpenCV:

  • Corro activate openCV_TF → cambia a Python 3.7. El kernel y las librerías de jmatlabNikola no están disponibles y no se mezclarán con este entorno.
    (openCV_TF) C:\Users\<user_name>\ML_project>python --version
    Python 3.7.6 :: Anaconda, Inc.

Notas

  • No uses el entorno base de Anaconda si quieres probar paquetes. Úsalo como referencia porque es el entorno por defecto para tu sistema operativo.
  • Si ya tienes instalado Python, puedes usar Anaconda sin problema. Solo asegúrate que el Anaconda python path esté configurado en VSCode.
  • Tus documentos y carpetas de trabajo pueden estar en cualquier ubicación de tu disco duro, pero no los crees dentro las carpetas de los entornos.

Instalación de Jupyter Notebook, Nikola y jmatlab

  • Abre el terminal en cd "C:\Users\<user_name>\.conda\envs\jmatlabNikola"
  • Instala Jupyter Notebook:
    • Jupyter Notebook es instaladon por defecto cuando creas un entorno usando el navegador de Anaconda.
    • Con conda.
      conda install -c conda-forge notebook
    • Con pip.
      pip install notebook
    • Instala las nbextensions.
      pip install jupyter_contrib_nbextensions
      jupyter contrib nbextension install --user
    • Instala el Jupyter nbextension configurator.
      pip install jupyter_nbextensions_configurator
      jupyter nbextensions_configurator enable --user
    • Corre Jupyter Notebook por línea de comando para verificar que está instalado correctamente junto con las nbextensions.
      jupyter notebook
      Abrirá tu navegador en http://localhost:8888
    • Recomiendo habilitar las siguientes nbextensions
      • (some) LaTex environments for Jupyter
      • Equation Auto Numbering
      • CodeMirror mode extensions -> Matlab/Octave highlighting
      • Table of Contents (2) -> auto ToC
  • Instala Nikola.
    pip install Nikola[extras]
  • Instala Matlab-kernel.
    pip install matlab_kernel
  • Verifica los kernels instalados.
    jupyter kernelspec list
  • Verás algo parecido.
    Available kernels:
    matlab     C:\Users\<user_name>\.conda\envs\jmatlabNikola\share\jupyter\kernels\matlab
    python3    C:\Users\<user_name>\.conda\envs\jmatlabNikola\share\jupyter\kernels\python3

Configurar Matlab

  • Abre la terminal como administrador
    activate jmatlabNikola
  • Ve a cd "C:\Program Files\MATLAB\R2018b\extern\engines\python"
  • Instala el Python engine.
    python setup.py install

Listo!, ahora ya tienes todo lo que necesita tu entorno.

Notas

  • Asegúrate que activaste el entorno jmatlabNikola como administrador solo para instalar el matlab_kernel.
  • Si tienes dudas sobre el kernel de Python, verifica con python --version cuando actives un entorno.

Crea un sitio demo de Nikola

  • Crea un nuevo folder llamado blog donde quieras excepto dentro la carpeta del entorno jmatlabNikola.
  • Abre la terminal dentro tu carpeta blog.
  • Activa el entorno.
    activate jmatlabNikola
  • Inicializa el demo y llena su contenido.
    nikola init --demo
  • Construye (genera) los documentos HTML del sitio.
    nikola build
  • Revísalo en tu navegador. Abrirá el localhost en http://127.0.0.1:8000.
    nikola serve -b
  • Automaticamente build y serve tu sitio si deseas ver los cambios de tu sitio constantemente (recomendado).
    nikola auto
  • Limpia el contenido de la carpeta /output/ cada vez que remuevas documentos manualmente de la carpeta blog. Úsalo antes del comando build.
    nikola check -f --clean-files
  • ctrl+c para detener el servidor.

Crear un nuevo post y una nueva página

  • Por defecto, ambos son creados en formato .rst.
    nikola new_post
    nikola new_page
    
  • Otros formatos diferentes (-f ipynb necesita configuración extra, lo veremos más adelante).
    nikola new_post -f md
    nikola new_post -f rst
    nikola new_post -f html
    nikola new_post -f ipynb
    

Crear un sitio limpio de Nikola

Lo mismo que en la anterior sección pero corre nikola init en vez de nikola init --demo.

Listo!. Navega a través de los documentos y archivos para ver que hizo Nikola en el demo y la versión limpia.

Directorios de Nikola

Aunque muchos de ellos se explican solos, pueden categorizarse en tres tipos:

  • Contenido: files, galleries, images, listings, pages, posts.
  • Personalización: plugins, templates, themes.
  • Salida visible: output. Acá, todo el contenido es convertido a .html para ser visible en cualquier servicio de alojamiento de páginas web como GitHub pages.
    ../__pycache__
    ../cache     
    ../files      # all the files of your blog, e.g. pdf, videos, etc.
    ../galleries  # galleries of images.
    ../images     # images of your website.
    ../listings   # code files, e.g. .py, .tex, .m, .cpp, etc.
    ../output     # the root directory of your website. 
    ../pages      # stores index.html, blog.html, home.html, about-me.html. 
    ../plugins    # additional plugins.
    ../posts      # stores all your posts, .md, .html, .ipynb, and .rst
    ../templates  # additional templates. 
    ../themes     # additional themes.
    

Configurar un website Nikola (no un blog)

Desde esta sección, configuraremos Nikola usando conf.py que está localizado en la raíz de tu directorio.

Crear las páginas index y bio

  • Primero, creamos ambas páginas usando la termina.
    nikola new_page --title="index"
    nikola new_page --title="bio"
    
  • Los agregamos a la lista de navegación.
    NAVIGATION_LINKS = {
        DEFAULT_LANG: (
            ("/index.html", "Home"),
            ("/bio/index.html", "Bio"),
            ...
        ),
    
  • Agrega otra página que desees, solo asegúrate añadirlos a la lista, e.g. about-me, contact, etc.

Usar Jupyter Notebooks

  • Por defecto, Nikola usa la configuración blog.
    POSTS = (
        ("posts/*.rst", "posts", "post.tmpl"),
        ("posts/*.md", "posts", "post.tmpl"),
        ("posts/*.txt", "posts", "post.tmpl"),
        ("posts/*.html", "posts", "post.tmpl"),
        ("posts/*.ipynb", "posts", "post.tmpl"),
    )
    PAGES = (
        ("pages/*.rst", "pages", "page.tmpl"),
        ("pages/*.md", "pages", "page.tmpl"),
        ("pages/*.txt", "pages", "page.tmpl"),
        ("pages/*.html", "pages", "page.tmpl"),
        ("pages/*.ipynb", "pages", "page.tmpl"), 
    )
    
  • Cámbialo a la configuración no blog.
    POSTS = (
        ("posts/*.rst", "blog", "post.tmpl"),
        ("posts/*.md", "blog", "post.tmpl"),
        ("posts/*.txt", "blog", "post.tmpl"),
        ("posts/*.html", "blog", "post.tmpl"),
        ("posts/*.ipynb", "blog", "post_ipynb.tmpl"),
    )
    PAGES = (
        ("pages/*.rst", "", "page.tmpl"),
        ("pages/*.md", "", "page.tmpl"),
        ("pages/*.txt", "", "page.tmpl"),
        ("pages/*.html", "", "page.tmpl"),
        ("pages/*.ipynb", "", "post_ipynb.tmpl"),
    )
    # And to avoid a conflict because blogs try to generate /index.html
    INDEX_PATH = "blog"
    
  • Verifica si .ipynb está listado como compilador.
    COMPILERS = {
        "rest": ['.rst', '.txt'],
        "markdown": ['.md', '.mdown', '.markdown'],
        "textile": ['.textile'],
        "txt2tags": ['.t2t'],
        "bbcode": ['.bb'],
        "wiki": ['.wiki'],
        "ipynb": ['.ipynb'],
        "html": ['.html', '.htm'],
        ...
    
  • Si usas build y serve en el sitio, este te dará un error de "missing post_ipynb.tmpl", lo crearemos en la siguiente sección.
  • Cambia post_ipynb.tmpl a post.tmpl, y corre nikola auto para ver el estílo por defecto de Jupyter Notebook.

Crear el template post_ipynb.tmpl

  • Crea un nuevo tema.
    nikola theme --new=themeBlog --parent=bootstrap4 --engine=mako
  • Copia post.tmpl del directorio del original de bootstrap4.
    nikola theme --copy-template=post.tmpl
  • Muevelo al folder /themes/themeBlog/templates/post_ipynb.tmpl y renombralo como post_ipynb.tmpl
  • Agrega lo siguiente a la sección extra head del .tmpl
    <%block name="extra_head">
        ... 
        <link rel="stylesheet" href="../../assets/css/post_ipynb.css">
    </%block>
    

Crea el post_ipynb.css

Crea el documento en /themes/themeBlog/assets/css/post_ipynb.css y copia lo siguiente en su contenido.

div.prompt {
    padding: 0.6em;
    font-size: 13px;
    background-color: #ffffff;
    margin-right: 0em;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    border-radius: 3px;
}

div.output_prompt {
    /* 5px right shift to account for margin in parent container */
    margin: 0 5px 0 0px;
}

  div.output_area pre {
    font-size: 13px;
}

div.text_cell_render {
    padding: 0px;
    color: #333333;
}

.rendered_html p {
    text-align: left;
}

.rendered_html ul {
    margin: 0 0 12px 25px;
}

.rendered_html :visited {
    text-decoration: none;
}

.rendered_html :link {
    text-decoration: none;
  }

.rendered_html pre, .rendered_html code {
    background-color: #eeeeee;
    margin: 1em 0em;
    font-size: 14px;
}

.rendered_html pre {
    padding-left: 0.5em;
    padding-right: 0.5em;
    padding-top: 0.05em;
    padding-bottom: 0.05em;
}

.page-content > .content p {
    margin: 0 0 0px;
}


div.input  {
    border: none;
    background-color: none;
}

/* set a max-width for horizontal fluid layout and make it centered */
.body-content {
    margin-right: auto;
    margin-left: auto;
    max-width: 100%; /* or 950px */
}

/* Widens image-containing divs so that image is full body width */
div.output_subarea {     
    max-width: 100%;
}

Personaliza a placer. En mi caso, entre otros cambios, puse background-color: #ffffff para eliminar la barra lateral gris de las celdas de Jupyter Notebook.

Versión limpia de post_ipynb.css

div.prompt {
    display: none;
}

div.input  {
    border: none;
    background-color: none;
}

div.input * {
    background-color: none;
}

/* set a max-width for horizontal fluid layout and make it centered */
.body-content {
  margin-right: auto;
  margin-left: auto;
  max-width: 100%; /* or 950px */
}

/* Widens image-containing divs so that image is full body width */
div.output_subarea {
    max-width: 100%;
}

Usa tu tema personalizado

Una ves estés conforme con los cambios.

  • Habilita el tema.
    THEME = "themeBlog"
    
  • Crea un post de Jupyter Notebook y empieza a editar con VSCode.
    nikola new_post -f ipynb --title="Jupyter-notebook-test"

Configuraciones extras

Ubicación del folder de salida files

Tus documentos guardados en el folder files serán copiados a /output/files en vez de la raíz, que es su ubicación por defecto.

FILES_FOLDERS = {'files': 'files'}

Evita publicar borrardores de los posts

Si no deseas publicarlos.

  • Agrega los siguiente al metadata del post.
    .. status: draft
  • Configura lo siguiente en conf.py
    DEPLOY_DRAFTS = False
    
    Será compilado y visto en tu localhost pero no será publicado en GitHub. También, cuando corras nikola github_deploy, el post borrador es removido del folder output.

Por defecto la metadata no tiene la linea status, agrégalo.

.. status: published

Habilitar una sola lista de los posts

Crea una sola lista grande de los posts en vez de una por año.

CREATE_SINGLE_ARCHIVE = True

Favicon

Agrega tu favicon al sitio

FAVICONS = (
    ("icon", "/files/blogFavicon.ico", "128x128"),
)

Licencia

Agrega una licencia a tu contenido.

LICENSE = """
<a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/">
<img alt="Creative Commons License BY-NC-SA"
style="border-width:0; margin-bottom:12px;"
src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"></a>"""

Header (Encabezado)

Agrega FontAwesone y Academic Icons para usarlos en el contenido del pie de los posts.

EXTRA_HEAD_DATA = '''
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css">
  <link rel="stylesheet" href="https://cdn.rawgit.com/jpswalsh/academicons/master/css/academicons.min.css">
'''

Personaliza el footer como desees. Una buena forma es mostrar tus perfiles de redes sociales.

CONTENT_FOOTER = '''
<div class="text-center">
    <p>
        <span class="fa-stack fa-2x">
        <a href="https://github.com/<user_name>">
            <i class="fa fa-github-square fa-stack-2x"></i>
        </a>
        </span>
        <span class="fa-stack fa-2x">
        <a href="https://scholar.google.com/citations?user=ID">
            <i class="ai ai-google-scholar-square ai-2x"></i>
        </a>
        </span>
        <span class="fa-stack fa-2x">
        <a href="https://www.linkedin.com/in/ID">
            <i class="fa fa-square fa-stack-2x"></i>
            <i class="fa fa-linkedin fa-inverse fa-stack-1x"></i>
        </a>
        </span>
        <span class="fa-stack fa-2x">
        <a href="mailto:{email}">
            <i class="fa fa-square fa-stack-2x"></i>
            <i class="fa fa-envelope fa-inverse fa-stack-1x"></i>
        </a>
        </span>
    </p>
    <p>
        {license} Contents &copy; {date}  <a href="mailto:{email}">{author}</a> - Powered by <a href="https://getnikola.com" rel="nofollow">Nikola</a>
    </p>
</div>
'''

Barra de búsqueda de Google

Habilitalo según lo siguiente.

SEARCH_FORM = """
<!-- Google custom search -->
<form method="get" action="https://www.google.com/search" class="navbar-form navbar-right" role="search">
    <div class="input-group">
        <input type="text" name="q" class="form-control" placeholder="Search">
        <button type="submit" class="btn btn-secondary">
            <i class="fa fa-search"></i>
        </button>
        <input type="hidden" name="sitesearch" value="%s">
    </div>    
</form>
<!-- End of custom search -->
""" % SITE_URL

Notas

Comentarios Disqus

  • Crea una cuenta en Disqus.
    • Crea un nuevo sitio.
    • Elige un disqus_shortname, e.g. github_user_name. Yo recomiendo no usar <user_name>.github.io
    • Agrega tu blog <user_name>.github.io.
    • Escoge el 'Plan Básico'
    • Salta las instrucciones en la sección 'Escoge Plataforma'.
  • Finalmente, habilita lo siguiente en conf.py
    COMMENT_SYSTEM = "disqus"
    COMMENT_SYSTEM_ID = "<disqus_shortname>"
    

Configura la barra del menu

Puedes configurar que la barra del menu se mantenga pegado en la parte superior mientras te deslizas en la página.

  • Copia el template base.
    nikola theme --copy-template=base.tmpl
    
  • Muévelo a /themes/themeBlog/templates/base.tmpl y agrega lo siguiente.
    <!-- Menubar -->
    <nav class="navbar navbar-expand-md sticky-top mb-4
    ...
    

Formateo de códigos

Por defecto, Nikola usa Pygments para formatear los códigos.

  • Para Markdown y Jupyter Notebook.

    ```python
    def fn()
    pass:
    print('hello world')
    ```
  • Para rST.

    .. code-block:: python
    
      def fn()
      pass:
      print('hello world')

Agregando Prism

Alternativamente, me gusta usar Prism due its JSONP Highlight plugin que permite importar código externo alojado en cualquier servidor como GitHub.

  • Escoge la versión Minifed con todos los lenguajes.
  • Agrega cualquier plugin. Mi selección fue la siguiente. Prism plugins
  • Descarga los archivos JS y CSS.
  • Guárdalos en /themes/themeBlog/assets/css/prism.css y /themes/themeBlog/assets/js/prism.js
  • Agrega los siguiente al documento de Nikola conf.py
    EXTRA_HEAD_DATA = '''
    ...
    <link href="../../assets/css/prism.css" rel="stylesheet" />
    '''
    BODY_END = '''
        <script src="../../assets/js/prism.js"></script>
    '''
    
  • También, agerga prism.css en post_ipynb.tmpl
    <%block name="extra_head">
        ...
        <link href="../../assets/css/prism.css" rel="stylesheet" />
    </%block>
    
  • Listo!.
  • Ahora, usa el siguiente código en Markdown y Jupyter Notebook para poder importar código externo.
    <pre class="lang-markup" data-jsonp="https://api.github.com/repos/<user_name>/<repository_name>/contents/<file_name>"></pre>
    
  • En rST.

    .. raw:: html
    
      <pre class="lang-markup" data-jsonp="https://api.github.com/repos/<user_name>/<repository_name>/contents/<file_name>"></pre>
    
  • Revisa Prism Plugins para más ejemplos de uso.

LaTex con Mathjax

Por defecto, Nikola usa MathJax, y con las Jupyter nbextensions, el comando \begin{align}...\end{align} y otros comandos de LaTex pueden usarse. Pero si deseas soporte para usar $...$ o $$...$$, decomenta lo siguiente en Nikola conf.py. También, puedes agregar comandos Tex para auto-numeración de ecuaciones. Más opciones en MathJax docs.

MATHJAX_CONFIG = """
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: { // https://docs.mathjax.org/en/v2.7-latest/options/preprocessors/tex2jax.html
        inlineMath: [ ['$','$'], ["\\\(","\\\)"] ],
        displayMath: [ ['$$','$$'], ["\\\[","\\\]"] ],
        processEscapes: true
    },
    displayAlign: 'center', // Change this to 'left' if you want left-aligned equations.
    "HTML-CSS": {
        styles: {'.MathJax_Display': {"margin": 0}}
    },
    TeX: { // https://docs.mathjax.org/en/v2.7-latest/options/input-processors/TeX.html
        equationNumbers: { 
            autoNumber: "AMS" // AMS, all, none                        
        } 
    }
});
</script>
"""

Alojar tu sitio en GitHub pages

  • Crear un nuevo repositorio llamado <user_name>.github.io en tu cuenta de GitHub.
  • Inicializa el Git y agrega el origen dentro el folder blog en tu disco interno.
    git init .
    git remote add origin https://github.com/<user_name>/<user_name>.github.io
    
  • Crea un .gitignore
    .vscode
    .doit.db*
    cache
    __pycache__
    output
    .ipynb_checkpoints
    */.ipynb_checkpoints/*
    
  • Edita Nikola conf.py
    GITHUB_SOURCE_BRANCH = 'src'
    GITHUB_DEPLOY_BRANCH = 'master'
    GITHUB_REMOTE_NAME = 'origin'
    GITHUB_COMMIT_SOURCE = True
    
  • Súbelo a GitHub.
    nikola github_deploy
    
  • Selecciona la rama master en la sección de GitHub Pages localizado en la configuración del repositorio.
  • Abre https://<user_name>.github.io para ver los resultados.

Notas

  • Nikola crea dos ramas, master aloja el contenido de la carpeta output, y src tiene el contenido original de los posts y página.

Probando Python y el Matlab kernel en Jupyter Notebook

Para esta sección, correremos nuestro entorno en VSCode. Si corres VSCode directamente, este te mostrará los kernels pero no estará disponible el Matlab-kernel.

  • Abre la terminal en tu folder raíz.
  • Activa el entorno.
    activate jmatlabNikola
    
  • Abre VSCode
    code
    
  • Revisa si los kernels están disponibles. drawing Están doblemente listados porque uno indica que la ubicación es correcta y el otro indica que está disponible. Tal vez es un bug, no estoy seguro.
  • Alternativamente, activa jmatlabNikola y corre VSCode con el navegador de Anaconda.
  • Recuerda cambiar los kernels de Matlab y Python kernels para cada celda que lo necesites.

Ahora todo está configurado, probemos ambos kernels.

Notas

  • Si usas el editor nativo de Jupyter Notebook en tu navegador, no verás la doble lista. Jupyter kernels

Prueba Python

In [1]:
print('hello world')

for i in range(0,12,2):
    print("i=",i)
hello world
i= 0
i= 2
i= 4
i= 6
i= 8
i= 10

Prueba Matlab

Para más ejemplos acá.

In [5]:
disp("hello world")
format compact
for i=0:2:10
    i
end
hello world
i =
     0
i =
     2
i =
     4
i =
     6
i =
     8
i =
    10

Funciones de Matlab

El Matlab-kernel no soporta las funciones referenciadas en el mismo código, así que necesitamos guardarlos externamente.

  • En el editor de Jupyter Notebook en el navegador, usa el magic command %%file /files/<file>.m. Lo guardará en /blog/files
  • Pero para VSCode, usa %%file 'c:/<absolute_path>/<file>.m'
In [2]:
%%file 'C:/Users/zurit/OneDrive/blog/files/fnc.m'

function c = multi_line_func(a,b)
    % in-file comments can be added like this
    a = a+1;
    b = b+2;
    c = a+sin(b);
end
Created file 'C:\Users\zurit\OneDrive\blog\files\fnc.m'.

Para asegurarse de usar fnc.m, abre el folder con el comando de Matlab cd c:/<absolute_path>/<file>.m. Recupera algo de espacio usando format compact.

In [3]:
cd 'C:/Users/zurit/OneDrive/blog/files'

format compact
for i=1:10
    c(i) = fnc(i,i+1);
end
disp(c)
plot(1:10,c)
1.2432    2.0411    3.7206    5.6570    6.9894    7.4121    7.4560    8.0000    9.4634   11.4202

Ploteo 3D

Usemos el magi command %plot inline.

In [3]:
tx = linspace (-8, 8, 41);
ty = tx;
[xx, yy] = meshgrid (tx, ty);
r = sqrt (xx .^ 2 + yy .^ 2) + eps;
tz = sin (r) ./ r;

%plot inline
mesh(tx, ty, tz);

Optimizador de Matlab

También podemos llamar algunos solucionadores de Matlab.

In [4]:
H = [1,-1,1
    -1,2,-2
    1,-2,4];
f = [2;-3;1];
lb = zeros(3,1);
ub = ones(size(lb));
Aeq = ones(1,3);
beq = 1/2;

x = quadprog(H,f,[],[],Aeq,beq,lb,ub)
Minimum found that satisfies the constraints.

Optimization completed because the objective function is non-decreasing in 
feasible directions, to within the default value of the optimality tolerance,
and constraints are satisfied to within the default value of the constraint tolerance.



x =
    0.0000
    0.5000
    0.0000

Prueba LaTex

Algunas fórmulas de LaTex. Ejemplo, $ f(x) = x^{2}$ $ f(x) = x^{2}$. Recuerda que también puedes usar $$...$$.

Ejemplos.

\begin{equation}
\begin{aligned}
\underbrace{
    \overbrace{
        \begin{bmatrix}
        Px              & 0               & \dots & 0     \\
        P_u \bar{\nu} K & 0               & \dots & 0     \\
        0               & P_x             & \dots & 0     \\
        0               & P_u \bar{\nu} K & \dots & 0     \\
        \dots           & \dots           & \dots & \dots
        \end{bmatrix}
    }^{\mathcal{M}}
    \begin{bmatrix}
    (A+B K)^0     \\
    (A+B K)^1     \\
    \vdots        \\
    (A+B K)^{n-1}
    \end{bmatrix}
}_{P_{x_N}}
\hat{x}_{k+N|k}
\leq
\underbrace{
    \begin{bmatrix}
    q_x    \\
    q_u    \\
    q_x    \\
    q_u    \\
    \vdots
    \end{bmatrix}
}_{q_{x_N}}
\end{aligned}
\end{equation}
\begin{equation} \begin{aligned} \underbrace{ \overbrace{ \begin{bmatrix} Px & 0 & \dots & 0 \\ P_u \bar{\nu} K & 0 & \dots & 0 \\ 0 & P_x & \dots & 0 \\ 0 & P_u \bar{\nu} K & \dots & 0 \\ \dots & \dots & \dots & \dots \end{bmatrix} }^{\mathcal{M}} \begin{bmatrix} (A+B K)^0 \\ (A+B K)^1 \\ \vdots \\ (A+B K)^{n-1} \end{bmatrix} }_{P_{x_N}} \hat{x}_{k+N|k} \leq \underbrace{ \begin{bmatrix} q_x \\ q_u \\ q_x \\ q_u \\ \vdots \end{bmatrix} }_{q_{x_N}} \end{aligned} \end{equation}
\begin{equation*}
\begin{cases}
\begin{aligned}
    \hat{x}_{k+1|k+1} & = \hat{x}_{k+1|k} + \gamma_{k+1} K_{k+1} \left( y_{k+1} -  C \hat{x}_{k+1|k} \right) \\
    e_{k+1|k+1}       & = \left(I-\gamma_{k+1} K_{k+1} C \right) e_{k+1|k} -\gamma_{k+1} K_{k+1} \nu_{k+1}   \\
    P_{k+1|k+1}       & = P_{k+1|k} - \gamma_{k+1} K_{k+1}C~P_{k+1|k}                                        \\
    K_{k+1}           & = P_{k+1|k} C^\intercal (C P_{k+1|k} C^\intercal+R_z)^{-1}
\end{aligned}
\end{cases}
\end{equation*}
\begin{equation*} \begin{cases} \begin{aligned} \hat{x}_{k+1|k+1} & = \hat{x}_{k+1|k} + \gamma_{k+1} K_{k+1} \left( y_{k+1} - C \hat{x}_{k+1|k} \right) \\ e_{k+1|k+1} & = \left(I-\gamma_{k+1} K_{k+1} C \right) e_{k+1|k} -\gamma_{k+1} K_{k+1} \nu_{k+1} \\ P_{k+1|k+1} & = P_{k+1|k} - \gamma_{k+1} K_{k+1}C~P_{k+1|k} \\ K_{k+1} & = P_{k+1|k} C^\intercal (C P_{k+1|k} C^\intercal+R_z)^{-1} \end{aligned} \end{cases} \end{equation*}

Formateo de código

  • Con Pygments.

    for k = 1:nk+1 
          % Constrained MPC control law (RH-FH) LQ-MPC at every step k        
          if mode == 'reg'
              [Ustar,fval,flag] = quadprog(H,L*x,Pc,qc+Sc*x); 
          elseif mode == 'trk'
              [NUstar,fval,flag] = quadprog(H,L*epsilon(:,k),Pc_ssto,qc_ssto+Sc_ssto*epsilon(:,k)); 
          end
          % check feasibility
          if flag < 1 
              disp(['Optimization is infeasible at k = ',num2str(k)]);
              break;    
          end
      end
    
  • Con Prism.

    
      for k = 1:nk+1 
          % Constrained MPC control law (RH-FH) LQ-MPC at every step k        
          if mode == 'reg'
              [Ustar,fval,flag] = quadprog(H,L*x,Pc,qc+Sc*x); 
          elseif mode == 'trk'
              [NUstar,fval,flag] = quadprog(H,L*epsilon(:,k),Pc_ssto,qc_ssto+Sc_ssto*epsilon(:,k)); 
          end
          % check feasibility
          if flag < 1 
              disp(['Optimization is infeasible at k = ',num2str(k)]);
              break;    
          end
      end
      

Adjuntar .pdf

Para adjuntar un documento .pdf local o externo, puedes usar el visor de Google Drive en html con Markdown.

<object data="https://drive.google.com/viewerng/viewer?embedded=true&url=https://raw.githubusercontent.com/<user_name/<repository_name>/master/<file_name>.pdf" width="100%" height="1200px"> 
    <p>It appears you don't have a PDF plugin for this browser or JavaScript is disabled. You can <a href="https://drive.google.com/viewerng/viewer?embedded=true&url=https://raw.githubusercontent.com/<user_name/<repository_name>/master/<file_name>.pdf">download the PDF.</a></p>  
</object>

Ejemplo

It appears you don't have a PDF plugin for this browser or JavaScript is disabled. You can download the PDF.

Incorrecto formateo de código en las celdas con dos kernels

El formateo de código en las celdas tiene problemas cuando tienes dos kernels en tu Notebook, el cuál es un problema del metada de Jupyter Notebook.

Ejemplo de formateo de código incompleto. drawing

Mi solución parcial es agregar la siguiente línea al metadata (raw data) del Notebook del post.

"metadata": {
  ...
  "language_info": {
    ...
    "pygments_lexer": "octave"
    },
},

Se hace solo una vez pero debes editar el Notebook con VSCode. Si lo editas con el editor Jupyter Notebook en el navegador, este cambiará el metadata cada vez que cambies de kernel. Inténtalo!.

  • With "pygments_lexer": "octave". drawing
  • With "pygments_lexer": "ipython3" Pygments. drawing

Extra

Se deseas postear con múltiples kernels de diferentes lenguajes, vale la pena revisar SoS Notebook.

Bueno, es todo por ahora. Gracias por leer.

Comentarios

Comments powered by Disqus