"""Independent state-vector and reduced-state comparison with Qiskit 2.5.2."""
import json,subprocess
from pathlib import Path
import numpy as np
from qiskit import QuantumCircuit
from qiskit.quantum_info import Statevector,partial_trace
ROOT=Path(__file__).resolve().parents[1]
js=r'''
import * as Q from './dist/quantum.js';
const r=Q.rng(2026),cases=[];
for(let n=2;n<=5;n++)for(let k=0;k<12;k++){
 const ops=[];for(let i=0;i<16;i++){let q=Math.floor(r()*n),c=(q+1+Math.floor(r()*(n-1)))%n;const names=['H','X','Y','Z','S','T','Rx','Ry','Rz','P','CX','CZ','CP','SWAP'];let name=names[Math.floor(r()*names.length)];ops.push({name,q,control:c,angle:(r()*2-1)*Math.PI});}
 const state=Q.circuit(n,ops).state;cases.push({n,ops,state,reduced:Q.reduced(state,n,[0])});
}process.stdout.write(JSON.stringify(cases));'''
cases=json.loads(subprocess.check_output(['node','--input-type=module','-e',js],cwd=ROOT,text=True))
max_error=0
for c in cases:
 n=c['n'];qc=QuantumCircuit(n)
 for o in c['ops']:
  q=n-1-o['q'];ctrl=n-1-o['control'];name=o['name']
  if name in ['CX','CZ','SWAP']:getattr(qc,name.lower())(ctrl,q)
  elif name=='CP':qc.cp(o['angle'],ctrl,q)
  elif name in ['Rx','Ry','Rz','P']:getattr(qc,name.lower())(o['angle'],q)
  else:getattr(qc,name.lower())(q)
 actual=Statevector.from_instruction(qc);expected=np.array([complex(*z) for z in c['state']]);err=np.max(np.abs(actual.data-expected));max_error=max(max_error,float(err));np.testing.assert_allclose(actual.data,expected,atol=1e-12,rtol=0)
 rho=partial_trace(actual,list(range(n-1))).data;target=np.array([[complex(*z) for z in row] for row in c['reduced']]);np.testing.assert_allclose(rho,target,atol=1e-12,rtol=0)
print(json.dumps({'circuits':len(cases),'gates_per_circuit':16,'qubits':'2–5','max_amplitude_error':max_error,'state_and_partial_trace_checks':'passed'},indent=2))
