##### Copyright 2020 The TensorFlow Authors.

```python
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#This code was modified from Tensorflow tutorial, MNIST classification
#https://www.tensorflow.org/quantum/tutorials/mnist
#I used CIFAR-10 database instead of MNIST database, and I modified and tuned the original code accordingly
```

Import TensorFlow and the module dependencies:

```python
import tensorflow as tf
import tensorflow_quantum as tfq

import cirq
import sympy
import numpy as np
import seaborn as sns
import collections

# visualization tools
%matplotlib inline
import matplotlib.pyplot as plt
from cirq.contrib.svg import SVGCircuit
```

### 1. Load the raw data

Load the CIFAR-10 dataset distributed with Keras.

```python
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data()

# Rescale the images from [0,255] to the [0.0,1.0] range.
x_train, x_test = x_train[..., np.newaxis]/255.0, x_test[..., np.newaxis]/255.0

train_samples = list(zip(x_train, map(int, y_train)))
test_samples = list(zip(x_test, map(int, y_test)))

print("Number of original training examples:", len(x_train))
print("Number of original test examples:", len(x_test))
```

    Number of original training examples: 50000
    Number of original test examples: 10000

Filter the dataset to keep just the automobile and deer images (labeled with 1 and 4 respectively),  remove the other classes.

```python
def filter_type(x):
    # automobile(1) and deer(4)
    i = 0
    while i < len(x):
        if (x[i][1] != 1 & x[i][1] != 4):
            del x[i]
        else:
            i += 1
    return x
```

```python
train_samples = filter_type(train_samples)
test_samples = filter_type(test_samples)

print("Number of filtered training examples:", len(train_samples))
print("Number of filtered test examples:", len(test_samples))
```

    Number of filtered training examples: 10000
    Number of filtered test examples: 2000

Show the first example:

```python
plt.imshow(train_samples[1][0][:,:,0])
plt.colorbar()
```

### 2. Downscale the images

An image size of 32x32 is much too large for current quantum computers. Resize the image down to 4x4:

```python
x_train_small = list()
x_test_small = list()

for i in range(len(train_samples)):
    x_train_small.append(tf.image.resize(train_samples[i][0], (4,4)).numpy());

for i in range(len(test_samples)):
    x_test_small.append(tf.image.resize(test_samples[i][0], (4,4)).numpy());
```

Show the first training example after resize:

```python
plt.imshow(x_train_small[1][0, :,:,0], vmin=0, vmax=1)
plt.colorbar()
```

### 3. Remove contradictory examples

From section *3.3 Learning to Distinguish Digits* of Farhi et al., filter the dataset to remove images that are labeled as belonging to both classes.

This is not a standard machine-learning procedure, but is included in the interest of following the paper.

```python
def remove_contradicting(xs, ys):
    mapping = collections.defaultdict(set)
    orig_x = {}
    # Determine the set of labels for each unique image:
    for x,y in zip(xs,ys):
       orig_x[tuple(x.flatten())] = x[1]
       mapping[tuple(x.flatten())].add(y)

    new_x = []
    new_y = []
    for flatten_x in mapping:
      x = orig_x[flatten_x]
      labels = mapping[flatten_x]
      if len(labels) == 1:
          new_x.append(x[1])
          new_y.append(next(iter(labels)))
      else:
          # Throw out images that match more than one label.
          pass

    return np.array(new_x), np.array(new_y)
```

```python
x_train_nocon, y_train_nocon = remove_contradicting(x_train_small, y_train)
```

```python
x_test_small, y_test = remove_contradicting(x_train_small, y_test)
```

### 4. Encode the data as quantum circuits

To process images using a quantum computer, Farhi et al. proposed representing each pixel with a qubit, with the state depending on the value of the pixel. The first step is to convert to a binary encoding.

```python
THRESHOLD = 0.5

x_train_bin = np.array(x_train_nocon > THRESHOLD, dtype=np.float32)
x_test_bin = np.array(x_test_small > THRESHOLD, dtype=np.float32)
```

The qubits at pixel indices with values that exceed a threshold, are rotated through an $X$ gate.

```python
def convert_to_circuit(image):
    """Encode truncated classical image into quantum datapoint."""
    values = np.ndarray.flatten(image)
    qubits = cirq.GridQubit.rect(4, 4)
    circuit = cirq.Circuit()
    # print(len(values))
    for i, value in enumerate(values):
        if value:
            circuit.append(cirq.X(qubits[i]))
    return circuit

x_train_circ = [convert_to_circuit(x) for x in x_train_bin]
x_test_circ = [convert_to_circuit(x) for x in x_test_bin]
```

Here is the circuit created for the first example (circuit diagrams do not show qubits with zero gates):

```python
SVGCircuit(x_train_circ[0])
```

Compare this circuit to the indices where the image value exceeds the threshold:

```python
bin_img = x_train_bin[0,:, :,0]
indices = np.array(np.where(bin_img)).T
indices
```

    array([[0],
           [1],
           [2],
           [3]])

Convert these `Cirq` circuits to tensors for `tfq`:

```python
x_train_tfcirc = tfq.convert_to_tensor(x_train_circ)
x_test_tfcirc = tfq.convert_to_tensor(x_test_circ)
```

### 5. Build the model circuit for Quantum Neural Network

This following example shows a layered approach. Each layer uses *n* instances of the same gate, with each of the data qubits acting on the readout qubit.

Start with a simple class that will add a layer of these gates to a circuit:

```python
class CircuitLayerBuilder():
    def __init__(self, data_qubits, readout):
        self.data_qubits = data_qubits
        self.readout = readout

    def add_layer(self, circuit, gate, prefix):
        for i, qubit in enumerate(self.data_qubits):
            symbol = sympy.Symbol(prefix + '-' + str(i))
            circuit.append(gate(qubit, self.readout)**symbol)
```

Build an example circuit layer to see how it looks:

```python
demo_builder = CircuitLayerBuilder(data_qubits = cirq.GridQubit.rect(4,1),
                                   readout=cirq.GridQubit(-1,-1))

circuit = cirq.Circuit()
demo_builder.add_layer(circuit, gate = cirq.XX, prefix='xx')
SVGCircuit(circuit)
```

Now build a two-layered model, matching the data-circuit size, and include the preparation and readout operations.

```python
def create_quantum_model():
    """Create a QNN model circuit and readout operation to go along with it."""
    data_qubits = cirq.GridQubit.rect(4, 4)  # a 4x4 grid.
    readout = cirq.GridQubit(-1, -1)         # a single qubit at [-1,-1]
    circuit = cirq.Circuit()

    # Prepare the readout qubit.
    circuit.append(cirq.X(readout))
    circuit.append(cirq.H(readout))

    builder = CircuitLayerBuilder(
        data_qubits = data_qubits,
        readout=readout)

    # Then add layers (experiment by adding more).
    builder.add_layer(circuit, cirq.XX, "xx1")
    builder.add_layer(circuit, cirq.ZZ, "zz1")

    # Finally, prepare the readout qubit.
    circuit.append(cirq.H(readout))

    return circuit, cirq.Z(readout)
```

```python
model_circuit, model_readout = create_quantum_model()
SVGCircuit(model_circuit)
```

### 6. Wrap the model-circuit in a tfq-keras model

Build the Keras model with the quantum components. This model is fed the "quantum data", from `x_train_circ`, that encodes the classical data. It uses a *Parametrized Quantum Circuit* layer, `tfq.layers.PQC`, to train the model circuit, on the quantum data.

To classify these images, Farhi et al. proposed taking the expectation of a readout qubit in a parameterized circuit. The expectation returns a value between 1 and -1.

```python
# Build the Keras model.
model = tf.keras.Sequential([
    # The input is the data-circuit, encoded as a tf.string
    tf.keras.layers.Input(shape=(), dtype=tf.string),
    # The PQC layer returns the expected value of the readout gate, range [-1,1].
    tfq.layers.PQC(model_circuit, model_readout),
])
```

Next, describe the training procedure to the model, using the `compile` method.

Since the the expected readout is in the range `[-1,1]`, optimizing the hinge loss is a somewhat natural fit.

Note: Another valid approach would be to shift the output range to `[0,1]`, and treat it as the probability the model assigns to class `3`. This could be used with a standard a `tf.losses.BinaryCrossentropy` loss.

To use the hinge loss here you need to make two small adjustments. First convert the labels, `y_train_nocon`, from boolean to `[-1,1]`, as expected by the hinge loss.

```python
y_train_hinge = 2.0*y_train_nocon-1.0
y_test_hinge = 2.0*y_test-1.0
```

Second, use a custiom `hinge_accuracy` metric that correctly handles `[-1, 1]` as the `y_true` labels argument.
`tf.losses.BinaryAccuracy(threshold=0.0)` expects `y_true` to be a boolean, and so can't be used with hinge loss).

```python
def hinge_accuracy(y_true, y_pred):
    y_true = tf.squeeze(y_true) > 0.0
    y_pred = tf.squeeze(y_pred) > 0.0
    result = tf.cast(y_true == y_pred, tf.float32)

    return tf.reduce_mean(result)
```

```python
model.compile(
    loss=tf.keras.losses.Hinge(),
    optimizer=tf.keras.optimizers.Adam(),
    metrics=[hinge_accuracy])
```

```python
print(model.summary())
```

    Model: "sequential_3"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #
    =================================================================
    pqc_1 (PQC)                  (None, 1)                 32
    =================================================================
    Total params: 32
    Trainable params: 32
    Non-trainable params: 0
    _________________________________________________________________
    None

### 7. Train and test the quantum model

```python
EPOCHS = 3
BATCH_SIZE = 32

NUM_EXAMPLES = 1500 # len(x_train_tfcirc)
```

```python
x_train_tfcirc_sub = x_train_tfcirc[:NUM_EXAMPLES]
y_train_hinge_sub = y_train_hinge[:NUM_EXAMPLES]
```

Training this model to convergence should achieve >85% accuracy on the test set.

```python
qnn_history = model.fit(
      x_train_tfcirc_sub, y_train_hinge_sub,
      batch_size=32,
      epochs=EPOCHS,
      verbose=1,
      validation_data=(x_test_tfcirc, y_test_hinge))

qnn_results = model.evaluate(x_test_tfcirc, y_test)
```

    Epoch 1/3
    47/47 [==============================] - 41s 877ms/step - loss: 0.6194 - hinge_accuracy: 0.9034 - val_loss: 0.3328 - val_hinge_accuracy: 0.9000
    Epoch 2/3
    47/47 [==============================] - 40s 865ms/step - loss: 0.3074 - hinge_accuracy: 0.8978 - val_loss: 0.2461 - val_hinge_accuracy: 0.9000
    Epoch 3/3
    47/47 [==============================] - 40s 868ms/step - loss: 0.2631 - hinge_accuracy: 0.8976 - val_loss: 0.2270 - val_hinge_accuracy: 0.9000
    313/313 [==============================] - 25s 80ms/step - loss: 0.2560 - hinge_accuracy: 0.9000

Note: The training accuracy reports the average over the epoch. The validation accuracy is evaluated at the end of each epoch.

The result accuracy is shown below as a bar plot. It is shown to have 90% accuracy over the test data.

```python
qnn_accuracy = qnn_results[1]
sns.barplot(["Quantum"], [qnn_accuracy])
```


```python
import numpy as np
from astropy.io import fits
from dla_cnn.desi.DesiMock import DesiMock
from os.path import join
from matplotlib import pyplot as plt
import sympy
```

```python
file_num = [705,706,711,718,723,731,735,743,747,748,761,773,777,785,789,791]
path = r"F:\Astronamy\desi-0.2-100\desi-0.2-100\desi-0.2-100\spectra-16\7"
file_path = join(path,str(file_num[0]))
spectra = join(file_path,"spectra-16-%s.fits"%file_num[0])
truth = join(file_path,"truth-16-%s.fits"%file_num[0])
zbest = join(file_path,"zbest-16-%s.fits"%file_num[0])#generate file path
```

```python
specs = DesiMock()
specs.read_fits_file(spectra,truth,zbest)#use DesiMock.read_fits_file(spectra, truth, zbest) to load all data from the fits file
```

```python
keys = list(specs.data.keys())#get spectra id
```

```python
sightline = specs.get_sightline(keys[0])#use DesiMock.get_sightline(id) to grab the specific spectra
```

```python
max_flux = max(sightline.flux)
plt.figure(figsize=(18,10))
plt.title('spec-%s'%(str(sightline.id)),fontdict=None,loc='center',pad='20',fontsize=30,color='black')
plt.xlabel('Wavelength'+'['+'$\AA$'+']',fontsize=18)
plt.ylabel('Flux',fontsize=18)
plt.xlim([4000,8000])
wavelength = np.exp(np.log(10)*sightline.loglam)
plt.plot(wavelength,sightline.flux)
plt.plot(wavelength,sightline.error,color='red',ls='--',linewidth=1)
for i in range(len(sightline.dlas)):
    plt.axvline(x=sightline.dlas[i].central_wavelength,ls="-",c="red",linewidth=1)
    plt.text(sightline.dlas[i].central_wavelength,max_flux-i,'%s'%(sightline.dlas[i].id),fontsize=20,color='green')
    plt.text(5400,max_flux-4-i,'%s,central_wavelength=%f,col_density=%f'%(sightline.dlas[i].id,sightline.dlas[i].central_wavelength,sightline.dlas[i].col_density),fontsize=20,color='red')
plt.show()
```


# [Module 1.5] 피쳐 엔지니어링

이 노트북은 아래와 같은 피쳐 엔지니어링을 통하여 새로운 피쳐를 생성 합니다.
- 날짜관련 피쳐 생성(월, 일, 요일)
- 기존의 피쳐들을 결합하여 새로운 피쳐 생성 (피쳐1 + 피쳐2 = 뉴피쳐)
- Product_ID를 기준으로 Target Encoding 하여 새로운 피쳐 생성
- Product_ID를 기준으로 Target Encoding Smoothing 하여 새로운 피쳐 생성
- Category 피쳐를 레이블 인코딩 함
- 로컬에 데이터 저장
    - 최종 레이블 인코딩 된 데이터 세트 저장 (XGBoost, CatBoost 용)
    - 레이블 인코딩 안한 데이터 세트 저장 (AutoGluon 용)

```python
import pandas as pd
pd.options.display.max_rows=5
import numpy as np
```

```python
%store -r full_data_file_name
```

```python
import os
os.getcwd()
```

    '/home/ec2-user/SageMaker/predict-delivery-time/brazil_ecommerce'

### 데이터 로딩 및 셔플링

```python
df = pd.read_csv(full_data_file_name)
df = df.sample(frac=1.0, random_state=1000)
df
```

      classes
      order_approved_at
      customer_id
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_id
      product_weight_g
      product_length_cm
      product_height_cm
      product_width_cm
      product_category_name_english
      seller_zip_code_prefix
      seller_city
      seller_state

      37413
      3
      2018-07-14 13:04:07
      4ee61c3905a5c398d44b089108961bb3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2f13d1dc8b4e1d9d8027be50339546a9
      2650.0
      30.0
      30.0
      30.0
      furniture_decor
      3204
      sao paulo
      SP

      54762
      3
      2017-03-25 10:25:16
      959292edcade77d6b60dc8f49f01cd71
      37880
      cabo verde
      MG
      23.99
      14.52
      b000447e24e31a4d7e628ca4d0622131
      250.0
      19.0
      4.0
      11.0
      telephony
      3504
      sao paulo
      SP

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      18782
      3
      2018-07-16 18:20:34
      609b34a18fd0d61719d0b3190ec05231
      21240
      rio de janeiro
      RJ
      200.00
      19.50
      92d5ae8e42c4599266f210bf0469ae9b
      439.0
      18.0
      11.0
      13.0
      watches_gifts
      14050
      ribeirao preto
      SP

      3776
      1
      2018-05-25 07:06:30
      dc275c5e585b7c3a3cddef527e34fc19
      26540
      nilopolis
      RJ
      18.90
      7.55
      15de022edf1005363381e66bed514528
      100.0
      16.0
      3.0
      23.0
      furniture_decor
      20270
      rio de janeiro
      RJ

67176 rows × 17 columns

```python
df.columns
```

    Index(['classes', 'order_approved_at', 'customer_id',
           'customer_zip_code_prefix', 'customer_city', 'customer_state', 'price',
           'freight_value', 'product_id', 'product_weight_g', 'product_length_cm',
           'product_height_cm', 'product_width_cm',
           'product_category_name_english', 'seller_zip_code_prefix',
           'seller_city', 'seller_state'],
          dtype='object')

## 날짜 피쳐 생성: Month, Day, WeeoOfDay(요일)

```python
def create_date_feature(raw_df):
    df = raw_df.copy()
    df['order_date'] = pd.to_datetime(df['order_approved_at'])
    df['order_weekday'] = df['order_date'].dt.weekday
    df['order_day'] = df['order_date'].dt.day
    df['order_month'] = df['order_date'].dt.month
    return df

f_df = create_date_feature(df)
f_df
```

      classes
      order_approved_at
      customer_id
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_id
      product_weight_g
      ...
      product_height_cm
      product_width_cm
      product_category_name_english
      seller_zip_code_prefix
      seller_city
      seller_state
      order_date
      order_weekday
      order_day
      order_month

      37413
      3
      2018-07-14 13:04:07
      4ee61c3905a5c398d44b089108961bb3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2f13d1dc8b4e1d9d8027be50339546a9
      2650.0
      ...
      30.0
      30.0
      furniture_decor
      3204
      sao paulo
      SP
      2018-07-14 13:04:07
      5
      14
      7

      54762
      3
      2017-03-25 10:25:16
      959292edcade77d6b60dc8f49f01cd71
      37880
      cabo verde
      MG
      23.99
      14.52
      b000447e24e31a4d7e628ca4d0622131
      250.0
      ...
      4.0
      11.0
      telephony
      3504
      sao paulo
      SP
      2017-03-25 10:25:16
      5
      25
      3

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      18782
      3
      2018-07-16 18:20:34
      609b34a18fd0d61719d0b3190ec05231
      21240
      rio de janeiro
      RJ
      200.00
      19.50
      92d5ae8e42c4599266f210bf0469ae9b
      439.0
      ...
      11.0
      13.0
      watches_gifts
      14050
      ribeirao preto
      SP
      2018-07-16 18:20:34
      0
      16
      7

      3776
      1
      2018-05-25 07:06:30
      dc275c5e585b7c3a3cddef527e34fc19
      26540
      nilopolis
      RJ
      18.90
      7.55
      15de022edf1005363381e66bed514528
      100.0
      ...
      3.0
      23.0
      furniture_decor
      20270
      rio de janeiro
      RJ
      2018-05-25 07:06:30
      4
      25
      5

67176 rows × 21 columns

## 기존 피쳐 결합하여 새로운 피쳐 생성 (컬럼1 + 컬럼2 = 뉴피쳐)

```python
def change_var_type(f_df):
    df = f_df.copy()
    df['customer_zip_code_prefix'] = df['customer_zip_code_prefix'].astype(str)
    df['seller_zip_code_prefix'] = df['seller_zip_code_prefix'].astype(str)
    return df

def comnbine_columns(f_df,src_col1, src_col2,new_col):
    df = f_df.copy()
    df[new_col] = df[str(src_col1)] + '_' + df[str(src_col2)]
    print("df shape: ", df.shape)
    return df

f_df = change_var_type(f_df)
```

### custoemr_state + seller_state

```python
f_df = comnbine_columns(f_df,src_col1='customer_state', src_col2='seller_state',new_col='customer_seller_state')
```

    df shape:  (67176, 22)

### custoemr_city + seller_city

```python
f_df = comnbine_columns(f_df,src_col1='customer_city', src_col2='seller_city',new_col='customer_seller_city')
```

    df shape:  (67176, 23)

### custoemr_zip + seller_zip

```python
f_df = comnbine_columns(f_df,src_col1='customer_zip_code_prefix',
                        src_col2='seller_zip_code_prefix',new_col='customer_seller_zip_code_prefix')
```

    df shape:  (67176, 24)

```python
f_df
```

      classes
      order_approved_at
      customer_id
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_id
      product_weight_g
      ...
      seller_zip_code_prefix
      seller_city
      seller_state
      order_date
      order_weekday
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix

      37413
      3
      2018-07-14 13:04:07
      4ee61c3905a5c398d44b089108961bb3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2f13d1dc8b4e1d9d8027be50339546a9
      2650.0
      ...
      3204
      sao paulo
      SP
      2018-07-14 13:04:07
      5
      14
      7
      RJ_SP
      armacao dos buzios_sao paulo
      28950_3204

      54762
      3
      2017-03-25 10:25:16
      959292edcade77d6b60dc8f49f01cd71
      37880
      cabo verde
      MG
      23.99
      14.52
      b000447e24e31a4d7e628ca4d0622131
      250.0
      ...
      3504
      sao paulo
      SP
      2017-03-25 10:25:16
      5
      25
      3
      MG_SP
      cabo verde_sao paulo
      37880_3504

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      18782
      3
      2018-07-16 18:20:34
      609b34a18fd0d61719d0b3190ec05231
      21240
      rio de janeiro
      RJ
      200.00
      19.50
      92d5ae8e42c4599266f210bf0469ae9b
      439.0
      ...
      14050
      ribeirao preto
      SP
      2018-07-16 18:20:34
      0
      16
      7
      RJ_SP
      rio de janeiro_ribeirao preto
      21240_14050

      3776
      1
      2018-05-25 07:06:30
      dc275c5e585b7c3a3cddef527e34fc19
      26540
      nilopolis
      RJ
      18.90
      7.55
      15de022edf1005363381e66bed514528
      100.0
      ...
      20270
      rio de janeiro
      RJ
      2018-05-25 07:06:30
      4
      25
      5
      RJ_RJ
      nilopolis_rio de janeiro
      26540_20270

67176 rows × 24 columns

```python
f_df.columns
```

    Index(['classes', 'order_approved_at', 'customer_id',
           'customer_zip_code_prefix', 'customer_city', 'customer_state', 'price',
           'freight_value', 'product_id', 'product_weight_g', 'product_length_cm',
           'product_height_cm', 'product_width_cm',
           'product_category_name_english', 'seller_zip_code_prefix',
           'seller_city', 'seller_state', 'order_date', 'order_weekday',
           'order_day', 'order_month', 'customer_seller_state',
           'customer_seller_city', 'customer_seller_zip_code_prefix'],
          dtype='object')

## Target Encoding 관련 피쳐 생성
- Product_ID 별 Classes의 평균, 갯수 (te_pdid_mean, te_pdid_count)
- Target Error (classes - te_pdid_mean)

```python

def create_target_encoding(cat, raw_df):
    df = raw_df.copy()
    te = df.groupby(cat).classes.agg(['mean','count']).reset_index()
    te.columns = cat + ['te_pdid_mean','te_pdid_count']
    te_df = df.merge(te, on=cat, how='left')
    te_df['te_pdid_error'] = (te_df['classes']  - te_df['te_pdid_mean']).abs()
    return te_df

cat = ['product_id']
te_df = create_target_encoding(cat, f_df)
```

```python
te_df.head(2)
```

      classes
      order_approved_at
      customer_id
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_id
      product_weight_g
      ...
      order_date
      order_weekday
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix
      te_pdid_mean
      te_pdid_count
      te_pdid_error

      0
      3
      2018-07-14 13:04:07
      4ee61c3905a5c398d44b089108961bb3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2f13d1dc8b4e1d9d8027be50339546a9
      2650.0
      ...
      2018-07-14 13:04:07
      5
      14
      7
      RJ_SP
      armacao dos buzios_sao paulo
      28950_3204
      2.705882
      17
      0.294118

      1
      3
      2017-03-25 10:25:16
      959292edcade77d6b60dc8f49f01cd71
      37880
      cabo verde
      MG
      23.99
      14.52
      b000447e24e31a4d7e628ca4d0622131
      250.0
      ...
      2017-03-25 10:25:16
      5
      25
      3
      MG_SP
      cabo verde_sao paulo
      37880_3504
      2.600000
      5
      0.400000

2 rows × 27 columns

```python
pd.options.display.max_rows=10
te_df.te_pdid_error.describe()
```

    count    67176.000000
    mean         0.597436
    std          0.602626
    min          0.000000
    25%          0.000000
    50%          0.500000
    75%          1.000000
    max          3.095238
    Name: te_pdid_error, dtype: float64

```python
te_df.columns
```

    Index(['classes', 'order_approved_at', 'customer_id',
           'customer_zip_code_prefix', 'customer_city', 'customer_state', 'price',
           'freight_value', 'product_id', 'product_weight_g', 'product_length_cm',
           'product_height_cm', 'product_width_cm',
           'product_category_name_english', 'seller_zip_code_prefix',
           'seller_city', 'seller_state', 'order_date', 'order_weekday',
           'order_day', 'order_month', 'customer_seller_state',
           'customer_seller_city', 'customer_seller_zip_code_prefix',
           'te_pdid_mean', 'te_pdid_count', 'te_pdid_error'],
          dtype='object')

## Target Encoding with Smoothing
아래 비디오 및 코드 참조 함
- Feature Engineering
    - RecSys 2020 Tutorial: Feature Engineering for Recommender Systems
        - https://www.youtube.com/watch?v=uROvhp7cj6Q
    - Git Repo
        - https://github.com/rapidsai/deeplearning/tree/main/RecSys2020Tutorial

\begin{equation} \label{eq:te}
TE_{target}([Categories]) = \frac{count([Categories]) * mean_{target}([Categories]) + w_{smoothing} * mean_{target}(global)}{count([Categories]) + w_{smoothing}}
\end{equation}

```python
w = 20 # global 평균에 더 높은 가중치를 주는 값
def create_target_encoding_smoothe(cat, raw_df, w):
    df = raw_df.copy()
    classes_mean_global = df.classes.mean()
    print(" classes_mean_global: ", classes_mean_global)
    df['te_pdid_mean_smoothed'] = (df['te_pdid_mean'] * df['te_pdid_count']) + (classes_mean_global * w) / (te_df['te_pdid_count'] + w)
    df['te_pdid_error_smoothed'] = (df['classes']  - df['te_pdid_mean_smoothed']).abs()

    return df

tes_df = create_target_encoding_smoothe(cat, te_df, w)
```

     classes_mean_global:  2.08827557460998

```python
tes_df.head()
```

      classes
      order_approved_at
      customer_id
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_id
      product_weight_g
      ...
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix
      te_pdid_mean
      te_pdid_count
      te_pdid_error
      te_pdid_mean_smoothed
      te_pdid_error_smoothed

      0
      3
      2018-07-14 13:04:07
      4ee61c3905a5c398d44b089108961bb3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2f13d1dc8b4e1d9d8027be50339546a9
      2650.0
      ...
      14
      7
      RJ_SP
      armacao dos buzios_sao paulo
      28950_3204
      2.705882
      17
      0.294118
      47.128798
      44.128798

      1
      3
      2017-03-25 10:25:16
      959292edcade77d6b60dc8f49f01cd71
      37880
      cabo verde
      MG
      23.99
      14.52
      b000447e24e31a4d7e628ca4d0622131
      250.0
      ...
      25
      3
      MG_SP
      cabo verde_sao paulo
      37880_3504
      2.600000
      5
      0.400000
      14.670620
      11.670620

      2
      1
      2018-03-24 12:27:28
      0d4a5cdbedc3aa83305c5d5ea18a19de
      4537
      sao paulo
      SP
      99.00
      9.05
      8983a3b149303c013fceabef902e835a
      450.0
      ...
      24
      3
      SP_SP
      sao paulo_sao paulo
      4537_4102
      1.238095
      21
      0.238095
      27.018671
      26.018671

      3
      0
      2017-11-28 03:21:09
      d2d34922fed7b3a54130c786b7cb0ecd
      5397
      sao paulo
      SP
      503.34
      25.53
      7614c62b86a81021243e438cfde78ccc
      9900.0
      ...
      28
      11
      SP_SP
      sao paulo_salto
      5397_13328
      1.666667
      12
      1.666667
      21.305172
      21.305172

      4
      2
      2018-03-25 16:10:31
      3fb1b736500b371cd8576c7050fe7256
      4037
      sao paulo
      SP
      64.90
      20.18
      23227b07fc69250d2fa4be6602011aea
      1250.0
      ...
      25
      3
      SP_DF
      sao paulo_brasilia
      4037_70740
      2.000000
      5
      0.000000
      11.670620
      9.670620

5 rows × 29 columns

## 최종 사용할 컬럼 지정

```python
def filter_df(raw_df, cols):
    df = raw_df.copy()
    df = df[cols]
    return df

cols = ['classes','customer_zip_code_prefix','customer_city',
       'customer_state', 'price', 'freight_value',
       'product_weight_g', 'product_length_cm', 'product_height_cm',
       'product_width_cm', 'product_category_name_english',
       'seller_zip_code_prefix','seller_city',
       'seller_state',
       'order_weekday',
       'order_day', 'order_month',
       'customer_seller_state',
       'customer_seller_city', 'customer_seller_zip_code_prefix',
#        'product_id',
#       'te_pdid_mean', 'te_pdid_count', 'te_pdid_error',
       'te_pdid_mean_smoothed','te_pdid_error_smoothed',

       ]

tes_df = filter_df(tes_df, cols)
tes_df

```

      classes
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_weight_g
      product_length_cm
      product_height_cm
      product_width_cm
      ...
      seller_city
      seller_state
      order_weekday
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix
      te_pdid_mean_smoothed
      te_pdid_error_smoothed

      0
      3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2650.0
      30.0
      30.0
      30.0
      ...
      sao paulo
      SP
      5
      14
      7
      RJ_SP
      armacao dos buzios_sao paulo
      28950_3204
      47.128798
      44.128798

      1
      3
      37880
      cabo verde
      MG
      23.99
      14.52
      250.0
      19.0
      4.0
      11.0
      ...
      sao paulo
      SP
      5
      25
      3
      MG_SP
      cabo verde_sao paulo
      37880_3504
      14.670620
      11.670620

      2
      1
      4537
      sao paulo
      SP
      99.00
      9.05
      450.0
      16.0
      3.0
      15.0
      ...
      sao paulo
      SP
      5
      24
      3
      SP_SP
      sao paulo_sao paulo
      4537_4102
      27.018671
      26.018671

      3
      0
      5397
      sao paulo
      SP
      503.34
      25.53
      9900.0
      30.0
      39.0
      38.0
      ...
      salto
      SP
      1
      28
      11
      SP_SP
      sao paulo_salto
      5397_13328
      21.305172
      21.305172

      4
      2
      4037
      sao paulo
      SP
      64.90
      20.18
      1250.0
      45.0
      10.0
      15.0
      ...
      brasilia
      DF
      6
      25
      3
      SP_DF
      sao paulo_brasilia
      4037_70740
      11.670620
      9.670620

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      67171
      4
      49015
      aracaju
      SE
      330.00
      25.03
      400.0
      34.0
      4.0
      22.0
      ...
      sao bernardo do campo
      SP
      1
      10
      7
      SE_SP
      aracaju_sao bernardo do campo
      49015_9628
      262.278437
      258.278437

      67172
      2
      12570
      aparecida
      SP
      55.00
      25.67
      250.0
      22.0
      14.0
      11.0
      ...
      goiania
      GO
      2
      10
      1
      SP_GO
      aparecida_goiania
      12570_74323
      24.392184
      22.392184

      67173
      0
      1532
      sao paulo
      SP
      399.00
      11.54
      975.0
      19.0
      18.0
      23.0
      ...
      santo andre
      SP
      1
      26
      6
      SP_SP
      sao paulo_santo andre
      1532_9230
      1.988834
      1.988834

      67174
      3
      21240
      rio de janeiro
      RJ
      200.00
      19.50
      439.0
      18.0
      11.0
      13.0
      ...
      ribeirao preto
      SP
      0
      16
      7
      RJ_SP
      rio de janeiro_ribeirao preto
      21240_14050
      6.898432
      3.898432

      67175
      1
      26540
      nilopolis
      RJ
      18.90
      7.55
      100.0
      16.0
      3.0
      23.0
      ...
      rio de janeiro
      RJ
      4
      25
      5
      RJ_RJ
      nilopolis_rio de janeiro
      26540_20270
      2.670620
      1.670620

67176 rows × 22 columns

## Category 레이블 Encoding

```python
def category_encoding(raw_df, cate_cols, encoding_option=0):
    '''
    encoding_option = 0 : One hot Encoding
    encoding_option = 1 : Label Encoding

    '''
    f_df = raw_df.copy()
    if encoding_option == 0: # one-hot-encoding
        f_df = pd.get_dummies(f_df)
    else:
        for item in cate_cols:
            f_df[item] = f_df[item].astype("category").cat.codes +1
    print(f_df.shape)

    return f_df

cate_cols = ['customer_state','customer_city','customer_zip_code_prefix',
             'product_category_name_english',
             'seller_state','seller_city','seller_zip_code_prefix',
             'customer_seller_city',
             'customer_seller_state',
             'customer_seller_zip_code_prefix',
             'order_weekday',
             'order_day',
             'order_month',
#             'product_id'
            ]

encoding_cate = category_encoding(tes_df,cate_cols, encoding_option=1)
encoding_cate.head()
```

    (67176, 22)

      classes
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_weight_g
      product_length_cm
      product_height_cm
      product_width_cm
      ...
      seller_city
      seller_state
      order_weekday
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix
      te_pdid_mean_smoothed
      te_pdid_error_smoothed

      0
      3
      3442
      219
      19
      105.00
      27.04
      2650.0
      30.0
      30.0
      30.0
      ...
      475
      21
      6
      14
      7
      240
      1223
      23560
      47.128798
      44.128798

      1
      3
      5183
      443
      11
      23.99
      14.52
      250.0
      19.0
      4.0
      11.0
      ...
      475
      21
      6
      25
      3
      132
      3422
      32864
      14.670620
      11.670620

      2
      1
      6294
      2730
      26
      99.00
      9.05
      450.0
      16.0
      3.0
      15.0
      ...
      475
      21
      6
      24
      3
      326
      21388
      37862
      27.018671
      26.018671

      3
      0
      7161
      2730
      26
      503.34
      25.53
      9900.0
      30.0
      39.0
      38.0
      ...
      428
      21
      2
      28
      11
      326
      21356
      41304
      21.305172
      21.305172

      4
      2
      5687
      2730
      26
      64.90
      20.18
      1250.0
      45.0
      10.0
      15.0
      ...
      75
      3
      7
      25
      3
      308
      21115
      35333
      11.670620
      9.670620

5 rows × 22 columns

## 레이블 Encoding 안하고 바로 사용(AutoGluon 용)

```python
no_encoding_cate = tes_df
```

```python
tes_df
```

      classes
      customer_zip_code_prefix
      customer_city
      customer_state
      price
      freight_value
      product_weight_g
      product_length_cm
      product_height_cm
      product_width_cm
      ...
      seller_city
      seller_state
      order_weekday
      order_day
      order_month
      customer_seller_state
      customer_seller_city
      customer_seller_zip_code_prefix
      te_pdid_mean_smoothed
      te_pdid_error_smoothed

      0
      3
      28950
      armacao dos buzios
      RJ
      105.00
      27.04
      2650.0
      30.0
      30.0
      30.0
      ...
      sao paulo
      SP
      5
      14
      7
      RJ_SP
      armacao dos buzios_sao paulo
      28950_3204
      47.128798
      44.128798

      1
      3
      37880
      cabo verde
      MG
      23.99
      14.52
      250.0
      19.0
      4.0
      11.0
      ...
      sao paulo
      SP
      5
      25
      3
      MG_SP
      cabo verde_sao paulo
      37880_3504
      14.670620
      11.670620

      2
      1
      4537
      sao paulo
      SP
      99.00
      9.05
      450.0
      16.0
      3.0
      15.0
      ...
      sao paulo
      SP
      5
      24
      3
      SP_SP
      sao paulo_sao paulo
      4537_4102
      27.018671
      26.018671

      3
      0
      5397
      sao paulo
      SP
      503.34
      25.53
      9900.0
      30.0
      39.0
      38.0
      ...
      salto
      SP
      1
      28
      11
      SP_SP
      sao paulo_salto
      5397_13328
      21.305172
      21.305172

      4
      2
      4037
      sao paulo
      SP
      64.90
      20.18
      1250.0
      45.0
      10.0
      15.0
      ...
      brasilia
      DF
      6
      25
      3
      SP_DF
      sao paulo_brasilia
      4037_70740
      11.670620
      9.670620

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      67171
      4
      49015
      aracaju
      SE
      330.00
      25.03
      400.0
      34.0
      4.0
      22.0
      ...
      sao bernardo do campo
      SP
      1
      10
      7
      SE_SP
      aracaju_sao bernardo do campo
      49015_9628
      262.278437
      258.278437

      67172
      2
      12570
      aparecida
      SP
      55.00
      25.67
      250.0
      22.0
      14.0
      11.0
      ...
      goiania
      GO
      2
      10
      1
      SP_GO
      aparecida_goiania
      12570_74323
      24.392184
      22.392184

      67173
      0
      1532
      sao paulo
      SP
      399.00
      11.54
      975.0
      19.0
      18.0
      23.0
      ...
      santo andre
      SP
      1
      26
      6
      SP_SP
      sao paulo_santo andre
      1532_9230
      1.988834
      1.988834

      67174
      3
      21240
      rio de janeiro
      RJ
      200.00
      19.50
      439.0
      18.0
      11.0
      13.0
      ...
      ribeirao preto
      SP
      0
      16
      7
      RJ_SP
      rio de janeiro_ribeirao preto
      21240_14050
      6.898432
      3.898432

      67175
      1
      26540
      nilopolis
      RJ
      18.90
      7.55
      100.0
      16.0
      3.0
      23.0
      ...
      rio de janeiro
      RJ
      4
      25
      5
      RJ_RJ
      nilopolis_rio de janeiro
      26540_20270
      2.670620
      1.670620

67176 rows × 22 columns

## Train, Val, Test 분리

```python
# One-Hot-Encoding
a,b,c = np.split(encoding_cate.sample(frac=1, random_state=1729),
                 [int(0.7 * len(encoding_cate)),
                  int(0.9 * len(encoding_cate))])   # Randomly sort the data then split out first 70%, second 20%, and last 10%
preproc_train_data =a
preproc_val_data =b
preproc_test_data =c
# No one-hot-encoding
a,b,c = np.split(no_encoding_cate.sample(frac=1, random_state=1729),
                 [int(0.7 * len(no_encoding_cate)),
                  int(0.9 * len(no_encoding_cate))])   # Randomly sort the data then split out first 70%, second 20%, and last 10%
train_data=a
val_data=b
test_data=c
```

## 로컬에 데이터 저장

```python
import os

def save_local(train_data, validation_data, test_data, preproc_folder):
    train_df = pd.concat([train_data['classes'], train_data.drop(['classes'], axis=1)], axis=1)
    train_file_name = os.path.join(preproc_folder, 'train.csv')
    train_df.to_csv(train_file_name, index=False)
    print(f'{train_file_name} is saved')

    val_df = pd.concat([validation_data['classes'], validation_data.drop(['classes'], axis=1)], axis=1)
    val_file_name = os.path.join(preproc_folder, 'val.csv')
    val_df.to_csv(val_file_name, index=False)
    print(f'{val_file_name} is saved')

    test_df = pd.concat([test_data['classes'], test_data.drop(['classes'], axis=1)], axis=1)
    test_file_name = os.path.join(preproc_folder, 'test.csv')
    test_df.to_csv(test_file_name, index=False)
    print(f'{test_file_name} is saved')

    return train_file_name, val_file_name, test_file_name

preproc_folder = 'preproc_data/feature_engineering'
os.makedirs(preproc_folder, exist_ok=True)
pre_train_file,pre_val_file, pre_test_file = save_local(preproc_train_data, preproc_val_data, preproc_test_data, preproc_folder)

preproc_folder = 'preproc_data/non_feature_engineering'
os.makedirs(preproc_folder, exist_ok=True)
train_file,val_file, test_file  = save_local(train_data, val_data, test_data, preproc_folder)
```

    preproc_data/feature_engineering/train.csv is saved
    preproc_data/feature_engineering/val.csv is saved
    preproc_data/feature_engineering/test.csv is saved
    preproc_data/non_feature_engineering/train.csv is saved
    preproc_data/non_feature_engineering/val.csv is saved
    preproc_data/non_feature_engineering/test.csv is saved

```python
%store pre_train_file
%store pre_val_file
%store pre_test_file

%store train_file
%store val_file
%store test_file
```

    Stored 'pre_train_file' (str)
    Stored 'pre_val_file' (str)
    Stored 'pre_test_file' (str)
    Stored 'train_file' (str)
    Stored 'val_file' (str)
    Stored 'test_file' (str)

```python

```

```python

```

```python

```

```python

```


```python
import matplotlib.pyplot as plt
import scipy.stats as st
import seaborn as sns
import pandas as pd
from scipy.stats import norm, uniform, expon, t, binom, binom_test, wilcoxon
from scipy.integrate import quad
from sympy.solvers import solve
from sympy import Symbol
import numpy as np
from pandas import Series, DataFrame
```

```python
import matplotlib.pyplot as plt
import pandas as pd
from pandas import DataFrame
pw_electric = pd.read_csv('pws.csv', sep=';', skiprows=2, header=0, encoding = "utf-8", index_col=0)
pw_electric.head()
pw_electric_luzern = DataFrame(pw_electric.ix["Luzern",1:])
pw_electric_luzern
pw_electric_luzern["Year"] = pd.to_datetime(pw_electric_luzern.index)
pw_electric_luzern.set_index("Year", inplace=True)
pw_electric_luzern.plot()
plt.xlabel("Jahr")
plt.ylabel("Anzahl Elektro-Autos Luzern")
plt.show()

```

```python
import matplotlib.pyplot as plt
import pandas as pd
from pandas import DataFrame
pw_electric = pd.read_csv('pws.csv', sep=';', skiprows=2, header=0, encoding = "utf-8", index_col=0)
pw_electric.head()
pw_electric_luzern = DataFrame(pw_electric.ix["Zürich",1:])
pw_electric_luzern
pw_electric_luzern["Year"] = pd.to_datetime(pw_electric_luzern.index)
pw_electric_luzern.set_index("Year", inplace=True)
pw_electric_luzern.plot()
plt.xlabel("Jahr")
plt.ylabel("Anzahl Elektro-Autos Luzern")
plt.show()

```

```python
import matplotlib.pyplot as plt
import pandas as pd
from pandas import DataFrame
pw_electric = pd.read_csv('pws.csv', sep=';', skiprows=2, header=0, encoding = "utf-8", index_col=0)
pw_electric.head()
pw_electric_luzern = DataFrame(pw_electric.ix["Luzern",1:])
pw_electric_luzern
pw_electric_luzern["Year"] = pd.to_datetime(pw_electric_luzern.index)
pw_electric_luzern.set_index("Year", inplace=True)
pw_electric_luzern.plot()
plt.xlabel("Jahr")
plt.ylabel("Anzahl Elektro-Autos Luzern")
plt.show()

```

```python

```


```python
# Erasmus+ ICCT project (2018-1-SI01-KA203-047081)

# Toggle cell visibility

from IPython.display import HTML
tag = HTML('''
Toggle cell visibility <a href="javascript:code_toggle()">here</a>.''')
display(tag)
```

Toggle cell visibility here.

```python
%matplotlib notebook
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
import ipywidgets as widgets
```

## Linearizacija - nihalo

V okviru modeliranja sistemov predstavlja linearizacija proces modeliranja nelinearnega sistema z linearno diferencialno enačbo v bližini izbrane obratovalne točke (običajno je to ravnovesna točka). V tem interaktivnem primeru je opisan proces prikazan na primeru preprostega nihala. Sila, ki povzroča oscilatorno gibanje nihala (prikazano na sliki spodaj), je definirana kot $-mgsin\theta$. Gibalno enačbo nihala lahko tako zapišemo kot:

\begin{equation}
    mL^2\frac{d^2\theta}{dt^2}=-mgsin\theta L.
\end{equation}

Po preureditvi zgornje enačbi dobimo naslednjo nelinearno diferencialno enačbo drugega reda:

\begin{equation}
    \frac{d^2\theta}{dt^2}+\frac{g}{L}sin\theta=0.
\end{equation}

V primeru majhnih kotnih pomikov lahko uporabimo izraz za aproksimacijo majhnih kotov ($sin\theta\approx\theta$) in zgornjo enačbo preoblikujemo v linearno diferencialno enačbo drugega reda:

\begin{equation}
    \frac{d^2\theta}{dt^2}+\frac{g}{L}\theta=0.
\end{equation}

---

        Preprosto nihalo

### Kako upravljati s tem interaktivnim primerom?

Z uporabo drsnikov spreminjaj dolžino nihala $L$ in vrednosti začetnih pogojev $\theta_0$ in $\dot{\theta_0}$.

```python
# create figure
fig = plt.figure(figsize=(9.8, 3),num='Linearizacija - nihalo')

# add sublot
ax = fig.add_subplot(111)
ax.set_title('Časovni odziv')
ax.set_ylabel('izhod')
ax.set_xlabel('$t$ [s]')
ax.axhline(y=0, xmin=-1, xmax=6, color='k', linewidth=1)

ax.grid(which='both', axis='both', color='lightgray')

nonlinear, = ax.plot([], [])
linear, = ax.plot([], [])

style = {'description_width': 'initial'}

g=9.81 # m/s^2

def model_nonlinear(ic,t,L):
    fi, fidot = ic
    return [fidot,-g/L*np.sin(fi)]

def model_linear(ic,t,L):
    fi, fidot = ic
    return [fidot,-g/L*fi]

def build_model(y0,ypika0,L):
    ic=[y0,ypika0]
    t=np.linspace(0,5,num=500)
    fi=odeint(model_nonlinear,ic,t,args=(L,))
    ys=fi[:,0]

    fi_linear=odeint(model_linear,ic,t,args=(L,))
    ys_linear=fi_linear[:,0]

    global nonlinear, linear

    ax.lines.remove(nonlinear)
    ax.lines.remove(linear)

    nonlinear, = ax.plot(t,ys,label='nelinearen sistem',color='C0', linewidth=5)
    linear, = ax.plot(t,ys_linear,label='lineariziran sistem',color='C3', linewidth=2)

    ax.legend()

    ax.relim()
    ax.autoscale_view()

L_slider=widgets.FloatSlider(value=0.3, min=.01, max=2., step=.01,
                                        description='$L$ [m]:',disabled=False,continuous_update=False,
                                        orientation='horizontal',readout=True,readout_format='.2f',)

ypika0_slider=widgets.FloatSlider(value=1, min=-3, max=3, step=0.1,
                                        description='$\dot \\theta_0$ [rad/s]:',disabled=False,continuous_update=False,
                                        orientation='horizontal',readout=True,readout_format='.2f',)

y0_slider=widgets.FloatSlider(value=1, min=-3, max=3, step=0.1,
                                        description='$\\theta_0$ [rad]:',disabled=False,continuous_update=False,
                                        orientation='horizontal',readout=True,readout_format='.2f',)

input_data=widgets.interactive_output(build_model, {'y0':y0_slider,'ypika0':ypika0_slider,'L':L_slider})

display(L_slider,y0_slider,ypika0_slider,input_data)
```

    <IPython.core.display.Javascript object>

    FloatSlider(value=0.3, continuous_update=False, description='$L$ [m]:', max=2.0, min=0.01, step=0.01)

    FloatSlider(value=1.0, continuous_update=False, description='$\\theta_0$ [rad]:', max=3.0, min=-3.0)

    FloatSlider(value=1.0, continuous_update=False, description='$\\dot \\theta_0$ [rad/s]:', max=3.0, min=-3.0)

    Output()


# GPyTorch Regression Tutorial

## Introduction

In this notebook, we demonstrate many of the design features of GPyTorch using the simplest example, training an RBF kernel Gaussian process on a simple function. We'll be modeling the function

\begin{align}
y &= \sin(2\pi x) + \epsilon \\
  \epsilon &\sim \mathcal{N}(0, 0.04)
\end{align}

with 100 training examples, and testing on 51 test examples.

**Note:** this notebook is not necessarily intended to teach the mathematical background of Gaussian processes, but rather how to train a simple one and make predictions in GPyTorch. For a mathematical treatment, Chapter 2 of Gaussian Processes for Machine Learning provides a very thorough introduction to GP regression (this entire text is highly recommended): http://www.gaussianprocess.org/gpml/chapters/RW2.pdf

```python
import math
import torch
import gpytorch
from matplotlib import pyplot as plt
import numpy as np
```

```python
import pandas as pd
import seaborn as sns
```

```python
df = pd.read_csv('yaz_steak.csv')
```

```python
df
```

      DEMAND_DATE
      Montag
      Dienstag
      Mittwoch
      Donnerstag
      Freitag
      Samstag
      Sonntag
      MONTH_JAN
      MONTH_FEB
      ...
      MONTH_SEP
      MONTH_OCT
      MONTH_NOV
      MONTH_DEC
      YEAR_2013
      YEAR_2014
      YEAR_2015
      ISHOLIDAY
      WEEKEND
      STEAK

      0
      2013-10-04
      0
      0
      0
      0
      1
      0
      0
      0
      0
      ...
      0
      1
      0
      0
      1
      0
      0
      0
      0
      36

      1
      2013-10-05
      0
      0
      0
      0
      0
      1
      0
      0
      0
      ...
      0
      1
      0
      0
      1
      0
      0
      0
      1
      30

      2
      2013-10-06
      0
      0
      0
      0
      0
      0
      1
      0
      0
      ...
      0
      1
      0
      0
      1
      0
      0
      0
      1
      16

      3
      2013-10-07
      1
      0
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      1
      0
      0
      1
      0
      0
      0
      0
      22

      4
      2013-10-08
      0
      1
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      1
      0
      0
      1
      0
      0
      0
      0
      29

      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...
      ...

      755
      2015-11-03
      0
      1
      0
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      1
      0
      0
      0
      1
      0
      0
      32

      756
      2015-11-04
      0
      0
      1
      0
      0
      0
      0
      0
      0
      ...
      0
      0
      1
      0
      0
      0
      1
      0
      0
      38

      757
      2015-11-05
      0
      0
      0
      1
      0
      0
      0
      0
      0
      ...
      0
      0
      1
      0
      0
      0
      1
      0
      0
      24

      758
      2015-11-06
      0
      0
      0
      0
      1
      0
      0
      0
      0
      ...
      0
      0
      1
      0
      0
      0
      1
      0
      0
      32

      759
      2015-11-07
      0
      0
      0
      0
      0
      1
      0
      0
      0
      ...
      0
      0
      1
      0
      0
      0
      1
      0
      1
      20

760 rows × 26 columns

```python
df.rename(columns={y:f'day{x}' for x,y in zip(range(7),df.columns[1:8])}, inplace=True)
df.rename(columns={y:f'x_month{x}' for x,y in zip(range(12),df.columns[8:20])}, inplace=True)
df.rename(columns={y:f'x_year{x}' for x,y in zip(range(3),df.columns[20:23])}, inplace=True)
df['id']=df.index
```

```python
#df_fil = df[(df.FilNr==2)&(df.artNr==101)]
#ax = sns.boxplot(x="dayofWeek", y="daySalesUnit", data=df_fil)
```

```python
df = pd.wide_to_long(df,["day"], i="id", j="weekday").reset_index()
df['id']=df.index
```

```python
df = pd.wide_to_long(df,["x_month"], i="id", j="months").reset_index()
df['id']=df.index
```

```python
df = pd.wide_to_long(df,["x_year"], i="id", j="years").reset_index()
df['id']=df.index
```

```python
df_fil = df[(df.day==1)&(df.x_month==1)&(df.x_year==1)].sort_values("DEMAND_DATE").copy()
```

```python
df_fil = df_fil.drop(columns=['x_year', 'x_month', 'day','id', 'DEMAND_DATE'])
```

```python
df_fil = df_fil[['years', 'months', 'weekday', 'WEEKEND', 'ISHOLIDAY', 'STEAK']]
```

```python
df_fil.to_csv('yaz_steak_small.csv', index=False)
```

```python
df_fil
```

      years
      months
      weekday
      WEEKEND
      ISHOLIDAY
      STEAK

      173280
      0
      9
      4
      0
      0
      36

      174041
      0
      9
      5
      1
      0
      30

      174802
      0
      9
      6
      1
      0
      16

      170243
      0
      9
      0
      0
      0
      22

      171004
      0
      9
      1
      0
      0
      29

      ...
      ...
      ...
      ...
      ...
      ...
      ...

      33435
      2
      10
      1
      0
      0
      32

      34196
      2
      10
      2
      0
      0
      38

      34957
      2
      10
      3
      0
      0
      24

      35718
      2
      10
      4
      0
      0
      32

      36479
      2
      10
      5
      1
      0
      20

760 rows × 6 columns

### Set up training data

In the next cell, we set up the training data for this example. We'll be using 100 regularly spaced points on [0,1] which we evaluate the function on and add Gaussian noise to get the training labels.

```python
train_x.shape
```

    torch.Size([760, 2])

```python
# Training data is 100 points in [0,1] inclusive regularly spaced
#train_x = torch.linspace(0, 1, 100)
#train_x = torch.tensor((df_fil.dayofWeek.astype('category').cat.codes/6.).astype(np.float32))
#train_x = torch.tensor((df_fil.TMK/df_fil.TMK.max()).astype(np.float32))
a = torch.tensor(np.array((df_fil.weekday/df_fil.weekday.max()).astype(np.float32)))
b = torch.tensor(np.array((df_fil.months/df_fil.months.max()).astype(np.float32)))
train_x = torch.tensor(np.vstack((a,b)).T)
# True function is sin(2*pi*x) with Gaussian noise
#train_y = torch.sin(train_x * (2 * math.pi)) + torch.randn(train_x.size()) * math.sqrt(0.04)
#train_y = torch.tensor(df_fil.daySalesUnit.astype(np.float32))
train_y = torch.tensor(np.array(df_fil.STEAK.astype(np.float32)))
train_y /= train_y.max()
```

## Setting up the model

The next cell demonstrates the most critical features of a user-defined Gaussian process model in GPyTorch. Building a GP model in GPyTorch is different in a number of ways.

First in contrast to many existing GP packages, we do not provide full GP models for the user. Rather, we provide *the tools necessary to quickly construct one*. This is because we believe, analogous to building a neural network in standard PyTorch, it is important to have the flexibility to include whatever components are necessary. As can be seen in more complicated examples, this allows the user great flexibility in designing custom models.

For most GP regression models, you will need to construct the following GPyTorch objects:

1. A **GP Model** (`gpytorch.models.ExactGP`) -  This handles most of the inference.
1. A **Likelihood** (`gpytorch.likelihoods.GaussianLikelihood`) - This is the most common likelihood used for GP regression.
1. A **Mean** - This defines the prior mean of the GP.(If you don't know which mean to use, a `gpytorch.means.ConstantMean()` is a good place to start.)
1. A **Kernel** - This defines the prior covariance of the GP.(If you don't know which kernel to use, a `gpytorch.kernels.ScaleKernel(gpytorch.kernels.RBFKernel())` is a good place to start).
1. A **MultivariateNormal** Distribution (`gpytorch.distributions.MultivariateNormal`) - This is the object used to represent multivariate normal distributions.

### The GP Model

The components of a user built (Exact, i.e. non-variational) GP model in GPyTorch are, broadly speaking:

1. An `__init__` method that takes the training data and a likelihood, and constructs whatever objects are necessary for the model's `forward` method. This will most commonly include things like a mean module and a kernel module.

2. A `forward` method that takes in some $n \times d$ data `x` and returns a `MultivariateNormal` with the *prior* mean and covariance evaluated at `x`. In other words, we return the vector $\mu(x)$ and the $n \times n$ matrix $K_{xx}$ representing the prior mean and covariance matrix of the GP.

This specification leaves a large amount of flexibility when defining a model. For example, to compose two kernels via addition, you can either add the kernel modules directly:

```python
self.covar_module = ScaleKernel(RBFKernel() + WhiteNoiseKernel())
```

Or you can add the outputs of the kernel in the forward method:

```python
covar_x = self.rbf_kernel_module(x) + self.white_noise_module(x)
```

```python
# We will use the simplest form of GP model, exact inference
class ExactGPModel(gpytorch.models.ExactGP):
    def __init__(self, train_x, train_y, likelihood):
        super(ExactGPModel, self).__init__(train_x, train_y, likelihood)
        self.mean_module = gpytorch.means.ConstantMean()
        self.covar_module = gpytorch.kernels.ScaleKernel(gpytorch.kernels.RBFKernel())

    def forward(self, x):
        mean_x = self.mean_module(x)
        covar_x = self.covar_module(x)
        return gpytorch.distributions.MultivariateNormal(mean_x, covar_x)

# initialize likelihood and model
likelihood = gpytorch.likelihoods.GaussianLikelihood()
model = ExactGPModel(train_x, train_y, likelihood)
```

### Model modes

Like most PyTorch modules, the `ExactGP` has a `.train()` and `.eval()` mode.
- `.train()` mode is for optimizing model hyperameters.
- `.eval()` mode is for computing predictions through the model posterior.

## Training the model

In the next cell, we handle using Type-II MLE to train the hyperparameters of the Gaussian process.

The most obvious difference here compared to many other GP implementations is that, as in standard PyTorch, the core training loop is written by the user. In GPyTorch, we make use of the standard PyTorch optimizers as from `torch.optim`, and all trainable parameters of the model should be of type `torch.nn.Parameter`. Because GP models directly extend `torch.nn.Module`, calls to methods like `model.parameters()` or `model.named_parameters()` function as you might expect coming from PyTorch.

In most cases, the boilerplate code below will work well. It has the same basic components as the standard PyTorch training loop:

1. Zero all parameter gradients
2. Call the model and compute the loss
3. Call backward on the loss to fill in gradients
4. Take a step on the optimizer

However, defining custom training loops allows for greater flexibility. For example, it is easy to save the parameters at each step of training, or use different learning rates for different parameters (which may be useful in deep kernel learning for example).

```python
# this is for running the notebook in our testing framework
import os
smoke_test = ('CI' in os.environ)
training_iter = 2 if smoke_test else 50

# Find optimal model hyperparameters
model.train()
likelihood.train()

# Use the adam optimizer
optimizer = torch.optim.Adam(model.parameters(), lr=0.1)  # Includes GaussianLikelihood parameters

# "Loss" for GPs - the marginal log likelihood
mll = gpytorch.mlls.ExactMarginalLogLikelihood(likelihood, model)

for i in range(training_iter):
    # Zero gradients from previous iteration
    optimizer.zero_grad()
    # Output from model
    output = model(train_x)
    # Calc loss and backprop gradients
    loss = -mll(output, train_y)
    loss.backward()
    print('Iter %d/%d - Loss: %.3f   lengthscale: %.3f   noise: %.3f' % (
        i + 1, training_iter, loss.item(),
        model.covar_module.base_kernel.lengthscale.item(),
        model.likelihood.noise.item()
    ))
    optimizer.step()
```

    Iter 1/50 - Loss: 0.761   lengthscale: 0.693   noise: 0.693
    Iter 2/50 - Loss: 0.725   lengthscale: 0.744   noise: 0.644
    Iter 3/50 - Loss: 0.687   lengthscale: 0.798   noise: 0.598
    Iter 4/50 - Loss: 0.650   lengthscale: 0.853   noise: 0.554
    Iter 5/50 - Loss: 0.611   lengthscale: 0.911   noise: 0.513
    Iter 6/50 - Loss: 0.572   lengthscale: 0.969   noise: 0.474
    Iter 7/50 - Loss: 0.533   lengthscale: 1.029   noise: 0.437
    Iter 8/50 - Loss: 0.492   lengthscale: 1.090   noise: 0.403
    Iter 9/50 - Loss: 0.452   lengthscale: 1.151   noise: 0.370
    Iter 10/50 - Loss: 0.411   lengthscale: 1.212   noise: 0.340
    Iter 11/50 - Loss: 0.369   lengthscale: 1.273   noise: 0.312
    Iter 12/50 - Loss: 0.327   lengthscale: 1.334   noise: 0.286
    Iter 13/50 - Loss: 0.285   lengthscale: 1.393   noise: 0.262
    Iter 14/50 - Loss: 0.242   lengthscale: 1.452   noise: 0.239
    Iter 15/50 - Loss: 0.199   lengthscale: 1.509   noise: 0.218
    Iter 16/50 - Loss: 0.156   lengthscale: 1.565   noise: 0.199
    Iter 17/50 - Loss: 0.113   lengthscale: 1.618   noise: 0.181
    Iter 18/50 - Loss: 0.069   lengthscale: 1.670   noise: 0.165
    Iter 19/50 - Loss: 0.026   lengthscale: 1.720   noise: 0.150
    Iter 20/50 - Loss: -0.017   lengthscale: 1.767   noise: 0.136
    Iter 21/50 - Loss: -0.060   lengthscale: 1.811   noise: 0.124
    Iter 22/50 - Loss: -0.103   lengthscale: 1.852   noise: 0.113
    Iter 23/50 - Loss: -0.145   lengthscale: 1.891   noise: 0.102
    Iter 24/50 - Loss: -0.187   lengthscale: 1.927   noise: 0.093
    Iter 25/50 - Loss: -0.228   lengthscale: 1.959   noise: 0.084
    Iter 26/50 - Loss: -0.268   lengthscale: 1.988   noise: 0.076
    Iter 27/50 - Loss: -0.308   lengthscale: 2.013   noise: 0.069
    Iter 28/50 - Loss: -0.346   lengthscale: 2.034   noise: 0.063
    Iter 29/50 - Loss: -0.383   lengthscale: 2.051   noise: 0.057
    Iter 30/50 - Loss: -0.419   lengthscale: 2.063   noise: 0.052
    Iter 31/50 - Loss: -0.454   lengthscale: 2.070   noise: 0.047
    Iter 32/50 - Loss: -0.487   lengthscale: 2.071   noise: 0.043
    Iter 33/50 - Loss: -0.518   lengthscale: 2.066   noise: 0.039
    Iter 34/50 - Loss: -0.548   lengthscale: 2.053   noise: 0.035
    Iter 35/50 - Loss: -0.575   lengthscale: 2.032   noise: 0.032
    Iter 36/50 - Loss: -0.601   lengthscale: 2.003   noise: 0.029
    Iter 37/50 - Loss: -0.624   lengthscale: 1.963   noise: 0.027
    Iter 38/50 - Loss: -0.645   lengthscale: 1.913   noise: 0.025
    Iter 39/50 - Loss: -0.663   lengthscale: 1.853   noise: 0.023
    Iter 40/50 - Loss: -0.680   lengthscale: 1.782   noise: 0.021
    Iter 41/50 - Loss: -0.695   lengthscale: 1.702   noise: 0.019
    Iter 42/50 - Loss: -0.708   lengthscale: 1.615   noise: 0.018
    Iter 43/50 - Loss: -0.719   lengthscale: 1.522   noise: 0.017
    Iter 44/50 - Loss: -0.728   lengthscale: 1.426   noise: 0.015
    Iter 45/50 - Loss: -0.735   lengthscale: 1.329   noise: 0.014
    Iter 46/50 - Loss: -0.742   lengthscale: 1.230   noise: 0.014
    Iter 47/50 - Loss: -0.749   lengthscale: 1.132   noise: 0.013
    Iter 48/50 - Loss: -0.758   lengthscale: 1.037   noise: 0.012
    Iter 49/50 - Loss: -0.767   lengthscale: 0.945   noise: 0.012
    Iter 50/50 - Loss: -0.777   lengthscale: 0.857   noise: 0.011

## Make predictions with the model

In the next cell, we make predictions with the model. To do this, we simply put the model and likelihood in eval mode, and call both modules on the test data.

Just as a user defined GP model returns a `MultivariateNormal` containing the prior mean and covariance from forward, a trained GP model in eval mode returns a `MultivariateNormal` containing the posterior mean and covariance. Thus, getting the predictive mean and variance, and then sampling functions from the GP at the given test points could be accomplished with calls like:

```python
f_preds = model(test_x)
y_preds = likelihood(model(test_x))

f_mean = f_preds.mean
f_var = f_preds.variance
f_covar = f_preds.covariance_matrix
f_samples = f_preds.sample(sample_shape=torch.Size(1000,))
```

The `gpytorch.settings.fast_pred_var` context is not needed, but here we are giving a preview of using one of our cool features, getting faster predictive distributions using [LOVE](https://arxiv.org/abs/1803.06058).

```python
# Get into evaluation (predictive posterior) mode
model.eval()
likelihood.eval()

# Test points are regularly spaced along [0,1]
# Make predictions by feeding model through likelihood
with torch.no_grad(), gpytorch.settings.fast_pred_var():
    test_x = torch.linspace(0, 1, 51)
    observed_pred = likelihood(model(test_x))
```

## Plot the model fit

In the next cell, we plot the mean and confidence region of the Gaussian process model. The `confidence_region` method is a helper method that returns 2 standard deviations above and below the mean.

```python
with torch.no_grad():
    # Initialize plot
    f, ax = plt.subplots(1, 1, figsize=(15, 15))

    # Get upper and lower confidence bounds
    lower, upper = observed_pred.confidence_region()
    # Plot training data as black stars
    ax.plot(train_x.numpy(), train_y.numpy(), 'k*')
    # Plot predictive means as blue line
    ax.plot(test_x.numpy(), observed_pred.mean.numpy(), 'b')
    # Shade between the lower and upper confidence bounds
    ax.fill_between(test_x.numpy(), lower.numpy(), upper.numpy(), alpha=0.5)
    ax.set_ylim([-3, 3])
    ax.legend(['Observed Data', 'Mean', 'Confidence'])
```

```python

```

```python

```

```python

```


# CSNAnalysis Tutorial
### A brief introduction to the use of the CSNAnalysis package
---
**Updated Aug 19, 2020**
*Dickson Lab, Michigan State University*

## Overview

The CSNAnalysis package is a set of tools for network-based analysis of molecular dynamics trajectories.
  CSNAnalysis is an easy interface between enhanced sampling algorithms
  (e.g. WExplore implemented in `wepy`), molecular clustering programs (e.g. `MSMBuilder`), graph analysis packages (e.g. `networkX`) and graph visualization programs (e.g. `Gephi`).

### What are conformation space networks?

A conformation space network is a visualization of a free energy landscape, where each node is a cluster of molecular conformations, and the edges show which conformations can directly interconvert during a molecular dynamics simulation. A CSN can be thought of as a visual representation of a transition matrix, where the nodes represent the row / column indices and the edges show the off-diagonal elements. `CSNAnalysis` offers a concise set of tools for the creation, analysis and visualization of CSNs.

**This tutorial will give quick examples for the following use cases:**

1. Initializing CSN objects from count matrices
2. Trimming CSNs
2. Obtaining steady-state weights from a transition matrix
  * By eigenvalue
  * By iterative multiplication
3. Computing committor probabilities to an arbitrary set of basins
4. Exporting gexf files for visualization with the Gephi program

## Getting started

Clone the CSNAnalysis repository:

```
git clone https://github.com/ADicksonLab/CSNAnalysis.git```

Navigate to the examples directory and install using pip:

```
cd CSNAnalysis
pip install --user -e
```

Go to the examples directory and open this notebook (`examples.ipynb`):

```
cd examples; jupyter notebook```

## Dependencies

I highly recommend using Anaconda and working in a `python3` environment. CSNAnalysis uses the packages `numpy`, `scipy` and `networkx`.  If these are installed then the following lines of code should run without error:

```python
import numpy as np
import networkx as nx
import scipy
```

If `CSNAnalysis` was installed (i.e. added to your `sys.path`), then this should also work:

```python
from csnanalysis.csn import CSN
from csnanalysis.matrix import *
```

This notebook also uses `matplotlib`, to visualize output.

```python
import matplotlib
```

Great!  Now let's load in the count matrix that we'll use for all the examples here:

```python
count_mat = scipy.sparse.load_npz('matrix.npz')
```

## Background: Sparse matrices

It's worth knowing a little about sparse matrices before we start. If we have a huge $N$ by $N$ matrix, where $N > 1000$, but most of the elements are zero, it is more efficient to store the data as a sparse matrix.

```python
type(count_mat)
```

    scipy.sparse.coo.coo_matrix

`coo_matrix` refers to "coordinate format", where the matrix is essentially a set of lists of matrix "coordinates" (rows, columns) and data:

```python
rows = count_mat.row
cols = count_mat.col
data = count_mat.data

for r,c,d in zip(rows[0:10],cols[0:10],data[0:10]):
    print(r,c,d)
```

    0 0 382.0
    0 651 2.0
    0 909 2.0
    0 920 2.0
    0 1363 1.0
    0 1445 2.0
    0 2021 5.0
    0 2022 7.0
    0 2085 4.0
    0 2131 1.0

Although it can be treated like a normal matrix ($4000$ by $4000$ in this case):

```python
count_mat.shape
```

    (4000, 4000)

It only needs to store non-zero elements, which are much fewer than $4000^2$:

```python
len(rows)
```

    44163

**OK, let's get started building a Conformation Space Network!**

---

## 1) Initializing CSN objects from count matrices

To get started we need a count matrix, which can be a `numpy` array, or a `scipy.sparse` matrix, or a list of lists:

```python
our_csn = CSN(count_mat,symmetrize=True)
```

Any of the `CSNAnalysis` functions can be queried using "?"

```python
CSN?
```

The `our_csn` object now holds three different representations of our data.  The original counts can now be found in `scipy.sparse` format:

```python
our_csn.countmat
```

    <4000x4000 sparse matrix of type '<class 'numpy.float64'>'
    	with 62280 stored elements in COOrdinate format>

A transition matrix has been computed from this count matrix according to:
\begin{equation}
t_{ij} = \frac{c_{ij}}{\sum_j c_{ij}}
\end{equation}

```python
our_csn.transmat
```

    <4000x4000 sparse matrix of type '<class 'numpy.float64'>'
    	with 62280 stored elements in COOrdinate format>

where the elements in each column sum to one:

```python
our_csn.transmat.sum(axis=0)
```

    matrix([[1., 1., 1., ..., 1., 1., 1.]])

Lastly, the data has been stored in a `networkx` directed graph:

```python
our_csn.graph
```

    <networkx.classes.digraph.DiGraph at 0x81f64e050>

that holds the nodes and edges of our csn, and we can use in other `networkx` functions.  For example, we can calculate the shortest path between nodes 0 and 10:

```python
nx.shortest_path(our_csn.graph,0,10)
```

    [0, 1445, 2125, 2043, 247, 1780, 10]

---
## 2) Trimming CSNs

A big benefit of coupling the count matrix, transition matrix and graph representations is that elements can be "trimmed" from all three simultaneously.  The `trim` function will eliminate nodes that are not connected to the main component (by inflow, outflow, or both), and can also eliminate nodes that do not meet a minimum count requirement:

```python
our_csn.trim(by_inflow=True, by_outflow=True, min_count=20)
```

The trimmed graph, count matrix and transition matrix are stored as `our_csn.trim_graph`, `our_csn.trim_countmat` and `our_csn.trim_transmat`, respectively.

```python
our_csn.trim_graph.number_of_nodes()
```

    2282

```python
our_csn.trim_countmat.shape
```

    (2282, 2282)

```python
our_csn.trim_transmat.shape
```

    (2282, 2282)

## 3) Obtaining steady-state weights from the transition matrix

Now that we've ensured that our transition matrix is fully-connected, we can compute its equilibrium weights.  This is implemented in two ways.

First, we can compute the eigenvector of the transition matrix with eigenvalue one:

```python
wt_eig = our_csn.calc_eig_weights()
```

This can exhibit some instability, especially for low-weight states, so we can also calculate weights by iterative multiplication of the transition matrix, which can take a little longer:

```python
wt_mult = our_csn.calc_mult_weights()
```

```python
import matplotlib.pyplot as plt
%matplotlib inline

plt.scatter(wt_eig,wt_mult)
plt.plot([0,wt_mult.max()],[0,wt_mult.max()],'r-')
plt.xlabel("Eigenvalue weight")
plt.ylabel("Mult weight")
plt.show()
```

These weights are automatically added as attributes to the nodes in `our_csn.graph`:

```python
our_csn.graph.node[0]
```

    {'label': 0,
     'count': 482,
     'trim': 0.0,
     'eig_weights': 0.002595528367725156,
     'mult_weights': 0.0025955283677248217}

## 4) Committor probabilities to an arbitrary set of basins

We are often doing simulations in the presence of one or more high probability "basins" of attraction.  When there more than one basin, it can be useful to find the probability that a simulation started in a given state will visit (or "commit to") a given basin before the others.

`CSNAnalysis` calculates committor probabilities by creating a sink matrix ($S$), where each column in the transition matrix that corresponds to a sink state is replaced by an identity vector. This turns each state into a "black hole" where probability can get in, but not out.

By iteratively multiplying this matrix by itself, we can approximate $S^\infty$.  The elements of this matrix reveal the probability of transitioning to any of the sink states, upon starting in any non-sink state, $i$.

Let's see this in action.  We'll start by reading in a set of three basins:  $A$, $B$ and $U$.

```python
Astates = [2031,596,1923,3223,2715]
Bstates = [1550,3168,476,1616,2590]
Ustates = list(np.loadtxt('state_U.dat',dtype=int))
```

We can then use the `calc_committors` function to calculate committors between this set of three basins. This will calculate $p_A$, $p_B$, and $p_U$ for each state, which sum to one.

```python
basins = [Astates,Bstates,Ustates]
labels = ['pA','pB','pU']
comms = our_csn.calc_committors(basins,labels=labels)
```

The committors can be interpreted as follows:

```python
i = our_csn.trim_indices[0]
print('comms['+str(i)+'] = ',comms[i])
print('\nIn other words, if you start in state {0:d}:'.format(i))
print('You will reach basin A first with probability {0:.2f}, basin B with probability {1:.2f} and basin U with probability {2:.2f}'.format(comms[i,0],comms[i,1],comms[i,2]))
```

    comms[0] =  [0.26406217 0.29477873 0.44115911]

    In other words, if you start in state 0:
    You will reach basin A first with probability 0.26, basin B with probability 0.29 and basin U with probability 0.44

## 5) Exporting graph for visualization in Gephi

`NetworkX` is great for doing graph-based analyses, but not stellar at greating graph layouts for large(r) networks. However, they do have excellent built-in support for exporting graph objects in a variety of formats.

Here we'll use the `.gexf` format to save our network, as well as all of the attributes we've calculated, to a file that can be read into [Gephi](https://gephi.org/), a powerful graph visualization program.  While support for Gephi has been spotty in the recent past, it is still one of the best available options for graph visualization.

Before exporting to `.gexf`, let's use the committors we've calculated to add colors to the nodes:

```python
rgb = our_csn.colors_from_committors(comms)
our_csn.set_colors(rgb)
```

Now we have added some properties to our nodes under 'viz', which will be interpreted by Gephi:

```python
our_csn.graph.node[0]
```

    {'label': 0,
     'count': 482,
     'trim': 0.0,
     'eig_weights': 0.002595528367725156,
     'mult_weights': 0.0025955283677248217,
     'pA': 0.26406216543613925,
     'pB': 0.2947787254045238,
     'pU': 0.4411591091593356,
     'viz': {'color': {'r': 152, 'g': 170, 'b': 255, 'a': 0}}}

And we can use an internal `networkx` function to write all of this to a `.gexf` file:

```python
nx.readwrite.gexf.write_gexf(our_csn.graph.to_undirected(),'test.gexf')
```

After opening this file in Gephi, I recommend creating a layout using the "Force Atlas 2" algorithm in the layout panel.  I set the node sizes to the "eig_weights" variable, and after exporting to pdf and adding some labels, I get the following:

**That's the end of our tutorial!**  I hope you enjoyed it and you find `CSNAnalysis` useful in your research.  If you are having difficulties with the installation or running of the software, feel free to create an [issue on the Github page](https://github.com/ADicksonLab/CSNAnalysis).

```python

```


### License (MIT)
Copyright (c) 2016 Kirill Moskovtsev

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

# Model for Si with deformation potential $\Xi_u$ shear strain effects ($\Xi_{sh}$)
Run the 'Definitions' cell first, then run the cells for Si or Ge.
## Definitions:

```python
'''Python 2.7'''
from sympy import *
import numpy as np
from itertools import combinations_with_replacement, permutations
from IPython.display import Math, display

def avg_wm(Xis, structure, eta_structure):
    res = sum_wetas_etam(Xis, structure, eta_structure)
    T_power = 0
    for i in structure:
        T_power = T_power + i
    return res/M**len(structure)/T**T_power

def sum_wetas_etam(Xis, structure, eta_structure):
    '''
    This is the most important function in the code.
    See explanation in a cell below.
    The version includes shear strain term, used when including mass effects.
    '''
    prod = 1
    M = len(Xis)
    for ns, ne in zip(structure, eta_structure):
        sumi = 0
        for i in range(M):
            #sumi = sumi + (einsum('ij,ij', Xis[i], eta_t) + Ds*eta_minus[i]**2)**ns*eta_minus[i]**ne
            sumi = sumi + (einsum('ij,ij', Xis[i], eta_t) + Ds*eta_minus[i]**2 + Ds4*eta_minus[i]**4)**ns*eta_minus[i]**ne
        prod = prod*sumi
    return expand(prod)

def einsum(string, *args):
    '''
    Analog of np.einsum which works for 'object' data,
    not only numbers
    Posted by Krastanov at http://stackoverflow.com/questions/15606937/how-do-i-get-numpy-einsum-to-play-well-with-sympy
    '''
    index_groups = map(list, string.split(','))
    assert len(index_groups) == len(args)
    tensor_indices_tuples = zip(index_groups, args)
    return reduce(einsum_for_two, tensor_indices_tuples)[1]

def einsum_for_two(tensor_indices1, tensor_indices2):
    '''
    component of einsum
    '''
    string1, tensor1 = tensor_indices1
    string2, tensor2 = tensor_indices2
    sum_over_indices = set(string1).intersection(set(string2))
    new_string = string1 + string2
    axes = ([], [])
    for i in sum_over_indices:
        new_string.remove(i)
        new_string.remove(i)
        axes[0].append(string1.index(i))
        axes[1].append(string2.index(i))
    return new_string, np.tensordot(tensor1, tensor2, axes)

def show_math(x, s = '', prnt = False):
    display(Math(s + latex(x)))
    if prnt:
        print s + latex(x)

def R(i,j):
    return Rational(i,j)

sd, su, N, T, F0, F1, F2, F3, F4, F32, J, Ds, Ds4= symbols("\\Xi_d \\Xi_u N T F_{1/2} {F_{1/2}}' {F_{1/2}}'' {F_{1/2}}'''" + \
                                                  " {F_{1/2}}'''' F_{3/2} J \\Xi_{s2} \\Xi_{s4}")
eta1, eta2, eta3, eta4, eta5, eta6, theta0, x, K = symbols("\\eta_1 \\eta_2 \\eta_3 \\eta_4 \\eta_5 \\eta_6 \\theta_0 x K")
eta_t = [[eta1, Rational(1,2)*eta6, Rational(1,2)*eta5],[Rational(1,2)*eta6, eta2, Rational(1,2)*eta4],\
         [Rational(1,2)*eta5, Rational(1,2)*eta4, eta3]]
eta_minus = [Rational(1,2)*eta4, Rational(1,2)*eta4, Rational(1,2)*eta5, \
             Rational(1,2)*eta5, Rational(1,2)*eta6, Rational(1,2)*eta6]
M = 6
unit = [[1,0,0], [0,1,0], [0,0,1]]
unitm = Matrix(unit)

Xis = []
for i in range(3):
    for j in [-1, 1]:
        a = np.reshape(np.array([0,0,0]), (1,3))
        a[0,i] = j
        at = np.reshape(a, (3,1))
        Xis.append(sd*unitm + su*np.dot(at, a))

```

**'sum_wetas_etam**(Xis, structure, eta_structure)':

Calculates the following expression:

$$
\left(\sum_\alpha \left(\delta E^{(\alpha)}\right)^{\text{structure[0]}}\eta_\alpha^{eta\_structure[0]}\right)...\left(\sum_\alpha \left(\delta E^{(\alpha)}\right)^{\text{structure[r]}}\eta_\alpha^{eta\_structure[r]}\right)
$$
where $\delta E^{(\alpha)}$ is the shift of valley $\alpha$, $\eta_\alpha$ defined as $\varepsilon_\alpha$ in the appendix of the paper, but $\eta_\alpha$ is written in Voigt notation.

If we ignore *'eta_structure'*, then $\Delta_\varepsilon$ structures from the paper are written as follows, for example:
$$
    \overline{\Delta_\varepsilon^k}\overline{\Delta_\varepsilon^n} = T^{-(k+n)}M^{-2}\left(\text{sum_wetas_etam}(Xis, (k,n), (0,0))\right)
$$

## Calculate expressions for $\delta c_{ij...}$ for doped Si:
$\Xi_{s2} \equiv \Xi_{sh}$;

$\Xi_{s4}$ is the hypothetical deformation potential for a quartic in strain shift of valleys, and it is assumed small.

```python
#Free energy terms expressed through strain
Free1 = N*T*avg_wm(Xis, (1,), (0,))
Free2 = -N*T/F0*(Rational(1,2)*F1*(avg_wm(Xis, (2,), (0,)) - avg_wm(Xis, (1,1), (0,0)) ))

Free3 = N*T/F0*(Rational(1,6)*F2*(avg_wm(Xis, (3,),(0,)) - 3*avg_wm(Xis, (2,1),(0,0)) + \
                                  2*avg_wm(Xis, (1,1,1),(0,0,0))) )

Free4_1 = Rational(1,24)*N*T*F3/F0*(-6*avg_wm(Xis, (2,1,1), (0,0,0)) + 4*avg_wm(Xis, (3,1),(0,0)) - avg_wm(Xis, (4,),(0,)) +\
                                    3*avg_wm(Xis, (1,1,1,1),(0,0,0,0)))
Free4_2 = Rational(1,8)*N*T*F2**2/F0/F1*(avg_wm(Xis, (2,2),(0,0)) - 2*avg_wm(Xis, (2,1,1),(0,0,0)) + \
                                         avg_wm(Xis, (1,1,1,1), (0,0,0,0)) )

Free4 = expand(Free4_1 + Free4_2)

Free_all = expand(Free1 + Free2 + Free3 + Free4)
subs_dict = {eta1: eta1*x, eta2: eta2*x, eta3: eta3*x, eta4: eta4*x, eta5: eta5*x, eta6: eta6*x}
Free_all_x = Free_all.subs(subs_dict)
Free_xdict = collect(Free_all_x, x, evaluate=False)
Free2 = Free_xdict[x**2]
Free3 = Free_xdict[x**3]
Free4 = Free_xdict[x**4]

#Differentiate to find elastic constants:

dc11 = simplify(diff(Free2, eta1, eta1))
dc12 = simplify(diff(Free2, eta1, eta2))
dc44 = simplify(diff(Free2, eta4, eta4))
print "Second order:"
show_math(dc11, '\\delta c_{11} = ')
show_math(dc12, '\\delta c_{12} = ')
show_math(dc44, '\\delta c_{44} = ')

dc111 = diff(Free3, eta1, eta1, eta1)
dc112 = diff(Free3, eta1, eta1, eta2)
dc123 = diff(Free3, eta1, eta2, eta3)
dc144 = diff(Free3, eta1, eta4, eta4)
dc155 = diff(Free3, eta1, eta5, eta5)
dc456 = diff(Free3, eta4, eta5, eta6)

print "Third order:"
show_math(dc111, '\\delta c_{111} = ')
show_math(dc112, '\\delta c_{112} = ')
show_math(dc123, '\\delta c_{123} = ')
show_math(dc144, '\\delta c_{144} = ')
show_math(dc155, '\\delta c_{155} = ')
show_math(dc456, '\\delta c_{456} = ', prnt = False)

dc1111 = expand(diff(Free4, eta1, eta1, eta1, eta1))
dc1112 = expand(diff(Free4, eta1, eta1, eta1, eta2))
dc1122 = expand(diff(Free4, eta1, eta1, eta2, eta2))
dc1123 = expand(diff(Free4, eta1, eta1, eta2, eta3))
dc1144 = expand(diff(Free4, eta1, eta1, eta4, eta4))
dc1155 = expand(diff(Free4, eta1, eta1, eta5, eta5))
dc1244 = expand(diff(Free4, eta1, eta2, eta4, eta4))
dc1266 = expand(diff(Free4, eta1, eta2, eta6, eta6))
dc1456 = expand(diff(Free4, eta1, eta4, eta5, eta6))
dc4444 = expand(diff(Free4, eta4, eta4, eta4, eta4))
dc4455 = expand(diff(Free4, eta4, eta4, eta5, eta5))
print "Fourth order:"
show_math(dc1111, '\\delta c_{1111} = ')
show_math(dc1112, '\\delta c_{1112} = ')
show_math(dc1122, '\\delta c_{1122} = ')
show_math(dc1123, '\\delta c_{1123} = ')
show_math(dc1144, '\\delta c_{1144} = ')
show_math(dc1155, '\\delta c_{1155} = ')
show_math(dc1244, '\\delta c_{1244} = ')
show_math(dc1266, '\\delta c_{1266} = ')
show_math(dc1456, '\\delta c_{1456} = ')
show_math(dc4444, '\\delta c_{4444} = ', prnt = False)
show_math(dc4455, '\\delta c_{4455} = ', prnt = False)
```

    Second order:

$$\delta c_{11} = - \frac{2 N \Xi_u^{2} {F_{1/2}}'}{9 F_{1/2} T}$$

$$\delta c_{12} = \frac{N \Xi_u^{2} {F_{1/2}}'}{9 F_{1/2} T}$$

$$\delta c_{44} = \frac{N \Xi_{s2}}{6}$$

    Third order:

$$\delta c_{111} = \frac{2 N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

$$\delta c_{112} = - \frac{N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

$$\delta c_{123} = \frac{2 N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

$$\delta c_{144} = - \frac{N \Xi_u \Xi_{s2} {F_{1/2}}'}{9 F_{1/2} T}$$

$$\delta c_{155} = \frac{N \Xi_u \Xi_{s2} {F_{1/2}}'}{18 F_{1/2} T}$$

$$\delta c_{456} = 0$$

    Fourth order:

$$\delta c_{1111} = - \frac{2 N \Xi_u^{4} {F_{1/2}}'''}{27 F_{1/2} T^{3}} + \frac{4 N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}$$

$$\delta c_{1112} = \frac{N \Xi_u^{4} {F_{1/2}}'''}{27 F_{1/2} T^{3}} - \frac{2 N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}$$

$$\delta c_{1122} = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{27 F_{1/2} T^{3}} + \frac{2 N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}$$

$$\delta c_{1123} = 0$$

$$\delta c_{1144} = \frac{N \Xi_u^{2} \Xi_{s2} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

$$\delta c_{1155} = - \frac{N \Xi_u^{2} \Xi_{s2} {F_{1/2}}''}{54 F_{1/2} T^{2}}$$

$$\delta c_{1244} = - \frac{N \Xi_u^{2} \Xi_{s2} {F_{1/2}}''}{54 F_{1/2} T^{2}}$$

$$\delta c_{1266} = \frac{N \Xi_u^{2} \Xi_{s2} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

$$\delta c_{1456} = 0$$

$$\delta c_{4444} = \frac{N \Xi_{s4}}{2} - \frac{N \Xi_{s2}^{2} {F_{1/2}}'}{6 F_{1/2} T}$$

$$\delta c_{4455} = \frac{N \Xi_{s2}^{2} {F_{1/2}}'}{36 F_{1/2} T}$$

## Save single-crystal $c$-expressions
to reuse them in the 'mode_calculation.ipynb'

```python
import pickle
c11, c12, c44, c111, c112, c123, c144, c155, c456 = \
symbols('c11 c12 c44 c111 c112 c123 c144 c155 c456')
c1111, c1112, c1122, c1123, c1144, c1155, c1244, c1266, c1456, c4444, c4455 = \
symbols('c1111 c1112 c1122 c1123 c1144 c1155 c1244 c1266 c1456 c4444 c4455')

c = {c11:dc11, c12:dc12, c44:dc44, c111:dc111, c112:dc112, c123:dc123, c144:dc144, \
            c155:dc155, c456:dc456, c1111:dc1111, c1112:dc1112, c1122:dc1122, c1123:dc1123, \
             c1144:dc1144,\
            c1155:dc1155, c1244:dc1244, c1266:dc1266, c1456:dc1456, c4444:dc4444, c4455:dc4455}
fname = './single_expressions/c_values_single.dat'
if not os.path.exists(os.path.dirname(fname)):
        os.makedirs(os.path.dirname(fname))
        print './single_expressions/ created'
ff = open(fname, 'w')
pickle.dump(c, ff)
ff.close()
```

# Germanium

```python
def sum_wetas_etam(Xis, structure, eta_structure):
    prod = 1
    M = len(Xis)
    for ns, ne in zip(structure, eta_structure):
        sumi = 0
        for i in range(M):
            #sumi = sumi + (einsum('ij,ij', Xis[i], eta_t) + Ds*eta_minus[i]**2)**ns*eta_minus[i]**ne
            sumi = sumi + (einsum('ij,ij', Xis[i], eta_t))**ns
        prod = prod*sumi
    return expand(prod)

M = 4
unit_vectors = np.array([[1,1,1], [-1,1,1], [1,-1, 1], [-1, -1, 1]])/sqrt(3)
unitm = np.array([[1,0,0], [0,1,0], [0,0,1]])
#unitm = Matrix(unit)

Xis = []
for a in unit_vectors:
    #for j in [-1/sqrt(3), 1/sqrt(3)]:
    a = np.reshape(a, (1,3))
    #a[0,2] = j
    at = np.reshape(a, (3,1))
    Xis.append(sd*unitm + su*np.dot(at, a))

Free1 = N*T*avg_wm(Xis, (1,), (0,))
Free2 = -N*T/F0*(Rational(1,2)*F1*(avg_wm(Xis, (2,), (0,)) - avg_wm(Xis, (1,1), (0,0)) ))
#Free2 = simplify(Free2)

Free3 = N*T/F0*(Rational(1,6)*F2*(avg_wm(Xis, (3,),(0,)) - 3*avg_wm(Xis, (2,1),(0,0)) + \
                                  2*avg_wm(Xis, (1,1,1),(0,0,0))) )

Free4_1 = Rational(1,24)*N*T*F3/F0*(-6*avg_wm(Xis, (2,1,1), (0,0,0)) + 4*avg_wm(Xis, (3,1),(0,0)) - avg_wm(Xis, (4,),(0,)) +\
                                    3*avg_wm(Xis, (1,1,1,1),(0,0,0,0)))
Free4_2 = Rational(1,8)*N*T*F2**2/F0/F1*(avg_wm(Xis, (2,2),(0,0)) - 2*avg_wm(Xis, (2,1,1),(0,0,0)) + \
                                         avg_wm(Xis, (1,1,1,1), (0,0,0,0)) )

Free4 = expand(Free4_1 + Free4_2)

Free_all = expand(Free1 + Free2 + Free3 + Free4).subs({Ds: 0, Ds4: 0}) #no \Xi_sh for Ge
subs_dict = {eta1: eta1*x, eta2: eta2*x, eta3: eta3*x, eta4: eta4*x, eta5: eta5*x, eta6: eta6*x}
Free_all_x = Free_all.subs(subs_dict)
Free_xdict = collect(Free_all_x, x, evaluate=False)
Free2 = Free_xdict[x**2]
Free3 = Free_xdict[x**3]
Free4 = Free_xdict[x**4]

dc11 = simplify(diff(Free2, eta1, eta1))
dc12 = simplify(diff(Free2, eta1, eta2))
dc44 = simplify(diff(Free2, eta4, eta4))
print "Second order:"
show_math(dc11, '\\delta c_{11} = ')
show_math(dc12, '\\delta c_{12} = ')
show_math(dc44, '\\delta c_{44} = ')

dc111 = diff(Free3, eta1, eta1, eta1)
dc112 = diff(Free3, eta1, eta1, eta2)
dc123 = diff(Free3, eta1, eta2, eta3)
dc144 = diff(Free3, eta1, eta4, eta4)
dc155 = diff(Free3, eta1, eta5, eta5)
dc456 = diff(Free3, eta4, eta5, eta6)

print "Third order:"
show_math(dc111, '\\delta c_{111} = ')
show_math(dc112, '\\delta c_{112} = ')
show_math(dc123, '\\delta c_{123} = ')
show_math(dc144, '\\delta c_{144} = ')
show_math(dc155, '\\delta c_{155} = ')
show_math(dc456, '\\delta c_{456} = ', prnt = True)

dc1111 = expand(diff(Free4, eta1, eta1, eta1, eta1))
dc1112 = expand(diff(Free4, eta1, eta1, eta1, eta2))
dc1122 = expand(diff(Free4, eta1, eta1, eta2, eta2))
dc1123 = expand(diff(Free4, eta1, eta1, eta2, eta3))
dc1144 = expand(diff(Free4, eta1, eta1, eta4, eta4))
dc1155 = expand(diff(Free4, eta1, eta1, eta5, eta5))
dc1244 = expand(diff(Free4, eta1, eta2, eta4, eta4))
dc1266 = expand(diff(Free4, eta1, eta2, eta6, eta6))
dc1456 = expand(diff(Free4, eta1, eta4, eta5, eta6))
dc4444 = expand(diff(Free4, eta4, eta4, eta4, eta4))
dc4455 = expand(diff(Free4, eta4, eta4, eta5, eta5))
print "Fourth order:"
show_math(dc1111, '\\delta c_{1111} = ')
show_math(dc1112, '\\delta c_{1112} = ')
show_math(dc1122, '\\delta c_{1122} = ')
show_math(dc1123, '\\delta c_{1123} = ')
show_math(dc1144, '\\delta c_{1144} = ')
show_math(dc1155, '\\delta c_{1155} = ')
show_math(dc1244, '\\delta c_{1244} = ')
show_math(dc1266, '\\delta c_{1266} = ')
show_math(dc1456, '\\delta c_{1456} = ')
show_math(dc4444, '\\delta c_{4444} = ', prnt = True)
show_math(dc4455, '\\delta c_{4455} = ', prnt = True)
```

    Second order:

$$\delta c_{11} = 0$$

$$\delta c_{12} = 0$$

$$\delta c_{44} = - \frac{N \Xi_u^{2} {F_{1/2}}'}{9 F_{1/2} T}$$

    Third order:

$$\delta c_{111} = 0$$

$$\delta c_{112} = 0$$

$$\delta c_{123} = 0$$

$$\delta c_{144} = 0$$

$$\delta c_{155} = 0$$

$$\delta c_{456} = \frac{N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}$$

    \delta c_{456} = \frac{N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}
    Fourth order:

$$\delta c_{1111} = 0$$

$$\delta c_{1112} = 0$$

$$\delta c_{1122} = 0$$

$$\delta c_{1123} = 0$$

$$\delta c_{1144} = 0$$

$$\delta c_{1155} = 0$$

$$\delta c_{1244} = 0$$

$$\delta c_{1266} = 0$$

$$\delta c_{1456} = 0$$

$$\delta c_{4444} = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}$$

    \delta c_{4444} = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}

$$\delta c_{4455} = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{81 F_{1/2} T^{3} {F_{1/2}}'}$$

    \delta c_{4455} = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{81 F_{1/2} T^{3} {F_{1/2}}'}

```python

```

```python
print '\delta c_{{11}} &= {}'.format(latex(dc11)) + '\\\\'
print '\delta c_{{12}} & = {}'.format(latex(dc12)) + '\\\\'
print '\delta c_{{44}} & = {}'.format(latex(dc44)) + '\\\\'
print '\delta c_{{111}} & = {}'.format(latex(dc111)) + '\\\\'
print '\delta c_{{112}} & = {}'.format(latex(dc112)) + '\\\\'
print '\delta c_{{123}} & = {}'.format(latex(dc123)) + '\\\\'
print '\delta c_{{144}} & = {}'.format(latex(dc144)) + '\\\\'
print '\delta c_{{155}} & = {}'.format(latex(dc155)) + '\\\\'
print '\delta c_{{456}} & = {}'.format(latex(dc456)) + '\\\\'
print '\delta c_{{1111}} & = {}'.format(latex(dc1111)) + '\\\\'
print '\delta c_{{1112}} & = {}'.format(latex(dc1112)) + '\\\\'
print '\delta c_{{1122}} & = {}'.format(latex(dc1122)) + '\\\\'
print '\delta c_{{1123}} & = {}'.format(latex(dc1123)) + '\\\\'
print '\delta c_{{1144}} & = {}'.format(latex(dc1144)) + '\\\\'
print '\delta c_{{1155}} & = {}'.format(latex(dc1155)) + '\\\\'
print '\delta c_{{1244}} & = {}'.format(latex(dc1244)) + '\\\\'
print '\delta c_{{1266}} & = {}'.format(latex(dc1266)) + '\\\\'
print '\delta c_{{1456}} & = {}'.format(latex(dc1456)) + '\\\\'
print '\delta c_{{4444}} & = {}'.format(latex(dc4444)) + '\\\\'
print '\delta c_{{4455}} & = {}'.format(latex(dc4455))
```

    \delta c_{11} &= 0\\
    \delta c_{12} & = 0\\
    \delta c_{44} & = - \frac{N \Xi_u^{2} {F_{1/2}}'}{9 F_{1/2} T}\\
    \delta c_{111} & = 0\\
    \delta c_{112} & = 0\\
    \delta c_{123} & = 0\\
    \delta c_{144} & = 0\\
    \delta c_{155} & = 0\\
    \delta c_{456} & = \frac{N \Xi_u^{3} {F_{1/2}}''}{27 F_{1/2} T^{2}}\\
    \delta c_{1111} & = 0\\
    \delta c_{1112} & = 0\\
    \delta c_{1122} & = 0\\
    \delta c_{1123} & = 0\\
    \delta c_{1144} & = 0\\
    \delta c_{1155} & = 0\\
    \delta c_{1244} & = 0\\
    \delta c_{1266} & = 0\\
    \delta c_{1456} & = 0\\
    \delta c_{4444} & = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{27 F_{1/2} T^{3} {F_{1/2}}'}\\
    \delta c_{4455} & = - \frac{N \Xi_u^{4} {F_{1/2}}'''}{81 F_{1/2} T^{3}} + \frac{N \Xi_u^{4} {F_{1/2}}''^{2}}{81 F_{1/2} T^{3} {F_{1/2}}'}