@@ -251,79 +251,13 @@ function projection_scaling_rows(; cutoff = 1e-10)
251251 end
252252end
253253
254- function penalty_resource_metrics (model; cutoff = 1e-10 )
255- H = TenSolver. tensorize (model. Q, model. l; cutoff, domain = 0 : 1 )
256- bond = ITensorMPS. maxlinkdim (H)
257- return (
258- objective_mpo_bond = bond,
259- projection_mpo_bond = missing ,
260- effective_hamiltonian_bond = bond,
261- )
262- end
263-
264- function qubo_hamiltonian (Q, l, sites; cutoff)
265- os = ITensorMPS. OpSum {Float64} ()
266- nvariables = length (sites)
267-
268- for i in 1 : nvariables
269- linear_coefficient = Q[i, i] + l[i]
270- if abs (linear_coefficient) > cutoff
271- os += (linear_coefficient, " D" , (domain = 0 : 1 ,), i)
272- end
273-
274- for j in (i + 1 ): nvariables
275- quadratic_coefficient = Q[i, j] + Q[j, i]
276- if abs (quadratic_coefficient) > cutoff
277- os += (quadratic_coefficient, " D" , (domain = 0 : 1 ,), i, " D" , (domain = 0 : 1 ,), j)
278- end
279- end
280- end
281-
282- return isempty (os) ? ITensorMPS. MPO (Float64, sites) : ITensorMPS. MPO (Float64, os, sites)
283- end
284-
285- function projection_hamiltonian (instance, sites; cutoff)
286- nitems = length (instance. weights)
287- H = qubo_hamiltonian (zeros (nitems, nitems), - instance. values, sites; cutoff)
288- constraint = TenSolver. SumConstraint (
289- collect (1 : nitems),
290- instance. weights,
291- instance. capacity;
292- relation = :(<= ),
293- )
294- P = TenSolver. projection_mpo (constraint, sites; domain = 0 : 1 )
295- H_effective = TenSolver. project_hamiltonian (H, P; cutoff)
296- for i in eachindex (H_effective)
297- source = (
298- only (ITensorMPS. siteinds (H_effective, i; plev = 0 )),
299- only (ITensorMPS. siteinds (H_effective, i; plev = 1 )),
300- )
301- target = (sites[i], sites[i]' )
302- H_effective[i] = ITensors. replaceinds (H_effective[i], source, target)
303- end
304- return H_effective
305- end
306-
307- function state_variance (H, mps)
308- expectation = real (ITensors. inner (mps' , H, mps))
309- second_moment = real (ITensors. inner (H, mps, H, mps))
310- return max (0.0 , second_moment - expectation^ 2 )
311- end
312-
313- function variance_observer (hamiltonian_builder)
314- hamiltonian = Ref {Any} ()
315- setup = Ref {Any} ()
254+ function variance_observer ()
316255 variances = Float64[]
317- callback = function (mps; kw... )
318- if ! isassigned (hamiltonian)
319- timed = @timed hamiltonian_builder (ITensorMPS. siteinds (mps))
320- hamiltonian[] = timed. value
321- setup[] = (time = timed. time, gctime = timed. gctime, memory = timed. bytes)
322- end
323- push! (variances, state_variance (hamiltonian[], mps))
256+ callback = function (_mps; variance, kw... )
257+ push! (variances, variance)
324258 return nothing
325259 end
326- return variances, setup, callback
260+ return variances, callback
327261end
328262
329263function benchmark_repeated (f; samples)
@@ -389,11 +323,16 @@ function runtime_metadata()
389323end
390324
391325function solution_stats (solution)
326+ stats = solution. stats
327+ bonds = stats. max_bonds
392328 return (
393- sweeps = length (solution. energies),
394- solution_max_bond = isempty (solution. bond_dims) ? 0 : maximum (solution. bond_dims),
395- solver_elapsed_seconds = isempty (solution. elapsed_times) ? 0.0 :
396- last (solution. elapsed_times),
329+ sweeps = length (stats. energies),
330+ solution_max_bond = isempty (stats. bond_dims) ? 0 : maximum (stats. bond_dims),
331+ solver_elapsed_seconds = isempty (stats. elapsed_times) ? 0.0 : last (stats. elapsed_times),
332+ initial_state_bond = bonds. initial_state,
333+ objective_mpo_bond = bonds. objective,
334+ projection_mpo_bond = isempty (bonds. projections) ? missing : maximum (bonds. projections),
335+ effective_hamiltonian_bond = bonds. hamiltonian,
397336 )
398337end
399338
@@ -457,7 +396,10 @@ function solver_options(iterations, cutoff, time_limit, on_iteration)
457396 inidim = 8 ,
458397 maxdim = [10 , 20 , 40 , 80 , 120 , 200 ],
459398 noise = [1e-6 , 1e-8 , 0.0 ],
460- check_variance_every_iteration = iterations + 1 ,
399+ check_variance_every_iteration = 1 ,
400+ # Collect variance on every sweep without letting convergence shorten the
401+ # fixed-sweep benchmark workload.
402+ vtol = - Inf ,
461403 on_iteration,
462404 callback_every = 1 ,
463405 verbosity = 0 ,
@@ -472,8 +414,7 @@ function benchmark_result_row(
472414 reported_objective,
473415 formulation_timed,
474416 case_timed,
475- solution,
476- resources;
417+ solution;
477418 variances,
478419 nvariables,
479420 iterations,
@@ -489,16 +430,10 @@ function benchmark_result_row(
489430 feasible = is_capacity_feasible (instance, items)
490431 value = item_value (instance, items)
491432 stats = solution_stats (solution)
492- observer_setup_seconds = component_median (case_timed. outputs, :observer_setup , :time )
493- observer_setup_gc_seconds = component_median (case_timed. outputs, :observer_setup , :gctime )
494- observer_setup_allocated_bytes =
495- component_median (case_timed. outputs, :observer_setup , :memory )
496433 sampling_seconds = component_median (case_timed. outputs, :sampling , :time )
497434 sampling_gc_seconds = component_median (case_timed. outputs, :sampling , :gctime )
498435 sampling_allocated_bytes = component_median (case_timed. outputs, :sampling , :memory )
499436 solver_call_seconds = max (0.0 , case_timed. time - sampling_seconds)
500- solver_excluding_observer_setup_seconds =
501- max (0.0 , solver_call_seconds - observer_setup_seconds)
502437 metadata = runtime_metadata ()
503438
504439 return (;
@@ -531,13 +466,10 @@ function benchmark_result_row(
531466 solve_gc_seconds = case_timed. gctime,
532467 solve_allocated_bytes = case_timed. memory,
533468 solve_allocations = case_timed. allocs,
534- observer_setup_seconds,
535- observer_setup_gc_seconds,
536- observer_setup_allocated_bytes,
537469 sampling_seconds,
538470 sampling_gc_seconds,
539471 sampling_allocated_bytes,
540- solver_excluding_observer_setup_seconds ,
472+ solver_call_seconds ,
541473 end_to_end_wall_seconds = formulation_timed. time + case_timed. time,
542474 solver_elapsed_seconds = stats. solver_elapsed_seconds,
543475 sweeps = stats. sweeps,
@@ -546,9 +478,10 @@ function benchmark_result_row(
546478 solution_max_bond = stats. solution_max_bond,
547479 final_variance = isempty (variances) ? missing : last (variances),
548480 truncation_error = missing ,
549- objective_mpo_bond = resources. objective_mpo_bond,
550- projection_mpo_bond = resources. projection_mpo_bond,
551- effective_hamiltonian_bond = resources. effective_hamiltonian_bond,
481+ initial_state_bond = stats. initial_state_bond,
482+ objective_mpo_bond = stats. objective_mpo_bond,
483+ projection_mpo_bond = stats. projection_mpo_bond,
484+ effective_hamiltonian_bond = stats. effective_hamiltonian_bond,
552485 )
553486end
554487
@@ -573,28 +506,22 @@ function projection_row(
573506 end
574507 constraint = formulation_timed. value
575508 case_timed = benchmark_repeated (; samples = timing_samples) do
576- variances, observer_setup, callback =
577- variance_observer (sites -> projection_hamiltonian (instance, sites; cutoff),)
509+ variances, callback = variance_observer ()
578510 Random. seed! (SOLVER_SEED)
579511 options = solver_options (iterations, cutoff, time_limit, callback)
580512 reported_objective, solution =
581513 TenSolver. maximize (instance. values; constraints = [constraint], options... )
582514 sampling = @timed best_projection_sample (instance, TenSolver. sample (solution, reads))
583- if ! (isassigned (observer_setup))
584- error (" projection variance observer did not run" )
585- end
586515 return (;
587516 reported_objective,
588517 solution,
589518 items = sampling. value,
590519 variances,
591- observer_setup = observer_setup[],
592520 sampling = (time = sampling. time, gctime = sampling. gctime, memory = sampling. bytes),
593521 )
594522 end
595523 items = assert_stable_items (case_timed. outputs)
596524 output = case_timed. value
597- resources = projection_resource_metrics (instance; cutoff)
598525 return benchmark_result_row (
599526 instance,
600527 exact,
@@ -603,8 +530,7 @@ function projection_row(
603530 output. reported_objective,
604531 formulation_timed,
605532 case_timed,
606- output. solution,
607- resources;
533+ output. solution;
608534 variances = output. variances,
609535 nvariables = nitems,
610536 iterations,
@@ -633,8 +559,7 @@ function penalty_row(
633559 end
634560 model = formulation_timed. value
635561 case_timed = benchmark_repeated (; samples = timing_samples) do
636- variances, observer_setup, callback =
637- variance_observer (sites -> qubo_hamiltonian (model. Q, model. l, sites; cutoff),)
562+ variances, callback = variance_observer ()
638563 Random. seed! (SOLVER_SEED)
639564 options = solver_options (iterations, cutoff, time_limit, callback)
640565 reported_objective, solution =
@@ -643,22 +568,17 @@ function penalty_row(
643568 assignment = best_penalty_sample (instance, model, TenSolver. sample (solution, reads))
644569 (assignment = assignment, items = item_bits (assignment, model. nitems))
645570 end
646- if ! (isassigned (observer_setup))
647- error (" penalty variance observer did not run" )
648- end
649571 return (;
650572 reported_objective,
651573 solution,
652574 assignment = sampling. value. assignment,
653575 items = sampling. value. items,
654576 variances,
655- observer_setup = observer_setup[],
656577 sampling = (time = sampling. time, gctime = sampling. gctime, memory = sampling. bytes),
657578 )
658579 end
659580 items = assert_stable_items (case_timed. outputs)
660581 output = case_timed. value
661- resources = penalty_resource_metrics (model; cutoff)
662582 return benchmark_result_row (
663583 instance,
664584 exact,
@@ -667,8 +587,7 @@ function penalty_row(
667587 output. reported_objective,
668588 formulation_timed,
669589 case_timed,
670- output. solution,
671- resources;
590+ output. solution;
672591 variances = output. variances,
673592 nvariables = length (output. assignment),
674593 iterations,
@@ -707,7 +626,8 @@ Run the hard-projection solve and a penalty-QUBO sensitivity sweep for every
707626instance. Returned rows report the original knapsack objective and feasibility,
708627not just each solver's encoded objective.
709628
710- Final-state variance is calculated from the MPS supplied to `on_iteration`.
629+ Final-state variance and operator bond dimensions come from solver-reported
630+ statistics.
711631Truncation error remains unavailable because the callback runs after discarded
712632singular values have been removed.
713633
0 commit comments