{
  "schema_version": 1,
  "name": "Noisy Floquet Ising chain",
  "description": "Local Qiskit statevector and density-matrix evolution of 2-8 qubits over 0-16 Floquet cycles. Little-endian basis: q0 is the least-significant bit. Neel is q0=0,q1=1,...; zero is all-zero. Each cycle applies RZZ(2J)=exp(-i J ZiZj) once per undirected nearest-neighbor edge, all before RX(2h)=exp(-i h Xi) on every qubit, followed by independent phase-flip channels rho -> (1-p)rho+p Zi rho Zi. Open chain edges are (0,1),...,(n-2,n-1); ring adds (n-1,0) only if n>2. J and h are in radians. Fidelity means Re(<psi_ideal|rho|psi_ideal>), with the ideal statevector following the same noise-free unitaries. Observables include purity, mean Z, mean edge ZZ, and base-2 von Neumann entropy for A={q0,...,q(floor(n/2)-1)} plus I(A:B)=S(A)+S(B)-S(AB) of the noisy state. Includes cycle 0 and every full cycle, trajectories, CSV, and final complex states as real/imaginary JSON arrays. Qiskit 2.5.2 and NumPy 2.3.5. Deterministic local simulation only; no quantum hardware or network. The analytic checks exercise zero-cycle initial-state values, noiseless fidelity/purity, and the stationary zero-rotation all-zero state, with 2e-10 absolute tolerance. Full final states are also saved without rounding in final_states.json. For n<=7 the state arrays remain inline; at n=8 the two state data values instead point to that artifact, avoiding r34's result JSON quotas. This is serialization only; the evolution and observables are identical.",
  "adapter": "python",
  "entrypoint": "main.py:run",
  "requirements": [
    {
      "distribution": "qiskit",
      "version": "2.5.2"
    },
    {
      "distribution": "numpy",
      "version": "2.3.5"
    }
  ],
  "parameters": [
    {
      "name": "n",
      "label": "Qubits",
      "type": "integer",
      "default": 6,
      "minimum": 2,
      "maximum": 8,
      "required": true,
      "help": "Local density matrix uses dimension 2**n; q0 is the least-significant bit."
    },
    {
      "name": "cycles",
      "label": "Floquet cycles",
      "type": "integer",
      "default": 8,
      "minimum": 0,
      "maximum": 16,
      "required": true,
      "help": "Cycle 0 and every completed cycle are recorded."
    },
    {
      "name": "J",
      "label": "Ising coupling J (rad)",
      "type": "number",
      "default": 0.34,
      "minimum": 0,
      "maximum": 3.141592653589793,
      "required": true,
      "help": "RZZ(2J) on each undirected edge once per cycle."
    },
    {
      "name": "h",
      "label": "Transverse rotation h (rad)",
      "type": "number",
      "default": 0.71,
      "minimum": 0,
      "maximum": 3.141592653589793,
      "required": true,
      "help": "RX(2h) on each qubit after all ZZ gates."
    },
    {
      "name": "p",
      "label": "Phase-flip probability",
      "type": "number",
      "default": 0.025,
      "minimum": 0,
      "maximum": 0.5,
      "required": true,
      "help": "Independent Z flip channel on every qubit after the unitary cycle."
    },
    {
      "name": "boundary",
      "label": "Boundary",
      "type": "choice",
      "default": "ring",
      "choices": [
        "open",
        "ring"
      ],
      "required": true,
      "help": "Ring adds the closing edge only for n>2, avoiding a duplicate edge for two qubits."
    },
    {
      "name": "initial_state",
      "label": "Initial product state",
      "type": "choice",
      "default": "neel",
      "choices": [
        "neel",
        "zero"
      ],
      "required": true,
      "help": "Neel: q0=0,q1=1,q2=0,...; zero: every qubit is 0."
    }
  ],
  "outputs": [
    {
      "name": "fidelity",
      "label": "Ideal-state overlap fidelity",
      "kind": "number"
    },
    {
      "name": "purity",
      "label": "Purity",
      "kind": "number"
    },
    {
      "name": "magnetization",
      "label": "Mean Z magnetization",
      "kind": "number"
    },
    {
      "name": "zz_correlation",
      "label": "Mean nearest-neighbor ZZ correlation",
      "kind": "number"
    },
    {
      "name": "half_entropy_bits",
      "label": "Half-system entropy (bits)",
      "kind": "number"
    },
    {
      "name": "mutual_information_bits",
      "label": "Mutual information (bits)",
      "kind": "number"
    },
    {
      "name": "fidelity_series",
      "label": "Ideal-state overlap fidelity versus cycle",
      "kind": "series"
    },
    {
      "name": "purity_series",
      "label": "Purity versus cycle",
      "kind": "series"
    },
    {
      "name": "magnetization_series",
      "label": "Mean Z magnetization versus cycle",
      "kind": "series"
    },
    {
      "name": "zz_correlation_series",
      "label": "Mean nearest-neighbor ZZ correlation versus cycle",
      "kind": "series"
    },
    {
      "name": "half_entropy_bits_series",
      "label": "Half-system entropy (bits) versus cycle",
      "kind": "series"
    },
    {
      "name": "mutual_information_bits_series",
      "label": "Mutual information (bits) versus cycle",
      "kind": "series"
    },
    {
      "name": "observables",
      "label": "Cycle observables",
      "kind": "table"
    },
    {
      "name": "observables_csv",
      "label": "Observables CSV",
      "kind": "file"
    },
    {
      "name": "settings",
      "label": "Input settings",
      "kind": "json"
    },
    {
      "name": "trajectory",
      "label": "Complete observable trajectory",
      "kind": "json"
    },
    {
      "name": "edges",
      "label": "Undirected edges",
      "kind": "json"
    },
    {
      "name": "final_density_matrix",
      "label": "Final noisy density matrix (real/imag)",
      "kind": "json"
    },
    {
      "name": "final_ideal_statevector",
      "label": "Final ideal statevector (real/imag)",
      "kind": "json"
    },
    {
      "name": "conventions",
      "label": "Scientific conventions",
      "kind": "json"
    },
    {
      "name": "dependencies",
      "label": "Dependency versions",
      "kind": "json"
    },
    {
      "name": "final_states_json",
      "label": "Full final states JSON",
      "kind": "file"
    },
    {
      "name": "state_artifact",
      "label": "Final states artifact location and format",
      "kind": "json"
    }
  ],
  "checks": [
    {
      "name": "Zero-cycle six-qubit Neel state",
      "inputs": {
        "n": 6,
        "cycles": 0,
        "initial_state": "neel",
        "boundary": "ring"
      },
      "expectations": [
        {
          "output": "/metrics/fidelity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/purity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/magnetization",
          "operator": "close",
          "value": 0,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/zz_correlation",
          "operator": "close",
          "value": -1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/half_entropy_bits",
          "operator": "close",
          "value": 0,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/mutual_information_bits",
          "operator": "close",
          "value": 0,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/data/trajectory",
          "operator": "length",
          "value": 1
        }
      ]
    },
    {
      "name": "Noiseless evolution remains pure and matches ideal",
      "inputs": {
        "n": 4,
        "cycles": 5,
        "p": 0
      },
      "expectations": [
        {
          "output": "/metrics/fidelity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/purity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/data/trajectory",
          "operator": "length",
          "value": 6
        }
      ]
    },
    {
      "name": "Zero rotations keep the zero state stationary under phase flips",
      "inputs": {
        "n": 3,
        "cycles": 4,
        "J": 0.83,
        "h": 0,
        "p": 0.5,
        "boundary": "open",
        "initial_state": "zero"
      },
      "expectations": [
        {
          "output": "/metrics/fidelity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/purity",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/magnetization",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/zz_correlation",
          "operator": "close",
          "value": 1,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/half_entropy_bits",
          "operator": "close",
          "value": 0,
          "atol": 2e-10,
          "rtol": 0
        },
        {
          "output": "/metrics/mutual_information_bits",
          "operator": "close",
          "value": 0,
          "atol": 2e-10,
          "rtol": 0
        }
      ]
    }
  ],
  "files": [
    {
      "path": "main.py",
      "content": "\"\"\"Deterministic Floquet Ising evolution with Qiskit quantum states/channels.\n\nQubit q0 is the least-significant computational-basis bit. A cycle consists of\nall RZZ(2*J) gates, all RX(2*h) gates, then a phase-flip channel on every qubit.\nFidelity here means ideal-state overlap Re(<psi_ideal|rho|psi_ideal>).\n\"\"\"\n\nimport csv\nimport json\nimport math\nfrom pathlib import Path\n\nimport numpy as np\nimport qiskit\nfrom qiskit import QuantumCircuit\nfrom qiskit.quantum_info import DensityMatrix, Kraus, Pauli, Statevector, partial_trace\n\n\nMETRIC_NAMES = (\n    \"fidelity\", \"purity\", \"magnetization\", \"zz_correlation\",\n    \"half_entropy_bits\", \"mutual_information_bits\",\n)\nDEFAULTS = {\n    \"n\": 6, \"cycles\": 8, \"J\": 0.34, \"h\": 0.71, \"p\": 0.025,\n    \"boundary\": \"ring\", \"initial_state\": \"neel\",\n}\n\n\ndef _settings(inputs):\n    \"\"\"Also validate direct Python calls, outside the typed workflow service.\"\"\"\n    unknown = set(inputs) - set(DEFAULTS)\n    if unknown:\n        raise ValueError(\"Unknown input(s): \" + \", \".join(sorted(unknown)))\n    values = dict(DEFAULTS)\n    values.update(inputs)\n    for name, low, high in ((\"n\", 2, 8), (\"cycles\", 0, 16)):\n        value = values[name]\n        if type(value) is not int or not low <= value <= high:\n            raise ValueError(f\"{name} must be an integer in [{low}, {high}]\")\n    for name, low, high in ((\"J\", 0.0, math.pi), (\"h\", 0.0, math.pi), (\"p\", 0.0, 0.5)):\n        value = values[name]\n        if type(value) not in (int, float) or not math.isfinite(value) or not low <= value <= high:\n            raise ValueError(f\"{name} must be finite and in [{low}, {high}]\")\n        values[name] = float(value)\n    if values[\"boundary\"] not in (\"open\", \"ring\"):\n        raise ValueError(\"boundary must be open or ring\")\n    if values[\"initial_state\"] not in (\"neel\", \"zero\"):\n        raise ValueError(\"initial_state must be neel or zero\")\n    return values\n\n\ndef _entropy_bits(state):\n    \"\"\"Von Neumann entropy in bits; discard eigenvalue roundoff below zero.\"\"\"\n    matrix = np.asarray(state.data, dtype=complex)\n    eigenvalues = np.linalg.eigvalsh((matrix + matrix.conj().T) / 2.0)\n    if float(eigenvalues.min()) < -1e-10:\n        raise ValueError(\"Density matrix has a materially negative eigenvalue\")\n    probabilities = np.clip(eigenvalues, 0.0, 1.0)\n    positive = probabilities[probabilities > 0.0]\n    return float(-np.sum(positive * np.log2(positive)))\n\n\ndef _observables(rho, ideal, n, edges):\n    matrix = rho.data\n    vector = ideal.data\n    subsystem_a = list(range(n // 2))\n    subsystem_b = list(range(n // 2, n))\n    entropy_a = _entropy_bits(partial_trace(rho, subsystem_b))\n    entropy_b = _entropy_bits(partial_trace(rho, subsystem_a))\n    entropy_ab = _entropy_bits(rho)\n    return {\n        \"fidelity\": float(np.real(np.vdot(vector, matrix @ vector))),\n        \"purity\": float(np.real(np.trace(matrix @ matrix))),\n        \"magnetization\": float(np.mean([\n            np.real(rho.expectation_value(Pauli(\"Z\"), qargs=[q])) for q in range(n)\n        ])),\n        \"zz_correlation\": float(np.mean([\n            np.real(rho.expectation_value(Pauli(\"ZZ\"), qargs=[i, j])) for i, j in edges\n        ])),\n        \"half_entropy_bits\": entropy_a,\n        \"mutual_information_bits\": entropy_a + entropy_b - entropy_ab,\n    }\n\n\ndef _complex_arrays(array):\n    return {\"real\": array.real.tolist(), \"imag\": array.imag.tolist()}\n\n\ndef run(inputs, context):\n    \"\"\"Return six metrics, full trajectories, states, and a real CSV artifact.\"\"\"\n    settings = _settings(inputs)\n    n, cycles = settings[\"n\"], settings[\"cycles\"]\n    edges = [(q, q + 1) for q in range(n - 1)]\n    if settings[\"boundary\"] == \"ring\" and n > 2:\n        edges.append((n - 1, 0))\n\n    preparation = QuantumCircuit(n)\n    if settings[\"initial_state\"] == \"neel\":\n        for q in range(1, n, 2):\n            preparation.x(q)\n    ideal = Statevector.from_instruction(preparation)\n    rho = DensityMatrix(ideal)\n\n    cycle = QuantumCircuit(n, name=\"Floquet_cycle\")\n    for i, j in edges:\n        cycle.rzz(2.0 * settings[\"J\"], i, j)\n    for q in range(n):\n        cycle.rx(2.0 * settings[\"h\"], q)\n    p = settings[\"p\"]\n    phase_flip = Kraus([\n        np.sqrt(1.0 - p) * np.eye(2, dtype=complex),\n        np.sqrt(p) * np.diag([1.0, -1.0]),\n    ])\n\n    trajectory = [{\"cycle\": 0, **_observables(rho, ideal, n, edges)}]\n    for index in range(1, cycles + 1):\n        ideal = ideal.evolve(cycle)\n        rho = rho.evolve(cycle)\n        for q in range(n):\n            rho = rho.evolve(phase_flip, qargs=[q])\n        trajectory.append({\"cycle\": index, **_observables(rho, ideal, n, edges)})\n\n    columns = [\"cycle\", *METRIC_NAMES]\n    rows = [[item[name] for name in columns] for item in trajectory]\n    output_dir = Path(context.output_dir)\n    output_dir.mkdir(parents=True, exist_ok=True)\n    with (output_dir / \"observables.csv\").open(\"w\", newline=\"\", encoding=\"utf-8\") as stream:\n        writer = csv.writer(stream)\n        writer.writerow(columns)\n        writer.writerows(rows)\n\n    final_states = {\n        \"final_density_matrix\": _complex_arrays(rho.data),\n        \"final_ideal_statevector\": _complex_arrays(ideal.data),\n    }\n    with (output_dir / \"final_states.json\").open(\"w\", encoding=\"utf-8\") as stream:\n        json.dump(final_states, stream, allow_nan=False, separators=(\",\", \":\"))\n    # At n=8 the full inline density arrays exceed r34's result quotas.\n    # Preserve the complete, unrounded arrays in the JSON artifact instead.\n    inline_states = final_states if n <= 7 else {\n        name: {\"artifact_path\": \"final_states.json\", \"json_pointer\": \"/\" + name}\n        for name in final_states\n    }\n\n    return {\n        \"metrics\": {name: trajectory[-1][name] for name in METRIC_NAMES},\n        \"tables\": [{\"name\": \"observables\", \"columns\": columns, \"rows\": rows}],\n        \"series\": [\n            {\"name\": name + \"_series\", \"x\": [item[\"cycle\"] for item in trajectory],\n             \"y\": [item[name] for item in trajectory]}\n            for name in METRIC_NAMES\n        ],\n        \"artifacts\": [\n            {\"name\": \"observables_csv\", \"path\": \"observables.csv\", \"mime_type\": \"text/csv\"},\n            {\"name\": \"final_states_json\", \"path\": \"final_states.json\", \"mime_type\": \"application/json\"},\n        ],\n        \"data\": {\n            \"settings\": settings,\n            \"trajectory\": trajectory,\n            \"edges\": [list(edge) for edge in edges],\n            \"final_density_matrix\": inline_states[\"final_density_matrix\"],\n            \"final_ideal_statevector\": inline_states[\"final_ideal_statevector\"],\n            \"state_artifact\": {\n                \"name\": \"final_states_json\", \"path\": \"final_states.json\",\n                \"format\": \"JSON with full final_density_matrix and final_ideal_statevector real/imag arrays\",\n                \"density_matrix_shape\": [2 ** n, 2 ** n],\n                \"ideal_statevector_shape\": [2 ** n],\n                \"inline_arrays\": n <= 7,\n                \"reason\": \"Full inline eight-qubit state arrays exceed r34 result JSON quotas; artifact retains all entries.\",\n            },\n            \"conventions\": {\n                \"basis\": \"Little-endian integer indexing; q0 is the least-significant bit.\",\n                \"initial_state\": \"neel: q0=0,q1=1,q2=0,...; zero: every qubit is 0.\",\n                \"cycle_order\": \"All undirected-edge RZZ(2J), then all RX(2h), then one phase-flip channel per qubit.\",\n                \"unitaries\": \"RZZ(2J)=exp(-i J ZiZj); RX(2h)=exp(-i h Xi); J,h are radians.\",\n                \"phase_flip\": \"rho -> (1-p)rho + p Zi rho Zi, independently on each qubit after each cycle.\",\n                \"fidelity\": \"Re(<psi_ideal|rho|psi_ideal>); psi_ideal has the same unitary evolution without noise.\",\n                \"magnetization\": \"Mean <Zq> over all n qubits.\",\n                \"zz_correlation\": \"Mean <ZiZj> over edges; ring adds (n-1,0) only for n>2.\",\n                \"entropy\": \"Von Neumann entropy in bits using log2; negative eigenvalue roundoff clipped at zero.\",\n                \"partition_a\": list(range(n // 2)),\n                \"partition_b\": list(range(n // 2, n)),\n                \"mutual_information\": \"S(A)+S(B)-S(AB), evaluated on the noisy density matrix.\",\n                \"sampling\": \"Deterministic local statevector/density-matrix simulation; no stochastic samples or hardware calls.\",\n                \"time_axis\": \"Cycle 0 is the prepared state; subsequent points follow full cycles including noise.\",\n            },\n            \"dependencies\": {\"qiskit\": qiskit.__version__, \"numpy\": np.__version__},\n        },\n    }\n"
    }
  ]
}
