poseidon666 commited on
Commit
0cdbf52
·
verified ·
1 Parent(s): 1f611d8

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. inference.py +57 -233
inference.py CHANGED
@@ -8,22 +8,17 @@ MANDATORY
8
  HF_TOKEN Your Hugging Face / API key.
9
  IMAGE_NAME The name of the local image to use for the environment if you are using
10
  from_docker_image() method.
11
-
12
  - Defaults are set only for API_BASE_URL and MODEL_NAME
13
  (and should reflect your active inference setup):
14
  API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
15
  MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
16
-
17
  - The inference script must be named `inference.py` and placed in the root directory of the project
18
  - Participants must use OpenAI Client for all LLM calls using above variables
19
-
20
  STDOUT FORMAT
21
  - The script must emit exactly three line types to stdout, in this order:
22
-
23
  [START] task=<task_name> env=<benchmark> model=<model_name>
24
  [STEP] step=<n> action=<action_str> reward=<0.00> done=<true|false> error=<msg|null>
25
  [END] success=<true|false> steps=<n> score=<score> rewards=<r1,r2,...,rn>
26
-
27
  Rules:
28
  - One [START] line at episode begin.
29
  - One [STEP] line per step, immediately after env.step() returns.
@@ -37,7 +32,6 @@ STDOUT FORMAT
37
 
38
  import asyncio
39
  import json
40
- import math
41
  import os
42
  import textwrap
43
  from typing import Any, Dict, List, Optional
@@ -66,13 +60,13 @@ SUCCESS_FIDELITY = 0.80 # minimum fidelity for "success"
66
 
67
  # Task configurations
68
  TASKS = [
69
- {"id": "easy", "name": "bell_state", "max_steps": 15},
70
- {"id": "medium", "name": "ghz_state", "max_steps": 15},
71
- {"id": "hard", "name": "unitary_approx", "max_steps": 15},
72
- {"id": "efficient", "name": "imperfect_efficient", "max_steps": 15},
73
- {"id": "noisy", "name": "noise_dominant", "max_steps": 15},
74
- {"id": "budget", "name": "budget_optimization", "max_steps": 15},
75
- # {"id": "approx", "name": "approximate_target", "max_steps": 15},
76
  ]
77
 
78
 
@@ -105,93 +99,31 @@ def log_end(success: bool, steps: int, score: float, rewards: List[float]) -> No
105
  # System prompt for the LLM
106
  # ---------------------------------------------------------------------------
107
 
108
- SYSTEM_PROMPT = textwrap.dedent("""
109
- You are an expert quantum circuit optimization agent.
110
-
111
- You are NOT a pattern generator.
112
- You MUST behave as a decision-making optimizer that improves the circuit step-by-step.
113
-
114
- Your goal:
115
- Maximize fidelity to the target while minimizing circuit depth and noise impact.
116
-
117
- ---
118
-
119
- AVAILABLE ACTIONS (respond with valid JSON only):
120
-
121
- 1. ADD:
122
- {"action_type": "ADD", "gate": "<H|X|CNOT|RX|RZ>", "qubits": [<int>, ...], "parameter": <float or null>}
123
-
124
- 2. REMOVE:
125
- {"action_type": "REMOVE", "qubits": []}
126
-
127
- 3. SWAP:
128
- {"action_type": "SWAP", "qubits": [q1, q2]}
129
-
130
- 4. PARAM:
131
- {"action_type": "PARAM", "qubits": [], "parameter": <float>}
132
-
133
- 5. STOP:
134
- {"action_type": "STOP", "qubits": []}
135
-
136
- ---
137
-
138
- CRITICAL DECISION PROCESS (YOU MUST FOLLOW THIS INTERNALLY):
139
-
140
- Step 1: Understand the target
141
- - What gates are required? (e.g., CNOT, RX, RZ)
142
- - Are parameters needed? (angles like π/3, π/4)
143
-
144
- Step 2: Analyze current circuit
145
- - What is already correct?
146
- - What is missing?
147
- - What is wrong or unnecessary?
148
-
149
- Step 3: Evaluate improvement
150
- - Which action will MOST increase fidelity?
151
- - Will adding this gate help or hurt under noise?
152
- - Is circuit becoming too deep?
153
-
154
- Step 4: Choose action strategically
155
- - Prefer actions that move toward target structure
156
- - Avoid random or repeated gates
157
- - Use parametric gates (RX, RZ) when precise tuning is required
158
-
159
- ---
160
-
161
- STRICT RULES:
162
-
163
- - DO NOT repeat the same useless pattern (e.g., H → CNOT blindly).
164
- - DO NOT use STOP unless:
165
- - Fidelity is already high (>0.95), OR
166
- - No further improvement is possible.
167
- - For unitary/parametric tasks:
168
- - You MUST use RX/RZ gates with meaningful parameters.
169
- - Avoid using H unless clearly useful.
170
- - Prefer minimal circuits (depth matters due to noise).
171
- - If a step reduces fidelity, consider REMOVE.
172
-
173
- ---
174
-
175
- ANTI-PATTERN WARNING (VERY IMPORTANT):
176
-
177
- If you find yourself repeating:
178
- H → CNOT → STOP
179
-
180
- You are WRONG.
181
-
182
- Re-evaluate the task and choose a better action.
183
-
184
- ---
185
-
186
- OUTPUT FORMAT:
187
-
188
- Return ONLY the best action as JSON:
189
- {
190
- "action_type": "...",
191
- "gate": "...",
192
- "qubits": [...],
193
- "parameter": ...
194
- }
195
  """)
196
 
197
 
@@ -199,41 +131,24 @@ Return ONLY the best action as JSON:
199
  # LLM interaction
200
  # ---------------------------------------------------------------------------
201
 
202
- def build_user_prompt(obs_data, step, history):
203
- history_block = "\n".join(history[-3:]) if history else "None"
204
-
205
- return textwrap.dedent(f"""
206
- You are optimizing a quantum circuit.
207
-
208
- TARGET:
209
- {obs_data.get('target_description')}
210
-
211
- CURRENT STATE:
212
- - Fidelity: {obs_data.get('fidelity'):.4f}
213
- - Score: {obs_data.get('score'):.4f}
214
- - Depth: {obs_data.get('depth')}
215
- - Steps remaining: {obs_data.get('max_steps') - obs_data.get('steps_taken')}
216
-
217
- CURRENT CIRCUIT:
218
- {json.dumps(obs_data.get('circuit_gates'))}
219
-
220
- RECENT HISTORY:
221
- {history_block}
222
-
223
- THINK BEFORE ACTING:
224
-
225
- 1. What gates are REQUIRED for the target?
226
- 2. What is MISSING in current circuit?
227
- 3. Will next action INCREASE fidelity?
228
-
229
- CRITICAL:
230
- - Avoid repeating useless patterns (H spam)
231
- - Use RY/RZ for parametric/unitary tasks
232
- - Do NOT STOP unless fidelity > 0.9
233
-
234
- Now choose the BEST next action.
235
-
236
- Return ONLY JSON.
237
  """)
238
 
239
 
@@ -274,82 +189,17 @@ def get_model_action(
274
  return action_dict
275
  except Exception as exc:
276
  print(f"[DEBUG] Model request/parse failed: {exc}", flush=True)
277
- # Fallback: try CNOT gate on qubits 0,1
278
- return {"action_type": "ADD", "gate": "CNOT", "qubits": [0, 1]}
279
-
280
- def validate_action(action_dict, obs_data, prev_reward, step, is_hard=False):
281
- # ❌ prevent oscillation
282
- if prev_reward < 0 and action_dict.get("action_type") == "ADD":
283
- return False
284
-
285
- # Prevent useless PARAM actions without an existing parameterized gate
286
- if action_dict.get("action_type") == "PARAM":
287
- if not any(g["gate"] in ["RX", "RZ"] for g in obs_data.get("circuit_gates", [])):
288
- return False
289
-
290
- # Prevent repeated same gate
291
- last_gate = obs_data.get("circuit_gates")[-1]["gate"] if obs_data.get("circuit_gates") else None
292
- if action_dict.get("gate") == last_gate:
293
- return False
294
-
295
- # Lock good structure after decent fidelity is achieved
296
- if obs_data.get("fidelity", 0.0) > 0.7 and action_dict.get("gate") == "CNOT":
297
- return False
298
-
299
- # Block early STOP
300
- if step < 4 and action_dict.get("action_type") == "STOP":
301
- return False
302
-
303
- # Block useless H spam in later steps
304
- if step > 2 and action_dict.get("gate") == "H":
305
- return False
306
-
307
- # For hard tasks, block H gates
308
- if is_hard and action_dict.get("gate") == "H":
309
- return False
310
-
311
- return True
312
-
313
-
314
- def enforce_ghz_structure(action_dict, obs_data, step):
315
- if "ghz" in obs_data.get("target_description", "").lower():
316
- if step == 1:
317
- return {"action_type": "ADD", "gate": "H", "qubits": [0]}
318
- return action_dict
319
-
320
-
321
- def parse_parameter(param):
322
- if param is None:
323
- return None
324
-
325
- if isinstance(param, (int, float)):
326
- return float(param)
327
-
328
- if isinstance(param, str):
329
- param = param.replace(" ", "").lower()
330
-
331
- # handle pi expressions
332
- if "pi" in param:
333
- try:
334
- param = param.replace("pi", f"{math.pi}")
335
- return float(eval(param))
336
- except:
337
- return None
338
-
339
- try:
340
- return float(param)
341
- except:
342
- return None
343
-
344
- return None
345
 
346
 
347
  def dict_to_action(action_dict: Dict[str, Any]) -> QuantumAction:
 
348
  return QuantumAction(
349
  action_type=action_dict.get("action_type", "STOP"),
350
  gate=action_dict.get("gate"),
351
  qubits=action_dict.get("qubits", []),
352
- parameter=parse_parameter(action_dict.get("parameter")),
353
  )
354
 
355
 
@@ -372,9 +222,6 @@ async def run_task(
372
  steps_taken = 0
373
  score = 0.0
374
  success = False
375
- best_fidelity = 0.0
376
- no_improve_steps = 0
377
- prev_reward = 0.0
378
 
379
  log_start(task=task_name, env=BENCHMARK, model=MODEL_NAME)
380
 
@@ -399,22 +246,8 @@ async def run_task(
399
  if result.done:
400
  break
401
 
402
- # Stop before chaos if repeated negative reward after step 8
403
- if step > 8 and prev_reward < 0:
404
- action_dict = {"action_type": "STOP", "qubits": []}
405
- elif no_improve_steps >= 2:
406
- action_dict = {"action_type": "STOP", "qubits": []}
407
- else:
408
- # Get action from LLM with retry and validation
409
- is_hard = task_id in ["hard", "approx"]
410
- for _ in range(3):
411
- action_dict = get_model_action(client, obs_data, step, history)
412
- action_dict = enforce_ghz_structure(action_dict, obs_data, step)
413
- # Parameter nudging for RX/RZ
414
- if action_dict.get("gate") in ["RX", "RZ"] and action_dict.get("parameter") is None:
415
- action_dict["parameter"] = 1.0
416
- if validate_action(action_dict, obs_data, prev_reward, step, is_hard):
417
- break
418
  action_str = json.dumps(action_dict, separators=(",", ":"))
419
 
420
  # Convert to QuantumAction and step
@@ -431,15 +264,6 @@ async def run_task(
431
 
432
  log_step(step=step, action=action_str, reward=reward, done=done, error=error)
433
 
434
- # Update improvement tracking
435
- if obs.fidelity > best_fidelity:
436
- best_fidelity = obs.fidelity
437
- no_improve_steps = 0
438
- else:
439
- no_improve_steps += 1
440
-
441
- prev_reward = reward
442
-
443
  # Update obs_data for next prompt
444
  obs_data = {
445
  "fidelity": obs.fidelity,
@@ -497,4 +321,4 @@ async def main() -> None:
497
 
498
 
499
  if __name__ == "__main__":
500
- asyncio.run(main())
 
8
  HF_TOKEN Your Hugging Face / API key.
9
  IMAGE_NAME The name of the local image to use for the environment if you are using
10
  from_docker_image() method.
 
11
  - Defaults are set only for API_BASE_URL and MODEL_NAME
12
  (and should reflect your active inference setup):
13
  API_BASE_URL = os.getenv("API_BASE_URL", "https://router.huggingface.co/v1")
14
  MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
 
15
  - The inference script must be named `inference.py` and placed in the root directory of the project
16
  - Participants must use OpenAI Client for all LLM calls using above variables
 
17
  STDOUT FORMAT
18
  - The script must emit exactly three line types to stdout, in this order:
 
19
  [START] task=<task_name> env=<benchmark> model=<model_name>
20
  [STEP] step=<n> action=<action_str> reward=<0.00> done=<true|false> error=<msg|null>
21
  [END] success=<true|false> steps=<n> score=<score> rewards=<r1,r2,...,rn>
 
22
  Rules:
23
  - One [START] line at episode begin.
24
  - One [STEP] line per step, immediately after env.step() returns.
 
32
 
33
  import asyncio
34
  import json
 
35
  import os
36
  import textwrap
37
  from typing import Any, Dict, List, Optional
 
60
 
61
  # Task configurations
62
  TASKS = [
63
+ {"id": "easy", "name": "bell_state", "max_steps": 15},
64
+ {"id": "medium", "name": "ghz_state", "max_steps": 15},
65
+ #{"id": "hard", "name": "unitary_approx", "max_steps": 15},
66
+ {"id": "efficient", "name": "imperfect_efficient", "max_steps": 15},
67
+ {"id": "noisy", "name": "noise_dominant", "max_steps": 15},
68
+ {"id": "budget", "name": "budget_optimization", "max_steps": 15},
69
+ {"id": "approx", "name": "approximate_target", "max_steps": 15},
70
  ]
71
 
72
 
 
99
  # System prompt for the LLM
100
  # ---------------------------------------------------------------------------
101
 
102
+ SYSTEM_PROMPT = textwrap.dedent("""\
103
+ You are an expert quantum circuit designer. You are interacting with an RL environment
104
+ that lets you build quantum circuits step by step.
105
+ AVAILABLE ACTIONS (respond with valid JSON only):
106
+ 1. ADD a gate:
107
+ {"action_type": "ADD", "gate": "<H|X|CNOT|RX|RZ>", "qubits": [<int>, ...], "parameter": <float or null>}
108
+ - H, X: single-qubit gates, qubits = [q]
109
+ - CNOT: two-qubit gate, qubits = [control, target]
110
+ - RX, RZ: parametric single-qubit gates, qubits = [q], parameter = angle in radians
111
+ 2. REMOVE the last gate:
112
+ {"action_type": "REMOVE", "qubits": []}
113
+ Note: Yields +0.05 bonus if depth decreases with no fidelity loss. Yields -0.05 penalty if fidelity drops.
114
+ 3. SWAP two qubits:
115
+ {"action_type": "SWAP", "qubits": [q1, q2]}
116
+ Note: Yields -0.02 penalty per SWAP since it represents real hardware routing overhead.
117
+ 4. PARAM -- tune the last parametric gate:
118
+ {"action_type": "PARAM", "qubits": [], "parameter": <float>}
119
+ 5. STOP -- end the episode:
120
+ {"action_type": "STOP", "qubits": []}
121
+ RULES:
122
+ - Respond with ONLY the JSON object, nothing else.
123
+ - Maximize fidelity to the target state while minimizing circuit depth.
124
+ - Consider REMOVE to revert a bad step to avoid depth penalties, or SWAP to map qubits.
125
+ - Respect any hardware connectivity constraints described in the observation.
126
+ - All episodes end at 15 steps max.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
  """)
128
 
129
 
 
131
  # LLM interaction
132
  # ---------------------------------------------------------------------------
133
 
134
+ def build_user_prompt(obs_data: Dict[str, Any], step: int, history: List[str]) -> str:
135
+ """Build a user prompt from the current observation."""
136
+ history_block = "\n".join(history[-5:]) if history else "None"
137
+ return textwrap.dedent(f"""\
138
+ Step: {step}
139
+ Task: {obs_data.get('target_description', 'unknown')}
140
+ Qubits: {obs_data.get('num_qubits', 2)}
141
+ Current fidelity: {obs_data.get('fidelity', 0.0):.4f}
142
+ Current depth: {obs_data.get('depth', 0)}
143
+ Gate count: {obs_data.get('gate_count', 0)}
144
+ Noise estimate: {obs_data.get('noise_estimate', 0.0):.4f}
145
+ Score: {obs_data.get('score', 0.0):.4f}
146
+ Valid actions: {obs_data.get('valid_actions', [])}
147
+ Steps remaining: {obs_data.get('max_steps', 20) - obs_data.get('steps_taken', 0)}
148
+ Current circuit gates: {json.dumps(obs_data.get('circuit_gates', []))}
149
+ Recent history:
150
+ {history_block}
151
+ Choose your next action (JSON only):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  """)
153
 
154
 
 
189
  return action_dict
190
  except Exception as exc:
191
  print(f"[DEBUG] Model request/parse failed: {exc}", flush=True)
192
+ # Fallback: try a simple H gate on qubit 0
193
+ return {"action_type": "ADD", "gate": "H", "qubits": [0]}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
 
195
 
196
  def dict_to_action(action_dict: Dict[str, Any]) -> QuantumAction:
197
+ """Convert a dict to a QuantumAction."""
198
  return QuantumAction(
199
  action_type=action_dict.get("action_type", "STOP"),
200
  gate=action_dict.get("gate"),
201
  qubits=action_dict.get("qubits", []),
202
+ parameter=action_dict.get("parameter"),
203
  )
204
 
205
 
 
222
  steps_taken = 0
223
  score = 0.0
224
  success = False
 
 
 
225
 
226
  log_start(task=task_name, env=BENCHMARK, model=MODEL_NAME)
227
 
 
246
  if result.done:
247
  break
248
 
249
+ # Get action from LLM
250
+ action_dict = get_model_action(client, obs_data, step, history)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  action_str = json.dumps(action_dict, separators=(",", ":"))
252
 
253
  # Convert to QuantumAction and step
 
264
 
265
  log_step(step=step, action=action_str, reward=reward, done=done, error=error)
266
 
 
 
 
 
 
 
 
 
 
267
  # Update obs_data for next prompt
268
  obs_data = {
269
  "fidelity": obs.fidelity,
 
321
 
322
 
323
  if __name__ == "__main__":
324
+ asyncio.run(main())