1use numpy::{IntoPyArray, PyArray1, PyArray2};
8use pyo3::prelude::*;
9use scirs2_autograd::ndarray::{Array1, Array2};
10use scirs2_core::random::{thread_rng, Rng};
12use std::collections::HashMap;
13
14#[pyfunction]
19pub fn get_version() -> String {
20 env!("CARGO_PKG_VERSION").to_string()
21}
22
23#[pyfunction]
25pub fn get_build_info() -> HashMap<String, String> {
26 let mut info = HashMap::new();
27
28 info.insert("version".to_string(), env!("CARGO_PKG_VERSION").to_string());
29 info.insert("authors".to_string(), env!("CARGO_PKG_AUTHORS").to_string());
30 info.insert(
31 "description".to_string(),
32 env!("CARGO_PKG_DESCRIPTION").to_string(),
33 );
34 info.insert(
35 "homepage".to_string(),
36 env!("CARGO_PKG_HOMEPAGE").to_string(),
37 );
38 info.insert(
39 "repository".to_string(),
40 env!("CARGO_PKG_REPOSITORY").to_string(),
41 );
42 info.insert("license".to_string(), env!("CARGO_PKG_LICENSE").to_string());
43 info.insert(
44 "rust_version".to_string(),
45 env!("CARGO_PKG_RUST_VERSION").to_string(),
46 );
47
48 info.insert(
50 "target_triple".to_string(),
51 std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string()),
52 );
53 info.insert(
54 "build_profile".to_string(),
55 if cfg!(debug_assertions) {
56 "debug"
57 } else {
58 "release"
59 }
60 .to_string(),
61 );
62
63 let features = [
65 #[cfg(feature = "pandas-integration")]
66 "pandas-integration",
67 ];
68
69 info.insert("features".to_string(), features.join(", "));
70
71 info.insert("scirs2_core_version".to_string(), "workspace".to_string());
73 info.insert("pyo3_version".to_string(), "0.26".to_string());
74 info.insert("numpy_version".to_string(), "0.26".to_string());
75
76 info
77}
78
79#[pyfunction]
81pub fn has_feature(feature_name: &str) -> bool {
82 match feature_name {
83 "pandas-integration" => {
84 #[cfg(feature = "pandas-integration")]
85 return true;
86 #[cfg(not(feature = "pandas-integration"))]
87 return false;
88 }
89 _ => false,
90 }
91}
92
93#[pyfunction]
95pub fn get_hardware_info() -> HashMap<String, bool> {
96 let mut info = HashMap::new();
97
98 #[cfg(target_arch = "x86_64")]
100 {
101 info.insert("x86_64".to_string(), true);
102 info.insert("avx2".to_string(), is_x86_feature_detected!("avx2"));
103 info.insert("fma".to_string(), is_x86_feature_detected!("fma"));
104 info.insert("sse4_1".to_string(), is_x86_feature_detected!("sse4.1"));
105 info.insert("sse4_2".to_string(), is_x86_feature_detected!("sse4.2"));
106 }
107
108 #[cfg(target_arch = "aarch64")]
109 {
110 info.insert("aarch64".to_string(), true);
111 info.insert("neon".to_string(), cfg!(target_feature = "neon"));
112 }
113
114 #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
116 {
117 info.insert("simd_support".to_string(), false);
118 }
119
120 info.insert("cuda_available".to_string(), false);
122 info.insert("opencl_available".to_string(), false);
123
124 info.insert("parallel_support".to_string(), true);
126 info.insert("num_cpus".to_string(), num_cpus::get() > 1);
127
128 info
129}
130
131#[pyfunction]
133pub fn get_memory_info() -> HashMap<String, u64> {
134 let mut info = HashMap::new();
135
136 info.insert("num_cpus".to_string(), num_cpus::get() as u64);
138
139 info.insert("available_memory_mb".to_string(), 0);
142 info.insert("used_memory_mb".to_string(), 0);
143
144 info
145}
146
147#[pyfunction]
149pub fn set_config(option: &str, _value: &str) -> PyResult<()> {
150 match option {
151 "n_jobs" => {
152 Ok(())
155 }
156 "assume_finite" => {
157 Ok(())
159 }
160 "working_memory" => {
161 Ok(())
163 }
164 _ => Err(pyo3::exceptions::PyValueError::new_err(format!(
165 "Unknown configuration option: {}",
166 option
167 ))),
168 }
169}
170
171#[pyfunction]
173pub fn get_config() -> HashMap<String, String> {
174 let mut config = HashMap::new();
175
176 config.insert("n_jobs".to_string(), "1".to_string());
178 config.insert("assume_finite".to_string(), "false".to_string());
179 config.insert("working_memory".to_string(), "1024".to_string());
180 config.insert("print_changed_only".to_string(), "true".to_string());
181 config.insert("display".to_string(), "text".to_string());
182
183 config
184}
185
186#[pyfunction]
188pub fn show_versions() -> String {
189 let mut output = String::new();
190
191 output.push_str("sklears information:\n");
192 output.push_str("=====================\n");
193
194 let build_info = get_build_info();
195 for (key, value) in &build_info {
196 output.push_str(&format!("{}: {}\n", key, value));
197 }
198
199 output.push_str("\nHardware information:\n");
200 output.push_str("====================\n");
201
202 let hardware_info = get_hardware_info();
203 for (key, value) in &hardware_info {
204 output.push_str(&format!("{}: {}\n", key, value));
205 }
206
207 output.push_str("\nMemory information:\n");
208 output.push_str("==================\n");
209
210 let memory_info = get_memory_info();
211 for (key, value) in &memory_info {
212 output.push_str(&format!("{}: {}\n", key, value));
213 }
214
215 output
216}
217
218#[pyfunction]
220pub fn benchmark_basic_operations() -> HashMap<String, f64> {
221 use std::time::Instant;
222
223 let mut results = HashMap::new();
224 let mut rng = thread_rng();
225
226 let start = Instant::now();
228 let a = Array2::from_shape_fn((100, 100), |_| rng.gen::<f64>());
229 let b = Array2::from_shape_fn((100, 100), |_| rng.gen::<f64>());
230 let _c = a.dot(&b);
231 let matrix_mul_time = start.elapsed().as_nanos() as f64 / 1_000_000.0; results.insert(
233 "matrix_multiplication_100x100_ms".to_string(),
234 matrix_mul_time,
235 );
236
237 let start = Instant::now();
239 let v1 = Array1::from_shape_fn(10000, |_| rng.gen::<f64>());
240 let v2 = Array1::from_shape_fn(10000, |_| rng.gen::<f64>());
241 let _dot_product = v1.dot(&v2);
242 let vector_ops_time = start.elapsed().as_nanos() as f64 / 1_000_000.0;
243 results.insert("vector_dot_product_10k_ms".to_string(), vector_ops_time);
244
245 let start = Instant::now();
247 let _large_array = Array2::<f64>::zeros((1000, 1000));
248 let allocation_time = start.elapsed().as_nanos() as f64 / 1_000_000.0;
249 results.insert(
250 "memory_allocation_1M_elements_ms".to_string(),
251 allocation_time,
252 );
253
254 results
255}
256
257pub fn numpy_to_ndarray2(_py_array: &PyArray2<f64>) -> PyResult<Array2<f64>> {
259 Ok(Array2::zeros((1, 1)))
261}
262
263pub fn numpy_to_ndarray1(_py_array: &PyArray1<f64>) -> PyResult<Array1<f64>> {
265 Ok(Array1::zeros(1))
267}
268
269pub fn ndarray_to_numpy<'py>(py: Python<'py>, array: Array2<f64>) -> Py<PyArray2<f64>> {
271 array.into_pyarray(py).into()
272}
273
274pub fn ndarray1_to_numpy<'py>(py: Python<'py>, array: Array1<f64>) -> Py<PyArray1<f64>> {
276 array.into_pyarray(py).into()
277}