Trait bound not satisfied building an ndarray from a tuple trait - matrix

I am very new to Rust. Currently, I am looking for a way to generate a matrix with dimension based on a tuple.
use itertools::zip;
use ndarray::Array;
fn main() {
let mut layer_width: [u64; 4] = [784, 512, 256, 10]; //in- & output layers of the nn
init_nn(&mut layer_width);
}
fn init_nn(layer_width: &mut [u64; 4]) {
for (layer_in, layer_out) in zip(&layer_width[.. 4], &layer_width[1 ..]) {
let mut params = Array::zeros((layer_in, layer_out)); //error
}
}
The iteration through the zip works fine and i get output for either layer_in and _out, but when creating the the matrix I get the following error:
the trait bound `(&i64, &i64): ndarray::Dimension` is not satisfied
the trait `ndarray::Dimension` is not implemented for `(&i64, &i64)`
note: required because of the requirements on the impl of `ndarray::IntoDimension` for `(&i64, &i64)`rustc(E0277)
main.rs(13, 39): the trait `ndarray::Dimension` is not implemented for `(&i64, &i64)`
I very much need help from the community on this issue here. Many thanks.

The issue is you're passing in (&i64, &i64) to Array::zeros(), which is not valid. Instead, you can pass in (usize, usize). After fixing that, the code will still not compile, as we haven't given the compiler any way of knowing the element type, but that error will resolve itself once you do something like assign to the array.
Here's working code:
use itertools::zip;
use ndarray::Array;
fn main() {
let mut layer_width: [usize; 4] = [784, 512, 256, 10]; // in- & output layers of the nn
init_nn(&mut layer_width);
}
fn init_nn(layer_width: &mut [usize; 4]) {
for (&layer_in, &layer_out) in zip(&layer_width[..4], &layer_width[1..]) {
let mut params = Array::zeros((layer_in, layer_out));
// Dummy assignment so the compiler can infer the element type
params[(0, 0)] = 1;
}
}
Notice the added & in for (&layer_in, &layer_out). The output of the zip() function is (&usize, &usize), so we are using destructuring to dereference the references into plain usizes. Equivalently, you could have done Array::zeros((*layer_in, *layer_out)).

Related

Generate random float from Standard Normal distribution and multiply by another float

Trying to generate a random number from the Standard Normal distribution. Need to multiply the value by 0.1 to get the number range i'm looking for. I tried using the documentation from rand_dist you can find here: https://docs.rs/rand_distr/0.3.0/rand_distr/struct.StandardNormal.html
My Cargo.toml is the following:
[package]
name = "test_rng"
version = "0.1.0"
authors = ["Jack"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.7.3"
rand_distr = "0.3.0"
The starting rust code is the example provided in the rand_dist docs from above:
use rand::prelude::*;
use rand_distr::StandardNormal;
fn main() {
let val: f64 = thread_rng().sample(StandardNormal);
println!("{}", val);
}
When I run this it works as expected and the output is:
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 2.11s
Running `target\debug\test_rng.exe`
0.48398855288705356
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
This is where I'm hitting an issue, when I try to multiply the number by 0.1 in the following code I get the resulting error:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0284]: type annotations needed: cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
--> src\main.rs:5:24
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal);
| ^ cannot satisfy `<f64 as std::ops::Mul<_>>::Output == f64`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0284`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
I tried to change 0.1 to 0.1_f64 but that gave the same error.
I tried to convert random number to f64 (which it should already be) with as f64 but that resulted in the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
error[E0282]: type annotations needed
--> src\main.rs:5:39
|
5 | let val: f64 = 0.1 * thread_rng().sample(StandardNormal) as f64;
| ^^^^^^ cannot infer type for type parameter `T` declared on the associated function `sample`
|
= note: type must be known at this point
help: consider specifying the type arguments in the method call
|
5 | let val: f64 = 0.1 * thread_rng().sample::<T, D>(StandardNormal) as f64;
| ^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0282`.
error: could not compile `test_rng`.
To learn more, run the command again with --verbose.
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Thought it was a precedence issue so I tried wrapping second half in parenthesis but got the same error.
I can get it to work by making the variable mutable and separating the line into two operations like the following:
fn main() {
let mut val: f64 = thread_rng().sample(StandardNormal);
val *= 0.1;
println!("{}", val);
}
C:\Users\Jack\Desktop\projects\software\rust\test_rng>cargo run
Compiling test_rng v0.1.0 (C:\Users\Jack\Desktop\projects\software\rust\test_rng)
Finished dev [unoptimized + debuginfo] target(s) in 1.62s
Running `target\debug\test_rng.exe`
-0.034993448117065
C:\Users\Jack\Desktop\projects\software\rust\test_rng>
Any idea what is going on with the multiplication of the f64 with the output of the random number?
You can use the following:
fn main() {
let val: f64 = 0.1 * thread_rng().sample::<f64,_>(StandardNormal);
println!("{}", val);
}
This explicitly forces the sample function to return a f64. What was likely going on is that the rust type inference doesn't realize that the RHS needs to be f64, though I'm not sure exactly why.
Edit:
I think some the blame here goes to the definition of sample, in that it uses an unrestricted type parameter. An MVE for this would be:
pub trait Marker{}
impl Marker for f64{}
impl Marker for f32{}
fn does_not_work<T>() -> T{
unimplemented!()
}
fn does_work<T: Marker>() -> T{
unimplemented!()
}
fn main() {
let val: f64 = 0.1 * does_work();
let val: f64 = 0.1 * does_not_work();
}
It's somewhat understandable that the compiler can't infer types for does_not_work, b/c how is it meant to know about every possible type that could multiply with f64? However of we restrict things to only certain types with a trait, then the list of possible types becomes finite and type inference works again.

How do I convert a C-style enum generated by bindgen to another enum?

I am creating bindings in Rust for a C library and Bindgen generated enums like:
// Rust
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum rmw_qos_history_policy_t {
RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT = 0,
RMW_QOS_POLICY_HISTORY_KEEP_LAST = 1,
RMW_QOS_POLICY_HISTORY_KEEP_ALL = 2,
RMW_QOS_POLICY_HISTORY_UNKNOWN = 3,
}
I need to convert these to:
// Rust
pub enum QoSHistoryPolicy {
SystemDefault = 0,
KeepLast = 1,
KeepAll = 2,
Unknown = 3,
}
When importing constant values from this C library:
// C library
const rmw_qos_history_policy_t some_value_from_C = RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT;
I would like to do something like:
let some_value: QoSHistoryPolicy = some_value_from_C;
How can I go about it?
The compiler does not inspect enums for ABI compatibility, and as such does not provide a direct way to convert values between these types. A few possible solutions follow.
1. One-by-one matching
This is trivial and safe, albeit leading to exhaustive code.
impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
fn from(x: rmw_qos_history_policy_t) -> Self {
use rmw_qos_history_policy_t::*;
match x {
RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT => QoSHistoryPolicy::SystemDefault,
RMW_QOS_POLICY_HISTORY_KEEP_LAST => QoSHistoryPolicy::KeepLast,
RMW_QOS_POLICY_HISTORY_KEEP_ALL => QoSHistoryPolicy::KeepAll,
RMW_QOS_POLICY_HISTORY_UNKNOWN => QoSHistoryPolicy::Unknown,
}
}
}
2. Casting + FromPrimitive
Rust allows you to convert field-less enums into an integer type using the as operator. The opposite conversion is not always safe however. Derive FromPrimitive using the num crate to obtain the missing piece.
#[derive(FromPrimitive)]
pub enum QoSHistoryPolicy { ... }
impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
fn from(x: rmw_qos_history_policy_t) -> Self {
FromPrimitive::from_u32(x as _).expect("1:1 enum variant matching, all good")
}
}
3. Need an enum?
In the event that you just want an abstraction to low-level bindings, you might go without a new enum type.
#[repr(transparent)]
pub struct QoSHistoryPolicy(rmw_qos_history_policy_t);
The type above contains the same information and binary representation, but can expose an encapsulated API. The conversion from the low-level type to the high-level type becomes trivial. The main downside is that you lose pattern matching over its variants.
4. You're on your own
When absolutely sure that the two enums are equivalent in their binary representation, you can transmute between them. The compiler won't help you here, this is far from recommended.
unsafe {
let policy: QoSHistoryPolicy = std::mem::transmute(val);
}
See also:
How do I match enum values with an integer?
It looks to be a good candidate for the From trait on QoSHistoryPolicy.
impl From<rmw_qos_history_policy_t> for QoSHistoryPolicy {
fn from(raw: rmw_qos_history_policy_t) -> Self {
match raw {
rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT => QoSHistoryPolicy::SystemDefault,
rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_LAST => QoSHistoryPolicy::KeepLast,
rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_KEEP_ALL => QoSHistoryPolicy::KeepAll,
rmw_qos_history_policy_t::RMW_QOS_POLICY_HISTORY_UNKNOWN => QoSHistoryPolicy::Unknown
}
}
}
so this should now work
let some_value: QoSHistoryPolicy = some_value_from_C.into();

How do I store a Random number generator in a struct?

I am trying to store a Random number generator in a struct. I can't seem to get the struct definition for any Rng structs to be recognized, like ThreadRng. This works:
use rand::{
self,
distributions::{Distribution, Uniform},
}; // 0.6.4
fn main() {
let mut rng = rand::thread_rng();
let die_range = Uniform::new_inclusive(1, 6);
let die = die_range.sample(&mut rng);
println!("{}", die);
}
However, if I try to define a variable to have the actual type of the Rng, I get an error:
use rand::{
self,
ThreadRng,
distributions::{Distribution, Uniform},
}; // 0.6.4
fn main() {
let mut rng :ThreadRng = rand::thread_rng();
let die_range = Uniform::new_inclusive(1, 6);
let die = die_range.sample(&mut rng);
println!("{}", die);
}
The error is:
error[E0432]: unresolved import `rand::ThreadRng`
--> src/main.rs:3:5
|
3 | ThreadRng,
| ^^^^^^^^^
| |
| no `ThreadRng` in the root
| help: a similar name exists in the module: `thread_rng`
I want to store the Rng in a struct, and I do not want a trait object. How do I import the definition of ThreadRng? Or XorShiftRng (which might be faster - I do not need cryptographic strength)? Is the type in some sub-module I don't know about? All the examples I read online call a method to get the Rng and use it locally; they never store it in a struct and never define any variables that use the struct name.
If you look at the documentation rand::thread_rng, you can click on its return type to see that its fully qualified name is actually rand::rngs::ThreadRng.

How to create a subscription for events in Windows using Rust and the winapi crate?

I'm trying to subscribe to Windows events using EvtSubscribe from the winapi crate, but I'm getting ERROR_INVALID_PARAMETER.
I can not find an example in Rust, but did find a C++ example.
My code that produces ERROR_INVALID_PARAMETER:
fn main() {
unsafe {
let mut callback: winapi::um::winevt::EVT_SUBSCRIBE_CALLBACK = None;
let mut session = std::ptr::null_mut();
let mut signal_event = std::ptr::null_mut();
let mut bookmark = std::ptr::null_mut();
let mut context = std::ptr::null_mut();
let channel_path = "Security";
let channel_path: winnt::LPWSTR = to_wchar(channel_path);
let query = "Event/System[EventID=4624]";
let query: winnt::LPWSTR = to_wchar(query);
let event_handle = winevt::EvtSubscribe(
session,
signal_event,
channel_path,
query,
bookmark,
context,
callback,
winevt::EvtSubscribeStartAtOldestRecord,
);
//println!("{:?}", &event_handle);
println!("{:?}", &winapi::um::errhandlingapi::GetLastError());
} //unsafe end
}
fn to_vec(str: &str) -> Vec<u16> {
return OsStr::new(str)
.encode_wide()
.chain(Some(0).into_iter())
.collect();
}
fn to_wchar(str: &str) -> *mut u16 {
return to_vec(str).as_mut_ptr();
}
The documentation for EvtSubscribe states:
SignalEvent
[...] This parameter must be NULL if the Callback parameter is not
NULL.
Callback
[...] This parameter must be NULL if the SignalEvent parameter is
not NULL.
The unstated implication here is that exactly one of these parameters must be provided. Passing both is explicitly disallowed, but passing neither would not make sense, as otherwise there would be no way for your code to receive the event.
Passing one of these values should cause the code to start working.
Editorially, this is a good example of where a Rust enum would have been a better way to model the API. This would clearly show that the two options are mutually exclusive and one is required:
enum Subscriber {
EventObject(HANDLE),
Callback(EVT_SUBSCRIBE_CALLBACK),
}
Incidentally, your implementation of to_wchar is incorrect and likely leads to memory unsafety. to_vec allocates memory, you take a pointer to it, then that memory is deallocated, creating a dangling pointer. The bad pointer is read by the C code inside of the unsafe block — part of the reason unsafe is needed.
You either need to use mem::forget, as shown in How to expose a Rust `Vec<T>` to FFI? (and then you need to prevent leaking the memory somehow), or you need to take a reference to the data instead of taking the raw pointer.

Unable to initialize a TriMat matrix from the SPRS library

I am trying to use the sparse matrix library SPRS and am having trouble initializing a matrix. Why does this not work?
extern crate sprs;
use sprs::TriMat;
fn main() {
let mut matrix = TriMat::new((5, 5));
}
The error is
error[E0282]: type annotations needed
--> src/main.rs:5:22
|
5 | let mut matrix = TriMat::new((5, 5));
| ---------- ^^^^^^^^^^^ cannot infer type for `N`
| |
| consider giving `matrix` a type
You just need to tell it the type of the elements of the matrix. For example, if it's a matrix of i32 then:
let mut matrix: TriMat<i32> = TriMat::new((5, 5));
This can't be inferred from the new constructor because that only takes an argument for the shape of the matrix, which doesn't include elements of the element type.
If you actually start storing data in the matrix, then the type annotation mostly won't be necessary because it will be inferred from the data:
let mut matrix = TriMat::new((5, 5));
matrix.add_triplet(0, 0, 42); // 42 literal is `i32` by default.
TriMat is:
type TriMat<N> = TriMatI<N, usize>;
TriMatI is:
type TriMatI<N, I> = TriMatBase<Vec<I>, Vec<N>>;
TriMatBase is:
pub struct TriMatBase<IStorage, DStorage> { /* fields omitted */ }
TriMatBase::new is:
pub fn new(shape: (usize, usize)) -> TriMatI<N, I>
Putting those together, you are effectively calling
TriMatBase::<_, usize>::new((5, 5));
The first type parameter is undecidable based on the code you've provided. In many cases, you do something with the value which will allow the compiler to pin down the concrete type. Since you just construct it and throw it away, there's a theoretical infinite number of types this could end up being.
You need to specify the type using the turbofish:
TriMat::<usize>::new((5, 5));
Or an explicit type on the variable:
let matrix: TriMat<usize> = TriMat::new((5, 5));
Or write some more code that will force the compiler to know the concrete type.

Resources