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)