Skip to content

Commit

Permalink
feat: add opencl3 on AE-QTS
Browse files Browse the repository at this point in the history
  • Loading branch information
Young-TW committed Oct 18, 2024
1 parent b4fd067 commit 171f3a9
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 2 deletions.
30 changes: 30 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ edition = "2021"
rand = "0.8.4"
serde = { version = "1.0", features = ["derive"] }
toml = "0.8.19"
opencl3 = "0.4"
71 changes: 71 additions & 0 deletions src/aeqts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,74 @@ pub fn aeqts(
let _ = record.write_file();
best_fit
}

use crate::opencl::OpenCL;

pub fn boosted_aeqts(
items: &Items,
capacity: f64,
max_gen: i32,
n_neighbors: i32,
test_count: i32,
) -> Solution {
let opencl = OpenCL::new().expect("Failed to initialize OpenCL");

let mut qubits: Qubits = vec![Default::default(); items.len()];
let mut best_fit: Solution = vec![false; items.len()];
adjust_solution(&items, &mut best_fit, capacity);
let mut neighbors: Vec<Solution> = vec![vec![false; items.len()]; n_neighbors as usize];
let mut record = Record::new(format!("csv/ae-qts/{}.csv", test_count));

// 開始進行計算
for i in 0..max_gen {
for j in 0..n_neighbors {
// 使用 OpenCL 進行量子比特的測量
let mut solution: Vec<i32> = vec![0; items.len()];
let alpha_values: Vec<f32> = qubits.iter().map(|q| q.alpha as f32).collect();

opencl
.measure_qubits(&alpha_values, &mut solution)
.expect("Failed to measure qubits");

// 調整解
adjust_solution(items, &mut neighbors[j as usize], capacity);
}

// 排序解
neighbors.sort_by(|a, b| {
calculate_values(items, a)
.partial_cmp(&calculate_values(items, b))
.unwrap()
});

// 選擇最佳解
if calculate_values(items, &neighbors[neighbors.len() - 1])
> calculate_values(items, &best_fit)
{
best_fit = neighbors[neighbors.len() - 1].clone();
}

// 記錄解
record.add_iteration(
i,
calculate_values(items, &best_fit),
calculate_weights(items, &best_fit),
best_fit.clone(),
qubits.clone(),
);

// 更新量子比特
for j in 0..neighbors.len() / 2 {
update_qubits_with_angle(
neighbors[neighbors.len() - j - 1].clone(),
neighbors[j].clone(),
&mut qubits,
0.01 / (j + 1) as f64,
);
}
}

// 將結果寫入文件
let _ = record.write_file();
best_fit
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod aeqts;
pub mod case;
pub mod config;
pub mod debug;
pub mod opencl;
pub mod qts;
pub mod quantum;
pub mod qubit;
Expand Down
4 changes: 2 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use qts_rust::aeqts::aeqts;
use qts_rust::aeqts::boosted_aeqts;
use qts_rust::case::{case_1, case_2, case_3};
use qts_rust::config::Config;
use qts_rust::qts::qts;
Expand Down Expand Up @@ -58,7 +58,7 @@ fn main() {
let config = config.clone();
let handle = thread::spawn(move || {
let items = items.lock().unwrap();
aeqts(
boosted_aeqts(
&items,
config.problem.capacity,
config.algorithm.max_gen,
Expand Down
100 changes: 100 additions & 0 deletions src/opencl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
use opencl3::command_queue::CommandQueue;
use opencl3::context::Context;
use opencl3::device::{get_device_ids, Device, CL_DEVICE_TYPE_GPU};
use opencl3::kernel::Kernel;
use opencl3::memory::{Buffer, CL_MEM_READ_WRITE};
use opencl3::program::Program;
use opencl3::types::{cl_float, cl_int};
use std::ptr;

pub struct OpenCL {
context: Context,
queue: CommandQueue,
kernel_measure: Kernel,
}

impl OpenCL {
pub fn new() -> opencl3::Result<Self> {
let platform = opencl3::platform::get_platforms()?
.first()
.cloned()
.unwrap();
let device_ids = get_device_ids(platform.id(), CL_DEVICE_TYPE_GPU)?;
let device = Device::new(device_ids[0]);

let context = Context::from_device(&device)?;
let queue = CommandQueue::create_with_properties(&context, device.id(), 0, 0)?;

let source = r#"
__kernel void measure(__global float *qubits_alpha, __global int *solution, const int num_qubits) {
int id = get_global_id(0);
if (id < num_qubits) {
// 使用線性同餘生成器 (LCG) 來生成隨機數
uint seed = id; // 使用 id 作為隨機種子
seed = (1103515245 * seed + 12345) & 0x7fffffff;
float r = (float)seed / 2147483648.0f; // 正規化為 [0, 1) 的浮點數
solution[id] = (r < qubits_alpha[id] * qubits_alpha[id]) ? 1 : 0;
}
}
"#;

let program = Program::create_and_build_from_source(&context, source, "")
.expect("Failed to build OpenCL program");
let kernel_measure = Kernel::create(&program, "measure")?;

Ok(Self {
context,
queue,
kernel_measure,
})
}

pub fn measure_qubits(
&self,
qubits_alpha: &[f32],
solution: &mut [i32],
) -> opencl3::Result<()> {
let num_qubits = qubits_alpha.len();

let mut buffer_qubits_alpha = Buffer::<cl_float>::create(
&self.context,
CL_MEM_READ_WRITE,
num_qubits,
ptr::null_mut(),
)?;
let mut buffer_solution = Buffer::<cl_int>::create(
&self.context,
CL_MEM_READ_WRITE,
num_qubits,
ptr::null_mut(),
)?;

self.kernel_measure.set_arg(0, &buffer_qubits_alpha)?;
self.kernel_measure.set_arg(1, &buffer_solution)?;
self.kernel_measure.set_arg(2, &(num_qubits as cl_int))?;

self.queue.enqueue_write_buffer(
&mut buffer_qubits_alpha,
0,
qubits_alpha.len(),
qubits_alpha,
&[],
)?;

let global_work_size = [num_qubits];
self.queue.enqueue_nd_range_kernel(
self.kernel_measure.get(),
1,
ptr::null(),
global_work_size.as_ptr(),
ptr::null(),
&[],
)?;

self.queue
.enqueue_read_buffer(&mut buffer_solution, 0, solution.len(), solution, &[])?;

Ok(())
}
}

0 comments on commit 171f3a9

Please sign in to comment.