_gpu_candidates was never populated (typo: _candidate_gpus), breaking
num_gpus()/available_gpu_ids() and the multi-GPU round-robin. available_gpu_ids
also indexed tuples with dict syntax (TypeError). disable_gpu() now frees the
memory pool before clearing refs (was leaking VRAM). to_cpu() and safe_gpu_call()
survive disable_gpu() via a persistent _cupy_ndarray type reference so orphaned
GPU arrays are recovered to CPU. log_gpu_status() now uses Device(0) instead of
the host index (CuPy renumbers to 0 after CUDA_VISIBLE_DEVICES).