A microstate is a list of all the states every particle in the system can be in. A configuration is a list of how many particles are in each microstate. The weight of a configuration is the number of unique microstates that are possible within a particular configuration.

Lagrange multipliers were used because we were taking an optimization with a constraint. In particular, we needed to constrain the number of particles and total energy so that dn_i can be treated independently.

import numpy as np
nlevels = 3
microstates = 0
for p1 in range(nlevels):
for p2 in range(nlevels):
iconfig = np.zeros(nlevels)
iconfig[p1] += 1
iconfig[p2] += 1
if iconfig[p1] == 2:
microstates += 1
else:
microstates += 2
print('%s' % str(iconfig))
print('Number of microstates:', microstates)

```
[2. 0. 0.]
[1. 1. 0.]
[1. 0. 1.]
[1. 1. 0.]
[0. 2. 0.]
[0. 1. 1.]
[1. 0. 1.]
[0. 1. 1.]
[0. 0. 2.]
Number of microstates: 15
```