Project: s41467-025-57007-1 | Function: H (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Calculates the Hamiltonian (total energy) of the Potts model system with hidden states. Takes spin configuration and adjacency matrix, returns energy value using Ising-like interaction formula normalized by network connectivity.

**KEY TERMS:** {
  "spin": "s_i (spin states)",
  "adj": "A_ij (adjacency matrix)",
  "J": "J (coupling constant)",
  "Ham": "H (Hamiltonian energy)",
  "spinE": "effective spins",
  "eff": "hidden state processing"
}

**CONTEXT CODE:**     Spins=np.random.choice(states, size=n, p=pSpins)
    return Spins

#Randomly initialize the spins of the particles all to +1
def initCold(n,nhid=1):
    return initSpin(n,nhid,pSpins=[1,0])

#Randomly initialize the spins of the particles to [-1,1] with equal probability (i.e., no hidden states)
def initHot(n,nhid=1):
    return initSpin(n,nhid,pSpins=[0.5, 0.5])

#Flips one spin. If not specified, it flips random spin.
def spinFlip(spin,nhid=1,ind=None):
    hidstates=[i for i in range(0,2*(nhid),2)]
    states=[1,-1]+hidstates
    spinNew=np.copy(spin)
    if ind is None:
        ind=np.random.randint(len(spin))
    curspin=spin[ind]
    spinNew[ind]=np.random.choice([x for x in states if x!=curspin])
    return(spinNew)

#count the number of spins corresponding to each state
def countSpins(spin,nhid):
    hidstates=[i for i in range(0,2*(nhid),2)]
    states=[1,-1]+hidstates
    return([list(spin).count(x) for x in states])


#Randomly initialize the underlying network. The function gives the (lower-triangle) adjacency matrix. Alternatively, it is possible to use any (lower-triangle) adjacency matrix
def initNetw(siz,probl):
    U = np.random.choice([0, 1], size=(siz,siz), p=[1-probl, probl])
    S = np.tril(U)
    S[np.diag_indices_from(S)]=0
    return S

#Calculates the matrix for matrix multiplication. It makes the lower-triangular matrix symmetrical 
#and makes the links between and to molecules equal to zero, so that they do not contribute to the Hamiltonian 
def sym(adj):
    return((adj+adj.T)%2)

#Returns the effective spin vector. Since the hidden states are represented as 0,2,4,etc., it assigns the effective spin to all hidden states to zero.
def eff(spin):
    spinE=np.copy(spin)
    spinE[spinE % 2 == 0] = 0
    return(spinE)

#Calculates the Hamiltonian of the system. Spins of particles in molecule state do not contribute.
#J is the coupling constant, h is the external field, 
#and n is another couling constant that is meant to compensate for different sizes
def H(spin,adj,J=1,h=0,n=None):
    """
    Calculates the Hamiltonian (total energy) of the Potts model system with hidden states.

    This function computes the energy using the Ising-like interaction formula:
    H(s)=-J/k∑_{i≠j}A_{ij}s_i s_j, where k is the average degree of the underlying
    network, and A_ij is the adjacency matrix. The Hamiltonian is normalized by k
    so that the Currie–Weiss temperature without molecule formation is independent of k.

    Args:
        spin: Spin configuration array including hidden states
        adj: Adjacency matrix A_ij representing network connections
        J: Coupling constant (default: 1)
        h: External field strength (default: 0)
        n: Network connectivity normalization factor (default: computed from adjacency)

    Returns:
        float: Hamiltonian energy value of the system

    Raises:
        NotImplementedError: Function has been masked for testing purposes
    """
    raise NotImplementedError("This function has been masked for testing purposes")


#Returns total magnetization (with making hidden spins equal to zero
def mag(spin):
    return(eff(spin).sum())


#Tests whether to accept a new state. If the Hamiltonian has decreased, always accept, otherwise use the MC formula
def MCcond(oldspin,newspin,adj,T,J=1,h=0,n=None):
    HamOld=H(oldspin,adj,J,h,n)
    HamNew=H(newspin,adj,J,h,n)
    if HamNew <= HamOld:
        return(True)
    else:
        r=np.exp(-1/T*(HamNew-HamOld))
        u=np.random.random()
        #print("probability: {}".format(r))
        if u<=r:
            return(True)
        else:
            return(False)

#initialize the system
def MCinit(npart,init,nhid=1,avdeg=None):
    #initialization of spins
    if init=="hot":
        spinN=initHot(npart,nhid)
    elif init=="cold":
        spinN=initCold(npart,nhid)
    else:
        pup=np.random.random()
        spinN=initSpin(npart,nhid,pSpins=[pup,1-pup])
        
#initialization of interaction matrix
    if avdeg is None:
        avdeg=npart-1
    adjN=initNetw(npart,avdeg/(npart-1))
    return(spinN,adjN)



#Make a MC step. Try to flip a spin and accept it with the MH probability. spin and adj are spin vector and adjacency matrix. 
#nhid is the number of hidden states, q does not have a purpose now, T is temperature, h is external field, J and n are coupling constants 
#quiet is for checking purposes (if false it prints whether t) 
def makeMove(spin,adj,T,nhid=1,q=1,J=1,h=0,n=None,quiet=True):
    spinOld=np.copy(spin)
    spinNew=spinFlip(spinOld,nhid)
    if MCcond(spinOld,spinNew,adj,T,J,h=0,n=None):
        if not quiet:
            print("accepted")
            print(H(spin,adj))
        return(spinNew) 
    else:
        if not quiet:
            print("rejected")
        return(spinOld)

#MC simulation of the whole trajectory. Initialize the system and then run the simulation for nSteps steps. 
def MCsimulation(T,npart,nSteps,init,nhid=1,avdeg=None,q=1,J=1,h=0,n=None,quiet=True):
   
    #initialization
    (spinN,adjN) = MCinit(npart,init,nhid,avdeg)

    #initial state
    statetraj=countSpins(spinN,nhid)

    #MC step
    t=0
    while t<nSteps:
        spinN = makeMove(spinN,adjN,T,nhid,q,J,h,n,quiet)
        statetraj=np.vstack([statetraj,countSpins(spinN,nhid)])
        t=t+1
    return(statetraj)

#wrapper function for asyncio paralellization
def background(f):
    def wrapped(*args,**kwargs):


Complete the function implementation replacing "raise NotImplementedError".