# Notebook from hummat/hummat.github.io
Path: notebooks/curvature.ipynb

# Code: Laplace Approximation for Bayesian Deep Learning_____no_output_____

import sys
import numpy as np
from statsmodels.distributions.empirical_distribution import ECDF
import plotly.graph_objects as go
import plotly.io as pio
import plotly.figure_factory as ff
from plotly.colors import qualitative_____no_output_____resnets = ["resnet18", "resnet34", "resnet50", "resnet101", "resnet152"]
new_resnets = ["wide_resnet50_2", "wide_resnet101_2", "resnext50_32x4d", "resnext101_32x8d"]
densenets = ["densenet121", "densenet161", "densenet169", "densenet201"]
vggs = ["vgg11", "vgg13", "vgg16", "vgg19"]
small = ["alexnet", "shufflenet_v2_x1_0", "mobilenet_v2", "squeezenet1_1", "mnasnet1_0"]
inception = ["googlenet", "inception_v3"]

all_models = resnets + new_resnets + densenets + vggs + small + inception_____no_output_____def logit(p):
    return np.log(np.asarray(p)) - np.log(1 - np.asarray(p))_____no_output_____def get_data(model, data, estimator, plot, reload=False):
    filename = f"{model}_{data}_{estimator}_{plot}"
    path = f"/home/matthias/Data/Ubuntu/git/hummat.github.io/data/{filename}.npy"
    try:
        if reload:
            raise FileNotFoundError
        if plot == "fgsm":
            return np.load(path.replace(".npy", ".npz"), allow_pickle=True)
        else:
            return np.load(path, allow_pickle=True).item()
    except FileNotFoundError:
        sys.path.append("/home/matthias/Data/Ubuntu/git/curvature")
        from curvature.utils import expected_calibration_error, calibration_curve, predictive_entropy

        data = np.load(f"/volume/USERSTORE/humt_ma/{model}/data/{estimator}/{model}_{data}.npz")
        labels, probabilities, bnn_probabilities = data["labels"], data["predictions"], data["bnn_predictions"]
        ood_probabilities, bnn_ood_probabilities = data["ood_predictions"], data["bnn_ood_predictions"]

        if plot in ["reliability", "calibration"]:
            if plot == "reliability":
                ece, aces, accs, confs = expected_calibration_error(probabilities, labels)
                bnn_ece, bnn_aces, bnn_accs, bnn_confs = expected_calibration_error(bnn_probabilities, labels)
            elif plot == "calibration":
                ece, confs, accs, _ = calibration_curve(probabilities, labels)
                bnn_ece, bnn_confs, bnn_accs, _ = calibration_curve(bnn_probabilities, labels)
                aces = confs - accs
                bnn_aces = bnn_confs - bnn_accs
            acc = 100 * np.mean(np.argmax(probabilities, axis=1) == labels)
            bnn_acc = 100 * np.mean(np.argmax(bnn_probabilities, axis=1) == labels)

            np.save(path,
                   {"acc": acc,
                    "ece": ece,
                    "aces": aces,
                    "accs": accs,
                    "confs": confs,
                    "bnn_acc": bnn_acc,
                    "bnn_ece": bnn_ece,
                    "bnn_aces": bnn_aces,
                    "bnn_accs": bnn_accs,
                    "bnn_confs": bnn_confs})
        elif plot == "entropy":
            np.save(path, {"num_classes": probabilities.shape[1],
                           "pred_ent": predictive_entropy(probabilities),
                           "bnn_pred_ent": predictive_entropy(bnn_probabilities),
                           "ood_pred_ent": predictive_entropy(ood_probabilities),
                           "bnn_ood_pred_ent": predictive_entropy(bnn_ood_probabilities)})

        return np.load(path, allow_pickle=True).item()_____no_output_____# Preprocess data
for model in all_models:
    for estimator in ["diag", "kfac", "efb"]:
        for plot in ["reliability", "calibration", "entropy"]:
            try:
                get_data(model, "imagenet", estimator, plot, reload=False)
            except FileNotFoundError:
                print(f"No data for {model}, {estimator}, {plot}.")_____no_output_____

## Reliability diagram_____no_output_____

# Choose a model from 'all_models' above and an estimator from 'sgd', 'diag', 'efb' or 'kfac'.
# 'sgd' is the deterministic NN.
model = "densenet121"
estimator = "sgd"

data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", plot="reliability")
accs = data["bnn_accs"] if estimator != "sgd" else data["accs"]
aces = data["bnn_aces"] if estimator != "sgd" else data["aces"]
acc = data["bnn_acc"] if estimator != "sgd" else data["acc"]
ece = data["bnn_ece"] if estimator != "sgd" else data["ece"]

x = np.linspace(0.05, 1.05, 11)

fig = go.Figure(data=[go.Bar(name=f"Accuracy | Avg.: {acc:.2f}%",
                             x=x,
                             y=accs,
                             hoverinfo="text",
                             hovertext=[f"{100 * acc:.2f}%" for acc in accs],
                             width=0.1,
                             marker=dict(line=dict(color="black",
                                                   width=1))),
                      go.Bar(name=f"ACE | ECE: {100 * ece:.2f}%",
                             x=x,
                             y=aces,
                             hoverinfo="text",
                             hovertext=[f"{100 * ace:.2f}%" for ace in aces],
                             width=0.1,
                             marker=dict(color="rgba(255, 0, 0, 0.5)",
                                         line=dict(color="crimson",
                                                   width=1))),
                      go.Scatter(x=[0, 0.5, 1],
                                 y=[0, 0.5, 1],
                                 name="Perfect calibration",
                                 hoverinfo="none",
                                 mode="lines",
                                 marker=dict(color="black"),
                                 line=dict(dash="dash",
                                           width=1))])
grid = False
visible = True
fig.update_layout(
    xaxis=dict(
        visible=visible,
        range=[0, 1],
        showgrid=grid,
        constrain="domain",
        title="Confidence",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        visible=visible,
        range=[aces.min() - 0.03, 1],
        showgrid=grid,
        scaleanchor="x",
        title="Accuracy",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        x=0.08,
        y=0.98,
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    barmode="stack",
    template="plotly_white",
    hoverlabel=dict(font_size=18),
    hovermode='x',
    height=700,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))
fig.show()_____no_output_____# Save figure
filename = f"{model}_imagenet_{estimator}_reliability"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Calibration curve_____no_output_____### 1. Estimator comparison_____no_output_____

model = "densenet161"
estimators = ["sgd", "diag", "kfac"]

min_ace, max_ace = 100., 0.
fig = go.Figure()
for estimator in estimators:
    data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", "calibration")
    confs = data["bnn_confs"] if estimator != "sgd" else data["confs"]
    accs = data["bnn_accs"] if estimator != "sgd" else data["accs"]
    aces = data["bnn_aces"] if estimator != "sgd" else data["aces"]
    acc = data["bnn_acc"] if estimator != "sgd" else data["acc"]
    ece = data["bnn_ece"] if estimator != "sgd" else data["ece"]

    min_ace = aces.min() if aces.min() < min_ace else min_ace
    max_ace = aces.max() if aces.max() > max_ace else max_ace

    fig.add_trace(go.Scatter(mode="markers+lines",
                             name=f"{estimator.upper()}   |   ECE: {100 * ece:.2f}%",
                             x=logit(confs),
                             y=aces,
                             hovertext=[f"{100 * ace:.2f}%" for ace in aces],
                             hoverinfo="text+name"))

fig.add_trace(go.Scatter(name="",
                         visible="legendonly",
                         hoverinfo="none",
                         x=[0],
                         y=[0],
                         marker_color="rgba(0, 0, 0, 0)"))
fig.add_trace(go.Scatter(x=logit([0.1, 0.1, 0.999999, 0.999999, 0.1]),
                         y=[min_ace, max_ace, max_ace, min_ace, min_ace],
                         mode="lines",
                         fill="toself",
                         hoverinfo="none",
                         line=dict(width=0),
                         fillcolor="rgba(255, 0, 0, 0.1)",
                         visible="legendonly",
                         name="error range"))

grid = False
visible = True
tickvals = [0.2, 0.759, 0.927, 0.978, 0.993, 0.998, 0.999999]
fig.update_layout(
    xaxis=dict(
        constrain="domain",
        zeroline=False,
        visible=visible,
        range=logit([0.1, 0.999999]),
        tickmode="array",
        tickvals=logit(tickvals),
        ticktext=[0.2, 0.759, 0.927, 0.978, 0.993, 0.998, 1],
        showgrid=grid,
        title="Confidence",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        zerolinewidth=2,
        scaleanchor="x",
        scaleratio=50,
        visible=visible,
        showgrid=grid,
        title="Confidence - Accuracy",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="top",
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    template="plotly_white",
    hoverlabel=dict(font_size=18,
                    namelength=max([len(est) for est in estimators]) + 3),
    hovermode="x",
    height=500,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{model}_imagenet_calibration"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

### 2. Network comparison_____no_output_____

compare = "densenets"
estimator = "sgd"

prefix = compare + '_'
colors = qualitative.Plotly
if compare == "all":
    models = all_models
    colors = qualitative.Light24
elif compare == "densenets":
    models = densenets
elif compare == "resnets":
    models = resnets

min_ace, max_ace = 100., 0.
fig = go.Figure()
index = 0
for model in models:
    try:
        data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", "calibration")
        confs = data["bnn_confs"] if estimator != "sgd" else data["confs"]
        accs = data["bnn_accs"] if estimator != "sgd" else data["accs"]
        aces = data["bnn_aces"] if estimator != "sgd" else data["aces"]
        acc = data["bnn_acc"] if estimator != "sgd" else data["acc"]
        ece = data["bnn_ece"] if estimator != "sgd" else data["ece"]

        min_ace = aces.min() if aces.min() < min_ace else min_ace
        max_ace = aces.max() if aces.max() > max_ace else max_ace

        fig.add_trace(go.Scatter(mode="markers+lines",
                                 line_color=colors[index],
                                 name=f"{model.capitalize()}   |   ECE: {100 * ece:.2f}%",
                                 x=logit(confs),
                                 y=aces,
                                 hovertext=[f"{100 * ace:.2f}%" for ace in aces],
                                 hoverinfo="text+name",
                                 visible="legendonly" if model in ["inception_v3", "googlenet"] else True))
        index += 1
        if index == len(colors):
            index = 0
    except FileNotFoundError:
        print(f"No data for {model} and estimator {estimator}.")

fig.add_trace(go.Scatter(name="",
                         visible="legendonly",
                         hoverinfo="none",
                         x=[0],
                         y=[0],
                         marker_color="rgba(0, 0, 0, 0)"))
fig.add_trace(go.Scatter(x=logit([0.1, 0.1, 0.999999, 0.999999, 0.1]),
                         y=[min_ace, max_ace, max_ace, min_ace, min_ace],
                         mode="lines",
                         fill="toself",
                         hoverinfo="none",
                         line=dict(width=0),
                         fillcolor="rgba(255, 0, 0, 0.1)",
                         visible="legendonly",
                         name="error range"))

grid = False
visible = True
tickvals = [0.2, 0.759, 0.927, 0.978, 0.993, 0.998, 0.999999]
fig.update_layout(
    xaxis=dict(
        constrain="domain",
        zeroline=False,
        visible=visible,
        range=logit([0.1, 0.999999]),
        tickmode="array",
        tickvals=logit(tickvals),
        ticktext=[0.2, 0.759, 0.927, 0.978, 0.993, 0.998, 1],
        showgrid=grid,
        title="Confidence",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        zerolinewidth=2,
        scaleanchor="x",
        scaleratio=50,
        visible=visible,
        showgrid=grid,
        title="Confidence - Accuracy",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="top",
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    template="plotly_white",
    hoverlabel=dict(font_size=18,
                    namelength=max([len(model) for model in models]) + 3),
    hovermode="x",
    height=500,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{prefix}{estimator}_imagenet_calibration"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Uncertainty NN vs BNN_____no_output_____### 1. Estimator comparison using ECDF_____no_output_____

model = "resnet50"
colors = qualitative.Plotly
fig = go.Figure()

for index, estimator in enumerate(["sgd", "diag", "kfac"]):
    data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", plot="entropy")
    x_lim = np.log(data["num_classes"])
    entropy_range = np.linspace(0, x_lim, data["num_classes"])

    ecdf = ECDF(data["bnn_pred_ent"] if estimator != "sgd" else data["pred_ent"])
    ood_ecdf = ECDF(data["bnn_ood_pred_ent"] if estimator != "sgd" else data["ood_pred_ent"])

    fig.add_trace(go.Scatter(x=entropy_range,
                             y=1 - ecdf(entropy_range),
                             marker_color=colors[index],
                             line=dict(dash="dash",
                                       width=2.5),
                             showlegend=False,
                             hovertemplate="%{y:.2f}<extra></extra>",
                             legendgroup=index,
                             visible="legendonly" if estimator in ["kfac", "efb"] else True))
    fig.add_trace(go.Scatter(name=estimator.upper(),
                             x=entropy_range,
                             y=1 - ood_ecdf(entropy_range),
                             marker_color=colors[index],
                             line_width=2.5,
                             hovertemplate="%{y:.2f}",
                             legendgroup=index,
                             hoverinfo="x+y+name",
                             visible="legendonly" if estimator in ["kfac", "efb"] else True))

# Hack to have a separated line style legend
fig.add_trace(go.Scatter(name="",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="rgba(0, 0, 0, 0)"))
fig.add_trace(go.Scatter(name="out-of-domain",
                         mode="lines",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="black"))
fig.add_trace(go.Scatter(name="in-domain",
                         mode="lines",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="black",
                         line=dict(dash="dash")))

fig.update_layout(
    xaxis=dict(
        #constrain="domain",
        zeroline=False,
        range=[-0.1, np.ceil(x_lim)],
        showgrid=False,
        title="Predictive entropy",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        #scaleanchor="x",
        #scaleratio=4,
        zeroline=False,
        range=[0, 1.01],
        showgrid=False,
        title="1-ecdf",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="top",
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    template="plotly_white",
    hoverlabel=dict(font_size=18),
    hovermode="x",
    #width=700,
    height=300,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{model}_imagenet_ecdf"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

### 2. Network comparison using ECDF_____no_output_____

compare = "resnets"
estimator = "sgd"

prefix = compare + '_'
colors = qualitative.Plotly
if compare == "all":
    models = all_models
    colors = qualitative.Light24
elif compare == "densenets":
    models = densenets
elif compare == "resnets":
    models = resnets

fig = go.Figure()
index = 0
for model in models:
    try:
        data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", plot="entropy")
        x_lim = np.log(data["num_classes"])
        entropy_range = np.linspace(0, x_lim, data["num_classes"])

        ecdf = ECDF(data["bnn_pred_ent"] if estimator != "sgd" else data["pred_ent"])
        ood_ecdf = ECDF(data["bnn_ood_pred_ent"] if estimator != "sgd" else data["ood_pred_ent"])

        fig.add_trace(go.Scatter(x=entropy_range,
                                 y=1 - ecdf(entropy_range),
                                 marker_color=colors[index],
                                 line=dict(dash="dash",
                                           width=2.5),
                                 showlegend=False,
                                 hovertemplate="%{y:.2f}<extra></extra>",
                                 legendgroup=index))
        fig.add_trace(go.Scatter(name=model.capitalize(),
                                 x=entropy_range,
                                 y=1 - ood_ecdf(entropy_range),
                                 marker_color=colors[index],
                                 line_width=2.5,
                                 hovertemplate="%{y:.2f}",
                                 hoverinfo="x+y+name",
                                 legendgroup=index))
        index += 1
    except FileNotFoundError:
        print(f"No data for {model} and estimator {estimator}.")

# Hack to have a separated line style legend
fig.add_trace(go.Scatter(name="",
                         visible="legendonly",
                         hoverinfo="none",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="rgba(0, 0, 0, 0)"))
fig.add_trace(go.Scatter(name="out-of-domain",
                         mode="lines",
                         hoverinfo="none",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="black"))
fig.add_trace(go.Scatter(name="in-domain",
                         mode="lines",
                         hoverinfo="none",
                         x=[0, 0],
                         y=[0, 0],
                         marker_color="black",
                         line=dict(dash="dash")))

fig.update_layout(
    xaxis=dict(
        #constrain="domain",
        zeroline=False,
        range=[-0.1, np.ceil(x_lim)],
        showgrid=False,
        title="Predictive entropy",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        #scaleanchor="x",
        #scaleratio=3.5,
        zeroline=False,
        range=[-0.01, 1.01],
        showgrid=False,
        title="1-ecdf",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="top",
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    template="plotly_white",
    hoverlabel=dict(font_size=18),
    hovermode="x",
    height=300,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{prefix}{estimator}_imagenet_ecdf"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

### In- vs out-of-distribution histogram_____no_output_____

model = "resnet50"
estimator = "kfac"
normalize = False
overlay = True

data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", plot="entropy")
in_domain = data["pred_ent"] if estimator == "sgd" else data["bnn_pred_ent"]
out_of_domain = data["ood_pred_ent"] if estimator == "sgd" else data["bnn_ood_pred_ent"]

fig = go.Figure(data=[go.Histogram(x=in_domain,
                                   nbinsx=100,
                                   name="Known domain",
                                   histnorm="probability" if normalize else "",
                                   marker=dict(line=dict(color="black", width=1 if overlay else 0)),
                                   hoverinfo="x+y+name",
                                   bingroup=1),
                      go.Histogram(x=out_of_domain,
                                   nbinsx=100,
                                   name="Unknown domain",
                                   histnorm="probability" if normalize else "",
                                   marker=dict(line=dict(color="black", width=1 if overlay else 0)),
                                   hoverinfo="x+y+name",
                                   bingroup=1)])
if overlay:
    fig.update_traces(opacity=0.75)

fig.update_layout(
    xaxis=dict(
        #constrain="domain",
        #range=[-0.1, np.ceil(np.log(data["num_classes"]))],
        zeroline=False,
        showgrid=False,
        title="Predictive entropy",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        #scaleanchor="x",
        #scaleratio=0.00065,
        zeroline=False,
        showgrid=False,
        title="Density" if normalize else "Frequency",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="top",
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    barmode="overlay" if overlay else "group",
    template="plotly_white",
    hoverlabel=dict(font_size=18),
    hovermode="x",
    height=500,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{model}_{estimator}_imagenet_hist"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## The Hessian_____no_output_____

fig = go.Figure()
fig.add_shape(
            type="rect",
            xref="x",
            yref="y",
            x0=0,
            y0=0,
            x1=1,
            y1=1,
            line=dict(width=0),
            fillcolor="floralwhite")

index = 0
for w in np.arange(0, 0.3, 0.1):
    fig.add_trace(go.Scatter(x=[w, 0.05 + w],
                             y=[0.95 - w, 1 - w],
                             name=f"|W.{index}|",
                             hoverinfo="name",
                             showlegend=False))
    fig.add_shape(
            type="rect",
            xref="x",
            yref="y",
            x0=w,
            y0=0.9 - w,
            x1=0.1 + w,
            y1=1 - w,
            line=dict(width=0),
            fillcolor="salmon")
    index += 1

fig.add_trace(go.Scatter(x=[0.3, 0.4],
                         y=[0.6, 0.7],
                         name=f"|W.{index}|",
                         hoverinfo="name",
                         showlegend=False))
fig.add_shape(
        type="rect",
        xref="x",
        yref="y",
        x0=0.3,
        y0=0.5,
        x1=0.5,
        y1=0.7,
        line=dict(width=0),
        fillcolor="salmon")

for i in range(3):
    fig.add_shape(type="circle",
                  xref='x',
                  yref='y',
                  x0=0.54 + (i * 0.05),
                  y0=0.46 - (i * 0.05),
                  x1=0.56 + (i * 0.05),
                  y1=0.44 - (i * 0.05),
                  line_width=0,
                  fillcolor="salmon")

fig.add_trace(go.Scatter(x=[0.7, 0.8],
                         y=[0.2, 0.3],
                         name="|W.L-1|",
                         hoverinfo="name",
                         showlegend=False))
fig.add_shape(
        type="rect",
        xref="x",
        yref="y",
        x0=0.7,
        y0=0.3,
        x1=0.9,
        y1=0.1,
        line=dict(width=0),
        fillcolor="salmon")

fig.add_trace(go.Scatter(x=[0.9, 0.95],
                         y=[0.05, 0.1],
                         name="|W.L|",
                         hoverinfo="name",
                         showlegend=False))
fig.add_shape(
        type="rect",
        xref="x",
        yref="y",
        x0=0.9,
        y0=0.1,
        x1=1,
        y1=0,
        line=dict(width=0),
        fillcolor="salmon")

fig.update_layout(
    xaxis=dict(title="|W|",
               range=[0, 1],
               constrain="domain",
               tickmode="array",
               tickvals=[],
               tick0=0,
               dtick=1,
               titlefont_size=16),
    yaxis=dict(title="|W|",
               range=[0, 1],
               scaleanchor='x',
               scaleratio=1,
               constrain="domain",
               tickmode ="array",
               tickvals=[],
               tick0=0,
               dtick=1,
               titlefont_size=16),
    hoverlabel=dict(font_size=18),
    margin=dict(t=0, b=0, l=0, r=0),
    height=350,
    template="plotly_white")_____no_output_____# Save figure
pio.write_html(fig,
               file=f"../_includes/figures/hessian.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Variance and Covariance_____no_output_____

def multivariate_gaussian(pos, mu, Sigma):
    """Return the multivariate Gaussian distribution on array pos.

    pos is an array constructed by packing the meshed arrays of variables
    x_1, x_2, x_3, ..., x_k into its _last_ dimension.

    """

    n = mu.shape[0]
    Sigma_det = np.linalg.det(Sigma)
    Sigma_inv = np.linalg.inv(Sigma)
    N = np.sqrt((2*np.pi)**n * Sigma_det)
    # This einsum call calculates (x-mu)T.Sigma-1.(x-mu) in a vectorized
    # way across all the input variables.
    fac = np.einsum('...k,kl,...l->...', pos-mu, Sigma_inv, pos-mu)

    return np.exp(-fac / 2) / N_____no_output_____# Our 2-dimensional distribution will be over variables X and Y
N = 60
x = np.linspace(-5, 5, N)
y = np.linspace(-5, 5, N)
X, Y = np.meshgrid(x, y)

# Mean vector and covariance matrix
mu = np.array([0., 0.])
Sigma = np.array([[2., 0.],
                  [0., 2.]])

# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y

# The distribution on the variables X, Y packed into pos.
fig = go.Figure()

for vx in np.arange(2, 7, 1):
    Sigma[0, 0] = vx
    Z = multivariate_gaussian(pos, mu, Sigma)
    fig.add_trace(go.Surface(x=X,
                             y=Y,
                             z=Z,
                             opacity=0.7,
                             visible=False,
                             hoverinfo="none"))

Sigma = np.array([[2., 0.],
                  [0., 2.]])
for vy in np.arange(2, 7, 1):
    Sigma[1, 1] = vy
    Z = multivariate_gaussian(pos, mu, Sigma)
    fig.add_trace(go.Surface(x=X,
                             y=Y,
                             z=Z,
                             opacity=0.7,
                             visible=False,
                             hoverinfo="none"))

Sigma = np.array([[2., 0.],
                  [0., 2.]])
for cov in np.arange(-1, 1.2, 0.25):
    Sigma[1, 0] = Sigma[0, 1] = cov
    Z = multivariate_gaussian(pos, mu, Sigma)
    fig.add_trace(go.Surface(x=X,
                             y=Y,
                             z=Z,
                             opacity=0.7,
                             visible=False,
                             hoverinfo="none"))

fig.update_traces(contours_z=dict(show=True,
                                  usecolormap=True,
                                  project_z=True),
                  showscale=False)

fig.data[0].visible = True

# Create and add slider
steps = []
for i in range(len(fig.data)):
    step = dict(
        label="",
        method="update",
        args=[{"visible": [False] * len(fig.data)}],  # layout attribute
    )
    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

sliders = [
    dict(active=0,
         currentvalue={"prefix": "Variance X"},
         pad={"l": 100, "r": 100},
         steps=steps[:5],
         tickwidth=0,
         ticklen=0,),
    dict(active=0,
         currentvalue={"prefix": "Variance Y"},
         pad={"l": 100, "r": 100, "t": 70},
         steps=steps[5:10],
         tickwidth=0,
         ticklen=0),
   dict(active=4,
         currentvalue={"prefix": "Covariance"},
         pad={"l": 100, "r": 100, "t": 140, "b": 10},
         steps=steps[10:],
         tickwidth=0,
         ticklen=0)]

fig.update_layout(scene=dict(
                    xaxis=dict(visible=False),
                    yaxis=dict(visible=False),
                    zaxis=dict(visible=False)),
                  height=700,
                  margin=dict(r=0, l=0, b=0, t=0, pad=0),
                  sliders=sliders,
                  scene_camera=dict(eye=dict(x=0.6, y=0, z=1),
                                    center=dict(x=0, y=0, z=-0.1)),
                  template="plotly_white")_____no_output_____# Save figure
pio.write_html(fig,
               file=f"../_includes/figures/gaussian_covariance.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Kronecker product_____no_output_____

def add_four_squares(fig, x0, y0, sidelength, colors):
    fig.add_shape(type="rect",
                  xref="x",
                  yref="y",
                  x0=x0,
                  y0=y0,
                  x1=x0 + sidelength,
                  y1=y0 + sidelength,
                  line=dict(width=1),
                  fillcolor=colors[0])
    fig.add_shape(type="rect",
                  xref="x",
                  yref="y",
                  x0=x0,
                  y0=y0 + sidelength,
                  x1=x0 + sidelength,
                  y1=y0 + 2*sidelength,
                  line=dict(width=1),
                  fillcolor=colors[1])
    fig.add_shape(type="rect",
                  xref="x",
                  yref="y",
                  x0=x0 + sidelength,
                  y0=y0 + sidelength,
                  x1=x0 + 2*sidelength,
                  y1=y0 + 2*sidelength,
                  line=dict(width=1),
                  fillcolor=colors[2])
    fig.add_shape(type="rect",
                  xref="x",
                  yref="y",
                  x0=x0 + sidelength,
                  y0=y0,
                  x1=x0 + 2*sidelength,
                  y1=y0 + sidelength,
                  line=dict(width=1),
                  fillcolor=colors[3])

fig = go.Figure()
add_four_squares(fig, 0, 0, 0.25, ["tomato", "tomato", "tomato", "tomato"])
add_four_squares(fig, 0.5, 0, 0.25, ["gold", "gold", "gold", "gold"])
add_four_squares(fig, 0.5, 0.5, 0.25, ["cornflowerblue", "cornflowerblue", "cornflowerblue", "cornflowerblue"])
add_four_squares(fig, 0, 0.5, 0.25, ["mediumspringgreen", "mediumspringgreen", "mediumspringgreen", "mediumspringgreen"])

add_four_squares(fig, 1.2, 0.25, 0.25, ["tomato", "mediumspringgreen", "cornflowerblue", "gold"])
add_four_squares(fig, 1.9, 0.25, 0.25, ["gray", "gray", "gray", "gray"])

annotations=[dict(x=1.1,
                  y=0.5,
                  xref="x",
                  yref="y",
                  text=r"$=$",
                  showarrow=False),
             dict(x=1.8,
                  y=0.5,
                  xref="x",
                  yref="y",
                  text=r"$\otimes$",
                  showarrow=False)]

fig.update_layout(
    xaxis=dict(range=[0, 2.5],
               visible=False,
               constrain="domain",
               tickmode="array",
               tickvals=[],
               tick0=0,
               dtick=1,
               titlefont_size=16),
    yaxis=dict(range=[0, 1],
               visible=False,
               scaleanchor='x',
               scaleratio=1,
               constrain="domain",
               tickmode ="array",
               tickvals=[],
               tick0=0,
               dtick=1,
               titlefont_size=16),
    hoverlabel=dict(font_size=18),
    margin=dict(t=0, b=0, l=0, r=0),
    height=150,
    annotations=annotations,
    template="plotly_white")_____no_output_____# Save figure
pio.write_html(fig,
               file=f"../_includes/figures/kronecker_product.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Hyperparameters_____no_output_____

# Our 2-dimensional distribution will be over variables X and Y
N = 60
x = np.linspace(-5, 5, N)
y = np.linspace(-5, 5, N)
X, Y = np.meshgrid(x, y)

# Mean vector and covariance matrix
mu = np.array([0., 0.])
inv_cov = np.linalg.inv([[3., 1.],
                         [1., 3.]])

# Pack X and Y into a single 3-dimensional array
pos = np.empty(X.shape + (2,))
pos[:, :, 0] = X
pos[:, :, 1] = Y

# The distribution on the variables X, Y packed into pos.
fig = go.Figure()

for n in np.arange(1., 2., 0.2):
    inv_cov *= n
    Z = multivariate_gaussian(pos, mu, np.linalg.inv(inv_cov))
    fig.add_trace(go.Surface(x=X,
                             y=Y,
                             z=Z,
                             opacity=0.7,
                             visible=False,
                             hoverinfo="none"))

inv_cov = np.linalg.inv([[3., 1.],
                         [1., 3.]])
for tau in np.arange(0., 1., 0.2):
    inv_cov += tau * np.eye(2)
    Z = multivariate_gaussian(pos, mu, np.linalg.inv(inv_cov))
    fig.add_trace(go.Surface(x=X,
                             y=Y,
                             z=Z,
                             opacity=0.7,
                             visible=False,
                             hoverinfo="none"))

fig.update_traces(contours_z=dict(show=True,
                                  usecolormap=True,
                                  start=0.01,
                                  end=0.3,
                                  size=0.02,
                                  project_z=True),
                  showscale=False)

fig.data[0].visible = True

# Create and add slider
steps = []
for i in range(len(fig.data)):
    step = dict(
        label="",
        method="update",
        args=[{"visible": [False] * len(fig.data)}],  # layout attribute
    )
    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

sliders = [
    dict(active=0,
         currentvalue={"prefix": "N"},
         pad={"l": 100, "r": 100},
         steps=steps[:5],
         tickwidth=0,
         ticklen=0,),
    dict(active=0,
         currentvalue={"prefix": "tau"},
         pad={"l": 100, "r": 100, "t": 70},
         steps=steps[5:],
         tickwidth=0,
         ticklen=0)]

fig.update_layout(scene=dict(
                    xaxis=dict(visible=False),
                    yaxis=dict(visible=False),
                    zaxis=dict(visible=False)),
                  height=700,
                  margin=dict(r=0, l=0, b=0, t=0, pad=0),
                  sliders=sliders,
                  scene_camera=dict(eye=dict(x=0.6, y=0, z=1),
                                    center=dict(x=0, y=0, z=-0.1)),
                  template="plotly_white")_____no_output_____# Save figure
pio.write_html(fig,
               file=f"../_includes/figures/gauss_hyper.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____

## Adversarial attack_____no_output_____

model = "resnet18"
metric = "ent"

fig = go.Figure()
for estimator in ['sgd', 'kfac', 'diag']:
    try:
        data = get_data(model, "imagenet", estimator if estimator != "sgd" else "kfac", plot="fgsm")
        stats, bnn_stats = data['stats'].item(), data['bnn_stats'].item()
        epsilons = stats['eps']
        fig.add_trace(go.Scatter(name=estimator.upper(),
                                 x=epsilons,
                                 y=stats[metric] if estimator == "sgd" else bnn_stats[metric],
                                 hovertemplate="%{y:.2f}"))
    except FileNotFoundError:
        print(f"Data for model {model} and estimator {estimator.upper()} not available.")

fig.update_layout(
    xaxis=dict(
        zeroline=False,
        showgrid=False,
        title="Step size",
        titlefont_size=16,
        tickfont_size=14),
    yaxis=dict(
        zeroline=False,
        showgrid=False,
        title="Predictive entropy",
        titlefont_size=16,
        tickfont_size=14),
    legend=dict(
        traceorder="normal",
        font=dict(size=16),
        xanchor="right",
        yanchor="bottom",
        y=0.1,
        bgcolor='rgba(0, 0, 0, 0)',
        bordercolor='rgba(0, 0, 0, 0)'),
    template="plotly_white",
    hoverlabel=dict(font_size=18),
    hovermode="x",
    height=400,
    margin=dict(r=0, l=0, b=0, t=0, pad=0))_____no_output_____# Save figure
filename = f"{model}_imagenet_fgsm"
pio.write_html(fig,
               file=f"../_includes/figures/curvature/{filename}.html",
               full_html=False,
               include_plotlyjs='cdn',
               config=dict(displayModeBar=False))_____no_output_____


# Notebook from NeilaCH/SturbucksCapstoneProject
Path: CapstoneProject.ipynb

# Predict Student Performance_____no_output_____### Introduction
Implementing machine learning techniques is receiving considerable attention in the educational technology research field. Different systems and techniques were proposed to predict student performance and gain insights regarding their learning needs. Thus, in this project, I focused on exploring the use of classification algorithms to predict student performance (final grades) based on their interaction with learning resources.
The dataset selected for this project is an opensource, gathered from learning management system (LMS) called Kalboard360. The dataset is available in [Kaggle](https://www.kaggle.com/aljarah/xAPI-Edu-Data). It included 480 records and 16 features collected through a learner activity tracker tool.
According to [Abu Amrieh et al. (2016)](http://article.nadiapub.com/IJDTA/vol9_no8/13.pdf) the data is collected using a learner activity tracker tool, which called experience API (xAPI). The xAPI is a component of the training and learning architecture (TLA) that enables to monitor learning progress and learner’s actions like reading an article or watching a training video. The experience API helps the learning activity providers to determine the learner, activity and objects that describe a learning experience._____no_output_____### Dataset Description
The dataset consists of 480 student records and 16 features. The features are classified into three major categories:
1. Demographic features such as gender and nationality.
2. Academic background features such as educational stage, grade Level and section.
3. Behavioral features such as raised hand on class, opening resources, answering survey by parents, and school satisfaction.

#### Attributes

1. Gender - student's gender (nominal: 'Male' or 'Female’)

2. Nationality- student's nationality (nominal:’ Kuwait’,’ Lebanon’,’ Egypt’,’ SaudiArabia’,’ USA’,’ Jordan’, ’Venezuela’,’ Iran’,’ Tunis’,’ Morocco’,’ Syria’,’ Palestine’,’ Iraq’,’ Lybia’)

3. Place of birth- student's Place of birth (nominal:’ Kuwait’,’ Lebanon’,’ Egypt’,’ SaudiArabia’,’ USA’,’ Jordan’,’Venezuela’,’ Iran’,’ Tunis’,’ Morocco’,’ Syria’,’ Palestine’,’ Iraq’,’ Lybia’)

4. Educational Stages- educational level student belongs (nominal: ‘lowerlevel’,’MiddleSchool’,’HighSchool’)

5. Grade Levels- grade student belongs (nominal: ‘G-01’, ‘G-02’, ‘G-03’, ‘G-04’, ‘G-05’, ‘G-06’, ‘G-07’, ‘G-08’, ‘G-09’, ‘G-10’, ‘G-11’, ‘G-12 ‘)

6. Section ID- classroom student belongs (nominal:’A’,’B’,’C’)

7. Topic- course topic (nominal:’ English’,’ Spanish’, ‘French’,’ Arabic’,’ IT’,’ Math’,’ Chemistry’, ‘Biology’, ‘Science’,’ History’,’ Quran’,’ Geology’)

8. Semester- school year semester (nominal:’ First’,’ Second’)

9. Parent responsible for student (nominal:’mom’,’father’)

10. Raised hand- how many times the student raises his/her hand on classroom (numeric:0-100)

11. Visited resources- how many times the student visits a course content(numeric:0-100)

12. Viewing announcements-how many times the student checks the new announcements(numeric:0-100)

13. Discussion groups- how many times the student participate on discussion groups (numeric:0-100)

14. Parent Answering Survey- parent answered the surveys which are provided from school or not (nominal:’Yes’,’No’)

15. Parent School Satisfaction- the Degree of parent satisfaction from school(nominal:’Yes’,’No’)

16. Student Absence Days-the number of absence days for each student (nominal: above-7, under-7)
_____no_output_____### Phase 1. Read Dataset_____no_output_____

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
from sklearn.model_selection import train_test_split_____no_output_____# Importing the dataset
data = pd.read_csv('education.csv')
data.isnull().any()
data = data.fillna(method='ffill')
data.head()_____no_output_____data.shape_____no_output_____print(data.info(),"\n")<class 'pandas.core.frame.DataFrame'>
RangeIndex: 480 entries, 0 to 479
Data columns (total 17 columns):
 #   Column                    Non-Null Count  Dtype
---  ------                    --------------  -----
 0   gender                    480 non-null    object
 1   NationalITy               480 non-null    object
 2   PlaceofBirth              480 non-null    object
 3   StageID                   480 non-null    object
 4   GradeID                   480 non-null    object
 5   SectionID                 480 non-null    object
 6   Topic                     480 non-null    object
 7   Semester                  480 non-null    object
 8   Relation                  480 non-null    object
 9   raisedhands               480 non-null    int64
 10  VisITedResources          480 non-null    int64
 11  AnnouncementsView         480 non-null    int64
 12  Discussion                480 non-null    int64
 13  ParentAnsweringSurvey     480 non-null    object
 14  ParentschoolSatisfaction  480 non-null    object
 15  StudentAbsenceDays        480 non-null    object
 16  Class                     480 non-null    object
dtypes: int64(4), object(13)
memory usage: 63.9+ KB
None

### Phase 2. Cleaning Dataset_____no_output_____

#Rename cols
data.rename(index=str, columns={'gender':'Gender', 'NationalITy':'Nationality','raisedhands':'RaisedHands', 'VisITedResources':'VisitedResources'},inplace=True)_____no_output_____data.head()_____no_output_____print(data.info(),"\n")<class 'pandas.core.frame.DataFrame'>
Index: 480 entries, 0 to 479
Data columns (total 16 columns):
 #   Column                    Non-Null Count  Dtype
---  ------                    --------------  -----
 0   Gender                    480 non-null    int64
 1   Nationality               480 non-null    int64
 2   StageID                   480 non-null    int64
 3   GradeID                   480 non-null    int64
 4   SectionID                 480 non-null    int64
 5   Topic                     480 non-null    int64
 6   Semester                  480 non-null    int64
 7   Relation                  480 non-null    int64
 8   RaisedHands               480 non-null    int64
 9   VisitedResources          480 non-null    int64
 10  AnnouncementsView         480 non-null    int64
 11  Discussion                480 non-null    int64
 12  ParentAnsweringSurvey     480 non-null    int64
 13  ParentschoolSatisfaction  480 non-null    int64
 14  StudentAbsenceDays        480 non-null    int32
 15  Class                     480 non-null    int64
dtypes: int32(1), int64(15)
memory usage: 81.9+ KB
None

#Drop col PlaceofBirth because it denotes Nationality
data.drop(columns='PlaceofBirth', inplace=True)_____no_output_____data.describe()_____no_output_____# check unique values
print("Unique Values:\n ",data.nunique(),"\n")Unique Values:
  Gender                       2
Nationality                 14
StageID                      3
GradeID                     10
SectionID                    3
Topic                       12
Semester                     2
Relation                     2
RaisedHands                 82
VisitedResources            89
AnnouncementsView           88
Discussion                  90
ParentAnsweringSurvey        2
ParentschoolSatisfaction     2
StudentAbsenceDays           2
Class                        3
dtype: int64

# explore values of col Topic
print("Topic: ","\n\n", data["Topic"].value_counts(), "\n")Topic:

 IT           95
French       65
Arabic       59
Science      51
English      45
Biology      30
Spanish      25
Geology      24
Chemistry    24
Quran        22
Math         21
History      19
Name: Topic, dtype: int64

The data includes 12 Topics_____no_output_____

data.isna().sum()_____no_output_____

### Phase 3. Exploring Dataset_____no_output_____#### How is the student Performance according to their Nationality?_____no_output_____

# Correlation between students' Ntionality and topics
display(pd.crosstab(data["Nationality"],data["Topic"]).reset_index())_____no_output_____fig,ax = plt.subplots(figsize=(18, 8))
sns.countplot(x='Nationality', hue='Class', data=data,hue_order = ['L', 'M', 'H'], ax=ax)
plt.show()_____no_output_____

The plot highlights that most of the enrolled students in the e-learning environment are from Jordan and Kuwait. Regarding student performance, the highest scores obtained among Jordanian students are middle, followed by Kuwaiti students._____no_output_____#### How is the students general performance?_____no_output_____

ax = sns.countplot(x='Class', data=data, order=['L', 'M', 'H'])
for p in ax.patches:
    ax.annotate('{:.2f}%'.format((p.get_height() * 100) / len(data)), (p.get_x() + 0.24, p.get_height() + 2))
plt.show()_____no_output_____

Based on this plot, it can be revealed that for all students enrolled in the platform, the highest obtained scores are Middle with an average of 43.96%, followed by high with 29.58%, and low with 26.46%. The percentage of students obtaining low grades can be considered high._____no_output_____#### How is the student performance according to their educational level?_____no_output_____

ax = sns.countplot(x='StageID', data=data)
plt.show()_____no_output_____

Most of the enrolled students are from middle schools with an average of 250 students, followed by lower educational levels with an average of 200 students. However, the number of high school students is only 50. _____no_output_____

ax = sns.countplot(x='StageID', hue='Class', data=data, hue_order = ['L', 'M', 'H'])
plt.show()_____no_output_____

Around 120 Students enrolled in Middle schools are obtaining middle grades. However, 60 are getting low grades. The plot also highlights that for the lower level, the average of students obtaining low grades is more important than those scoring high grades._____no_output_____#### How is the student performance according to the sections?_____no_output_____

ax = sns.countplot(x='SectionID', hue='Class', data=data, order=['A', 'B', 'C'],hue_order = ['L', 'M', 'H'])
plt.show()_____no_output_____

From this plot it can be revealed that the highest performance is scored mong students erolled in section A. However, the lowes grades are obtained among students belonging to section C_____no_output_____#### How is the student performance according to the learning topics?_____no_output_____

fig,ax = plt.subplots(figsize=(18, 8))
ax = sns.countplot(x='Topic', hue='Class', data=data,hue_order = ['L', 'M', 'H'])
plt.show()_____no_output_____

The plot highlights that students performance is different according to the learning topic. It can be revealed that students are mostly obtaining midlle and low grades in the IT topic.However, in the Maths the results are slightly similar._____no_output_____

data.groupby('Topic').median()_____no_output_____

The correlation between students' interaction in the e-learning environment and the learning topics highlight that the highest interaction behavior is scored in the Biology topic. However, in Math, students are rarely visiting the resources or considering the announcements. This may denote an impact on students' interaction behavior and their learning performance._____no_output_____#### How is the student performance according to the semester ?_____no_output_____

ax = sns.countplot(x='Semester', hue='Class', data=data,hue_order = ['L', 'M', 'H'])
plt.show()_____no_output_____

From these results, it can be revealed that during the summer semester, the low grades increased compared to the fall semester. However, in terms of the middle grades, students performance remains similar. _____no_output_____#### How is the student performance according to their absence ?_____no_output_____

ax = sns.countplot(x='StudentAbsenceDays', hue='Class', data=data, order=['Under-7', 'Above-7'],hue_order = ['L', 'M', 'H'])
plt.show()_____no_output_____

Based on this plot it can be pointed out that students being absent for more than 7 days are scoring low grades leading to their poor performance._____no_output_____### Phase 4. Data Modeling_____no_output_____The exploration of data highlights that student performance is impacted by different factors including their inetarction behavior, learning engagement, and the enrolled topics. Thus, it is required to build a learning model to predict student performance and enhance it in the context of e-learning environment._____no_output_____#### 1. Features Encoding_____no_output_____

data.groupby("Class").count()
grade_class = {"L":0, "M":1, "H":2}
data["Class"] = data["Class"].map(grade_class)_____no_output_____#Source https://www.kaggle.com/roshansharma/student-performance-analysis#Label-Encoding
from sklearn.preprocessing import LabelEncoder

# creating an encoder
le = LabelEncoder()

# label encoding for class
data['Class'] = le.fit_transform(data['Class'])

# label encoding for gender
data['Gender'] = le.fit_transform(data['Gender'])

# label encoding for nationality
data['Nationality'] = le.fit_transform(data['Nationality'])

#label encoding for stage
data['StageID'] = le.fit_transform(data['StageID'])

# label encoding for grade
data['GradeID'] = le.fit_transform(data['GradeID'])

# label encoding for section
data['SectionID'] = le.fit_transform(data['SectionID'])

# label encoding for topic
data['Topic'] = le.fit_transform(data['Topic'])

# label encoding for semester
data['Semester'] = le.fit_transform(data['Semester'])

# label encoding for parent relation
data['Relation'] = le.fit_transform(data['Relation'])

# label encoding for parent survey answering
data['ParentAnsweringSurvey'] = le.fit_transform(data['ParentAnsweringSurvey'])

# label encoding for parent satisfaction
data['ParentschoolSatisfaction'] = le.fit_transform(data['ParentschoolSatisfaction'])

# label encoding for Absence
data['StudentAbsenceDays'] = le.fit_transform(data['StudentAbsenceDays'])_____no_output_____data.head()_____no_output_____

#### 2. Spliting Data into training and testing sets_____no_output_____

X = data.drop(columns='Class')
y = data['Class']_____no_output_____X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)_____no_output_____X_train.shape_____no_output_____#DecisionTree
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier().fit(X_train, y_train)
print('Accuracy of Decision Tree classifier on training set: {:.2f}'
     .format(clf.score(X_train, y_train)))
print('Accuracy of Decision Tree classifier on test set: {:.2f}'
     .format(clf.score(X_test, y_test)))Accuracy of Decision Tree classifier on training set: 1.00
Accuracy of Decision Tree classifier on test set: 0.61
#Linear Discriminant Analysis
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
lda = LinearDiscriminantAnalysis()
lda.fit(X_train, y_train)
print('Accuracy of LDA classifier on training set: {:.2f}'
     .format(lda.score(X_train, y_train)))
print('Accuracy of LDA classifier on test set: {:.2f}'
     .format(lda.score(X_test, y_test)))Accuracy of LDA classifier on training set: 0.77
Accuracy of LDA classifier on test set: 0.76
#Gaussian Naive Bayes
from sklearn.naive_bayes import GaussianNB
gnb = GaussianNB()
gnb.fit(X_train, y_train)
print('Accuracy of GNB classifier on training set: {:.2f}'
     .format(gnb.score(X_train, y_train)))
print('Accuracy of GNB classifier on test set: {:.2f}'
     .format(gnb.score(X_test, y_test)))Accuracy of GNB classifier on training set: 0.75
Accuracy of GNB classifier on test set: 0.75
#Support Vector Machine
from sklearn.svm import SVC
svm = SVC()
svm.fit(X_train, y_train)
print('Accuracy of SVM classifier on training set: {:.2f}'
     .format(svm.score(X_train, y_train)))
print('Accuracy of SVM classifier on test set: {:.2f}'
     .format(svm.score(X_test, y_test)))Accuracy of SVM classifier on training set: 0.65
Accuracy of SVM classifier on test set: 0.63
#K-Nearest Neighbors
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(X_train, y_train)
print('Accuracy of K-NN classifier on training set: {:.2f}'
     .format(knn.score(X_train, y_train)))
print('Accuracy of K-NN classifier on test set: {:.2f}'
     .format(knn.score(X_test, y_test)))Accuracy of K-NN classifier on training set: 0.75
Accuracy of K-NN classifier on test set: 0.65
from sklearn.ensemble import RandomForestClassifier
#Create a Gaussian Classifier
rfc=RandomForestClassifier(n_estimators=100)
rfc.fit(X_train,y_train)
print('Accuracy of RandomForest classifier on training set: {:.2f}'
     .format(rfc.score(X_train, y_train)))
print('Accuracy of RandomForest classifier on test set: {:.2f}'
     .format(rfc.score(X_test, y_test)))Accuracy of RandomForest classifier on training set: 1.00
Accuracy of RandomForest classifier on test set: 0.81
from sklearn.metrics import classification_report
from sklearn.metrics import confusion_matrix
target_names = ['class 0(H)', 'class 1(L)', 'class 2(M)']
pred = rfc.predict(X_test)
print(confusion_matrix(y_test, pred))
print(classification_report(y_test, pred, target_names = target_names))[[21  0 10]
 [ 0 40  5]
 [ 5  7 56]]
              precision    recall  f1-score   support

  class 0(H)       0.81      0.68      0.74        31
  class 1(L)       0.85      0.89      0.87        45
  class 2(M)       0.79      0.82      0.81        68

    accuracy                           0.81       144
   macro avg       0.82      0.80      0.80       144
weighted avg       0.81      0.81      0.81       144

from sklearn.metrics import plot_confusion_matrix
plot_confusion_matrix(rfc, X_test, y_test, display_labels=target_names)
plt.show()_____no_output_____

The confusion matrix highlights that among 144  students, Random Forest correctly classified 56 in the Middle Class, 40 were classified in the low class, however 20 were predicted in the high class_____no_output_____### Results
The results pointed out that the use of features related to student profile, academic performance, and behavior with the virtual learning environment may lead to an accurate prediction of students performance while interacting with learning content.
The classification results revealed that Random Forest outperformed other classifiers for both datasets
with an accuracy of 81%. With the set of selected features, the results highlighted that Random Forest classifier would rank a randomly selected student and predict their performance based on their academic and behavioral interaction with the learning platform.
Further improvements are required including:
1. The application of Gridsearch to find the optimal values for the classification model.
2. Including further classification techniques in the comparative phase
3. Explore features correlation to enhance the accuracy of the prediction model.
Building student model will further support implementing recommendation strategies to (a) support the cognitive development of students, (b) detect their interaction behavior, (c) determine their preferences, and (d) empower their learning performance. Thus, in future work, I will consider examine the task of recommending activities to have a better understanding of the impact of interaction behavior  on student performance in e-learning environment._____no_output_____#### References
1. The dataset extracted from [Kaggle](https://www.kaggle.com/aljarah/xAPI-Edu-Data)
2. Thank you Udacity for supporting the knowledge building
3. Amrieh, E. A., Hamtini, T., & Aljarah, I. (2016). Mining Educational Data to Predict Student’s academic Performance using Ensemble Methods. International Journal of Database Theory and Application, 9(8), 119-136._____no_output_____


# Notebook from GrupoTuring/Aprendizado-por-Reforco
Path: Aprendizado por Reforço Profundo/Deep Q-Learning/Prioritized Experience Replay/Prioritized Experience Replay.ipynb

# Prioritized Experience Replay

Baseado no paper [Prioritized Experience Replay, Schaul et al, 2015.](https://deepmind.com/research/publications/prioritized-experience-replay)_____no_output_____## Motivação_____no_output_____Conforme já vimos, a técnica de [experience replay](https://github.com/GrupoTuring/Aprendizado-por-Reforco/tree/per/Aprendizado%20por%20Refor%C3%A7o%20Profundo/Deep%20Q-Learning/Experience%20Replay) é muito importante para garantir a convergência do agente de [DQN](https://github.com/GrupoTuring/Aprendizado-por-Reforco/tree/per/Aprendizado%20por%20Refor%C3%A7o%20Profundo/Deep%20Q-Learning/Deep%20Q-Network). Por um lado, experience replay permite que o agente relembre ao longo do tempo suas experiências antigas, de forma análoga ao epochs utilizados em outras aplicações. Por outro lado, mais matemático, essa prática diminui a correlação entre as observações passadas à rede neural, o que tende a melhorar o treinamento.

Essa noção de que experience replay ajuda o agente a relembrar o passado encontra uma analogia no comportamento animal:

> Numerous neuroscience studies have identified evidence of experience replay in the hippocampus of rodents, suggesting that sequences of **prior experience are replayed**, either during awake resting or sleep. Sequences associated with rewards appear to be replayed more frequently (Atherton et al., 2015; Ólafsdóttir et al., 2015; Foster & Wilson, 2006). **Experiences with high magnitude TD error also appear to be replayed more often** (Singer & Frank, 2009; McNamara et al., 2014).
>
> Prioritized Experience Replay, Schaul et al, 2015. [1](https://deepmind.com/research/publications/prioritized-experience-replay)_____no_output_____## Teoria_____no_output_____### Prioritized Experience Replay_____no_output_____Conforme destacam os pesquisadores em [1](https://deepmind.com/research/publications/prioritized-experience-replay), uma estratégia melhor que simplesmente escolher experiências aleatórias é escolher, de alguma forma, as experiências que mais contribuem para o aprendizado do agente. Inicialmente, consideraremos o ambiente Blind Cliffwalk, abaixo, em que as setas vermelhas são terminais e a seta verde é a única ação com recompensa não-nula. Nesse caso, a transição mais relevante, destacada em verde, provavelmente será vista muito pouco pelo agente.

No gráfico da direita, vemos a comparação entre um agente que escolhe experiências aleatóriamente (_uniform_) e outro que utiliza um oráculo (_oracle_), que sempre sabe qual a ação que acarreta na maior redução do custo. O eixo horizontal indica o tamanho do replay buffer, enquanto o eixo vertical indica o número de updates necessários para treinar o agente. Claramente, o agente com o oráculo aprende mais rápido.

![blind cliffwalk](imgs/blind_cliffwalk.png)

Como não temos um oráculo à disposição, precisamos de alguma métrica que nos indique o quão surpreendente uma dada experiência é. Uma boa alternativa é a função de custo (ou o TD-error, no caso de Q-Learning tabular), visto que ela está associada à diferença entre a estimativa atual do agente de _Q_(_s_,_a_) e a estimativa de bootstrap.

O gráfico abaixo, também de [1], mostra que o uso do erro TD é uma aproximação razoável. A linha preta, que indica o método básico de experience replay, é sempre a de aprendizado mais lento. A linha vermelha (_greedy_) corresponde ao erro TD e é claramente melhor do que o método básico, mas pior do que o oráculo (azul).

![comparação entre formas de experience replay](imgs/per_comparison.png)_____no_output_____### Stochastic Prioritized Experience Replay_____no_output_____A escolha sempre da experiência de maior prioridade (gulosa) é muito sucetível a ruído e incentiva pouco a exploração. Por isso, em geral, amostramos aleatoriamente as experiências, mas dando maior probabilidade para as experiências de maior prioridade:
$$P(i) = \frac{p_i^\alpha}{\sum_k p_k^\alpha} \propto p_i^\alpha,$$
onde $\alpha$ determina a quantidade de priorização utilizada. Quando $\alpha=0$, tem-se o caso uniforme.

Em geral, a prioridade é dada por $p_i = \left|J_i\right| + \epsilon$, onde $\epsilon$ é uma constante positiva pequena. O propósito da adição de $\epsilon$ ao custo é de garantir que todas as experiências tenham alguma probabilidade de serem revisitadas, mesmo se atingirem erro zero._____no_output_____### Redução do Viés_____no_output_____Em DQN, utilizamos uma função de custo, e.g. o MSE:

\begin{align*}
    J_{\mathrm{ideal}}       &= E\left[{\left(Q(s,a) - Q_{\theta}(s,a)\right)}^2\right] \\
    J_{\mathrm{bootstrap},i} &= {\left(Q_{\mathrm{bootstrap}}(s_i,a_i) - Q_{\theta}(s_i,a_i)\right)}^2 \\
\\
  \theta       &\leftarrow \theta + \eta \Delta\theta \\
  \Delta\theta &= -\frac{1}{2}\nabla_{\theta} J_{\mathrm{bootstrap}}\\
               &= \left(Q_{\mathrm{bootstrap}}(s_i,a_i) - Q_{\theta}(s_i,a_i)\right) \cdot \nabla_{\theta} Q_{\theta}(s_i,a_i) \\
               &= \delta_i \cdot \nabla_{\theta} Q_{\theta}(s_i,a_i).
\end{align*}_____no_output_____A aproximação de bootstrap, de que $J_{\mathrm{bootstrap}} \approx J_{\mathrm{ideal}}$, é não enviesada quando as experiências utilizadas para calcular $Q_{\mathrm{bootstrap}}$ tem a mesma distribuição que na esperança. Em outras palavras, quando as ditribuições são as mesmas, espera-se que erros positivos e negativos nessa aproximação se "anulem" com o tempo.

O uso de priorização muda a distribuição das experiências, de forma que essa aproximação se torna enviesada. Uma técnica chamada _importance sampling_ pode ser utilizada para corrigir esse viés, multiplicando a atualização dos pesos por um coeficiente $w_i$:_____no_output_____$\tilde w_i = \left(\frac1N \cdot \frac{1}{P(i)}\right)^\beta,
  \quad
  w_i = \frac{\tilde w_i}{\max_i \tilde w_i}
  \qquad
  \Delta\theta = w_i \cdot \delta_i \cdot \nabla_{\theta} Q_{\theta}(s_i,a_i),$_____no_output_____onde $\beta=1$ corresponde ao caso não-enviesado (note que as probabilidades ficam uniformes). Analisando as equações, observa-se que as experiências de maior prioridade (que são amostradas mais frequentemente) são dadas menor peso na atualização de $\theta$, reduzindo o viés. Essa redução de $w_i$ quando o erro é alto também ajuda a mitigar a probabilidade de overshooting.

Em relação ao treinamento do agente, observa-se que a priorização é mais importante no início do treinamento, enquanto o não-enviesamento é mais importante no final do treinamento, quando o agente já está mais estável. Por isso, é comum aumentar o $\beta$ linearmente de seu valor inicial $\beta=\beta_0$ até o valor final $\beta=1$._____no_output_____## Importações_____no_output_____Usaremos, como sempre, numpy para lidarmos com arrays e operações matemáticas, e torch para lidar com tensores e aprendizado profundo._____no_output_____

import random
import numpy as np
import matplotlib.pyplot as plt
import gym

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim_____no_output_____

## Memória com Amostras Prioritárias_____no_output_____

class PrioritizedExperienceReplay:
    """Classe de um Experience Replay Buffer para DQNs,com priority sampling."""
    def __init__(self, sdim, maxlen, alpha, offset):
        """Cria um Replay Buffer.

        Parâmetros
        ----------
        sdim: int
            Tamanho do espaço de observação.
        maxlen: int
            Tamanho máximo do Replay Buffer.
        alpha: float no intervalo (0,1)
            Quanto a priorização é relevante.
        offset: float < 1
            Garante que todas as experiências podem ser revisitadas.
        """
        self._maxlen = maxlen
        self._alpha  = alpha
        self._offset = offset
        self._memory = {
            "states":   np.zeros((maxlen, *sdim), dtype=np.float32),
            "actions":  np.zeros((maxlen), dtype=np.float32),
            "rewards":  np.zeros((maxlen), dtype=np.float32),
            "nstates":  np.zeros((maxlen, *sdim), dtype=np.float32),
            "dones":    np.zeros((maxlen), dtype=np.float32),
            "priority": np.zeros((maxlen), dtype=np.float32)
        }
        self._index = 0
        self._len = 0

    def _iindex(self):
        """Incrementa o índice de acordo o maxlen.
        Se o índice for maior que o maxlen, ele
        começa novamente."""
        self._index = (self._index+1) % self._maxlen

    def push(self, s, a, r, s2, d):
        """Adiciona uma experiência ao Replay Buffer.

        Parâmetros
        ----------
        s: np.array
            Estado da transição.
        a: int
            Ação tomada.
        r: float
            Recompensa recebida.
        s2: np.array
            Estado seguinte.
        d: int
            Flag indicando se o episódio acabou.
        """
        if len(self) > 0:
            mx = np.max(self._memory["priority"][:len(self)])
        else:
            mx = 1
        if len(self) < self._maxlen:
            self._len += 1
        self._memory["states"][self._index]  = s
        self._memory["actions"][self._index] = a
        self._memory["rewards"][self._index] = r
        self._memory["nstates"][self._index] = s2
        self._memory["dones"][self._index]   = d
        self._memory["priority"][self._index] = mx
        self._iindex()

    def sample(self, batch):
        """Retorna um batch de experiências.

        Parâmetros
        ----------
        batch_size: int
            Tamanho do batch de experiências.

        Retorna
        -------
        tupla de:
        states: np.array
            Batch de estados.
        actions: np.array
            Batch de ações.
        rewards: np.array
            Batch de recompensas.
        next_states: np.array
            Batch de estados seguintes.
        dones: np.array
            Batch de flags indicando se o episódio acabou.
        priority: np.array
            Batch das prioridades.
        indexes: int
            índice aleatório com base nas prioridades.
        """
        n = len(self)
        indexes = random.choices(range(n),
                                 weights = self._memory["priority"][:n],
                                 k = batch)
        to_return = (
            self._memory["states"  ][indexes],
            self._memory["actions" ][indexes],
            self._memory["rewards" ][indexes],
            self._memory["nstates" ][indexes],
            self._memory["dones"   ][indexes],
            self._memory["priority"][indexes]/self._memory["priority"].sum(),
            indexes)
        return to_return

    def update_priority(self, index, newp):
        q = (newp.type(torch.float64) + self._offset)**self._alpha
        self._memory["priority"][index] = q.detach().cpu().numpy().flatten()

    def __len__(self):
        return self._len_____no_output_____

## Rede Neural_____no_output_____

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F

class Network(nn.Module):
    def __init__(self, in_dim, out_dim):
        super(Network, self).__init__()

        self.layers = nn.Sequential(
            nn.Linear(in_dim[0], 64),
            nn.ReLU(),
            nn.Linear(64, 64),
            nn.ReLU(),
            nn.Linear(64, out_dim)
        )

    def forward(self, x):
        return self.layers(x)_____no_output_____

## O Agente_____no_output_____Pelo nosso agente ainda utilizar principalmente [DQN](https://github.com/GrupoTuring/Aprendizado-por-Reforco/tree/per/Aprendizado%20por%20Refor%C3%A7o%20Profundo/Deep%20Q-Learning/Deep%20Q-Network) muitos de seus parâmetros são análogos ao agente DQN.

Os parâmetros exclusivos do Prioritized Experience Replay são:
- ```alpha```: o quanto a priorização é relevante
- ```loss_param```: correção de viés nas experiências
- ```lp_increase```: o quanto a correção vai deixando de ser relevante
_____no_output_____

class Agent:
    """
    Uma classe que cria um agente DQN que utiliza Experience Replay com
    priority sample como memória.
    """
    def __init__(self,
                 env,
                 hyperparameters):

        self._alpha       = hyperparameters["a"]
        self._loss_param  = hyperparameters["b"]
        self._lp_increase = hyperparameters["beta_decay"]
        self._lr          = hyperparameters["lr"]
        self._batch       = hyperparameters["batch"]
        self._epsilon     = hyperparameters["e0"]
        self._epsilon_min = hyperparameters["ef"]
        self._gamma       = hyperparameters["gamma"]
        self._steps       = 0

        self.device        = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self._memory       = PrioritizedExperienceReplay(env.observation_space.shape, 100000, self._alpha, 0.0001)
        self._action_space = env.action_space

        self._decay = self._epsilon_min**(1/hyperparameters["decay"])

        self.dqn        = Network(env.observation_space.shape, env.action_space.n).to(self.device)

        self._opt       = optim.Adam(self.dqn.parameters(), lr=self._lr)

    def apply_decay(self):
        self._epsilon = max(self._epsilon*self._decay, self._epsilon_min)

    def act(self, state):
        if random.random() < self._epsilon:
            return self._action_space.sample()

        with torch.no_grad():
            state = torch.FloatTensor(state).to(self.device,non_blocking=True)
            action = self.dqn.forward(state).argmax(dim=-1)
            action = action.cpu().numpy()

            return action

    def save_on_memory(self, s, a, r, s2, d):
        self._memory.push(s, a, r, s2, d)

    def train(self):
        self._steps += 1
        if len(self._memory) < self._batch:
            return -float("inf")

        s, a, r, s2, d, p, i = self._memory.sample(self._batch)

        s = torch.as_tensor(s).to(self.device, non_blocking=True)
        a = torch.as_tensor(a).to(self.device, non_blocking=True).unsqueeze(-1)
        r = torch.as_tensor(r).to(self.device, non_blocking=True).unsqueeze(-1)
        s2 = torch.as_tensor(s2).to(self.device, non_blocking=True)
        d = torch.as_tensor(d).to(self.device, non_blocking=True).unsqueeze(-1)

        q_eval = self.dqn.forward(s).gather(-1, a.long())

        with torch.no_grad():
            q_next = self.dqn.forward(s2).max(dim=-1, keepdim=True)[0]
            target = (r + self._gamma*q_next*(1 - d)).to(self.device)
            N      = len(self._memory)
            w      = (N * p)**(-self._loss_param)
            w      = w/w.max()
            self._loss_param *= 1 + self._lp_increase if self._loss_param < 1 else 1

        loss = F.mse_loss(q_eval, target, reduction="none")
        self._memory.update_priority(i, torch.abs(loss))

        w = torch.as_tensor(w).to(self.device).unsqueeze(-1)
        weighted_loss = loss * w
        final_loss    = torch.mean(weighted_loss)
        self._opt.zero_grad()
        final_loss.backward()
        for param in self.dqn.parameters():
            param.grad.data.clamp_(-100, 100)
        self._opt.step()

        return final_loss

    @property
    def epsilon(self):
        return self._epsilon

    @property
    def beta(self):
        return self._loss_param

    @property
    def memory(self):
        return self._memory
_____no_output_____

## Hiperparâmetros e Loop Principal_____no_output_____

hparams = {
    "a":0.6,
    "b":0.4,
    "beta_decay": 2.5e-5,
    "lr":1e-3,
    "gamma":0.999,
    "e0":1,
    "ef":0.01,
    "decay":150,
    "batch":64,
}

env = gym.make("CartPole-v1")
agent = Agent(env, hparams)

episodes = 400
history = []
tts = 0
for i in range(1, episodes + 1):
    steps = 0
    rewards = 0
    total_loss = 0
    done = False
    state = env.reset()
    while not done:
        action = agent.act(state)
        sstate, reward, done, _ = env.step(action)
        agent.save_on_memory(state, action, reward, sstate, done)
        loss = agent.train()
        state = sstate
        rewards += reward
        steps += 1
        total_loss += loss
    # if i%100 == 0:
    #     save(agent.dqn.state_dict(), f"{str(i)}.pth")
    print(f"\r episode [{i:04d}] - rewards [{rewards}] - duration [{steps:04d}] - epsilon [{100*agent.epsilon:.2f}%] - beta [{agent.beta:.2f}]", end="")
    history.append(rewards)
    agent.apply_decay() episode [0400] - rewards [316.0] - duration [0316] - epsilon [1.00%] - beta [1.00]

## Curva de Aprendizado_____no_output_____

means = [0]*episodes
high = [0]*episodes
low  = [0]*episodes
for i in range(episodes):
    start = max(0, i - 20)
    end = min(episodes, i + 21)
    slice = history[ start : end ]
    mean = sum(slice)/(end - start)
    std = np.std(slice)
    means[i] = mean
    high[i] = mean + std
    low[i] = mean - std

plt.figure(figsize=(12,7))
with plt.style.context("seaborn-pastel"):
    x = [k for k in range(episodes)]
    plt.fill_between(x, low, high, alpha=0.2)
    plt.plot(x, means, linewidth=4)
    plt.plot(x, history)
    plt.show()_____no_output_____


# Notebook from baidu/Quanlse
Path: Tutorial/EN/tutorial-error-analysis.ipynb

# Error Analysis

*Copyright (c) 2021 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.*_____no_output_____## Outline

This tutorial will use the example of a Cross Resonance (CR) gate to demonstrate how to analyze errors that arise during a quantum operation, using tools including dynamical analysis to understand the state evolution, and the truth table to visualize the leakage errors outside of the computational space. The outline of this tutorial is as follows:
- Introduction
- Preparation
- Construct Hamiltonian and pulse optimization
- Dynamical analysis
- Truth table
- Summary_____no_output_____## Introduction

When a target quantum gate is implemented using control pulses, the actual quantum operation might differ from the target operation. This difference is normally quantified as infidelity. Understanding the sources of errors that lead to this infidelity is important for us to design pulse sequences that can mitigate these errors and improve gate fidelity.

Quanlse provides the functionality to analyze the population evolution of qubit states through dynamical analysis, and visualize the leakage out of the computational space through a truth table. In this tutorial, we will demonstrate these two functions using the Cross Resonance (CR) gate implementation as an example. More details on the CR gate can be found in [Cross Resonance gate](https://quanlse.baidu.com/#/doc/tutorial-cr)._____no_output_____## Preparation

After you have successfully installed Quanlse, you could run the Quanlse program below following this tutorial. To run this particular tutorial, you would need to import the following packages from Quanlse and other commonly-used Python libraries:_____no_output_____

# This module is imported for creating Hamiltonian dictionary
from Quanlse.QHamiltonian import QHamiltonian as QHam

# These functions are imported to define useful operators matrices to free us from defining them manually
from Quanlse.QOperator import number, duff

# These functions are imported to helps us perform matrix calculation
from Quanlse.Utils.Functions import basis, tensor, projector

# This function is imported to perform CR gate optimization using Quanlse Cloud Service
from Quanlse.remoteOptimizer import remoteOptimizeCr

# Import the necessary packages
import numpy
import matplotlib.pyplot as plt_____no_output_____

To use the `remoteOptimizeCr()` function, we need a token to get access to Quanlse Cloud Service._____no_output_____

# Import Define class and set the token
# Please visit http://quantum-hub.baidu.com
from Quanlse import Define
Define.hubToken = ""_____no_output_____

## Construct Hamiltonian and pulse optimization

Using the following lines of code, we first construct the system Hamiltonian and optimize the control parameters to implement a high-fidelity CR gate._____no_output_____

# Define parameters to initialize the Hamiltonian
dt = 2.0  # Sampling period
qubits = 2  # Number of qubits
level = 3  # Energy level

# Define qubit parameters
g = 0.0038 * (2 * numpy.pi)  # Coupling strength, GHz
wq0  = 4.914 * (2 * numpy.pi)  # Transition frequency for qubit 0, GHz
wq1 = 4.714 * (2 * numpy.pi)  # Transition frequency for qubit 1, GHz
wd1 = wq1  # Drive frequency is the frequency for qubit 1
anharm0 = - 0.33 * (2 * numpy.pi)  # Anharmonicity of qubit 0, GHz
anharm1 = - 0.33 * (2 * numpy.pi)  # Anharmonicity of qubit 1, GHz

# Initialize the Hamiltonian
ham = QHam(subSysNum=qubits, sysLevel=level, dt=dt)

# Add the detuning terms
ham.addDrift(number, onSubSys=0, coef=wq0 - wd1)
ham.addDrift(number, onSubSys=1, coef=wq1 - wd1)

# Add the anharmonicity terms
ham.addDrift(duff, onSubSys=0, coef=anharm0 / 2)
ham.addDrift(duff, onSubSys=1, coef=anharm0 / 2)

# Add the coupling term
ham.addCoupling([0, 1], g=g / 2)

# Set amplitude bound
aBound = (1.0, 3.0)

# Run the optimization on Quanlse Cloud Service
job, infidelity = remoteOptimizeCr(ham, aBound=aBound, tg=200, maxIter=3, targetInfidelity=0.01)_____no_output_____

## Dynamical analysis

Studying how the initial qubit state evolves during a quantum operation helps us understand the effect of control pulses on the qubit and the sources of errors. The dynamical analysis functionality in Quanlse simulates the population evolution of different qubits' states for a given initial state. In the following example, we demonstrate how to simulate the population evolution of basis states in the computational space for a two-qubit system ($|00\rangle$, $|01\rangle$, $|10\rangle$, and $|11\rangle$) when a CR gate is implemented. We will look at the population evolution of basis states when the initial qubit state is $|01\rangle$ as an example._____no_output_____We first define our complete set of computational basis states for a two-qubit system by firstly generating a state vector for each qubit using `basis()` function, which takes the number of energy levels (e.g., 3 for a three-level system) as the first input, and the state (0 or 1 in this case) as the second input. The state vectors representing these two qubits are then constructed from each state vector using `tensor()` function._____no_output_____

# Define basis states: 00, 01, 10 and 11
state00 = tensor(basis(3, 0), basis(3, 0))
state01 = tensor(basis(3, 0), basis(3, 1))
state10 = tensor(basis(3, 1), basis(3, 0))
state11 = tensor(basis(3, 1), basis(3, 1))
stateList = [state00, state01, state10, state11]_____no_output_____

We then construct the projection matrices to calculate the population for each basis state from the expectation value of each projection matrix. We use `projector()` function to create the projection matrix. `projector(a, b)` takes two previously defined state vectors (a and b) and generates the projection matrix $|a\rangle\langle b|$. If only one state vector is taken as the input, for example, $|a\rangle$, this function will return $|a\rangle\langle a|$._____no_output_____

# Construct projection matrices from basis states
matrix00 = projector(state00)
matrix01 = projector(state01)
matrix10 = projector(state10)
matrix11 = projector(state11)
matrixList = [matrix00, matrix01, matrix10, matrix11]_____no_output_____

We are now ready to evaluate the evolution of the expectation value for each projection matrix during the CR gate operation. We use the function `Benchmark.evolution()` to do so. This function takes the following inputs: the constructed Hamiltonian, the list of initial state vectors, and the list of projection matrices._____no_output_____

# Run the simulation to evaluate evolution of the expectation values
from Quanlse.Utils import Benchmark
ham.job = job
evolutionResult = Benchmark.evolution(ham, stateInitial=stateList, matrix=matrixList)_____no_output_____

The returned **result** is a dictionary containing various terms. The keys *'0'*, *'1'*, *'2'* … refer to the indices of the initial states. Corresponding to each key for state index, there is a sub-dictionary that contains the following terms:

* 'state_form': the initial state vector
* 'state_evolution_history': the evolution of the initial state vector
* 'result': the evolution of the expectation values for the projection matrices corresponding to different states. Within this sub-dictionary, it contains the expectation value for each projection matrix._____no_output_____Now we can plot the population evolution of different basis states by taking the absolute value of each expectation value. In the following lines, we plot the population evolution as a function of time with an initial state defined to be $|01\rangle$._____no_output_____

# Define x values to be the time for evolution
endTimeNs, endTimeDt = ham.job.computeMaxTime()
x = numpy.linspace(0, endTimeNs, endTimeDt)

# Define y values to be the expectation value for each projection matrix when the initial state is in 01, which corresponds to index 1
y1 = numpy.array(evolutionResult['1']['result']['matrix-0-value'])
y2 = numpy.array(evolutionResult['1']['result']['matrix-1-value'])
y3 = numpy.array(evolutionResult['1']['result']['matrix-2-value'])
y4 = numpy.array(evolutionResult['1']['result']['matrix-3-value'])

# Plot the population as absolute value of the expectation values
plt.plot(x, abs(y1), linewidth=3, label='00')
plt.plot(x, abs(y2), linewidth=3, label='01')
plt.plot(x, abs(y3), linewidth=3, label='10')
plt.plot(x, abs(y4), linewidth=3, label='11')
plt.title(r'Population Evolution for $|01\rangle$ Initial State ')
plt.xlabel('Time (ns)')
plt.ylabel('Population')
plt.legend()
plt.show()_____no_output_____

## Truth table

A truth table of a quantum gate contains the probability of the system is in each possible basis state at the end of an operation for each possible initial state. Initial states are always selected to be in the computational space, while the final states can be outside of the computational space, corresponding to a leakage event. Quanlse provides the functionality to calculate the elements of the truth table for a quantum operation and visualize the results using a 2D plot. This is a convenient tool for analyzing the errors corresponding to the leakage for all initial basis states.

Here, we will introduce this tool by analyzing the unitary operator of the CR gate:_____no_output_____

# Import the function for generating the truth table
from Quanlse.Utils.Benchmark import stateTruthTable

# Import the function for plotting the heat map
from Quanlse.Utils.Plot import plotHeatMap

# Import the functions for basis operations
from Quanlse.Utils.Functions import generateBasisIndexList, computationalBasisList

# Indicate the input state list, and generate the list of the state indices
inputStateStr = ['00', '01', '10', '11']
initStateList = generateBasisIndexList(inputStateStr, level)

# Generate the matrix of the truth table
result = ham.simulate()
matrix = stateTruthTable(result[0]["unitary"], qubits, level, initStateList)

# Generate the list of the output state strings and plot the heat map
outputStateStr = computationalBasisList(qubits, level)
plotHeatMap(matrix, xTicks=outputStateStr, yTicks=inputStateStr, xLabel="Output State", yLabel="Input State", useLog=True)_____no_output_____

From the above heat map, we can easily obtain the information about dynamical evolution and the leakage error. _____no_output_____## Summary

In summary, this tutorial illustrated the Quanlse functionalities for analyzing errors that might arise when a quantum gate is implemented through control pulses. Dynamical analysis gives us a complete picture of the state evolution, and truth table informs us the distribution of errors on different states.

After reading this tutorial on error analysis, the users could follow this link [tutorial-error-analysis.ipynb](https://github.com/baidu/Quanlse/blob/main/Tutorial/EN/tutorial-error-analysis.ipynb) to the GitHub page of this Jupyter Notebook document and run this program for themselves. The users are encouraged to explore other advanced research techniques that are not shown in this tutorial._____no_output_____## References
\[1\] [Nielsen, Michael A., and Isaac L. Chuang. Quantum Computation and Quantum Information: 10th Anniversary Edition. Cambridge University Press, 2010.](https://doi.org/10.1017/CBO9780511976667)_____no_output_____


# Notebook from jjonhwa/Policy-to-utilize-DT-in-traditional-markets
Path: pmedian/pmedian.ipynb

<code>
# !pip install folium
# !pip install pyproj_____no_output_____import pandas as pd
import folium
import math

from itertools import combinations
from pyproj import Proj, transform
from tqdm import tqdm

import warnings
warnings.filterwarnings('ignore')

from typing import List_____no_output_____def preprocess_data(path: str) -> pd.DataFrame:
    """
    "Note": Modify and use according to your own data.
    Or you don't need to use this code, and you just insert some code about preprocess in "main"

    Explanation
    Data Path is received as inputs and data is purified in the order of "name"/"latitude"/"longitude".

    Arguments
        path: A path of a file in the form of 'xlsx' and 'csv' is input.

    Return
        Pandas Data Frame: Form of Pandas Data Frame with Column in the order of "Name", "Latitude", and "Longitude"
    """

    if "xlsx" in path:
        data = pd.read_excel(path)
        ############ input/output에 따라 수정 ####################
        if "대구분명칭" in data.columns:
            data = data[["대구분명칭", "위도", "경도"]]
        elif "시장명" in data.columns:
            data = data[["시장명", "위도", "경도"]]
        data.columns = ["name", "latitude", "longitude"]
        ##########################################################
    elif "csv" in path:
        data = pd.read_csv(path, header=None)  # header 옵션 역시 본인의 데이터에 맞추어 수정한다.
        ############ input/output에 따라 수정 ####################
        data.columns = ["longitude", "latitude", "name"]
        data = data[["name", "latitude", "longitude"]]
        ##########################################################
    return data_____no_output_____# market: 지역_공공공장소/위도/경도
# population: 지역_유동인구/위도/경도
market_location_path = '../data/울진군예상좌표.xlsx'
population_location_path = '../data/울진_편의점.csv'

market_data = preprocess_data(market_location_path)
population_data = preprocess_data(population_location_path)_____no_output_____def coordinate_change(data: pd.DataFrame, c1: str, c2: str) -> pd.DataFrame:
    """
    Explanation
        The latitude and longitude existing in the data frame are converted from the coordinate c1 to the coordinate c2 to be converted.
    Arguments
        data: The columns are in the form of a Pandas Data Frame in the order of "name", "latitude", and "longitude".
        c1: The original latitude and longitude coordinate system.
        c2: The latitude and longitude coordinate system to convert.
            c1 & c2: something like 'epsg:5178', 'epsg:4326', etc..

    Return
        Pandas Data Frame: Data frame with converted latitude and longitude coordinates.
    """
    proj_c1 = Proj(init=c1)
    proj_c2 = Proj(init=c2)

    for i in tqdm(range(len(data))):
        change_long, change_lat = transform(
            proj_c1, proj_c2, data["longitude"][i], data["latitude"][i]
        )

        data["longitude"][i] = change_long
        data["latitude"][i] = change_lat

    return data_____no_output_____market_data = coordinate_change(market_data, 'epsg:4326', 'epsg:5178')
population_data = coordinate_change(population_data, 'epsg:4326', 'epsg:5178')100%|██████████| 50/50 [00:01<00:00, 47.88it/s]
100%|██████████| 86/86 [00:01<00:00, 55.09it/s]
def shortest_distance(F: pd.DataFrame, L: pd.DataFrame):
    """
    Explanation
        Create the shortest matrix between public facilities and floating population.

    Arguments
        F: Coordinates of public facilities.
        L: Coordinates of the floating population.

    Return
        Pandas Data Frame: Shortest distance matrix between public facilities and floating population
    """
    F_list = []
    L_list = []
    for i in range(len(F)):
        name = f"F_{i}"
        F_list.append(name)

    for i in range(len(L)):
        name = f"L_{i}"
        L_list.append(name)

    distance = pd.DataFrame(columns=F_list, index=L_list)
    for i in range(len(distance)):
        for j, col in enumerate(distance.columns):
            square_sum = ((F["latitude"][j] - L["latitude"][i]) ** 2) + (
                (F["longitude"][j] - L["longitude"][i]) ** 2
            )
            dist = math.sqrt(square_sum)
            distance[col][i] = dist

    return distance_____no_output_____distance = shortest_distance(market_data, population_data)
distance_____no_output_____def p_list_set(distance_data: pd.DataFrame, p: int) -> List[List]:
    """
    Explanation
        Based on F(Public Facilities), '2p' public facilities with the shortest
         distance from the floating population coordinates are selected

    Args
        distance_data: The matrix of distances between F and L. (column = F, row = L)
        p: The number of public facilities to be finally selected.

    return
        p_list_set: A set of p lists tied up in p
        ex) candidate= [1,2,3,4,5,6,7,8,9,10] / p=3
            p_list_set = [
                [1,2,3],
                [2,3,4],
                [3,4,5]
            ]
    """
    # The sum of the distances between the coordinates of the floating population for public facilities.
    col_sum = list(distance_data.sum(axis=0))

    col_sum_tuple = []  # Tie col_sum with index.
    for i in range(len(col_sum)):
        tup = (i, col_sum[i])
        col_sum_tuple.append(tup)

    col_sum_tuple.sort(key=lambda x: x[1])
    col_sum_tuple = col_sum_tuple[: 2 * p]  # Choose the top 2p based on distance.

    p_list_set = [col_sum_tuple[i : i + p] for i in range(p)]

    return p_list_set_____no_output_____def candidate_place(
    pb: pd.DataFrame, distance: pd.DataFrame, p_list_set: List[List]
) -> List:
    """
    Explanation
        Only names are extracted from DataFrame having a minimal distance within each set.

    Args:
        pb: DataFrame for public facilities.
        distance: DataFrame about the distance between F and L

        p_list_set: In distance, a set of p lists grouped by p based on distance

    Return:
        List: List of names of p public facilities.
    """
    min_sum_list = []  # take the minimum values in the pth list.
    for i in range(len(p_list_set)):
        tup_check = []
        for j in p_list_set[i]:
            tup_check.append(f"F_{j[0]}")
        check_df = distance[tup_check]

        check_df["min"] = 0  # generate 'min' column
        for k in range(len(check_df)):
            k_th_row = check_df.iloc[k][:-1]  # exclude 'min' column
            check_df["min"][k] = min(k_th_row)

        min_sum_value = sum(check_df["min"])
        min_sum_list.append(min_sum_value)

    final_index = min_sum_list.index(min(min_sum_list))
    final_set = p_list_set[final_index]
    final_set.sort(key=lambda x: x[0])

    final_idx = [idx for idx, dist in final_set]
    final_market_data = pb.iloc[final_idx, :]
    final_market_data.reset_index(drop=True, inplace=True)

    name_list = [name for name in final_market_data["name"]]
    return name_list_____no_output_____char_list = []
for p in range(3, 11) :
    p_list = p_list_set(distance, p)
    name_list = candidate_place(market_data, distance, p_list)

    char_list.extend(name_list)_____no_output_____def top_value(char_list: List) -> int:
    """Heuristic Method with P-Median
    Explanation
        Get the top three to six. (If there is a duplicate value, bring up to six.)

    Args:
        char_list: A list of the names of the final candidates.

    Return:
        int: The number of final candidates to get
    """
    appearance_candidate = list(pd.Series(char_list).value_counts())

    num_of_candidate = 3
    for first, second in zip(appearance_candidate[2:], appearance_candidate[3:]):
        if first == second:
            num_of_candidate += 1
        else:
            break

    return num_of_candidate_____no_output_____def make_finalset(market_data: pd.DataFrame, char_list: List) -> pd.DataFrame:
    """Heuristic Method with P-Median
    Explanation
        After receiving the char_list, which is the list of the final candidates,
         The final candidates is mapped with public facility data
         to return a DataFrame containing only the final candidates.

    Args:
        market_data: Data containing market location information.
        char_list: The list with the names of the final candidates overlapped.

    Return:
        Pandas DataFrame: The final DataFrame containing the names, latitudes, and longitude of the final candidates.
    """

    num_of_candidate = top_value(char_list)
    final_name_list = pd.Series(char_list).value_counts().index[:num_of_candidate]

    market_index = [
        (market_data[market_data["name"] == name].index)[0] for name in final_name_list
    ]

    market_final = market_data.iloc[market_index, :]
    market_final.reset_index(drop=True, inplace=True)
    return market_final_____no_output_____market_final = make_finalset(market_data, char_list)
market_final = coordinate_change(market_final,'epsg:5178',  'epsg:4326')
100%|██████████| 6/6 [00:00<00:00, 39.97it/s]
market_final_____no_output_____sijang = preprocess_data('../data/울진시장.xlsx')
sijang = coordinate_change(sijang, 'epsg:5178', 'epsg:4326')100%|██████████| 14/14 [00:00<00:00, 41.96it/s]
def mark(
    m: folium.Map,
    data: pd.DataFrame,
    color: str,
    icon: str,
    size: float,
    popup: bool = True,
):
    """
    Explanation
        Marker is displayed on the map according to the top
         and longitude of the data and its name is displayed on Marker.

    Args:
        data: DataFrame which has name, lattitude, and longitude
        color: Specify the color of the marker to be displayed on the folium map.
        icon:Specify the icon of the marker to be displayed on the folium map.
        size: Specify the size of the marker to be displayed on the folium map.
        popup: Specifies that text is extracted when a marker is clicked (where name is specified).
    """

    for i in range(len(data)):
        long = data["latitude"][i]
        lat = data["longitude"][i]
        name = data["name"][i]
        folium.Marker(
            location=[long, lat],
            popup=name if popup else None,
            icon=folium.Icon(color=color, icon=icon, size=size),
        ).add_to(m)_____no_output_____m = folium.Map(location = [36.85, 129.4004195], zoom_start = 10)
mark(m, sijang, 'yellow', 'star', 0.1)
mark(m, market_final, 'blue', 'flag', 0.1)
m_____no_output_____m_____no_output_____
</code>