1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
use std::{ffi::CString, path::Path, pin::Pin, ptr};
use smile::{
autocxx::{c_int, c_void, cxx::let_cxx_string, WithinBox},
ffi::DSL_network,
};
use crate::{
errors::{CIntExt, Result},
traits::ToDslValue,
};
use super::{BayesianNetworkAlgorithm, InfluenceDiagramAlgorithm};
/// A Bayesian Network.
pub struct Network {
pub(super) dsl_network: Pin<Box<DSL_network>>,
}
impl PartialEq for Network {
fn eq(&self, other: &Self) -> bool {
// TODO: compare nodes, arcs, beliefs, and all other network properties
true
}
}
impl Eq for Network {}
impl Network {
/// Create a new uninitialized network.
pub fn new_uninitialized() -> Self {
let dsl_network = DSL_network::new().within_box();
Self { dsl_network }
}
/// Create a new network from an XDSL string.
///
/// Example usage:
/// ```rust
/// # use nice_smile::network::Network;
/// # use nice_smile::errors::Result;
/// # fn try_main() -> Result<()> {
/// # let mut network1 = Network::new_uninitialized();
/// # let xdsl = network1.to_xdsl_string()?;
/// let network = Network::from_xdsl_string(&xdsl)?;
/// # assert!(network == network1);
/// assert_ne!(xdsl, "".to_string());
/// # Ok(()) }
/// ```
pub fn from_xdsl_string(xdsl_string: impl AsRef<str>) -> Result<Self> {
let mut network = Self::new_uninitialized();
let null_void_ptr: *mut c_void = ptr::null_mut();
unsafe {
network
.dsl_network
.as_mut()
.ReadString(CString::new(xdsl_string.as_ref())?.as_ptr(), null_void_ptr)
.into_result()?
}
Ok(network)
}
/// Export the network to an XDSL string.
///
/// Example usage:
/// ```rust
/// # use nice_smile::network::Network;
/// # use nice_smile::errors::Result;
/// # fn try_main() -> Result<()> {
/// let mut network = Network::new_uninitialized();
/// let xdsl = network.to_xdsl_string()?;
/// assert_ne!(xdsl, "".to_string());
/// # Ok(()) }
/// ```
pub fn to_xdsl_string(&mut self) -> Result<String> {
let null_void_ptr: *mut c_void = ptr::null_mut();
let_cxx_string!(xdsl = "");
unsafe {
self.dsl_network
.as_mut()
.WriteString(xdsl.as_mut(), null_void_ptr)
.into_result()?;
}
Ok(xdsl.to_string())
}
/// Read a network from a file.
///
/// The file type is determined automaticaly by the file_path extension.
/// For the supported file types list, refer to the [smile::ffi::DSL_network::ReadFile].
pub fn read_from_file(file_path: impl AsRef<Path>) -> Result<Network> {
let mut network = Network::new_uninitialized();
let null_void_ptr: *mut c_void = ptr::null_mut();
let file_path =
CString::new(file_path.as_ref().to_string_lossy().into_owned().as_str())?.as_ptr();
unsafe {
network
.dsl_network
.as_mut()
.ReadFile(file_path, c_int(0), null_void_ptr)
.into_result()?;
}
Ok(network)
}
/// Write the network to a file.
///
/// The file type is determined automaticaly by the file_path extension.
/// For the supported file types list, refer to the [smile::ffi::DSL_network::ReadFile].
pub fn write_to_file(&mut self, file_path: impl AsRef<Path>) -> Result<()> {
let null_void_ptr: *mut c_void = ptr::null_mut();
let file_path =
CString::new(file_path.as_ref().to_string_lossy().into_owned().as_str())?.as_ptr();
unsafe {
self.dsl_network
.as_mut()
.WriteFile(file_path, c_int(0), null_void_ptr)
.into_result()
}
}
/// Executes inference algorithm to update node values. Returns DSL_OKAY on success, or a negative error code on failure.
pub fn update_beliefs(&mut self) -> Result<()> {
self.dsl_network.as_mut().UpdateBeliefs().into_result()
}
/// Invalidates values in all nodes of the [Network].
pub fn invalidate_all_beliefs(&mut self) -> Result<()> {
self.dsl_network
.as_mut()
.InvalidateAllBeliefs()
.into_result()
}
/// Sets the immediate update flag.
///
/// If the flag is set to `true`, [Self::update_beliefs] will be called after changes in the network structure, parameters or evidence.
pub fn is_update_immediate(&self) -> bool {
self.dsl_network.as_ref().IsUpdateImmediate()
}
/// Returns the update immediate flag.
///
/// For more information, refer to the [Self::is_update_immediate].
pub fn set_update_immediate(&mut self, immediate: bool) {
self.dsl_network.as_mut().SetUpdateImmediate(immediate);
}
/// Sets the algorithm used for inference in Bayesian networks.
pub fn set_bayesian_network_algorithm(&mut self, algorithm: BayesianNetworkAlgorithm) {
self.dsl_network
.as_mut()
.SetDefaultBNAlgorithm(algorithm.to_dsl_value());
}
/// Sets the algorithm used for inference in influence diagrams.
pub fn set_influence_diagram_algorithm(&mut self, algorithm: InfluenceDiagramAlgorithm) {
self.dsl_network
.as_mut()
.SetDefaultIDAlgorithm(algorithm.to_dsl_value());
}
// TODO: CalcProbEvidence
}
impl Clone for Network {
/// Clone the network.
/// ```rust
/// # use nice_smile::network::Network;
/// let network1 = Network::new_uninitialized();
/// // TODO: add nodes to the network
/// let network2 = network1.clone();
/// assert!(network1 == network2);
/// ```
fn clone(&self) -> Self {
let mut network = Self::new_uninitialized();
network
.dsl_network
.as_mut()
.Copy(&self.dsl_network, c_int(0));
network
}
}