From 46eb0d86eb77a749cb5fac010068ccdf02d9ea5d Mon Sep 17 00:00:00 2001
From: Thomas <purcell@fhi-berlin.mpg.de>
Date: Sun, 5 Sep 2021 17:15:34 +0200
Subject: [PATCH] Update docs as per Luca's suggestions

---
 docs/index.rst                                |   7 --
 docs/quick_start/QuickStart.rst               |   2 +-
 docs/quick_start/code_ref.md                  |   8 +-
 docs/tutorial/0_intro.md                      |   8 +-
 docs/tutorial/1_command_line.md               |  74 ++++++++++++++++--
 docs/tutorial/3_classification.md             |   9 ++-
 docs/tutorial/command_line/cv/3d_model.png    | Bin 0 -> 21458 bytes
 src/python/postprocess/plot/parity_plot.py    |  11 ++-
 src/python/postprocess/plot/utils.py          |  33 +++++---
 .../bindings_docstring_keyed.cpp              |   6 ++
 src/utils/string_utils.cpp                    |   2 +-
 src/utils/string_utils.hpp                    |   1 +
 12 files changed, 115 insertions(+), 46 deletions(-)
 create mode 100644 docs/tutorial/command_line/cv/3d_model.png

diff --git a/docs/index.rst b/docs/index.rst
index bcbfd93b..bfab53a7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -12,19 +12,12 @@ SISSO++
 This package provides a C++ implementation of SISSO with built in Python bindings for an efficient python interface.
 Future work will expand the python interface to include more postporcessing analysis tools.
 
-Indices
-=======
-
-* :ref:`genindex`
-* :ref:`search`
-
 Table of Contents
 ^^^^^^^^^^^^^^^^^
 
 .. toctree::
    :maxdepth: 2
 
-   self
    quick_start/QuickStart
    tutorial/tutorial
    cpp_api/cpp_api
diff --git a/docs/quick_start/QuickStart.rst b/docs/quick_start/QuickStart.rst
index 393a3952..0eadf441 100644
--- a/docs/quick_start/QuickStart.rst
+++ b/docs/quick_start/QuickStart.rst
@@ -1,6 +1,6 @@
 .. _quick_start:
 
-Quick Start Guide
+Quick-Start Guide
 =================
 .. toctree::
     :maxdepth: 2
diff --git a/docs/quick_start/code_ref.md b/docs/quick_start/code_ref.md
index cde3e05c..50b60f33 100644
--- a/docs/quick_start/code_ref.md
+++ b/docs/quick_start/code_ref.md
@@ -31,7 +31,7 @@ A list containing the set of all operators that will be used during the feature
 
 #### `param_opset`
 
-A list containing the set of all operators, for which the non-linear scale and bias terms will be optimized, that will be used during the feature creation step of SISSO. (If empty none of the available features)
+A list containing the set of all operators, for which the non-linear scale and bias terms will be optimized, that will be used during the feature creation step of SISSO. (If empty none of the available features are used)
 
 #### `calc_type`
 
@@ -39,15 +39,15 @@ The type of calculation to run either regression, log regression, or classificat
 
 #### `desc_dim`
 
-The maximum dimension of the model to be created
+The maximum dimension of the model to be created (no default value)
 
 #### `n_sis_select`
 
-The number of features that SIS selects over each iteration
+The number of features that SIS selects over each iteration (no default value)
 
 #### `max_rung`
 
-The maximum rung of the feature (height of the tallest possible binary expression tree - 1)
+The maximum rung of the feature (height of the tallest possible binary expression tree - 1) (no default value)
 
 #### `n_residual`
 
diff --git a/docs/tutorial/0_intro.md b/docs/tutorial/0_intro.md
index 852b98a8..ee76cd06 100644
--- a/docs/tutorial/0_intro.md
+++ b/docs/tutorial/0_intro.md
@@ -2,17 +2,17 @@
 
 This tutorial is based on the [Predicting energy differences between crystal structures: (Meta-)stability of octet-binary compounds](https://analytics-toolkit.nomad-coe.eu/public/user-redirect/notebooks/tutorials/descriptor_role.ipynb) tutorial created by Mohammad-Yasin Arif, Luigi Sbailò, Thomas A. R. Purcell, Luca M. Ghiringhelli, and Matthias Scheffler.
 The goal of the tutorial is to teach a user how to use `SISSO++` to find and analyze quantitative models for materials properties.
-In particular we will use SISSO to predict the crystal structure (rock salt or zincblende) of a series of octet binaries.
+In particular we will use SISSO to predict the crystal structure (rock-salt or zinc-blende) of a series of octet binaries.
 The tutorial will be split into three parts: 1) explaining how to use the executable to perform the calculations and the python utilities to analyze the results and 2) How to use only python to run, analyze, and demonstrate results 3) How to perform classification problems using SISSO.
 
 ## Outline
 The following tutorials are available:
 
-- [Combined Binary and Python](1_combined.md)
-- [Python only](2_python.md)
+- [Using the Command Line Interface](1_command_line.md)
+- [Using the Python Interface](2_python.md)
 - [Classification](3_classification.md)
 
-All tutorials use the octet binary dataset first described in [PRL-2015](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.10550) with the goal of predicting whether a material will crystallize in a rock salt or zincblende phase.
+All tutorials use the octet binary dataset first described in [PRL-2015](http://journals.aps.org/prl/abstract/10.1103/PhysRevLett.114.10550) with the goal of predicting whether a material will crystallize in a rock-salt or zinc-blende phase.
 For all applications of SISSO a data set has to be passed via a standard `csv` file where the first row represents the feature and property label and the first column are the index-label for each sample for example
 ```
 Material, energy_diff (eV), rs_A (AA), rs_B (AA), E_HOMO_A (eV), E_HOMO_B (eV),....
diff --git a/docs/tutorial/1_command_line.md b/docs/tutorial/1_command_line.md
index c82de077..65656a07 100644
--- a/docs/tutorial/1_command_line.md
+++ b/docs/tutorial/1_command_line.md
@@ -64,7 +64,7 @@ The standard output provides information about what step the calculation just fi
 When all calculations are complete the code prints out a summary of the best 1D, 2D, ..., {desc_dim}D models with their training RMSE/Testing RMSE (Only training if there is no test set provided).
 Additionally, two additional output files are stored in `feature_space/`: `SIS_summary.txt` and `selected_features.txt`.
 These files represent a human readable (`SIS_summary.txt`) and computer readable (`selected_features.txt`) summary of the selected feature space from SIS.
-Below are reconstructions of both files for this calculation
+Below are reconstructions of both files for this calculation (To see the file click the triangle)
 
 <details>
     <summary>feature_space/SIS_summary.txt</summary>
@@ -284,10 +284,12 @@ An example of these files is provided here:
     ```
 </details>
 
+
+
 ## Determining the Ideal Model Complexity with Cross-Validation
 While the training error always decreases with descriptor dimensionality for a given application, over-fitting can reduce the general applicability of the models outside of the training set.
 In order to determine the optimal dimensionality of a model and optimize the hyperparameters associated with SISSO, we need to perform cross-validation.
-As an example we will discuss how to perform leave-out 10% using the command line
+As an example we will discuss how to perform leave-out 10% using the command line.
 To do this we have to modify the `sisso.json` file to automatically leave out a random sample of the training data and use that as a test set by changing `"leave_out_frac": 0.0,` do `"leave_out_frac": 0.10,`.
 
 <details>
@@ -415,7 +417,7 @@ As can be seen from the standard error measurements the results are now reasonab
 <details>
     <summary> Converged cross-validation results </summary>
 
-![image](combined/cv/cv_100_error.png)
+![image](command_line/cv/cv_100_error.png)
 </details>
 
 Because the validation error for the three and four dimensional models are within each others error bars and the standard error increases when going to the fourth dimension, we conclude that the three-dimensional model has the ideal complexity.
@@ -431,11 +433,13 @@ To see the distributions for this system we run
 <details>
 <summary> Distribution of Errors </summary>
 
-![image](./combined/error_cv.png)
+![image](./command_line/error_cv.png)
 </details>
+
 One thing that stands out in the plot is the large error seen in a single point for both the one and two dimensional models.
-By looking at the validation errors, we find that the point with the largest error is diamond for all model dimensions, which is by far the most stable zincblende structure in the data set.
+By looking at the validation errors, we find that the point with the largest error is diamond for all model dimensions, which is by far the most stable zinc-blende structure in the data set.
 As a note for this setup there is a 0.22\% chance that one of the samples is never in the validation set so if `max_error_ind != 21` check if that sample is in one of the validation sets.
+
 ```python
 >>> import numpy as np
 >>> import pandas as pd
@@ -585,12 +589,66 @@ To get the final models we will perform the same calculation we started off the
 From here we can use `models/train_dim_3_model_0.dat` for all of the analysis.
 In order to generate a machine learning plot for this model in matplotlib, run the following in python
 ```python
->>> from sissopp.postprocess.plot.parity_plot import plot_model_ml_plot_from_file
->>> plot_model_ml_plot_from_file("models/train_dim_3_model_0.dat", filename="3d_model.pdf").show()
+>>> from sissopp.postprocess.plot.parity_plot import plot_model_parity_plot
+>>> plot_model_parity_plot("models/train_dim_3_model_0.dat", filename="3d_model.pdf").show()
 ```
 The result of which is shown below:
 <details>
 <summary> Final 3D model </summary>
 
-![image](./combined/3d_model.png)
+![image](./command_line/3d_model.png)
+</details>
+
+Additionally you can generate a output the model as a Matlab function or a LaTeX string using the following commands.
+```python
+>>> from sissopp.postprocess.load_models import load_model
+>>> model = load_model("models/train_dim_3_model_0.dat")
+>>> print(model.latex_str)
+
+>>> model.write_matlab_fxn("matlab_fxn/model.m")
+```
+
+A copy of the generated matlab function is below.
+<details>
+<summary> Final 3D model </summary>
+
+    ```matlab
+    function P = model(X)
+    % Returns the value of E_{RS} - E_{ZB} = c0 + a0 * ((r_d_B / r_d_A) * (r_p_B * E_HOMO_A)) + a1 * ((IP_A^3) * (|r_sigma - r_s_B|)) + a2 * ((IP_A / r_p_A) / (r_p_B + r_p_A))
+    %
+    % X = [
+    %     r_d_B,
+    %     r_d_A,
+    %     r_p_B,
+    %     E_HOMO_A,
+    %     IP_A,
+    %     r_sigma,
+    %     r_s_B,
+    %     r_p_A,
+    % ]
+
+    if(size(X, 2) ~= 8)
+        error("ERROR: X must have a size of 8 in the second dimension.")
+    end
+    r_d_B    = reshape(X(:, 1), 1, []);
+    r_d_A    = reshape(X(:, 2), 1, []);
+    r_p_B    = reshape(X(:, 3), 1, []);
+    E_HOMO_A = reshape(X(:, 4), 1, []);
+    IP_A     = reshape(X(:, 5), 1, []);
+    r_sigma  = reshape(X(:, 6), 1, []);
+    r_s_B    = reshape(X(:, 7), 1, []);
+    r_p_A    = reshape(X(:, 8), 1, []);
+
+    f0 = ((r_d_B ./ r_d_A) .* (r_p_B .* E_HOMO_A));
+    f1 = ((IP_A).^3 .* abs(r_sigma - r_s_B));
+    f2 = ((IP_A ./ r_p_A) ./ (r_p_B + r_p_A));
+
+    c0 = -1.3509197357e-01;
+    a0 = 2.8311062079e-02;
+    a1 = 3.7282871777e-04;
+    a2 = -2.3703222974e-01;
+
+    P = reshape(c0 + a0 * f0 + a1 * f1 + a2 * f2, [], 1);
+    end
+    ```
 </details>
diff --git a/docs/tutorial/3_classification.md b/docs/tutorial/3_classification.md
index 1ff724f5..2c1a9650 100644
--- a/docs/tutorial/3_classification.md
+++ b/docs/tutorial/3_classification.md
@@ -1,11 +1,12 @@
 Performing Classification with SISSO++
 ---
-Finally `SISSO++` can be used to solve classification problems as well as regression problems.
-As an example of this we will adapt the previous example by replacing the property with the identifier of if the material favors the rock-salt or zincblende structure, and change the calculation type to be `classification`.
+inally, besides regression problems, `SISSO++` can be used to solve classification problems.
+As an example of this we will adapt the previous example by replacing the property with the identifier of if the material favors the rock-salt or zinc-blende structure, and change the calculation type to be `classification`.
 It is important to note that while this problem only has two classes, multi-class classification is also possible.
 
 ## The Data File
-Here is the updated data file, with the property `E_RS - E_ZB (eV)` replaced with a `Class` column where any negative `E_RS - E_ZB (eV)` is replaced with 0 and any positive value replaced with 1.
+Here is the updated data file, with the property `E_RS - E_ZB (eV)` replaced with a `Class` column where any negative `E_RS - E_ZB (eV)` is replaced with 0 and any positive value replaced with 1. While this example has only one task and two classes, the method works for an arbitrary number of classes and tasks.
+
 <details>
     <summary>Here is the full data_class.csv file for the calculation</summary>
 
@@ -300,7 +301,7 @@ The estimated property vector in this case refers to the predicted class from SV
     ```
 </details>
 
-## Updating the SVM Model the Python Interface
+## Updating the SVM Model Using `sklearn`
 Because the basis of the classification algorithm is based on the overlap region of the convex hull, the `c` value for the SVM model is set at a fairly high value of 1000.0.
 This will prioritize reducing the number of misclassified points, but does make the model more susceptible to being over fit.
 To account for this the python interface has the ability to refit the Linear SVM using the `svm` module of `sklearn`.
diff --git a/docs/tutorial/command_line/cv/3d_model.png b/docs/tutorial/command_line/cv/3d_model.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9eb59412557ebad45d65d0e4b8ae438fdd3b4c1
GIT binary patch
literal 21458
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
Mr>mdKI;Vst07M9JZ~y=R

literal 0
HcmV?d00001

diff --git a/src/python/postprocess/plot/parity_plot.py b/src/python/postprocess/plot/parity_plot.py
index d653c67c..714c1e7f 100644
--- a/src/python/postprocess/plot/parity_plot.py
+++ b/src/python/postprocess/plot/parity_plot.py
@@ -20,9 +20,9 @@ plot_model_parity_plot: Wrapper to plot_model for a set of training and testing
 import numpy as np
 import toml
 from sissopp.postprocess.check_cv_convergence import jackknife_cv_conv_est
-
 from sissopp.postprocess.load_models import load_model
-from sissopp.postprocess.plot.utils import setup_plot_ax
+from sissopp.postprocess.plot.utils import setup_plot_ax, latexify
+from sissopp import ModelClassifier
 
 
 def plot_model_parity_plot(model, filename=None, fig_settings=None):
@@ -52,9 +52,12 @@ def plot_model_parity_plot(model, filename=None, fig_settings=None):
 
     fig_config, fig, ax = setup_plot_ax(fig_settings)
 
-    ax.set_xlabel(model.prop_label + " (" + model.prop_unit.latex_str + ")")
+    ax.set_xlabel(latexify(model.prop_label) + " (" + model.prop_unit.latex_str + ")")
     ax.set_ylabel(
-        f"Estimated {model.prop_label}" + " (" + model.prop_unit.latex_str + ")"
+        f"Estimated {latexify(model.prop_label)}"
+        + " ("
+        + model.prop_unit.latex_str
+        + ")"
     )
     if len(model.prop_test) > 0:
         lims = [
diff --git a/src/python/postprocess/plot/utils.py b/src/python/postprocess/plot/utils.py
index eafde92c..6b768bcd 100644
--- a/src/python/postprocess/plot/utils.py
+++ b/src/python/postprocess/plot/utils.py
@@ -91,19 +91,26 @@ def adjust_box_widths(ax, fac):
 def latexify(s):
     """Convert a string s into a latex string"""
     power_split = s.split("^")
-
-    print(power_split)
-
     if len(power_split) == 1:
-        return s
-
-    power_split[0] += "$"
-    for pp in range(1, len(power_split)):
-        unit_end = power_split[pp].split(" ")
-        unit_end[0] = "{" + unit_end[0] + "}$"
+        temp_s = s
+    else:
+        power_split[0] += "$"
+        for pp in range(1, len(power_split)):
+            unit_end = power_split[pp].split(" ")
+            unit_end[0] = "{" + unit_end[0] + "}$"
+            unit_end[-1] += "$"
+            power_split[pp] = " ".join(unit_end)
+        temp_s = "^".join(power_split)[:-1]
+
+    subscript_split = temp_s.split("_")
+    if len(subscript_split) == 1:
+        return temp_s
+
+    subscript_split[0] += "$"
+    for pp in range(1, len(subscript_split)):
+        unit_end = subscript_split[pp].split(" ")
+        unit_end[0] = "\\mathrm{" + unit_end[0] + "}$"
         unit_end[-1] += "$"
-        power_split[pp] = " ".join(unit_end)
-
-    print("^".join(power_split)[:-1])
+        subscript_split[pp] = " ".join(unit_end)
 
-    return "^".join(power_split)[:-1]
+    return "_".join(subscript_split)[:-1]
diff --git a/src/python/py_binding_cpp_def/bindings_docstring_keyed.cpp b/src/python/py_binding_cpp_def/bindings_docstring_keyed.cpp
index 514b5209..d3c83e45 100644
--- a/src/python/py_binding_cpp_def/bindings_docstring_keyed.cpp
+++ b/src/python/py_binding_cpp_def/bindings_docstring_keyed.cpp
@@ -121,6 +121,12 @@ void sisso::register_all()
         "@DocString_str_utils_matlabify@"
     );
 
+    def(
+        "latexify",
+        &str_utils::latexify,
+        (arg("str")),
+        "@DocString_str_utils_latexify@"
+    );
     #ifdef PARAMETERIZE
         sisso::feature_creation::node::registerAddParamNode();
         sisso::feature_creation::node::registerSubParamNode();
diff --git a/src/utils/string_utils.cpp b/src/utils/string_utils.cpp
index 8989dc2d..0558e640 100644
--- a/src/utils/string_utils.cpp
+++ b/src/utils/string_utils.cpp
@@ -75,7 +75,7 @@ std::string str_utils::matlabify(const std::string str)
     std::string copy_str = str;
     std::replace(copy_str.begin(), copy_str.end(), ' ', '_');
 
-    std::vector<std::string> split_str = split_string_trim(str, "\\");
+    std::vector<std::string> split_str = split_string_trim(str, "\\}{");
     for(auto& term_str : split_str)
     {
         std::string add_str = term_str;
diff --git a/src/utils/string_utils.hpp b/src/utils/string_utils.hpp
index d022a951..ce628972 100644
--- a/src/utils/string_utils.hpp
+++ b/src/utils/string_utils.hpp
@@ -42,6 +42,7 @@ namespace str_utils
      */
     std::vector<std::string> split_string_trim(const std::string str, const std::string split_tokens = ",;:");
 
+    // DocString: str_utils_latexify
     /**
      * @brief Convert a string into a latex string
      *
-- 
GitLab