```
%load_ext autoreload
```

```
autoreload 2
```

```
%matplotlib inline
```

```
import matplotlib.pyplot as plt
import numpy as np
import sympy as sym

import inputs
import models
import shooting
```

# Example:

## Worker skill and firm productivity are $\sim U[a, b]$...

```
# define some workers skill
x, a, b = sym.var('x, a, b')
skill_cdf = (x - a) / (b - a)
skill_params = {'a': 1.0, 'b': 2.0}
skill_bounds = [skill_params['a'], skill_params['b']]

workers = inputs.Input(var=x,
                       cdf=skill_cdf,
                       params=skill_params,
                       bounds=skill_bounds,
                       )

# define some firms
y = sym.var('y')
productivity_cdf = (y - a) / (b - a)
productivity_params = skill_params
productivity_bounds = skill_bounds

firms = inputs.Input(var=y,
                     cdf=productivity_cdf,
                     params=productivity_params,
                     bounds=productivity_bounds,
                     )
```

## ...and production function is multiplicatively separable.
A particularly attractive case arises under multiplicative separability of the form

$$F(x, y, l, r) = A(x, y)B(l, r)$$

In this case the condition for positive assortative matching can be written as

$$\frac{AA_{xy}}{A_xA_y}\frac{BB_{lr}}{B_lB_r} \ge 1$$

If $B$ has constant elasticity of substitution form, then we obtain an even simpler condition

$$\frac{AA_{xy}}{A_xA_y} \frac{1}{\sigma_{lr}}\ge 1$$

where $\sigma_{lr}$ is the elasticity of substitution between $l$ and $r$.

Finally, if $A$ also has constant elasticity of substitution form, then we obtain an even simpler condition

$$\frac{1}{\sigma_{xy}\sigma_{lr}}\ge 1 \iff \sigma_{xy}\sigma_{lr} \le 1$$

where $\sigma_{xy}$ is the elasticity of substitution between $x$ and $y$.

```
# define symbolic expression for CES between x and y
omega_A, sigma_A = sym.var('omega_A, sigma_A')
A = ((omega_A * x**((sigma_A - 1) / sigma_A) +
     (1 - omega_A) * y**((sigma_A - 1) / sigma_A))**(sigma_A / (sigma_A - 1)))

# define symbolic expression for Cobb-Douglas between l and r
l, r, omega_B, sigma_B = sym.var('l, r, omega_B, sigma_B')
B = l**omega_B * r**(1 - omega_B)

F = A * B
```

Create an instance of the `models.Model` class and an instance of the `solvers.ShootingSolver` class...

### Positive assortative matching

```
F_params = {'omega_A':0.25, 'omega_B':0.75, 'sigma_A':0.95, 'sigma_B':1.0}

model = models.Model(assortativity='positive',
                     workers=workers,
                     firms=firms,
                     production=F,
                     params=F_params)

solver = shooting.ShootingSolver(model=model)
```

```
solver.solve(1e1, tol=1e-6, number_knots=100, atol=1e-15, rtol=1e-12)
```

    Success! All workers and firms are matched

```
# examine the solution attribute
solver.solution
```

      $\mu(x)$
      $\theta(x)$
      $w(x)$
      $\pi(x)$

      x

      1.000000
       1.000000
       0.304740
       1.009436
       0.102539

      1.010101
       1.031666
       0.333492
       1.012825
       0.112590

      1.020202
       1.060752
       0.361288
       1.016194
       0.122380

      1.030303
       1.087712
       0.388244
       1.019543
       0.131944

      1.040404
       1.112885
       0.414452
       1.022872
       0.141310

      1.050505
       1.136532
       0.439987
       1.026181
       0.150502

      1.060606
       1.158861
       0.464912
       1.029470
       0.159538

      1.070707
       1.180035
       0.489278
       1.032740
       0.168432

      1.080808
       1.200191
       0.513130
       1.035990
       0.177199

      1.090909
       1.219439
       0.536507
       1.039222
       0.185850

      1.101010
       1.237874
       0.559441
       1.042434
       0.194393

      1.111111
       1.255575
       0.581962
       1.045627
       0.202839

      1.121212
       1.272609
       0.604097
       1.048802
       0.211193

      1.131313
       1.289035
       0.625867
       1.051958
       0.219462

      1.141414
       1.304903
       0.647295
       1.055096
       0.227653

      1.151515
       1.320258
       0.668397
       1.058215
       0.235769

      1.161616
       1.335140
       0.689192
       1.061318
       0.243817

      1.171717
       1.349582
       0.709694
       1.064402
       0.251800

      1.181818
       1.363615
       0.729919
       1.067469
       0.259722

      1.191919
       1.377268
       0.749877
       1.070519
       0.267586

      1.202020
       1.390563
       0.769582
       1.073552
       0.275395

      1.212121
       1.403525
       0.789045
       1.076568
       0.283153

      1.222222
       1.416173
       0.808274
       1.079567
       0.290862

      1.232323
       1.428525
       0.827281
       1.082551
       0.298525

      1.242424
       1.440598
       0.846073
       1.085518
       0.306142

      1.252525
       1.452407
       0.864659
       1.088469
       0.313718

      1.262626
       1.463967
       0.883046
       1.091404
       0.321253

      1.272727
       1.475289
       0.901242
       1.094324
       0.328750

      1.282828
       1.486386
       0.919253
       1.097228
       0.336210

      1.292929
       1.497269
       0.937085
       1.100117
       0.343634

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

      1.707071
       1.831889
       1.562269
       1.207393
       0.628758

      1.717172
       1.838327
       1.575673
       1.209777
       0.635404

      1.727273
       1.844710
       1.589012
       1.212150
       0.642041

      1.737374
       1.851041
       1.602288
       1.214515
       0.648667

      1.747475
       1.857319
       1.615501
       1.216870
       0.655285

      1.757576
       1.863546
       1.628653
       1.219215
       0.661893

      1.767677
       1.869723
       1.641744
       1.221552
       0.668492

      1.777778
       1.875852
       1.654775
       1.223879
       0.675082

      1.787879
       1.881932
       1.667748
       1.226198
       0.681663

      1.797980
       1.887965
       1.680664
       1.228507
       0.688236

      1.808081
       1.893953
       1.693523
       1.230808
       0.694800

      1.818182
       1.899895
       1.706325
       1.233099
       0.701356

      1.828283
       1.905792
       1.719073
       1.235383
       0.707904

      1.838384
       1.911647
       1.731767
       1.237657
       0.714445

      1.848485
       1.917458
       1.744408
       1.239923
       0.720977

      1.858586
       1.923228
       1.756996
       1.242181
       0.727502

      1.868687
       1.928956
       1.769532
       1.244430
       0.734019

      1.878788
       1.934645
       1.782017
       1.246671
       0.740530

      1.888889
       1.940293
       1.794452
       1.248903
       0.747033

      1.898990
       1.945903
       1.806838
       1.251128
       0.753528

      1.909091
       1.951474
       1.819174
       1.253344
       0.760017

      1.919192
       1.957008
       1.831463
       1.255553
       0.766500

      1.929293
       1.962505
       1.843704
       1.257753
       0.772975

      1.939394
       1.967966
       1.855899
       1.259946
       0.779444

      1.949495
       1.973391
       1.868047
       1.262131
       0.785907

      1.959596
       1.978780
       1.880150
       1.264308
       0.792363

      1.969697
       1.984136
       1.892208
       1.266477
       0.798813

      1.979798
       1.989457
       1.904222
       1.268639
       0.805256

      1.989899
       1.994745
       1.916192
       1.270793
       0.811694

      2.000000
       2.000000
       1.928118
       1.272940
       0.818126

100 rows × 4 columns

```
solver.solution.plot()
```

```
solver.interpolated_solution
```

      $\hat{\mu}(x)$
      $\hat{\theta}(x)$
      $\hat{w}(x)$
      $\hat{\pi}(x)$

      x

      1.000000
       1.000000
       0.304740
       1.009436
       0.102539

      1.001001
       1.003269
       0.307636
       1.009773
       0.103547

      1.002002
       1.006507
       0.310521
       1.010109
       0.104553

      1.003003
       1.009716
       0.313396
       1.010445
       0.105557

      1.004004
       1.012896
       0.316260
       1.010782
       0.106557

      1.005005
       1.016046
       0.319115
       1.011118
       0.107554

      1.006006
       1.019169
       0.321959
       1.011453
       0.108549

      1.007007
       1.022265
       0.324793
       1.011789
       0.109541

      1.008008
       1.025334
       0.327618
       1.012124
       0.110530

      1.009009
       1.028376
       0.330432
       1.012459
       0.111516

      1.010010
       1.031393
       0.333238
       1.012794
       0.112500

      1.011011
       1.034384
       0.336034
       1.013129
       0.113482

      1.012012
       1.037351
       0.338820
       1.013464
       0.114461

      1.013013
       1.040293
       0.341598
       1.013798
       0.115437

      1.014014
       1.043212
       0.344366
       1.014132
       0.116411

      1.015015
       1.046107
       0.347126
       1.014466
       0.117383

      1.016016
       1.048979
       0.349877
       1.014800
       0.118352

      1.017017
       1.051829
       0.352619
       1.015134
       0.119319

      1.018018
       1.054657
       0.355353
       1.015467
       0.120283

      1.019019
       1.057463
       0.358078
       1.015800
       0.121245

      1.020020
       1.060248
       0.360795
       1.016133
       0.122205

      1.021021
       1.063012
       0.363504
       1.016466
       0.123163

      1.022022
       1.065755
       0.366204
       1.016799
       0.124119

      1.023023
       1.068479
       0.368896
       1.017131
       0.125072

      1.024024
       1.071182
       0.371581
       1.017463
       0.126023

      1.025025
       1.073867
       0.374257
       1.017795
       0.126972

      1.026026
       1.076532
       0.376926
       1.018127
       0.127920

      1.027027
       1.079178
       0.379587
       1.018459
       0.128865

      1.028028
       1.081806
       0.382241
       1.018790
       0.129808

      1.029029
       1.084416
       0.384887
       1.019121
       0.130749

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

      1.970971
       1.984809
       1.893726
       1.266750
       0.799626

      1.971972
       1.985337
       1.894918
       1.266965
       0.800264

      1.972973
       1.985865
       1.896109
       1.267179
       0.800903

      1.973974
       1.986393
       1.897300
       1.267393
       0.801542

      1.974975
       1.986920
       1.898491
       1.267608
       0.802180

      1.975976
       1.987448
       1.899681
       1.267822
       0.802819

      1.976977
       1.987974
       1.900871
       1.268036
       0.803457

      1.977978
       1.988501
       1.902060
       1.268250
       0.804096

      1.978979
       1.989027
       1.903249
       1.268464
       0.804734

      1.979980
       1.989553
       1.904438
       1.268678
       0.805372

      1.980981
       1.990078
       1.905626
       1.268891
       0.806011

      1.981982
       1.990603
       1.906813
       1.269105
       0.806649

      1.982983
       1.991128
       1.908001
       1.269319
       0.807287

      1.983984
       1.991652
       1.909187
       1.269532
       0.807925

      1.984985
       1.992177
       1.910374
       1.269746
       0.808563

      1.985986
       1.992700
       1.911560
       1.269959
       0.809201

      1.986987
       1.993224
       1.912745
       1.270173
       0.809839

      1.987988
       1.993747
       1.913930
       1.270386
       0.810477

      1.988989
       1.994270
       1.915115
       1.270599
       0.811115

      1.989990
       1.994792
       1.916299
       1.270812
       0.811752

      1.990991
       1.995315
       1.917483
       1.271025
       0.812390

      1.991992
       1.995837
       1.918666
       1.271238
       0.813027

      1.992993
       1.996358
       1.919849
       1.271451
       0.813665

      1.993994
       1.996879
       1.921032
       1.271664
       0.814303

      1.994995
       1.997400
       1.922214
       1.271877
       0.814940

      1.995996
       1.997921
       1.923396
       1.272090
       0.815577

      1.996997
       1.998441
       1.924577
       1.272302
       0.816215

      1.997998
       1.998961
       1.925758
       1.272515
       0.816852

      1.998999
       1.999481
       1.926938
       1.272727
       0.817489

      2.000000
       2.000000
       1.928118
       1.272940
       0.818126

1000 rows × 4 columns

```
solver.residuals
```

      $\hat{\mu}(x)$
      $\hat{\theta}(x)$

      x

      1.000000
       2.520123e-04
       1.316397e-04

      1.001001
       1.435552e-04
       7.647546e-05

      1.002002
       6.452786e-05
       3.617476e-05

      1.003003
       9.316151e-06
       7.891311e-06

      1.004004
       2.693030e-05
       1.082766e-05

      1.005005
       4.837258e-05
       2.208111e-05

      1.006006
       5.855111e-05
       2.765063e-05

      1.007007
       6.044888e-05
       2.903386e-05

      1.008008
       5.654987e-05
       2.747520e-05

      1.009009
       4.889295e-05
       2.399410e-05

      1.010010
       3.912173e-05
       1.941098e-05

      1.011011
       2.853066e-05
       1.437116e-05

      1.012012
       1.810759e-05
       9.366835e-06

      1.013013
       8.573277e-06
       4.757287e-06

      1.014014
       4.178820e-07
       7.875574e-07

      1.015015
       6.065166e-06
       2.394403e-06

      1.016016
       1.074780e-05
       4.721918e-06

      1.017017
       1.363824e-05
       6.195011e-06

      1.018018
       1.485396e-05
       6.866977e-06

      1.019019
       1.459671e-05
       6.831997e-06

      1.020020
       1.312919e-05
       6.213729e-06

      1.021021
       1.075350e-05
       5.154787e-06

      1.022022
       7.791087e-06
       3.807036e-06

      1.023023
       4.564062e-06
       2.322654e-06

      1.024024
       1.377904e-06
       8.458864e-07

      1.025025
       1.494656e-06
       4.945540e-07

      1.026026
       3.828620e-06
       1.592488e-06

      1.027027
       5.460649e-06
       2.370723e-06

      1.028028
       6.302029e-06
       2.787000e-06

      1.029029
       6.350722e-06
       2.839462e-06

      ...
      ...
      ...

      1.970971
       3.679751e-12
       2.511555e-12

      1.971972
       3.720433e-12
       2.538449e-12

      1.972973
       3.269734e-12
       2.228750e-12

      1.973974
       2.331231e-12
       1.583675e-12

      1.974975
       9.683969e-13
       6.479500e-13

      1.975976
       7.096119e-13
       5.036583e-13

      1.976977
       2.557009e-12
       1.771805e-12

      1.977978
       4.404153e-12
       3.039650e-12

      1.978979
       6.068133e-12
       4.182129e-12

      1.979980
       7.364331e-12
       5.072507e-12

      1.980981
       8.116416e-12
       5.589259e-12

      1.981982
       8.169100e-12
       5.627466e-12

      1.982983
       7.397647e-12
       5.100391e-12

      1.983984
       5.719148e-12
       3.951169e-12

      1.984985
       3.103389e-12
       2.159804e-12

      1.985986
       4.166330e-13
       2.518324e-13

      1.986987
       4.733764e-12
       3.210266e-12

      1.987988
       9.656769e-12
       6.585475e-12

      1.988989
       1.489891e-11
       1.018016e-11

      1.989990
       2.006863e-11
       1.372673e-11

      1.990991
       2.465809e-11
       1.687832e-11

      1.991992
       2.803393e-11
       1.920158e-11

      1.992993
       2.942631e-11
       2.016913e-11

      1.993994
       2.791943e-11
       1.915574e-11

      1.994995
       2.244085e-11
       1.542715e-11

      1.995996
       1.175177e-11
       8.136266e-12

      1.996997
       5.562501e-12
       3.683520e-12

      1.997998
       3.110312e-11
       2.112744e-11

      1.998999
       6.666716e-11
       4.542438e-11

      2.000000
       1.142570e-10
       7.794185e-11

1000 rows × 2 columns

Here are what the absolute residuals look like...

```
solver.residuals.plot(logy=True, alpha=0.5)
```

### Negative assortative matching

```
# negative assortativity requires that sigma_A * sigma_B > 1
F_params = {'omega_A':0.25, 'omega_B':0.75, 'sigma_A':1.5, 'sigma_B':1.0}
```

```
model = models.Model(assortativity='negative',
                     workers=workers,
                     firms=firms,
                     production=F,
                     params=F_params)

solver = shooting.ShootingSolver(model=model)
```

```
solver.solve(1e1, tol=1e-6, number_knots=100, atol=1e-15, rtol=1e-12)
```

    Success! All workers and firms are matched

```
solver.solution
```

      $\mu(x)$
      $\theta(x)$
      $w(x)$
      $\pi(x)$

      x

      1.000000
       2.000000
       2.421887
       1.025798
       0.828122

      1.010101
       1.995810
       2.399133
       1.028683
       0.822649

      1.020202
       1.991579
       2.376467
       1.031556
       0.817153

      1.030303
       1.987308
       2.353889
       1.034417
       0.811635

      1.040404
       1.982997
       2.331395
       1.037268
       0.806094

      1.050505
       1.978643
       2.308983
       1.040108
       0.800530

      1.060606
       1.974247
       2.286651
       1.042937
       0.794944

      1.070707
       1.969808
       2.264396
       1.045755
       0.789334

      1.080808
       1.965325
       2.242217
       1.048563
       0.783702

      1.090909
       1.960798
       2.220112
       1.051361
       0.778046

      1.101010
       1.956225
       2.198077
       1.054149
       0.772367

      1.111111
       1.951607
       2.176112
       1.056927
       0.766664

      1.121212
       1.946942
       2.154214
       1.059695
       0.760937

      1.131313
       1.942229
       2.132381
       1.062454
       0.755186

      1.141414
       1.937467
       2.110612
       1.065204
       0.749410

      1.151515
       1.932657
       2.088903
       1.067944
       0.743611

      1.161616
       1.927796
       2.067255
       1.070676
       0.737786

      1.171717
       1.922884
       2.045663
       1.073399
       0.731937

      1.181818
       1.917920
       2.024127
       1.076113
       0.726063

      1.191919
       1.912903
       2.002645
       1.078818
       0.720164

      1.202020
       1.907832
       1.981215
       1.081516
       0.714238

      1.212121
       1.902706
       1.959835
       1.084205
       0.708288

      1.222222
       1.897524
       1.938503
       1.086886
       0.702311

      1.232323
       1.892284
       1.917218
       1.089559
       0.696307

      1.242424
       1.886986
       1.895978
       1.092224
       0.690278

      1.252525
       1.881629
       1.874780
       1.094882
       0.684221

      1.262626
       1.876210
       1.853624
       1.097533
       0.678137

      1.272727
       1.870730
       1.832507
       1.100176
       0.672026

      1.282828
       1.865185
       1.811427
       1.102811
       0.665888

      1.292929
       1.859577
       1.790384
       1.105440
       0.659721

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

      1.707071
       1.545353
       0.935258
       1.208641
       0.376797

      1.717172
       1.534427
       0.913888
       1.211084
       0.368932

      1.727273
       1.523243
       0.892447
       1.213525
       0.361002

      1.737374
       1.511786
       0.870930
       1.215965
       0.353007

      1.747475
       1.500042
       0.849332
       1.218404
       0.344943

      1.757576
       1.487995
       0.827646
       1.220842
       0.336808

      1.767677
       1.475627
       0.805868
       1.223279
       0.328600

      1.777778
       1.462919
       0.783989
       1.225715
       0.320316

      1.787879
       1.449851
       0.762004
       1.228152
       0.311952

      1.797980
       1.436400
       0.739905
       1.230588
       0.303506

      1.808081
       1.422539
       0.717683
       1.233024
       0.294973

      1.818182
       1.408241
       0.695330
       1.235461
       0.286351

      1.828283
       1.393474
       0.672835
       1.237899
       0.277634

      1.838384
       1.378203
       0.650189
       1.240337
       0.268818

      1.848485
       1.362389
       0.627380
       1.242777
       0.259898

      1.858586
       1.345987
       0.604395
       1.245219
       0.250868

      1.868687
       1.328946
       0.581220
       1.247663
       0.241722

      1.878788
       1.311208
       0.557839
       1.250109
       0.232453

      1.888889
       1.292707
       0.534234
       1.252558
       0.223053

      1.898990
       1.273365
       0.510386
       1.255011
       0.213513

      1.909091
       1.253093
       0.486271
       1.257468
       0.203824

      1.919192
       1.231782
       0.461865
       1.259930
       0.193972

      1.929293
       1.209306
       0.437136
       1.262397
       0.183946

      1.939394
       1.185511
       0.412050
       1.264871
       0.173730

      1.949495
       1.160208
       0.386566
       1.267352
       0.163305

      1.959596
       1.133164
       0.360634
       1.269841
       0.152649

      1.969697
       1.104078
       0.334194
       1.272340
       0.141736

      1.979798
       1.072566
       0.307171
       1.274851
       0.130532

      1.989899
       1.038111
       0.279470
       1.277375
       0.118996

      2.000000
       1.000000
       0.250968
       1.279915
       0.107073

100 rows × 4 columns

Now we can do all the cool things that one can do with Pandas...

```
solver.solution.plot()
```

```
solver.residuals.plot(logy=True, alpha=0.5)
```

```

```

```

```

# Example:

Multiplicative separability with log-normal worker skill and firm productivity distributions...

```
# define some workers skill
mu1, sigma1 = sym.var('mu1, sigma1')
skill_cdf = 0.5 + 0.5 * sym.erf((sym.log(x) - mu1) / sym.sqrt(2 * sigma1**2))
skill_params = {'mu1': 0.0, 'sigma1': 1.0}
skill_bounds = [1e-2, 1e2]

workers = inputs.Input(var=x,
                       cdf=skill_cdf,
                       params=skill_params,
                       bounds=skill_bounds,
                       )

# define some firms
mu2, sigma2 = sym.var('mu2, sigma2')
productivity_cdf = 0.5 + 0.5 * sym.erf((sym.log(y) - mu2) / sym.sqrt(2 * sigma2**2))
productivity_params = {'mu2': 0.0, 'sigma2': 1.0}
productivity_bounds = [1e-2, 1e2]

firms = inputs.Input(var=y,
                     cdf=productivity_cdf,
                     params=productivity_params,
                     bounds=productivity_bounds,
                     )
```

### Positive assortative matching

```
# define symbolic expression for CES between x and y
omega_A, sigma_A = sym.var('omega_A, sigma_A')
A = ((omega_A * x**((sigma_A - 1) / sigma_A) +
     (1 - omega_A) * y**((sigma_A - 1) / sigma_A))**(sigma_A / (sigma_A - 1)))

# define symbolic expression for Cobb-Douglas between l and r
l, r, omega_B, sigma_B = sym.var('l, r, omega_B, sigma_B')
B = l**omega_B * r**(1 - omega_B)

F = A * B

F_params = {'omega_A':0.75, 'omega_B':0.25, 'sigma_A':0.05, 'sigma_B':1.0}

model = models.Model('positive',
                     workers=workers,
                     firms=firms,
                     production=F,
                     params=F_params)

solver = shooting.ShootingSolver(model=model)
```

```
solver.solve(1e0, tol=1e-2, number_knots=10000, integrator='lsoda',
             with_jacobian=True, atol=1e-12, rtol=1e-9, message=True)
```

```
solver.solution
```

      $\mu(x)$
      $\theta(x)$
      $w(x)$
      $\pi(x)$

      x

      0.010000
         0.049637
       1690.660083
        0.000010
        0.048826

      0.030002
         0.049697
         20.866881
        0.000780
        0.048826

      0.050004
         0.052109
          2.818415
        0.005791
        0.048967

      0.070006
         0.064119
          1.477636
        0.012566
        0.055704

      0.090008
         0.080982
          1.334629
        0.017229
        0.068983

      0.110010
         0.098667
          1.288824
        0.021568
        0.083390

      0.130012
         0.116516
          1.261339
        0.025890
        0.097967

      0.150014
         0.134409
          1.240395
        0.030245
        0.112548

      0.170016
         0.152317
          1.222976
        0.034641
        0.127095

      0.190018
         0.170231
          1.207911
        0.039077
        0.141605

      0.210020
         0.188146
          1.194596
        0.043550
        0.156075

      0.230022
         0.206063
          1.182656
        0.048058
        0.170510

      0.250024
         0.223981
          1.171833
        0.052599
        0.184911

      0.270026
         0.241899
          1.161941
        0.057169
        0.199280

      0.290028
         0.259817
          1.152835
        0.061767
        0.213621

      0.310030
         0.277735
          1.144403
        0.066391
        0.227935

      0.330032
         0.295653
          1.136556
        0.071040
        0.242223

      0.350034
         0.313572
          1.129221
        0.075712
        0.256488

      0.370036
         0.331490
          1.122338
        0.080407
        0.270730

      0.390038
         0.349408
          1.115857
        0.085122
        0.284951

      0.410040
         0.367327
          1.109734
        0.089857
        0.299153

      0.430042
         0.385245
          1.103935
        0.094611
        0.313335

      0.450044
         0.403164
          1.098427
        0.099384
        0.327499

      0.470046
         0.421082
          1.093185
        0.104174
        0.341645

      0.490048
         0.439000
          1.088185
        0.108981
        0.355775

      0.510050
         0.456919
          1.083407
        0.113805
        0.369890

      0.530052
         0.474837
          1.078832
        0.118643
        0.383989

      0.550054
         0.492756
          1.074445
        0.123497
        0.398073

      0.570056
         0.510674
          1.070231
        0.128366
        0.412144

      0.590058
         0.528592
          1.066179
        0.133249
        0.426200

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

      99.419942
        98.809768
          0.482066
       42.892921
       62.031604

      99.439944
        98.849887
          0.481854
       42.918049
       62.040743

      99.459946
        98.890069
          0.481643
       42.943213
       62.049868

      99.479948
        98.930316
          0.481431
       42.968413
       62.058979

      99.499950
        98.970626
          0.481219
       42.993650
       62.068077

      99.519952
        99.011001
          0.481007
       43.018923
       62.077160

      99.539954
        99.051440
          0.480794
       43.044233
       62.086230

      99.559956
        99.091945
          0.480581
       43.069579
       62.095286

      99.579958
        99.132514
          0.480368
       43.094962
       62.104327

      99.599960
        99.173149
          0.480155
       43.120382
       62.113355

      99.619962
        99.213850
          0.479941
       43.145839
       62.122368

      99.639964
        99.254616
          0.479727
       43.171332
       62.131367

      99.659966
        99.295449
          0.479513
       43.196862
       62.140352

      99.679968
        99.336348
          0.479298
       43.222429
       62.149322

      99.699970
        99.377314
          0.479084
       43.248033
       62.158278

      99.719972
        99.418347
          0.478869
       43.273674
       62.167220

      99.739974
        99.459447
          0.478653
       43.299353
       62.176147

      99.759976
        99.500615
          0.478438
       43.325068
       62.185060

      99.779978
        99.541851
          0.478222
       43.350821
       62.193959

      99.799980
        99.583155
          0.478006
       43.376610
       62.202842

      99.819982
        99.624527
          0.477790
       43.402438
       62.211712

      99.839984
        99.665968
          0.477573
       43.428302
       62.220566

      99.859986
        99.707477
          0.477356
       43.454204
       62.229406

      99.879988
        99.749056
          0.477139
       43.480144
       62.238231

      99.899990
        99.790705
          0.476922
       43.506121
       62.247041

      99.919992
        99.832423
          0.476704
       43.532135
       62.255837

      99.939994
        99.874212
          0.476486
       43.558188
       62.264617

      99.959996
        99.916070
          0.476268
       43.584278
       62.273383

      99.979998
        99.958000
          0.476049
       43.610406
       62.282134

      100.000000
       100.000000
          0.475831
       43.636571
       62.290870

5000 rows × 4 columns

```
solver.interpolated_solution
```

      $\hat{\mu}(x)$
      $\hat{\theta}(x)$
      $\hat{w}(x)$
      $\hat{\pi}(x)$

      x

      0.010000
         0.049637
       1690.660083
        0.000010
        0.048826

      0.012000
         0.050251
       1331.502441
        0.000104
        0.049043

      0.014000
         0.050623
       1031.821402
        0.000148
        0.049193

      0.016000
         0.050799
        784.349504
        0.000164
        0.049282

      0.017999
         0.050824
        582.407361
        0.000171
        0.049317

      0.019999
         0.050735
        419.879830
        0.000187
        0.049306

      0.021999
         0.050567
        291.192167
        0.000224
        0.049256

      0.023999
         0.050354
        191.286194
        0.000293
        0.049175

      0.025999
         0.050121
        115.596453
        0.000405
        0.049071

      0.027999
         0.049895
         60.026374
        0.000566
        0.048952

      0.029998
         0.049698
         20.924433
        0.000780
        0.048826

      0.031998
         0.049546
         -4.939688
        0.001050
        0.048703

      0.033998
         0.049458
        -20.398936
        0.001378
        0.048589

      0.035998
         0.049445
        -27.912729
        0.001763
        0.048494

      0.037998
         0.049518
        -29.590795
        0.002204
        0.048425

      0.039998
         0.049687
        -27.217006
        0.002697
        0.048389

      0.041997
         0.049957
        -22.273225
        0.003240
        0.048395

      0.043997
         0.050332
        -15.963136
        0.003826
        0.048450

      0.045997
         0.050815
         -9.236088
        0.004450
        0.048559

      0.047997
         0.051407
         -2.810935
        0.005107
        0.048729

      0.049997
         0.052106
          2.800131
        0.005789
        0.048966

      0.051997
         0.052911
          7.267735
        0.006489
        0.049274

      0.053996
         0.053819
         10.421486
        0.007201
        0.049658

      0.055996
         0.054825
         12.226133
        0.007918
        0.050122

      0.057996
         0.055924
         12.757729
        0.008632
        0.050667

      0.059996
         0.057110
         12.179791
        0.009338
        0.051297

      0.061996
         0.058376
         10.719465
        0.010029
        0.052011

      0.063996
         0.059717
          8.643680
        0.010701
        0.052810

      0.065996
         0.061124
          6.235315
        0.011350
        0.053692

      0.067995
         0.062591
          3.769361
        0.011971
        0.054656

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

      99.942005
        99.878416
          0.476464
       43.560809
       62.265499

      99.944004
        99.882599
          0.476442
       43.563416
       62.266376

      99.946004
        99.886782
          0.476421
       43.566024
       62.267253

      99.948004
        99.890966
          0.476399
       43.568632
       62.268130

      99.950004
        99.895151
          0.476377
       43.571240
       62.269006

      99.952004
        99.899336
          0.476355
       43.573849
       62.269882

      99.954004
        99.903523
          0.476333
       43.576458
       62.270759

      99.956004
        99.907710
          0.476312
       43.579067
       62.271635

      99.958003
        99.911897
          0.476290
       43.581677
       62.272511

      99.960003
        99.916085
          0.476268
       43.584287
       62.273386

      99.962003
        99.920274
          0.476246
       43.586898
       62.274262

      99.964003
        99.924464
          0.476224
       43.589509
       62.275137

      99.966003
        99.928655
          0.476202
       43.592120
       62.276013

      99.968003
        99.932846
          0.476181
       43.594732
       62.276888

      99.970002
        99.937038
          0.476159
       43.597344
       62.277763

      99.972002
        99.941230
          0.476137
       43.599957
       62.278638

      99.974002
        99.945423
          0.476115
       43.602569
       62.279512

      99.976002
        99.949617
          0.476093
       43.605183
       62.280387

      99.978002
        99.953812
          0.476071
       43.607796
       62.281261

      99.980002
        99.958007
          0.476049
       43.610410
       62.282135

      99.982001
        99.962203
          0.476028
       43.613025
       62.283010

      99.984001
        99.966400
          0.476006
       43.615640
       62.283883

      99.986001
        99.970598
          0.475984
       43.618255
       62.284757

      99.988001
        99.974796
          0.475962
       43.620870
       62.285631

      99.990001
        99.978995
          0.475940
       43.623486
       62.286504

      99.992001
        99.983194
          0.475918
       43.626102
       62.287378

      99.994000
        99.987395
          0.475896
       43.628719
       62.288251

      99.996000
        99.991596
          0.475875
       43.631336
       62.289124

      99.998000
        99.995798
          0.475853
       43.633953
       62.289997

      100.000000
       100.000000
          0.475831
       43.636571
       62.290870

50000 rows × 4 columns

```
solver.interpolated_solution.plot(loglog=True)
```

```
solver.residuals.plot(loglog=True, alpha=0.5)
```

### Negative assortative matching

```
# define some workers skill
mu1, sigma1 = sym.var('mu1, sigma1')
skill_cdf = 0.5 + 0.5 * sym.erf((sym.log(x) - mu1) / sym.sqrt(2 * sigma1**2))
skill_params = {'mu1': 0.0, 'sigma1': 1.0}
skill_bounds = [1e-3, 1e3]

workers = inputs.Input(var=x,
                       cdf=skill_cdf,
                       params=skill_params,
                       bounds=skill_bounds,
                       )

# define some firms
mu2, sigma2 = sym.var('mu2, sigma2')
productivity_cdf = 0.5 + 0.5 * sym.erf((sym.log(y) - mu2) / sym.sqrt(2 * sigma2**2))
productivity_params = {'mu2': 0.0, 'sigma2': 1.0}
productivity_bounds = [1e-3, 1e3]

omega_A, sigma_A = sym.var('omega_A, sigma_A')
A = ((omega_A * x**((sigma_A - 1) / sigma_A) +
     (1 - omega_A) * y**((sigma_A - 1) / sigma_A))**(sigma_A / (sigma_A - 1)))

# define symbolic expression for Cobb-Douglas between l and r
l, r, omega_B, sigma_B = sym.var('l, r, omega_B, sigma_B')
B = l**omega_B * r**(1 - omega_B)

F = A * B

firms = inputs.Input(var=y,
                     cdf=productivity_cdf,
                     params=productivity_params,
                     bounds=productivity_bounds,
                     )
F_params = {'omega_A':0.25, 'omega_B':0.75, 'sigma_A':1.5, 'sigma_B':1.0}

model = models.Model('negative',
                     workers=workers,
                     firms=firms,
                     production=F,
                     params=F_params)

solver = shooting.ShootingSolver(model=model)
```

```
solver.solve(1e9, tol=1e-3, number_knots=10000, integrator='dop853',
             atol=1e-12, rtol=1e-9, message=True)
```

    Exhausted workers: initial guess of 500000000.0 for firm size is too high!
    Exhausted workers: initial guess of 250000000.0 for firm size is too high!

```
solver.solution
```

      firm productivity
      firm size
      wage
      profit

      x

      0.001000
       1000.000000
       1.220703e+08
       3.040383
       1.237135e+08

      0.101010
        348.057094
       1.813997e+06
       3.203886
       1.937280e+06

      0.201020
        156.824015
       7.964676e+04
       3.286307
       8.724790e+04

      0.301030
         93.485533
       1.070454e+04
       3.358928
       1.198526e+04

      0.401040
         62.358554
       2.261469e+03
       3.426909
       2.583282e+03

      0.501050
         43.873790
       5.949377e+02
       3.492500
       6.926067e+02

      0.601059
         31.549225
       1.725873e+02
       3.557111
       2.046374e+02

      0.701069
         22.608750
       5.027735e+01
       3.621914
       6.070008e+01

      0.801079
         15.615638
       1.307599e+01
       3.688232
       1.607576e+01

      0.901089
          9.592070
       2.312030e+00
       3.758238
       2.896386e+00

      1.001099
          2.073143
       1.383323e-02
       3.839895
       1.770605e-02

      1.005032
          0.006514
       1.820565e-08
       3.844460
       2.333030e-08

```
solver.solution.plot(loglog=True)
```

```
solver.residuals
```

      firm productivity
      firm size

      x

      0.001000
       -21360.843509
      -1.166961e+05

      0.011000
       214057.758160
       3.088759e+07

      0.021000
       401017.639649
       5.436097e+07

      0.031000
       253834.218544
       3.293469e+07

      0.041000
       105415.023097
       1.306172e+07

      0.051000
        33420.559949
       3.962162e+06

      0.061001
         7235.487420
       8.515208e+05

      0.071001
         -582.343742
      -1.500115e+04

      0.081001
        -2282.917310
      -1.906684e+05

      0.091001
        -2167.530698
      -1.825196e+05

      0.101001
        -1377.194759
      -1.356549e+05

      0.111001
        -1528.692672
                NaN

      0.121001
         -902.538148
                NaN

      0.131001
         -504.495586
                NaN

      0.141001
         -222.017062
                NaN

      0.151001
          -30.112645
                NaN

      0.161001
           87.439341
                NaN

      0.171002
          142.915230
                NaN

      0.181002
          140.699615
                NaN

      0.191002
            8.851732
                NaN

      0.201002
          284.585456
       2.722496e+04

      0.211002
          139.882543
       2.117810e+04

      0.221002
           60.188497
       1.452769e+04

      0.231002
           -9.114354
       7.869441e+03

      0.241002
          -69.840184
       1.705493e+03

      0.251002
         -119.557593
      -3.560794e+03

      0.261002
         -155.690539
      -7.634711e+03

      0.271002
         -176.322869
      -1.034026e+04

      0.281003
         -180.110417
      -1.162676e+04

      0.291003
         -164.598168
      -1.157104e+04

      ...
      ...
      ...

      999.709997
           -0.000107
      -5.251048e-09

      999.719997
           -0.000107
      -5.270074e-09

      999.729998
           -0.000093
      -4.680108e-09

      999.739998
           -0.000067
      -3.448820e-09

      999.749998
           -0.000028
      -1.600698e-09

      999.759998
            0.000021
       7.840911e-10

      999.769998
            0.000078
       3.571220e-09

      999.779998
            0.000139
       6.574180e-09

      999.789998
            0.000199
       9.556799e-09

      999.799998
            0.000251
       1.223641e-08

      999.809998
            0.000290
       1.428778e-08

      999.819998
            0.000308
       1.534815e-08

      999.829998
            0.000296
       1.502359e-08

      999.839999
            0.000247
       1.289776e-08

      999.849999
            0.000153
       8.544066e-09

      999.859999
            0.000006
       1.543752e-09

      999.869999
           -0.000201
      -8.486052e-09

      999.879999
           -0.000471
      -2.184704e-08

      999.889999
           -0.000806
      -3.868363e-08

      999.899999
           -0.001199
      -5.884973e-08

      999.909999
           -0.001630
      -8.166544e-08

      999.919999
           -0.002056
      -1.054491e-07

      999.929999
           -0.002392
      -1.265619e-07

      999.939999
           -0.002463
      -1.373110e-07

      999.950000
           -0.001906
      -1.209235e-07

      999.960000
            0.000097
      -3.809962e-08

      999.970000
            0.005592
       2.143550e-07

      999.980000
            0.020557
       9.566089e-07

      999.990000
            0.066930
       3.457784e-06

      1000.000000
            0.259280
       1.507616e-05

100000 rows × 2 columns

```
np.abs(solver.residuals).plot(logy=True, alpha=0.5)
```

# Example:

More sophisticated production function that is not multiplicatively separable...

```
# define some workers skill
x, mu1, sigma1 = sym.var('x, mu1, sigma1')
skill_cdf = 0.5 + 0.5 * sym.erf((sym.log(x) - mu1) / sym.sqrt(2 * sigma1**2))
skill_params = {'mu1': 0.0, 'sigma1': 1e0}
skill_bounds = [1e-2, 1e2]

workers = inputs.Input(var=x,
                       cdf=skill_cdf,
                       params=skill_params,
                       bounds=skill_bounds,
                       )

# define some firms
y, mu2, sigma2 = sym.var('y, mu2, sigma2')
productivity_cdf = 0.5 + 0.5 * sym.erf((sym.log(y) - mu2) / sym.sqrt(2 * sigma2**2))
productivity_params = {'mu2': 0.0, 'sigma2': 1e0}
productivity_bounds = [1e-2, 1e2]

firms = inputs.Input(var=y,
                     cdf=productivity_cdf,
                     params=productivity_params,
                     bounds=productivity_bounds,
                     )

# define some valid model params
F_params = {'eta': 0.89, 'kappa': 1.0, 'gamma': 0.54, 'rho': 0.24, 'A': 1.0, 'k': 1.0}

# define a valid production function
A, k, kappa, eta, rho, l, gamma, r = sym.var('A, k, kappa, eta, rho, l, gamma, r')
F = r * A * kappa * eta * ((k * x)**rho + (1 - eta) * (y * (l / r))**rho)**(gamma / rho)

model = models.Model('negative',
                     workers=workers,
                     firms=firms,
                     production=F,
                     params=F_params)
```

```
solver = shooting.ShootingSolver(model=model)
```

```
solver.solve(1e6, tol=1e-3, number_knots=5000, integrator='dopri5',
             atol=1e-12, rtol=1e-9, message=True)
```

    Exhausted workers: initial guess of 500000.0 for firm size is too high!
    Exhausted workers: initial guess of 250000.0 for firm size is too high!
    Exhausted workers: initial guess of 125000.0 for firm size is too high!
    Exhausted firms: initial guess of 62500.0 for firm size is too low.
    Exhausted workers: initial guess of 93750.0 for firm size is too high!
    Exhausted firms: initial guess of 78125.0 for firm size is too low.
    Exhausted workers: initial guess of 85937.5 for firm size is too high!
    Exhausted firms: initial guess of 82031.25 for firm size is too low.
    Exhausted workers: initial guess of 83984.375 for firm size is too high!
    Exhausted firms: initial guess of 83007.8125 for firm size is too low.
    Exhausted firms: initial guess of 83496.09375 for firm size is too low.
    Exhausted firms: initial guess of 83740.234375 for firm size is too low.
    Exhausted workers: initial guess of 83862.3046875 for firm size is too high!
    Exhausted workers: initial guess of 83801.2695312 for firm size is too high!
    Exhausted workers: initial guess of 83770.7519531 for firm size is too high!
    Exhausted firms: initial guess of 83755.4931641 for firm size was too low!
    Exhausted firms: initial guess of 83763.1225586 for firm size was too low!
    Exhausted workers: initial guess of 83766.9372559 for firm size is too high!
    Exhausted workers: initial guess of 83765.0299072 for firm size is too high!
    Exhausted firms: initial guess of 83764.0762329 for firm size was too low!
    Exhausted firms: initial guess of 83764.5530701 for firm size was too low!
    Exhausted firms: initial guess of 83764.7914886 for firm size was too low!
    Exhausted firms: initial guess of 83764.9106979 for firm size was too low!
    Exhausted workers: initial guess of 83764.9703026 for firm size is too high!
    Exhausted workers: initial guess of 83764.9405003 for firm size is too high!
    Exhausted firms: initial guess of 83764.9255991 for firm size was too low!
    Exhausted firms: initial guess of 83764.9330497 for firm size was too low!
    Exhausted firms: initial guess of 83764.936775 for firm size was too low!
    Exhausted firms: initial guess of 83764.9386376 for firm size was too low!
    Exhausted firms: initial guess of 83764.9395689 for firm size was too low!
    Exhausted workers: initial guess of 83764.9400346 for firm size is too high!
    Exhausted firms: initial guess of 83764.9398018 for firm size was too low!
    Exhausted workers: initial guess of 83764.9399182 for firm size is too high!
    Exhausted workers: initial guess of 83764.93986 for firm size is too high!
    Exhausted workers: initial guess of 83764.9398309 for firm size is too high!
    Exhausted firms: initial guess of 83764.9398163 for firm size was too low!
    Exhausted firms: initial guess of 83764.9398236 for firm size was too low!
    Exhausted workers: initial guess of 83764.9398272 for firm size is too high!
    Exhausted workers: initial guess of 83764.9398254 for firm size is too high!
    Exhausted workers: initial guess of 83764.9398245 for firm size is too high!
    Success! All workers and firms are matched

```
solver.solution
```

      firm productivity
      firm size
      wage
      profit

      x

      0.010000
       100.000000
       8.376494e+04
            0.000237
       19.326771

      0.030002
        99.970172
       7.386098e+04
            0.000258
       19.321035

      0.050004
        99.807695
       6.860303e+04
            0.000270
       19.290554

      0.070006
        99.428551
       6.478157e+04
            0.000280
       19.220773

      0.090008
        98.802805
       6.163299e+04
            0.000289
       19.107376

      0.110010
        97.941115
       5.886610e+04
            0.000296
       18.953254

      0.130012
        96.877773
       5.635129e+04
            0.000302
       18.765229

      0.150014
        95.657334
       5.402687e+04
            0.000308
       18.551615

      0.170016
        94.325533
       5.186192e+04
            0.000314
       18.320649

      0.190018
        92.923965
       4.983945e+04
            0.000319
       18.079622

      0.210020
        91.487623
       4.794858e+04
            0.000324
       17.834521

      0.230022
        90.044284
       4.618083e+04
            0.000329
       17.589989

      0.250024
        88.614975
       4.452854e+04
            0.000334
       17.349448

      0.270026
        87.214916
       4.298429e+04
            0.000338
       17.115299

      0.290028
        85.854608
       4.154073e+04
            0.000343
       16.889132

      0.310030
        84.540862
       4.019067e+04
            0.000347
       16.671917

      0.330032
        83.277695
       3.892712e+04
            0.000351
       16.464158

      0.350034
        82.067057
       3.774343e+04
            0.000355
       16.266031

      0.370036
        80.909407
       3.663332e+04
            0.000359
       16.077474

      0.390038
        79.804159
       3.559091e+04
            0.000363
       15.898270

      0.410040
        78.750011
       3.461078e+04
            0.000367
       15.728093

      0.430042
        77.745192
       3.368794e+04
            0.000370
       15.566556

      0.450044
        76.787647
       3.281781e+04
            0.000374
       15.413238

      0.470046
        75.875160
       3.199620e+04
            0.000378
       15.267700

      0.490048
        75.005451
       3.121930e+04
            0.000381
       15.129505

      0.510050
        74.176242
       3.048365e+04
            0.000385
       14.998223

      0.530052
        73.385297
       2.978610e+04
            0.000388
       14.873438

      0.550054
        72.630451
       2.912377e+04
            0.000391
       14.754757

      0.570056
        71.909633
       2.849407e+04
            0.000395
       14.641801

      0.590058
        71.220873
       2.789461e+04
            0.000398
       14.534218

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

      99.339934
        10.234099
       3.231405e-06
         5485.934090
       10.717951

      99.359936
         9.988517
       2.937533e-06
         5863.658198
       10.717527

      99.379938
         9.739497
       2.662701e-06
         6279.689014
       10.717099

      99.399940
         9.486904
       2.406184e-06
         6739.277376
       10.716666

      99.419942
         9.230591
       2.167265e-06
         7248.597608
       10.716229

      99.439944
         8.970401
       1.945239e-06
         7814.948889
       10.715787

      99.459946
         8.706161
       1.739406e-06
         8447.009762
       10.715340

      99.479948
         8.437686
       1.549075e-06
         9155.162481
       10.714888

      99.499950
         8.164772
       1.373567e-06
         9951.910019
       10.714430

      99.519952
         7.887195
       1.212208e-06
        10852.417367
       10.713966

      99.539954
         7.604712
       1.064336e-06
        11875.221468
       10.713496

      99.559956
         7.317049
       9.292946e-07
        13043.172831
       10.713019

      99.579958
         7.023907
       8.064398e-07
        14384.699839
       10.712534

      99.599960
         6.724948
       6.951350e-07
        15935.529259
       10.712041

      99.619962
         6.419794
       5.947533e-07
        17741.062400
       10.711539

      99.639964
         6.108016
       5.046770e-07
        19859.710831
       10.711027

      99.659966
         5.789126
       4.242979e-07
        22367.665088
       10.710504

      99.679968
         5.462559
       3.530173e-07
        25365.852383
       10.709968

      99.699970
         5.127658
       2.902459e-07
        28990.324536
       10.709419

      99.719972
         4.783647
       2.354045e-07
        33428.179736
       10.708854

      99.739974
         4.429595
       1.879234e-07
        38942.715144
       10.708270

      99.759976
         4.064361
       1.472426e-07
        45914.588829
       10.707665

      99.779978
         3.686515
       1.128124e-07
        54912.056352
       10.707033

      99.799980
         3.294205
       8.409267e-08
        66817.026810
       10.706370

      99.819982
         2.884928
       6.055309e-08
        83065.903242
       10.705664

      99.839984
         2.455083
       4.167265e-08
       106148.112042
       10.704903

      99.859986
         1.999009
       2.693824e-08
       140755.379416
       10.704061

      99.879988
         1.506344
       1.584003e-08
       196879.381815
       10.703088

      99.899990
         0.951599
       7.847826e-09
       300667.949090
       10.701843

      99.919992
         0.010003
       7.845860e-10
       579714.785810
       10.696970

4996 rows × 4 columns

```
solver.solution['firm productivity'].plot()
```

```
solver.solution.plot(loglog=True)
```

```
np.abs(solver.residuals).plot(logy=True, alpha=0.5)
```

```
solver.ivp.compute_residual?
```

```

```


# Python fundamentals 1 (Week 2)

## Module: Learning outcomes

* Describe the six stages of a data processing pipeline (using CRISP-DM)

* Demonstrate an understanding of the python programming language through the production of elementary data analysis programme

* Analyse at least three different data sources by applying at least one python data processing library to extract and explore pertinent features

* Be able to design a set of data requirements for a specified business problem

* Describe and apply (using the python programming language) the main approaches to supervised learning for a given classification problem

* Understand the use cases of Big Data technology (in particular Spark)

* Produce a report including appropriate data visualisations covering the analysis of a business problem using a data science based approach

## Week 2: Learning outcome

* At the end of week 2, you will have a foundational level knowledge of Python. You will be able to write code and text using Markdown.

## An introduction to Markdown

Let's start with the text interface, which allows Markdown to be written. Markdown is a lightweight markup language (similar to HTML for webpages) that allows us to write text and embed images and mathematics. This allows for interactive visualisations, allowing for better reproducibility, sharing, and decision making.

Example:

# Title 1

## Title 2

### Title 3

This is a line of text.

* This is a bullet
* This is a second bullet
* This is a bullet with _italic_ text
* This is a bullet with **bold** text

This is an equation written in LaTex:
\begin{equation}
f(x) = x^2
\end{equation}

This is an equation $x^2$ written inline.

Further details on Markdown and LaTex can be found here:
Mandatory exercises
- [ ] Read this reference: https://colab.research.google.com/notebooks/markdown_guide.ipynb

Optional exercises
- [ ] Use this cheat sheet when writing Markdown for your own work: https://medium.com/ibm-data-science-experience/markdown-for-jupyter-notebooks-cheatsheet-386c05aeebed
- [ ] Read this reference: https://www.math.ubc.ca/~pwalls/math-python/jupyter/latex/

## Mathematical foundations

### Notation

* $4\times4\times4 = 4^3 = 64$
* $x\times x\times x = x^3$ (e.g. when $x=4$, $x^3 = 64$)
* In the expression above, $x$ is a _variable_

```
4 * 4 * 4
```

    64

This can be equivalently written as:

```
4 ** 3
```

    64

We can introduce variables, such as $x = 4$

```
x = 4
```

We can then manipulate variable x, rather than specific values.

```
x * x * x
```

    64

```
y = 2
```

```
x ** y
```

    16

We can then change the values of x and y, to maximise code reuse.

* We could generalise further and say $f(x) = x^2$, where "$f$ is a function of the variable $x$" (e.g. $f(4) = 16$)
* A function is a relation between sets that associates to every element of a first set exactly one element of the second set
* A set is a well defined collection of distinct items. e.g. $\{apple,orange,banana\}$

Let's look at how we do this in Python.

In Python, a function is defined using the def keyword:

```
def print_hello():
  print("Hello world")

# this is a comment
x = 4
print(x)
```

    4

```
def print_hello_user(user):
  print("Hello "+user)
```

```
print_hello_user("Mark")
```

    Hello Mark

```
print_hello()
```

    Hello world

We can pass variable arguments to functions:

```
def square(x):
  return x ** 2
```

We can use this function several times, in order to reduce the amount of code that we need to write and to maximise code sharing.

```
x = 3
print(x)
print(x == 4)
```

    3
    False

```
square(5)
```

    25

We can also define recursive functions (e.g. factorial(5) = 5! = 5 x 4 x 3 x 2 x 1)

```
def factorial(n):
   if n == 1:
       return n
   else:
       return n*factorial(n-1)
```

```
factorial(5)
```

    120

```
factorial(3)
```

    6

We can perform operations with different Python native datatypes (Boolean, Integer, Float, List, String).

Booleans are either assigned to True or False. Python expects an expression to evaluate to a boolean value. These are called Boolean contexts.

```
x > 10
```

    False

```
x == 2
```

    False

```
if x < 4:
  print("x<4")
else:
  print("x>=4")
```

    x>=4

```
x = 10
```

A float (floating point real number) is defined with a decimal, or explicitly:

```
pi = 3.14
```

```
print(pi)
```

    3.14

```
float(2)
```

    2.0

## Libraries

The power of Python (with respect to data science) is its extensibility. We can import libraries and use functions and data types from such libraries. NumPy (https://numpy.org/) is the basis of many data science libraries. We import it as follows:

```
import numpy as np
```

We can use numpy to define _vectors_ and _matrices_, and to perform mathematical operations:

```
# Create a vector as a row
vector_row = np.array([1, 2, 3])
```

```
print(vector_row)
```

    [1 2 3]

```
# Create a vector as a column
vector_column = np.array([[1],
                          [2],
                          [3]])
```

```
print(vector_column)
```

    [[1]
     [2]
     [3]]

Let's call the _linspace_ function, in order to produce a list of values that are equally spaced:

```
# Build array/vector:
x = np.linspace(-np.pi, np.pi, 10)
print(x)
```

    [-3.14159265 -2.44346095 -1.74532925 -1.04719755 -0.34906585  0.34906585
      1.04719755  1.74532925  2.44346095  3.14159265]

```
print(x[0])  # first element
print(x[2])  # third element
print(x[-1]) # last element
print(x[-2]) # second to last element
```

    -3.141592653589793
    -1.7453292519943295
    3.141592653589793
    2.443460952792061

```
print(x[1:4])     # second to fourth element. Element 5 is not included
print(x[0:-1:2])  # every other element
print(x[:])       # print the whole vector
print(x[-1:0:-1]) # reverse the vector!
```

    [-2.44346095 -1.74532925 -1.04719755]
    [-3.14159265 -1.74532925 -0.34906585  1.04719755  2.44346095]
    [-3.14159265 -2.44346095 -1.74532925 -1.04719755 -0.34906585  0.34906585
      1.04719755  1.74532925  2.44346095  3.14159265]
    [ 3.14159265  2.44346095  1.74532925  1.04719755  0.34906585 -0.34906585
     -1.04719755 -1.74532925 -2.44346095]

Consider if we want the part of the vector where x > 2:

```
print(x > 2)
y = x[x > 2]
print(y)
y[0]
```

    [False False False False False False False False  True  True]
    [2.44346095 3.14159265]

    2.443460952792061

In the above, we have been programmatically manipulating arrays. A mathematical representation of an array is known as a vector.
* (Imprecisely) a *vector* is an ordered set of elements, $\vec{x}=(x_{1}~x_{2}~\ldots~x_{n})\in\mathbb{R}^n$

* Let:
\begin{eqnarray}
   \vec{a} = \left[\begin{matrix}
   a_{11} \\
   a_{21} \\
   a_{31} \\
   \end{matrix}\right], & ~~~ &
   \vec{b} = \left[\begin{matrix}
   b_{11} \\
   b_{21} \\
   b_{31} \\
   \end{matrix}\right]
\end{eqnarray}

* Then:
\begin{equation}
\vec{a}+\vec{b} = \left[\begin{matrix}
   a_{11}+b_{11} \\
   a_{21}+b_{21} \\
   a_{31}+b_{31} \\
   \end{matrix}\right]
  \end{equation}

We will return to this when we delve deeper into modelling, later in the course.

## Matrix

* A matrix is a two-dimensional representation of numbers (a grid)
* In data science, we will use linear representations to map our input to our output space, to store neural network weights, while features are stored as vector inputs
* This allows us to have compact mathematical representations of the models, and to exploit computational resources (such as GPUs) in order to perform extremely fast processing
* Example:
\begin{equation}
A =
   \left[\begin{matrix}
   11 & 14 & 18 & 9 \\
   32 & 14 & 24 & 17 \\
   10 & 7 & 6 & 28 \\
   \end{matrix}\right]
\end{equation}
* We can define operations between matrices, or between matrices and vectors

```
# Create a matrix
matrix = np.array([[11, 14, 18, 9],
                   [32, 14, 24, 17],
                   [10, 7, 6, 28]])
```

```
matrix[0,2]
```

    18

```
matrix.size
```

    12

```
matrix.shape
```

    (3, 4)

```
matrix.T
```

    array([[11, 32, 10],
           [14, 14,  7],
           [18, 24,  6],
           [ 9, 17, 28]])

We can perform algebraic operations on matrices:

```
# Create matrix
matrix_a = np.array([[1, 1, 1],
                     [1, 1, 1],
                     [1, 1, 2]])

# Create matrix
matrix_b = np.array([[1, 3, 1],
                     [1, 3, 1],
                     [1, 3, 8]])

# Add two matrices
np.add(matrix_a, matrix_b)
```

    array([[ 2,  4,  2],
           [ 2,  4,  2],
           [ 2,  4, 10]])

Or equivalently:

```
matrix_a + matrix_b
```

    array([[ 2,  4,  2],
           [ 2,  4,  2],
           [ 2,  4, 10]])

```
matrix_a - matrix_b
```

    array([[ 0, -2,  0],
           [ 0, -2,  0],
           [ 0, -2, -6]])

## Exercises

Mandatory exercises:
- [ ] Introduce a function that computes $x+2$ for any value of $x$. Call the function addTwo.
- [ ] Replicate all of the code in this notebook.

Advanced (optional) exercises (for students with existing Python knowledge):
- [ ] By reading the NumPy documentation, create a 3-dimensional array (a _tensor_)
- [ ] Create your own simple Python class for a Matrix, that is, an object based representation of a two-dimensional array


$\newcommand{\ket}[1]{\left|\, #1 \right\rangle }$ $\newcommand{\bra}[1]{\left\langle #1\, \right|}$
$\newcommand{\braket}[2]{\left\langle \left. #1\, \right| #2 \right\rangle}$ $\newcommand{\V}{\mathbb{V}}$
$\DeclareMathOperator{\tr}{tr}$

[comment]: <> (Written by Andrés Cárdenas)
[comment]: <> (July 2021)
[comment]: <> (www.fysixs.com)
[comment]: <> (andres.cardenas@gmail.com)

    **A Julia/Jupyter Companion**

  *Andrés Cárdenas, 2021*, www.fysixs.com

***Principles of Quantum Mechanics***
 by R. Shankar  (text on Amazon)

 Chapter 1. Mathematical Introduction

```julia
using NBInclude
@nbinclude("ShankarSRC.ipynb")
```

##  **Definitions**

####  *Definition 1*

Let $\mathbb{V} = \big\{ \ket{1}, \ket{2}, \ldots, \ket{V}, \ket{W}, \ldots \big\}$ with $\ket{V}$ a *vector*. Together with $\mathbb{V}$ we also have an addition operation: $\ket{V} + \ket{W}$, and a multiplication by a scalar from the field $\mathcal{F}$: $a\ket{V}, a\in \mathcal{F}$. We assume addition to be *associative* and *commutative* and scalar multiplication to be *distributive* and *associative*.

We say $\mathbb{V}$ is a *vector space* if the following are satisfied:
> *Closure*: If $\ket{V}, \ket{W} \in\mathbb{V}$ and $a\in\mathcal{F}$ then $\ket{V} + \ket{W}\in\mathbb{V}$ and $a\ket{V}\in\mathbb{V}$.
>
> *Existence of a zero*: There exists a *null* vector $\ket{0}$ such so that $\ket{V} + \ket{0} = \ket{V}$ for $\ket{V}\in\mathbb{V}$.
>
> *Existence of an additive inverse*: For every $\ket{V}\in\mathbb{V}$ there exists a $\ket{-V}$ so that $\ket{V} + \ket{-V} = \ket{0}$.

####  *Definition 2*

If the field $\mathcal{F}$ is the real numbers, the vector space is called *real*. If the field $\mathcal{F}$ is the complex numbers, the vector space is called *complex*.

####  *Definition 3*

A set of vectors $\mathcal{B} = \big\{ \ket{1}, \ket{2}, \ldots, \ket{n} \big\}$ is said to be *linearly independent* if the only solutions to
\begin{equation}
    \sum_{i=1}^n a_i \ket{i} = \ket{0},
\end{equation}
are $a_i=0$ for all $i$. They are called *linearly dependent* if that is not the case.

####  *Definition 4*

A vector space is said to have *dimension* $n$ if the largest set of linearly independent vectors has $n$ elements. If the vector space is real it will be denoted $\mathbb{V}^n(\mathbb{R})$, if it is complex, $\mathbb{V}^n(\mathbb{C})$.

####  *Definition 5*

The set $\mathcal{B} = \big\{ \ket{1}, \ket{2}, \ldots, \ket{n} \big\}$ of linearly independent vectors is called a *basis* for $\V$.

####  *Definition 6*

Let $\mathcal{B}$ be a basis for $\V$ so that
\begin{equation}
    \ket{V} = \sum_{i=1}^n v_i \ket{i}, \quad \ket{i}\in\mathcal{B}.
\end{equation}
We call $v_i$ the the $i$-th component of $\ket{V}$ in the basis $\mathcal{B}$.

####  *Definition 7*

Let $\ket{V}, \ket{W}, \ket{Z}\in\V$ and denote by $\braket{V}{W}\in\mathbb{C}$, the *scalar or inner product* of the vectors. We demand the inner product to satisfy the following properties
> *Skew-symmetry*: $\braket{V}{W} = \braket{W}{V}^*$
>
> *Positive semidefinite*: $\braket{V}{V}\geq 0$ with equality only for $\ket{V} = \ket{0}$.
>
> *Ket linearity*: $\bra{V}\big(a\ket{W} + b\ket{Z}\big) = \braket{V}{aW + bZ} = a\braket{V}{W} + b\braket{V}{Z}$.

A vector space $\V$ with an inner product is called an *inner product space*.

####  *Definition 8*

We say $\ket{V}, \ket{W}$ are *orthogonal* if $\braket{V}{W} = 0$.

####  *Definition 9*

We denote by $\lVert V \rVert \equiv \sqrt{\braket{V}{V}}$, the *norm* of $\ket{V}$. A *normalized vector* has unit norm.

####  *Definition 10*

If a basis $\mathcal{B}$ is made up of mutually orhogonal normalized vectors it is called an *orthonormal basis*.

####  *Definition 11*

A *subspace* is a subset of a vector space $\V$ who itself satisfies all the properties of a vector space. Denote the $i$-th subspace of $\V$ with dimension $n_i$ by $\V_i^{n_i}$.

####  *Definition 12*

Given subspaces $\V_i^{n_i}, \V_j^{n_j} \subset \V$, we define their sum,
$$ \V_i^{n_i} \oplus \V_j^{n_j} = \V_k^{n_k}, $$
as the space containing all of $\V_i^{n_i}$, all of $\V_j^{n_j}$ and all their linear combinations.

####  *Definition 13*

An operator $\Omega$ is called *Hermitian* if $\Omega^\dagger = \Omega$.

####  *Definition 14*

An operator $\Omega$ is called *anti-Hermitian* if $\Omega^\dagger = -\Omega$.

####  *Definition 15*

An operator $U$ is *unitary* if $$ UU^\dagger = I. $$

##  **Theorems**

####  *Theorem 1*

Let $\ket{V}\in\V^n$ and let $\mathcal{B} = \big\{ \ket{1}, \ket{2}, \ldots, \ket{n}\big\}$ be a linearly independent set then we can always write
\begin{equation}
    \ket{V} = \sum_{i=1}^n v_i \ket{i},
\end{equation}
for some scalars $v_i$. We say that $\ket{V}$ can be written as a *linear combination* of vectors in $\mathcal{B}$.

####  *Theorem 2*

The expansion above is unique given a basis $\mathcal{B}$.

####  *Theorem 3*

We can create an orthonormal basis from any basis $\mathcal{B}$.

####  *Theorem 4*

The maximum number of mutually orthogonal vectors is number of *dimensions* of the space.

####  *Theorem 5: Schwarz Inequality*

\begin{equation}
    \braket{V}{W}^2 \leq \braket{V}{V}\braket{W}{W}
\end{equation}

####  *Theorem 6: Triangle Inequality*

\begin{equation}
    \lVert V + W \rVert  \leq  \lVert V \rVert +  \lVert V + W \rVert
\end{equation}

####  *Theorem 7:*

Unitary operators preserve the inner product.

####  *Theorem 8:*

If $U$ is unitary of dimension $n$ then its rows and columns both form orthonormal sets.

####  *Theorem 9:*

The eigenvalues of a Hermitian operator are real.

####  *Theorem 10:*

The set of eigenvectors of a Hermitian operator form an orthonormal basis under which it is diagonal with the eigenvalues as its entries.

####  *Theorem 11:*

The eigenvalues of a unitary operator are complex of unit modulus.

####  *Theorem 12:*

The eigenvectors of a unitary operator are mutually orthogonal.

##  **Select Exercises/Examples**

For the Julia codes here, kets will be denoted by over-right arrows while bras will be denoted by over-left arrows:
\begin{align}
\ket{\psi} &\to \overrightarrow{\psi}, \\
\bra{\psi} &\to \overleftarrow{\psi}, \\
\end{align}

###  *The Gram-Schmidt Algorithm*

We start with a random complex basis ℬ of dimension $N$ and apply the following algorithm to construct ℬ′:
1. Let $\ket{1}\in ℬ′$, set $\ket{1} = \ket{I}\in ℬ$.
2. Replace $\ket{1}$ by its unit-vector: $$ \frac{\ket{1}}{\sqrt{\braket{1}{1}}} \to \ket{1}.$$
3. Let $\ket{2}\in ℬ′$, set $\ket{2} = \ket{II}\in ℬ$ and subtract out the overlap with $\ket{1}$:
    $$\ket{2} = \ket{II} - \ket{1}\braket{1}{II}.$$
4. Replace $\ket{2}$ by its unit-vector: $$ \frac{\ket{2}}{\sqrt{\braket{2}{2}}} \to \ket{2}.$$
5. Let $\ket{3}\in ℬ′$, set $\ket{3} = \ket{III}\in ℬ$ and subtract out the overlap with $\ket{1}$ and $\ket{2}$:
    $$\ket{3} = \ket{III} - \ket{1}\braket{1}{III} - \ket{2}\braket{2}{III}.$$
6. So on...

####  *Exercise 1.3.2*:

```julia
# ℬ is our starting ket basis which is not orthonormal as shown
ℬ = [ ket(3.0, 0.0, 0.0), ket(0.0, 1.0, 2.0), ket(0.0, 2.0, 5.0) ]

disp("ℬ = $(TeX(ℬ[1].|> Sym)), $(TeX(ℬ[2].|> Sym)), $(TeX(ℬ[3].|> Sym)).")
```

ℬ = $\left[\begin{matrix}3.0\\0.0\\0.0\end{matrix}\right]$, $\left[\begin{matrix}0.0\\1.0\\2.0\end{matrix}\right]$, $\left[\begin{matrix}0.0\\2.0\\5.0\end{matrix}\right]$.

we get after the Gram-Schmidt algorithm,

```julia
ℬ′ = gramschmidt( ℬ );
disp("ℬ′ = $(TeX(ℬ′[1].|> Sym)), $(TeX(ℬ′[2].|> Sym)), $(TeX(ℬ′[3].|> Sym)).")
```

ℬ′ = $\left[\begin{matrix}1.0\\0.0\\0.0\end{matrix}\right]$, $\left[\begin{matrix}0.0\\0.447213595499958\\0.894427190999916\end{matrix}\right]$, $\left[\begin{matrix}0.0\\-0.894427190999916\\0.447213595499958\end{matrix}\right]$.

Which is as Shankar obtains and is clearly orthonormal:

```julia
disp("⟨1|2⟩ = $(ℬ′[1]'|ℬ′[2]), ⟨2|2⟩ = $(ℬ′[2]'|ℬ′[2])." )
```

⟨1|2⟩ = 0.0, ⟨2|2⟩ = 0.9999999999999999.

###  *The Rotation Operators*

```julia
î = ket(1, 0, 0); ĵ = ket(0, 1, 0); k̂ = ket(0, 0, 1);

disp("""
    In $(L"$\mathbb{R}^3$") we have 3 main rotation operators about each of the axes:
    > $(TeX( R(θ, î) )) for rotations about the *x*-axis.<br> <br>
    > $(TeX( R(θ, ĵ) )) for rotations about the *y*-axis.<br> <br>
    > $(TeX( R(θ, k̂) )) for rotations about the *z*-axis.<br>
    """
    )
```

In $\mathbb{R}^3$ we have 3 main rotation operators about each of the axes:
> $\left[\begin{matrix}1 & 0 & 0\\0 & \cos{\left(θ \right)} & - \sin{\left(θ \right)}\\0 & \sin{\left(θ \right)} & \cos{\left(θ \right)}\end{matrix}\right]$ for rotations about the *x*-axis.

> $\left[\begin{matrix}\cos{\left(θ \right)} & 0 & - \sin{\left(θ \right)}\\0 & 1 & 0\\\sin{\left(θ \right)} & 0 & \cos{\left(θ \right)}\end{matrix}\right]$ for rotations about the *y*-axis.

> $\left[\begin{matrix}\cos{\left(θ \right)} & - \sin{\left(θ \right)} & 0\\\sin{\left(θ \right)} & \cos{\left(θ \right)} & 0\\0 & 0 & 1\end{matrix}\right]$ for rotations about the *z*-axis.

```julia
V⃗ = (α₁)î + (α₂)ĵ + (α₃)k̂;

RHS = (α₁)R(θ, ĵ)î + (α₂)R(θ, ĵ)ĵ + (α₃)R(θ, ĵ)k̂;    # Same as linear combination of operator on each ket

disp("""
    Given a generic vector V⃗ = $( TeX(V⃗) ), we use the linearity of the operator to obtain R(θ, ĵ)V⃗ by acting on the basis vectors:
    <center> $(L"R_\hat{\jmath}(\theta)\ket{V} = R_\hat{\jmath}(\theta)\vec{V} = \alpha_1 R_\hat{\jmath}(\theta)\hat\imath +
    \alpha_2 R_\hat{\jmath}(\theta)\hat\jmath + \alpha_3 R_\hat{\jmath}(\theta)\hat{k} =") $( TeX(RHS) ). </center>
    """
    )
```

Given a generic vector V⃗ = $\left[\begin{matrix}α₁\\α₂\\α₃\end{matrix}\right]$, we use the linearity of the operator to obtain R(θ, ĵ)V⃗ by acting on the basis vectors:
 $R_\hat{\jmath}(\theta)\ket{V} = R_\hat{\jmath}(\theta)\vec{V} = \alpha_1 R_\hat{\jmath}(\theta)\hat\imath +
    \alpha_2 R_\hat{\jmath}(\theta)\hat\jmath + \alpha_3 R_\hat{\jmath}(\theta)\hat{k} =$ $\left[\begin{matrix}α₁ \cos{\left(θ \right)} - α₃ \sin{\left(θ \right)}\\α₂\\α₁ \sin{\left(θ \right)} + α₃ \cos{\left(θ \right)}\end{matrix}\right]$.

####  ***Commutation***
Now, although rotations in 2D commute: (about the same axis in 3D)

```julia
RHS = R(θ₂, k̂)R(θ₁, k̂)R(θ₃, k̂) - R(θ₂, k̂)R(θ₃, k̂)R(θ₁, k̂)
disp("""
    <center> For example, $(L"R_\hat{k}(\theta_2)R_\hat{k}(\theta_1)R_\hat{k}(\theta_3)
    - R_\hat{k}(\theta_2)R_\hat{k}(\theta_3)R_\hat{k}(\theta_1) = ")
    $(TeX( RHS  |> simplify )).
    """)
```

 For example, $R_\hat{k}(\theta_2)R_\hat{k}(\theta_1)R_\hat{k}(\theta_3)
    - R_\hat{k}(\theta_2)R_\hat{k}(\theta_3)R_\hat{k}(\theta_1) = $
$\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]$.

Once we change the rotate about different axes, the we don't have commutativity any longer:

```julia
R(θ₂, k̂)R(θ₁, k̂)R(θ₃, ĵ) - R(θ₂, k̂)R(θ₃, ĵ)R(θ₁, k̂) .|> simplify
```

$\left[ \begin{array}{rrr}\left(1 - \cos{\left(θ₃ \right)}\right) \sin{\left(θ₁ \right)} \sin{\left(θ₂ \right)}&\left(\cos{\left(θ₃ \right)} - 1\right) \sin{\left(θ₁ \right)} \cos{\left(θ₂ \right)}&\left(\cos{\left(θ₂ \right)} - \cos{\left(θ₁ + θ₂ \right)}\right) \sin{\left(θ₃ \right)}\\\left(\cos{\left(θ₃ \right)} - 1\right) \sin{\left(θ₁ \right)} \cos{\left(θ₂ \right)}&\left(\cos{\left(θ₃ \right)} - 1\right) \sin{\left(θ₁ \right)} \sin{\left(θ₂ \right)}&\left(\sin{\left(θ₂ \right)} - \sin{\left(θ₁ + θ₂ \right)}\right) \sin{\left(θ₃ \right)}\\\left(1 - \cos{\left(θ₁ \right)}\right) \sin{\left(θ₃ \right)}&\sin{\left(θ₁ \right)} \sin{\left(θ₃ \right)}&0\end{array}\right]$

Thus we define the ***commutator*** between operators $\Omega$ and $\Lambda$,
$$
    \texttt{Com(Ω, Λ)} = [\Omega, \Lambda] = \Omega\Lambda - \Lambda\Omega.
$$
You can play around with the commutator on the rotation operators:

```julia
# Rotations about diff axes DO NOT commute:
RHS = Com( R(θ₁, î), R(θ₂, ĵ) );
disp("<center> $(L"\big[R_\hat{\imath}(\theta_1), R_\hat{\jmath}(\theta_2)\big] = ")
    $(TeX( RHS ))")
```

 $\big[R_\hat{\imath}(\theta_1), R_\hat{\jmath}(\theta_2)\big] = $
    $\left[\begin{matrix}0 & \sin{\left(θ₁ \right)} \sin{\left(θ₂ \right)} & \sin{\left(θ₂ \right)} \cos{\left(θ₁ \right)} - \sin{\left(θ₂ \right)}\\- \sin{\left(θ₁ \right)} \sin{\left(θ₂ \right)} & 0 & - \sin{\left(θ₁ \right)} \cos{\left(θ₂ \right)} + \sin{\left(θ₁ \right)}\\\sin{\left(θ₂ \right)} \cos{\left(θ₁ \right)} - \sin{\left(θ₂ \right)} & - \sin{\left(θ₁ \right)} \cos{\left(θ₂ \right)} + \sin{\left(θ₁ \right)} & 0\end{matrix}\right]$

```julia
# Rotations about the same axes DO commute
RHS = Com( R(θ₂, î), R(θ₁, î) );
disp("<center> $(L"\big[R_\hat{\imath}(\theta_1), R_\hat{\imath}(\theta_2)\big] = ")
    $(TeX( RHS )).")
```

 $\big[R_\hat{\imath}(\theta_1), R_\hat{\imath}(\theta_2)\big] = $
    $\left[\begin{matrix}0 & 0 & 0\\0 & 0 & 0\\0 & 0 & 0\end{matrix}\right]$.

Identity 1.5.10:
\begin{equation} [A, BC] = B[A,C] + [A,B]C. \end{equation}

```julia
LHS = Com( R(θ₁, î), R(θ₂, ĵ)R(θ₃, k̂) ) |> simplify;
RHS = R(θ₂, ĵ)Com( R(θ₁, î), R(θ₃, k̂) ) + Com( R(θ₁, î), R(θ₂, ĵ) )R(θ₃, k̂) |> simplify;

LHS == RHS # Testing their equality
```

    true

####  ***Matrix Elements***

To obtain the matrix elements of the operator $\Omega$ in the basis ℬ, we obtain all combinations
\begin{equation}
    \Omega_{ij} = \braket{i}{\Omega j} = \bra{i}\Omega\ket{j},
\end{equation}
where $\ket{i}$ labels the $i$-th basis ket.

```julia
# We take Ω to be a rotation operator here
ℬ = [î, ĵ, k̂]              # The standard basis
Rmat = mat( R(θ, î), ℬ )   # The mat routine defined in the source file calculates the matrix elements
disp("<center> Matrix rep for $(L"R_\hat{\imath}(\theta)") in the basis ℬ = $(TeX( Rmat )),")
```

 Matrix rep for $R_\hat{\imath}(\theta)$ in the basis ℬ = $\left[\begin{matrix}1 & 0 & 0\\0 & \cos{\left(θ \right)} & - \sin{\left(θ \right)}\\0 & \sin{\left(θ \right)} & \cos{\left(θ \right)}\end{matrix}\right]$,

so that for example,

```julia
disp("<center> $(L"$\bra{2}R\ket{3} = \bra{\hat{j}}R\ket{\hat{k}}$") = $(TeX( ĵ|(R(θ, î)k̂) ))")
```

 $\bra{2}R\ket{3} = \bra{\hat{j}}R\ket{\hat{k}}$ = $- \sin{\left(θ \right)}$

which are different under a different basis ℬ′:

```julia
ℬ′ = gramschmidt( [ ket(1.0,1.0,0.0), ket(-1.0, 1.0, 0.0) , k̂ ] ) # GramSchmidt always clutch with the bases: ℬ′ is orthonormal!
disp("""
    <center> Matrix rep for R(θ, î) in the basis ℬ′ = $(TeX( mat( R(θ, î), ℬ′ ) )), <br><br>
             $(L"$\bra{2'}R\ket{3'}= $") $(TeX( ℬ′[2]|(R(θ, î)ℬ′[3]) ))
    """)
```

 Matrix rep for R(θ, î) in the basis ℬ′ = $\left[\begin{matrix}0.5 \cos{\left(θ \right)} + 0.5 & 0.5 \cos{\left(θ \right)} - 0.5 & - 0.707106781186547 \sin{\left(θ \right)}\\0.5 \cos{\left(θ \right)} - 0.5 & 0.5 \cos{\left(θ \right)} + 0.5 & - 0.707106781186547 \sin{\left(θ \right)}\\0.707106781186547 \sin{\left(θ \right)} & 0.707106781186547 \sin{\left(θ \right)} & 1.0 \cos{\left(θ \right)}\end{matrix}\right]$,

         $\bra{2'}R\ket{3'}= $ $- 0.707106781186547 \sin{\left(θ \right)}$

Just like the coordinates of a vector change with a change of basis. Vectors, like operators, are abstract objects which *can* be expressed as arrays when setting a basis.

####  ***Unitarity***

Here we show the properties followed by unitary operators as it applies to the rotation operators which are actually orthogonal:

```julia
disp("<center> \$ R^{-1}R = R R^{-1} = \$ $(TeX( inv( R(θ, î) )R(θ, î) |> simplify )).") # Definition of orthogonality
```

 $ R^{-1}R = R R^{-1} = $ $\left[\begin{matrix}1 & 0 & 0\\0 & 1 & 0\\0 & 0 & 1\end{matrix}\right]$.

> **1. They preserve inner products:**
$$ \braket{ R_{\hat{n}}(\theta) V }{ R_{\hat{n}}(\theta) V } = \bra{V}\left(R_{\hat{n}}(\theta)\right)^T R_{\hat{n}}(\theta)\ket{V} = \braket{V}{V}.$$

```julia
# Acting on a generic vector:
V⃗ = (α₁)î + (α₂)ĵ + (α₃)k̂    # |V⟩
V⃖ = V⃗'                       # ⟨V| = (|V⟩)ᵀ

expr1 = (R(θ, î)V⃗)|(R(θ, î)V⃗) |> simplify; expr2 = ((V⃖)transpose(R(θ, î))R(θ, î)V⃗)[1] |> simplify; expr3 = (V⃖|V⃗);
disp("<center> $(L"\braket{R_\hat{i} V}{R_\hat{i}V}") =  $(TeX(expr1)) = $(TeX(expr2)) = $(TeX(expr3)) = $(L"\braket{V}{V}").")
```

 $\braket{R_\hat{i} V}{R_\hat{i}V}$ =  $α₁ α₁^{\dagger} + α₂ α₂^{\dagger} + α₃ α₃^{\dagger}$ = $α₁ α₁^{\dagger} + α₂ α₂^{\dagger} + α₃ α₃^{\dagger}$ = $α₁ α₁^{\dagger} + α₂ α₂^{\dagger} + α₃ α₃^{\dagger}$ = $\braket{V}{V}$.

> **2. Their determinant is of modulus 1:**

```julia
disp("<center> $(L"\det(R_\hat{i}) = ") $(TeX( det( R(θ, î) ) |> simplify )).")
```

 $\det(R_\hat{i}) = $ $1$.

> **3. They should not change the trace of operators.**
 *Exercise 1.6.6 in Shankar*: We will use the operator defined there,
$$ U = \frac{1}{\sqrt{2}}\begin{bmatrix} 1 & i \\ i & 1 \end{bmatrix}, $$ to show this property holds using two different but equivalent points of view,

```julia
# Defined in Ex 1.6.6
U = (1/sqrt(2)) * SMatrix{2, 2, Sym, 4}(1.0, 1.0im, 1.0im, 1.0)

# Define the standard 2D basis
ℬ²ᴰ = [ ket(1, 0), ket(0, 1) ]

# Define the rotated 2D basis (about k̂)
idx = SVector(1,2)
ℬ²ᴰ′ = [ R(θ, k̂)[idx,idx]ket(1.0,0.0), R(θ, k̂)[idx,idx]ket(0.0,1.0) ]

disp("""
    >> **A. Active Transformation**:<br> Given \$U\$ we show its trace
    does not change after a <u>rotation of the basis</u>:
    <center> $(L"\tr(U) =\sum \langle i|U|i\rangle = ") $(TeX( tr(mat( U, ℬ²ᴰ )) )) <br>
    $(L"\tr(U) = \sum \langle  R_{\hat{n}}(\theta) i|U| R_{\hat{n}}(\theta) i\rangle = ") $(TeX( tr(mat( U, ℬ²ᴰ′ )) |> simplify )).
    """)
```

>> **A. Active Transformation**:
 Given $U$ we show its trace
does not change after a rotation of the basis:
 $\tr(U) =\sum \langle i|U|i\rangle = $ $1.41421356237309$

$\tr(U) = \sum \langle  R_{\hat{n}}(\theta) i|U| R_{\hat{n}}(\theta) i\rangle = $ $1.41421356237309$.

```julia
disp("""
    >> **B. Passive Transformation**:<br> Given \$U\$ we show its trace
    does not change after a <u>rotation of the operator</u>:
    <center> $(L"\tr(U) =\sum \langle i|U|i\rangle = ") $(TeX( tr(mat( U, ℬ²ᴰ )) )) <br>
    $(L"\tr\left(R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)\right)
    =\sum \langle i| R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)| i\rangle = ")
    $(TeX( tr(mat( R(θ, k̂)[idx,idx]'*U*R(θ, k̂)[idx,idx], ℬ²ᴰ )) |> simplify )).
    """)
```

>> **B. Passive Transformation**:
 Given $U$ we show its trace
does not change after a rotation of the operator:
 $\tr(U) =\sum \langle i|U|i\rangle = $ $1.41421356237309$

$\tr\left(R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)\right)
    =\sum \langle i| R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)| i\rangle = $
$1.41421356237309$.

>**4. The determinant post-unitary transformations does not change:**

```julia
disp("""<center> $(L"U \longrightarrow R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)") <br>
    $(L"\det\left(R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)\right) - \det(U) = ")
    $(TeX( det(R(θ, k̂)[idx,idx]'*U*R(θ, k̂)[idx,idx])  - det(U) |> simplify )).""")
```

 $U \longrightarrow R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)$

$\det\left(R_{\hat{n}}(\theta)^\dagger U R_{\hat{n}}(\theta)\right) - \det(U) = $
$0$.

###  *Projection Operators*

We define
$$ \mathbb{P}(\ket{i}) = \ket{i}\bra{i}, $$
and as we can see below when applied to a generic ket $\ket{V}$, it gives you *how much of $\ket{V}$ is along $\ket{i}$*:

```julia
V⃗ = (α₁)î + (α₂)ĵ + (α₃)k̂
disp("<center> $(L"\mathbb{P}(\hat{k})\vec{V} = \ket{\hat{k}}\braket{\hat{k}}{V} = ") $(TeX( ℙ(k̂)V⃗ )).")
```

 $\mathbb{P}(\hat{k})\vec{V} = \ket{\hat{k}}\braket{\hat{k}}{V} = $ $\left[\begin{matrix}0\\0\\α₃\end{matrix}\right]$.

If we add all projection operators for a basis we get the identity operator as expected:

```julia
ℙ(ℬ[1]) + ℙ(ℬ[2]) + ℙ(ℬ[3]) .|> Sym
```

$\left[ \begin{array}{rrr}1&0&0\\0&1&0\\0&0&1\end{array}\right]$

###  *The Eigenvalue Problem*

We start by defining a generic 2D operator (it is defined by its matrix representation under the standard basis):

```julia
Ω = @SMatrix[
    Ω₁₁  Ω₁₂ ;
    Ω₂₁  Ω₂₂ ;
    ]
```

$\left[ \begin{array}{rr}Ω₁₁&Ω₁₂\\Ω₂₁&Ω₂₂\end{array}\right]$

which defines the *characteristic equation* in steps:

```julia
# Define the standard 2D basis
ℬ²ᴰ = [ ket(1, 0), ket(0, 1) ]
# Define the characteristic matrix/polynomial
charmat = mat( Ω - (ω)I, ℬ²ᴰ )
charpol = det( charmat )

disp("""
    > 1. *characteristic matrix*: <br>
    > <center> $(L"\Omega - \omega\mathbf{I} = ") $(TeX( charmat )) </center>
    > 2. *characteristic polynomial*: <br>
    > <center> $(L"\det(\Omega - \omega\mathbf{I}) = ") $(TeX( charpol )) </center>
    > 3. *characteristic equation*: <br>
    > <center> $(TeX( charpol |> expand )) = 0 </center>
    """)
```

> 1. *characteristic matrix*:

>  $\Omega - \omega\mathbf{I} = $ $\left[\begin{matrix}Ω₁₁ - ω & Ω₁₂\\Ω₂₁ & Ω₂₂ - ω\end{matrix}\right]$
> 2. *characteristic polynomial*:

>  $\det(\Omega - \omega\mathbf{I}) = $ $- Ω₁₂ Ω₂₁ + \left(Ω₁₁ - ω\right) \left(Ω₂₂ - ω\right)$
> 3. *characteristic equation*:

>  $Ω₁₁ Ω₂₂ - Ω₁₁ ω - Ω₁₂ Ω₂₁ - Ω₂₂ ω + ω^{2}$ = 0

Using `Sympy` we can solve the latter for $\omega$ to obtain the set of eigenvalues for the operator:

```julia
disp("<center> $(TeX( charpol |> expand )) = 0 $(L"\implies \omega = ") $(TeX( solve(charpol, ω) ))")
```

 $Ω₁₁ Ω₂₂ - Ω₁₁ ω - Ω₁₂ Ω₂₁ - Ω₂₂ ω + ω^{2}$ = 0 $\implies \omega = $ $\left[\begin{matrix}\frac{Ω₁₁}{2} + \frac{Ω₂₂}{2} - \frac{\sqrt{Ω₁₁^{2} - 2 Ω₁₁ Ω₂₂ + 4 Ω₁₂ Ω₂₁ + Ω₂₂^{2}}}{2}\\\frac{Ω₁₁}{2} + \frac{Ω₂₂}{2} + \frac{\sqrt{Ω₁₁^{2} - 2 Ω₁₁ Ω₂₂ + 4 Ω₁₂ Ω₂₁ + Ω₂₂^{2}}}{2}\end{matrix}\right]$

the `eigvals` function does all these steps for us:

```julia
eigvals(mat(Ω, ℬ²ᴰ) |> Array)
```

$\left[ \begin{array}{r}\frac{Ω₁₁}{2} + \frac{Ω₂₂}{2} - \frac{\sqrt{Ω₁₁^{2} - 2 Ω₁₁ Ω₂₂ + 4 Ω₁₂ Ω₂₁ + Ω₂₂^{2}}}{2}\\\frac{Ω₁₁}{2} + \frac{Ω₂₂}{2} + \frac{\sqrt{Ω₁₁^{2} - 2 Ω₁₁ Ω₂₂ + 4 Ω₁₂ Ω₂₁ + Ω₂₂^{2}}}{2}\end{array} \right]$

notice that you can say ***eigenvalues of the operator*** because the set of eigenvalues does not change with a change in basis:

```julia
ℬ²ᴰ′ = [ ket(-1/sqrt(2), 1/sqrt(2)), ket(1/sqrt(2), 1/sqrt(2)) ]
mat(Ω, ℬ²ᴰ′) |> Array |> eigvals    # notice the beautiful Julia syntax
```

$\left[ \begin{array}{r}0.5 Ω₁₁ + 0.5 Ω₂₂ - 1.0 \sqrt{0.25 Ω₁₁^{2} - 0.5 Ω₁₁ Ω₂₂ + 1.0 Ω₁₂ Ω₂₁ + 0.25 Ω₂₂^{2}}\\0.5 Ω₁₁ + 0.5 Ω₂₂ + 1.0 \sqrt{0.25 Ω₁₁^{2} - 0.5 Ω₁₁ Ω₂₂ + 1.0 Ω₁₂ Ω₂₁ + 0.25 Ω₂₂^{2}}\end{array} \right]$

####  *Example 1.8.4*:

Solving for the eigenset (eigenvalues together eigenvectors) of the rotation operator $R_{\hat{\imath}}\left(\dfrac{\pi}{2}\right)$.

```julia
ℬ³ᴰ = [ î, ĵ, k̂ ]    # The standard basis in 3D
ωR =  eigvals( mat(R(π/2,î), ℬ³ᴰ) |> Array );    # obtain the eigenvalues of the operator
disp("""
    The eigenvalues of $(L"R_\hat{\imath}(\pi/2)") with matrix representation $(TeX( mat(R(π/2,î), ℬ³ᴰ) .|> Sym) ) in the standard 3D basis
    are given by the set $(TeX( [eigvalsRot[i] for i ∈ 1:length(ωR)])), where \$10^{-17}\$ is a roundoff to 0 here.
    """)
```

The eigenvalues of $R_\hat{\imath}(\pi/2)$ with matrix representation $\left[\begin{matrix}1.0 & 0.0 & 0.0\\0.0 & 6.12323399573677 \cdot 10^{-17} & -1.0\\0.0 & 1.0 & 6.12323399573677 \cdot 10^{-17}\end{matrix}\right]$ in the standard 3D basis
are given by the set $\mathtt{\text{[6.123234e-17-1.j 6.123234e-17+1.j 1.000000e+00+0.j]}}$, where $10^{-17}$ is a roundoff to 0 here.

To solve for the eigenvectors we must solve the equation
\begin{equation}
    \big(R_\hat\imath(\pi/2) - \omega_i\mathbf{I}\big)\ket{i} = 0,
\end{equation}
for the $i$-th ket $\ket{i}$ given $\omega_i$, the $i$-th eigenvalue.

```julia
charMat = mat(R(π/2,î), ℬ³ᴰ) - ωR[1]*I;
v⃗₁ = ket( x₁, x₂, x₃ );
disp("<center> For the eigenvalue $(TeX( ωR[1] )) we must solve $(TeX( charMat * v⃗₁ ) ) $(L" = \begin{bmatrix} 0 \\ 0 \\ 0 \end{bmatrix}").")
```

 For the eigenvalue $\mathtt{\text{(6.123233995736766e-17-1j)}}$ we must solve $\left[\begin{matrix}x₁ \left(1.0 + 1.0 i\right)\\1.0 i x₂ - 1.0 x₃\\1.0 x₂ + 1.0 i x₃\end{matrix}\right]$ $ = \begin{bmatrix} 0 \\ 0 \\ 0 \end{bmatrix}$.

```julia
solns = solve.(charMat * v⃗₁) .|> Sym;
disp("<center> The solution of the system is given by $(TeX( solns )), so that, $(L" \ket{1} = \begin{bmatrix} 0 \\ -i x_3 \\ x_3 \end{bmatrix}") for any \$x_3\$.")
```

 The solution of the system is given by $\left[\begin{matrix}0.0\\\left[ \left\{ x₂ : - i x₃\right\}\right]\\\left[ \left\{ x₂ : - i x₃\right\}\right]\end{matrix}\right]$, so that, $ \ket{1} = \begin{bmatrix} 0 \\ -i x_3 \\ x_3 \end{bmatrix}$ for any $x_3$.

To define the eigenvector then, we let $x_3=1$ and normalize our vector:

```julia
v⃗₁ = ket( 0, -1*im , 1 );
v⃗₁ = uvec( v⃗₁ )
```

$\left[ \begin{array}{r}0\\- 0.707106781186547 i\\0.707106781186547\end{array}\right]$

Repeating the procedure for the rest of the eigenvalues:

```julia
charMat = mat(R(π/2,î), ℬ³ᴰ) - ωR[2]*I;
v⃗₂ = ket( x₁, x₂, x₃ );
solns_2 = solve.(charMat * v⃗₂) .|> Sym;

charMat = mat(R(π/2,î), ℬ³ᴰ) - ωR[3]*I;
v⃗₃ = ket( x₁, x₂, x₃ );
solns_3 = solve.(charMat * v⃗₃) .|> Sym;

disp("""
    For $(TeX( ωR[2] )) we get a solution $(TeX( solns_2 )), for $(TeX( ωR[3] )) we get $(TeX( solns_3 )).
    This implies we can take $(L"\ket{2} =  \begin{bmatrix} 0 \\ i \\ 1 \end{bmatrix} \text{and} \ket{3} =  \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix}.")
    """)
```

For $\mathtt{\text{(6.123233995736766e-17+1j)}}$ we get a solution $\left[\begin{matrix}0.0\\\left[ \left\{ x₂ : i x₃\right\}\right]\\\left[ \left\{ x₂ : i x₃\right\}\right]\end{matrix}\right]$, for $\mathtt{\text{(1+0j)}}$ we get $\left[\begin{matrix}\left[ \right]\\\left[ \left\{ x₂ : - x₃\right\}\right]\\\left[ \left\{ x₂ : x₃\right\}\right]\end{matrix}\right]$.
This implies we can take $\ket{2} =  \begin{bmatrix} 0 \\ i \\ 1 \end{bmatrix} \text{and} \ket{3} =  \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix}$

After normalizing we finally obtain the eigenset of the rotation operator

```julia
v⃗₂ = ket( 0, 1*im , 1 );  v⃗₃ = ket( 1, 0 , 0 );
v⃗₂ = uvec( v⃗₂ );          v⃗₃ = uvec( v⃗₃ );
disp("""
    <center> $(TeX(ωR[1])), $(TeX(v⃗₁)), <br> $(TeX(ωR[2])), $(TeX(v⃗₂)), <br> $(TeX(ωR[3])), $(TeX(v⃗₃)).
    """)
```

 $\mathtt{\text{(6.123233995736766e-17-1j)}}$, $\left[\begin{matrix}0\\- 0.707106781186547 i\\0.707106781186547\end{matrix}\right]$,
 $\mathtt{\text{(6.123233995736766e-17+1j)}}$, $\left[\begin{matrix}0\\0.707106781186547 i\\0.707106781186547\end{matrix}\right]$,
 $\mathtt{\text{(1+0j)}}$, $\left[\begin{matrix}1.0\\0.0\\0.0\end{matrix}\right]$.

```julia
ℬᴿⁱ = [ v⃗₁, v⃗₂, v⃗₃ ];
newmat = mat( R(π/2, î) .|> Complex, ℬᴿⁱ ) .|> Sym;
disp("""
    In this eigenset we see that just like Theorem 10 promised, the Hermitian operator (here the rotation)
    is diagonal in its eigenbasis and the eigenvalues are along the diagonal: $(TeX( newmat )).
    """)
```

In this eigenset we see that just like Theorem 10 promised, the Hermitian operator (here the rotation)
is diagonal in its eigenbasis and the eigenvalues are along the diagonal: $\left[\begin{matrix}6.12323399573676 \cdot 10^{-17} - 1.0 i & 0 & 0\\0 & 6.12323399573676 \cdot 10^{-17} + 1.0 i & 0\\0 & 0 & 1.0\end{matrix}\right]$.

####  *Example 1.8.5*:
Repeat above for
\begin{equation*}
    \Omega = \begin{bmatrix} 1 & 0 & 1 \\ 0 & 2 & 0 \\ 1 & 0 & 1\\ \end{bmatrix},
\end{equation*}
however we use our `Sympy` tools to simplify the process:

```julia
Ω = @SMatrix[
    1 0 1;
    0 2 0;
    1 0 1;
    ];
ωΩ = eigvals( Ω );  # Get the eigenvalues
eigvΩ = eigvecs( Ω .|> Float64 ); # Get the eigenvectors
eigvΩ = [ eigvΩ[:,i] for i∈1:3 ];
ℬ′ = [ ket(vec) for vec in eigvΩ ]; # Form a basis
Ω′ = mat( Ω, ℬ′ ) .|> Sym; # The matrix rep under the eigenbasis

disp("""
    Ω has eigenvalues $(TeX(ωΩ)) with corresponding eigenvectors $(TeX([ ℬ′[i] .|> Sym for i∈1:3 ] |> Sym)). You can see the degenerate subspace perpendicular to the last eigenvector.
    """)
```

Ω has eigenvalues $\left[ 0.0, \  2.0, \  2.0\right]$ with corresponding eigenvectors $\left[ \left[\begin{matrix}0.707106781186547\\0.0\\-0.707106781186548\end{matrix}\right], \  \left[\begin{matrix}-0.707106781186548\\0.0\\-0.707106781186547\end{matrix}\right], \  \left[\begin{matrix}0.0\\-1.0\\0.0\end{matrix}\right]\right]$. You can see the degenerate subspace perpendicular to the last eigenvector.

####  *Exercise 1.8.1*:

\begin{equation*}
    \Omega = \begin{bmatrix} 1 & 3 & 1 \\ 0 & 2 & 0 \\ 0 & 1 & 4\\ \end{bmatrix},
\end{equation*}

```julia
Ω = @SMatrix[
    1 3 1;
    0 2 0;
    0 1 4;
    ];
ωΩ = eigvals( Ω |> Array );  # Get the eigenvalues
eigvΩ = eigvecs( Ω .|> Float64 ); # Get the eigenvectors
eigvΩ = [ eigvΩ[:,i] for i∈1:3 ];
ℬ′ = [ ket(vec) for vec in eigvΩ ]; # Form a basis
Ω′ = mat( Ω, ℬ′ ) .|> Sym; # The matrix rep under the eigenbasis

disp("""
    Ω has eigenvalues $(TeX(ωΩ)) with corresponding eigenvectors $(TeX([ ℬ′[i] .|> Sym for i∈1:3 ] |> Sym)). Which is clearly NOT orthogonal since Ω is not Hermitian.
    """)
```

Ω has eigenvalues $\mathtt{\text{[1. 2. 4.]}}$ with corresponding eigenvectors $\left[ \left[\begin{matrix}1.0\\0.0\\0.0\end{matrix}\right], \  \left[\begin{matrix}0.912870929175277\\0.365148371670111\\-0.182574185835055\end{matrix}\right], \  \left[\begin{matrix}0.316227766016838\\0.0\\0.948683298050514\end{matrix}\right]\right]$. Which is clearly NOT orthogonal since Ω is not Hermitian.

####  *Exercise 1.8.2*:

\begin{equation*}
    \Omega = \begin{bmatrix} 0 & 0 & 1 \\ 0 & 0 & 0 \\ 1 & 0 & 0\\ \end{bmatrix},
\end{equation*}

```julia
Ω = @SMatrix[
    0 0 1;
    0 0 0;
    1 0 0;
    ];
ωΩ = eigvals( Ω |> Array );  # Get the eigenvalues
eigvΩ = eigvecs( Ω .|> Float64 ); # Get the eigenvectors
eigvΩ = [ eigvΩ[:,i] for i∈1:3 ];
ℬ′ = [ ket(vec) for vec in eigvΩ ]; # Form a basis
Ω′ = mat( Ω, ℬ′ ) .|> Sym; # The matrix rep under the eigenbasis

U = eigvecs( Ω .|> Float64 );

disp("""
    Ω has eigenvalues $(TeX(ωΩ)) with corresponding eigenvectors $(TeX([ ℬ′[i] .|> Sym for i∈1:3 ] |> Sym)).
    These are orthogonal since Ω is Hermitian in this case. Furthermore as promised, if we let $(L"U") be the matrix built
    out of Ω's eigenvectors, the product $(L"U^\dagger \Omega U") is diagonal, $(TeX(U'*Ω*U .|> Sym)).
    """)
```

Ω has eigenvalues $\mathtt{\text{[-1.  0.  1.]}}$ with corresponding eigenvectors $\left[ \left[\begin{matrix}0.707106781186547\\0.0\\-0.707106781186548\end{matrix}\right], \  \left[\begin{matrix}0.0\\-1.0\\0.0\end{matrix}\right], \  \left[\begin{matrix}-0.707106781186548\\0.0\\-0.707106781186547\end{matrix}\right]\right]$.
These are orthogonal since Ω is Hermitian in this case. Furthermore as promised, if we let $U$ be the matrix built
out of Ω's eigenvectors, the product $U^\dagger \Omega U$ is diagonal, $\left[\begin{matrix}-1.0 & 0.0 & 2.22044604925031 \cdot 10^{-16}\\0.0 & 0.0 & 0.0\\2.22044604925031 \cdot 10^{-16} & 0.0 & 1.0\end{matrix}\right]$.

####  *Exercise 1.8.5*:

\begin{equation*}
    \Omega = \begin{bmatrix} \cos\theta & \sin\theta \\ -\sin\theta & \cos\theta \\ \end{bmatrix},
\end{equation*}

```julia
Ω = @SMatrix[
    cos(θ) sin(θ);
    -sin(θ) cos(θ);
    ];
unitary = Ω'Ω .|> simplify;
charMat = Ω - ω*I;
eigs = solve( det(charMat), ω );

disp("We have thus checked that Ω is unitary, $(L"U^\dagger U = ") $(TeX( unitary )) with eigenvalues $(TeX( eigs )).")
```

We have thus checked that Ω is unitary, $U^\dagger U = $ $\left[\begin{matrix}1 & 0\\0 & 1\end{matrix}\right]$ with eigenvalues $\left[\begin{matrix}e^{- i θ}\\e^{i θ}\end{matrix}\right]$.

To solve for the eigenvectors we will get the first one through the usual method,

```julia
charMat = Ω - eigs[2]*I;
v⃗₂ = ket( x₁, x₂ );
solns = solve.(charMat * v⃗₂, x₁);
v⃗₂ = ket( -im, 1 ) |> uvec;

disp("For eigenvalue $(TeX( eigs[2] )) we get $(L"x_1 = ") $(TeX( solns[1][1])), so that $(L"\vec{v}_2 = \begin{bmatrix} -i \\ 1\end{bmatrix}"), which after normalization becomes $(TeX( v⃗₂ )).")
```

For eigenvalue $e^{i θ}$ we get $x_1 = $ $- i x₂$, so that $\vec{v}_2 = \begin{bmatrix} -i \\ 1\end{bmatrix}$, which after normalization becomes $\left[\begin{matrix}- 0.707106781186547 i\\0.707106781186547\end{matrix}\right]$.

Now since we know $\vec{v}_1$ is perpendicular to $\vec{v}_2$ because $\Omega$ is Hermitian, we can guess a form for it:

```julia
v⃗₁ = ket( -v⃗₂'[2], v⃗₂'[1] );
disp("Our guess $(L"\vec{v}_1 = ") $(TeX( v⃗₁ )), is clearly orthogonal: $(L"\braket{1}{2} = \vec{v}_1^\dagger \cdot \vec{v}_2 = ") $(TeX( v⃗₁|v⃗₂ )).")
```

Our guess $\vec{v}_1 = $ $\left[\begin{matrix}-0.707106781186547\\0.707106781186547 i\end{matrix}\right]$, is clearly orthogonal: $\braket{1}{2} = \vec{v}_1^\dagger \cdot \vec{v}_2 = $ $0$.

```julia
U = [v⃗₁ v⃗₂];
Ω′= U' * Ω * U; # UᵀΩU
disp("Placing the eigenvectors as columns in an operator $(L"U = ") $(TeX( U )), so that as promised, $(L"\Omega' = U^\dagger \Omega U = ") $(TeX( Ω′ .|> simplify )) is diagonal with its eigenvalues.")
```

Placing the eigenvectors as columns in an operator $U = $ $\left[\begin{matrix}-0.707106781186547 & - 0.707106781186547 i\\0.707106781186547 i & 0.707106781186547\end{matrix}\right]$, so that as promised, $\Omega' = U^\dagger \Omega U = $ $\left[\begin{matrix}1.0 e^{- i θ} & 0\\0 & 1.0 e^{i θ}\end{matrix}\right]$ is diagonal.


***************************************************************

***************************************************************
##$\text{Visualization of Consecutive and Parallel Chemical Reaction Kinetics}$

####$\text{Notebook by: } Abhiraj\ Mengade$

```python
#1.1 Imports
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import solve_ivp
```

#Cosecutive Reaction
The Reaction:
$\text{A} \overset{k_1}{\longrightarrow} \text{B} \overset{k_2}{\longrightarrow} \text{C}$

Reaction Rates:

$\dfrac{d \left[ \text{A} \right]}{dt} = -k_1 \left[ \text{A} \right]$

$\dfrac{d \left[ \text{B} \right]}{dt} = k_1 \left[ \text{A} \right] - k_2 \left[ \text{B} \right]$

$\dfrac{d \left[ \text{C} \right]}{dt} = k_2 \left[ \text{B} \right]$

```python
#2.1 Defining the Equations of Consecutive Reactions
#y=[A,B,C], K=[k1,k2]
def f(t, y, k):
    dydt =[-k[0]*y[0],k[0]*y[0]-k[1]*y[1] , k[1]*y[1]]
    return dydt
```

```python
#2.2 Define time spans, initial values, and constants
tspan = np.linspace(0, 10, 100)
yinit = [5, 1, 0]
k = [0.8, 0.6]

```

```python
#2.3 Solving differential equation
sol = solve_ivp(lambda t, y: f(t, y, k),
                [tspan[0], tspan[-1]], yinit, t_eval=tspan, rtol = 1e-5)
```

###$\text{Equations attained after solving DE:}$

$\left[ \text{A} \right] = \left[ \text{A} \right]_0 e^{-k_1 t}$

$\left[ \text{B} \right] = \dfrac{k_1 \left[ \text{A} \right]_0}{k_2 - k_1} \left( e^{-k_1 t} - e^{-k_2 t} \right)$

$\left[ \text{C} \right] = \left[ \text{A} \right]_0 \left[ 1 + \dfrac{1}{k_1 - k_2} \left( k_2 e^{-k_1 t} - k_1 e^{-k_2 t} \right) \right]$

```python
#2.4 Plotting the Graphs
Labels=["A","B","C"]
plt.figure(figsize=(10,5))
for i in range(sol.y.shape[0]):
    plt.plot(sol.t, sol.y[i], label=f'${Labels[i]}(t)$')
plt.title("Consecutive Reaction Kinetics")
plt.xlabel('$Time$')
plt.ylabel('$Concentration$')
plt.legend()
plt.show()
```

***************************************************************

***************************************************************

#Parallel Reaction
The Reaction:

$\begin{align} \text{A} &\overset{k_1}{\rightarrow} \text{B} \\ \text{A} &\overset{k_2}{\rightarrow} \text{C} \end{align}$

Reaction Rates:

$\dfrac{d \left[ \text{A} \right]}{dt} = -k_1 \left[ \text{A} \right] - k_2 \left[ \text{A} \right] = - \left( k_1 + k_2 \right) \left[ \text{A} \right]$

$\dfrac{d \left[ \text{B} \right]}{dt} = k_1 \left[ \text{A} \right]$

$\dfrac{d \left[ \text{C} \right]}{dt} = k_2 \left[ \text{A} \right]$

```python
#3.1 Defining the Equations of Parallel Reactions
#y=[A,B,C], K=[k1,k2]
def f(t, y, k):
    dydt =[-(k[0]+c[1])*y[0],k[0]*y[0], k[1]*y[0]]
    return dydt
```

```python
#3.2 Define time spans, initial values, and constants (Parallel Reaction)
tspan = np.linspace(0, 10, 100)
yinit = [19, 1, 0]
k = [0.8, 0.6]
```

```python
#3.3 Solving differential equation
sol = solve_ivp(lambda t, y: f(t, y, k),
                [tspan[0], tspan[-1]], yinit, t_eval=tspan, rtol = 1e-5)
```

###$\text{Equations attained after solving DE:}$

$\left[ \text{A} \right] = \left[ \text{A} \right]_0 e^{-\left( k_1 + k_2 \right) t}$

$\left[ \text{B} \right] = \dfrac{k_1 \left[ \text{A} \right]_0}{k_1 + k_2} \left( 1 - e^{-\left( k_1 + k_2 \right) t} \right)$

$\left[ \text{C} \right] = \dfrac{k_2 \left[ \text{A} \right]_0}{k_1 + k_2} \left( 1 - e^{-\left( k_1 + k_2 \right) t} \right) $

```python
#3.4 Plotting the Graphs
Labels=["A","B","C"]
plt.figure(figsize=(10,5))
for i in range(sol.y.shape[0]):
    plt.plot(sol.t, sol.y[i], label=f'${Labels[i]}(t)$')
plt.title("Parallel Reaction Kinetics")
plt.xlabel('$Time$')
plt.ylabel('$Concentration$')
plt.legend()
plt.show()
```

##$References:$
More Complex Reactions. (2019, May 11). Retrieved September 1, 2021, from https://chem.libretexts.org/@go/page/41344

Science & Computation/1. Chemical Kinetics/Consecutive_and_Parallel_Chemical_Kinetics.ipynb