Open13

適当なメモ

tomozosantomozosan

Rust ファイル参照して開くときどうやって参照したら良いのか指定方法.

cargo new my_cargo

で作ったプロジェクト

my_cargo
├── Cargo.lock
├── Cargo.toml
└── src
    ├── iris.csv
    └── main.rs

main.rs から iris.csv を読み込みたい場合どうすんの ?

プロジェクトのホームディレクトリmy_cargoからのパスで指定.

main.rs
fn main()  {
    let my_path = "src/iris.csv";
    let file = File::open(&my_path).expect("Cannot open file.");
}

main.rsからの相対パスだと思って let my_path = "./iris.csv";だと思っていたら違った.

tomozosantomozosan

YOLOX の訓練のときに要求するディレクトリ構造がわかりづらい

公式レポのREADME.md に明示的に書いてないんで、初見でやろうとすると絶対つまづく。
一応 ここ
に記載されているけども.. それにしてももう少しわかりやすく書いてくれないかなあ。

.
├── datasets  # my_custom_exp.py に記載した Exp classで指定する.
│   ├── annotations  # この名前の通りでないとだめ.
│   │   ├── instances_train2017.json # my_custom_exp.py に記載した Exp classで指定する.
│   │   └── instances_val2017.json # my_custom_exp.py に記載した Exp classで指定する.
│   ├── train2017  #  この名前の通りでないとだめ.
│   │   ├── train_image1.jpg 
│   │   └── train_image2.jpg
│   └── val2017 #  この名前の通りでないとだめ.
│       ├── val_image1.jpg
│       └── val_image2.jpg
├── my_custom_exp.py
└── train.py  #  訓練ファイル 公式レポをそのまま自分の作業ディレクトリにコピー
tomozosantomozosan

ラズパイ新しくインストールし直して接続 有線LAN ケーブルを使って, 他のMac などPCからssh 接続しようとする場合エラー出るのでそのときの解決方法

mac, windowsなどの hostから
ssh pi@raspberrypi.local

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@ WARNING: POSSIBLE DNS SPOOFING DETECTED! @

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
The ECDSA host key for raspberrypi.local has changed,
and the key for the corresponding IP address XXXXXXXXXXXXXXXXX
is unknown. This could either mean that
DNS SPOOFING is happening or the IP address for the host
and its host key have changed at the same time.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
SHA256:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Please contact your system administrator.
Add correct host key in /Users/XXXXXX/.ssh/known_hosts to get rid of this message.
Offending ECDSA key in /Users/XXXXXX/.ssh/known_hosts:10
ECDSA host key for raspberrypi.local has changed and you have requested strict checking.
Host key verification failed.

mac, windowsなどの hostから
ssh-keygen -R raspberrypi.local

参考URL

  1. 【Raspberry Pi 備忘録】ラズベリーパイのSSH接続時のエラー「POSSIBLE DNS SPOOFING DETECTED! 」「REMOTE HOST IDENTIFICATION HAS CHANGED! 」
  2. SSH接続エラー回避方法:.ssh/known_hostsから特定のホストを削除する/削除しないで対処する3つの方法
tomozosantomozosan

Rust で Quicksortを実装してみる.

Test

#[cfg(test)]
mod tests {
    use crate::quick_sort;

    #[test]
    fn test_quick_sort_when_some_i32_elements_exist_in_input() {
        // Given input v
        let v = vec![3, 1, 5, 4, 6, 2];
        // When calling quick_sort
        let result = quick_sort(v);
        // Then the numbers should be nicely sorted !!
        assert_eq!(vec![1, 2, 3, 4, 5, 6], result);
    }

    #[test]
    fn test_quick_sort_when_single_i32_element_exists_in_input() {
        // Given input v
        let v = vec![1];
        // When calling quick_sort
        let result = quick_sort(v);
        // Then the number should be returned the same as the input.
        assert_eq!(vec![1], result);
    }

    #[test]
    fn test_quick_sort_when_vacant_vector_given_as_input() {
        // Given vacant vector as input,
        let v = vec![];
        // When calling quick_sort
        let result = quick_sort(v);
        // Then the number should be returned as vec![] as Vec<i32>.
        assert_eq!(Vec::<i32>::new(), result);
    }
}

実装

fn quick_sort(v: Vec<i32>) -> Vec<i32> {
    println!("quick_sort called here {:?}", v);
    let res: Option<(&i32, &[i32])> = (&v).split_first();
    if v.len() == 0 {
        return v;
    }
    if v.len() == 1 {
        return v;
    }
    let (pivot, rest_v) = res.unwrap();
    let left = rest_v.iter()
        .filter(|item| item < &pivot)
        .collect::<Vec<&i32>>();

    let right = rest_v.iter()
        .filter(|item| item >= &pivot)
        .collect::<Vec<&i32>>();

    println!("Recursive call 'left' from here");

    let left = quick_sort(left.iter()
        .map(|x| **x)
        .collect::<Vec<i32>>());

    println!("Recursive call 'right' from here");


    let right = quick_sort(right.iter()
        .map(|x| **x)
        .collect::<Vec<i32>>());

    println!("Recursive call end");
    println!("left: {:?}, center: {:?} right: {:?}", &left, vec![&pivot], &right);

    let sorted = [left, vec![*pivot], right].concat().iter()
        .map(|x| *x)
        .collect::<Vec<i32>>();
    println!("Concat result: {:?}", &sorted);

    return sorted
}
tomozosantomozosan

コメント

  • Iteratorまわりの振る舞いが難しい. Vec<i32>.iter()で取り出される要素が参照になったり, 再帰呼び出しを行うために, 参照外しを行ったり, 自分がやっている型変換が正しいのか? もし正しくても, もっとまともなやり方あるんじゃあねえか?と思考の迷子になりがち, Rustが難しいと言われる理由はこういうところにあるのだろなと.
fn main() {
    let v = vec![3, 5, 6, 2, 4, 1];
    assert_eq!(vec![1, 2, 3, 4, 5, 6], quick_sort(v));
}
  • 再帰呼び出しの振る舞いがつかみづらい.
  • 呼び出し順は left を再帰で呼び出しまくって, その後で rightを呼び出しまくって,concatで結合.
quick_sort called here [3, 5, 6, 2, 4, 1]
#  --- まずは split_firstを使って 最初の3 (pivot) と残り (rest)に分けて,
#  --- 3より小さいものを left = [1, 2], 大きいものを right = [5, 6, 4]として

#  --- left をまたquick_sortに入れて呼び出し.
Recursive call 'left' from here
quick_sort called here [2, 1]
Recursive call 'left' from here
quick_sort called here [1]
#  --- 要素の数 1になったので 最初の left の再帰呼び出し終了.

# --- ここからは pivot=3と[2, 1]の配列に対する右側配列だから空.
Recursive call 'right' from here
quick_sort called here []
Recursive call end
left: [1], center: [2] right: []
Concat result: [1, 2]
#  ---これでようやくpivot=3と[2, 1]に対する処理が終了.

#  ---最初の[3, 5, 6, 2, 4, 1]に対する pivot=3, right=[5, 4, 6]の入力がここからスタート.
Recursive call 'right' from here
quick_sort called here [5, 6, 4]
Recursive call 'left' from here
quick_sort called here [4]
Recursive call 'right' from here
quick_sort called here [6]
Recursive call end
left: [4], center: [5] right: [6]
Concat result: [4, 5, 6]
Recursive call end
#  ----pivot=3と[5, 6, 4]に対する処理が終了.
left: [1, 2], center: [3] right: [4, 5, 6]
Concat result: [1, 2, 3, 4, 5, 6]
tomozosantomozosan

Rust の std::str::FromStr と filter_mapの合わせ技が超強力!!

FromStrについて

こんな使い方ができる.

use std::str::FromStr;

#[test]
fn test_f64_from_str() {
    let n = f64::from_str("2").unwrap();
    assert_eq!(n, 2f64);
}

#[test]
#[should_panic(expected = "kind: Invalid")]
fn test_文字列はParseFloatError() {
    let s = f64::from_str("a"); // ParseFloatError
    s.unwrap();
}


#[test]
#[should_panic(expected = "kind: Invalid")]
fn test_f64_from_str_with_space() {
    f64::from_str("2  ").unwrap();
    // ParseFloatError {kind: Invalid}
}

#[test]
fn test_f64_from_str_containing_space_require_trim() {
    let actual = f64::from_str("  2  ".trim()).unwrap();
    assert_eq!(actual, 2f64);
}

#[test]
fn test_f64_from_str_dot_exists_before_int_can_convert_to_f64() {
    let actual = f64::from_str(".2").unwrap();
    assert_eq!(actual, 0.2f64);
}

filter_mapについて

15.3 イテレータアダプタ 330ページより
https://www.oreilly.co.jp/books/9784873119786/

use std::str::FromStr;
#[test]
fn test_filter_from_str_with_filer_map() {
    let text = "1\nfrond .25 289\n3.1415 estuary\n";
    let numbers = text.split_whitespace()
        .filter_map(|w| f64::from_str(w)  // std::str::FromStr
            // filter_mapは Someの中身を取り出し Noneの値をDropする
            .ok()) // .okによりErr の場合はNoneを返す
        .collect::<Vec<f64>>();
    assert_eq!(numbers, [1f64, 0.25, 289f64, 3.1415f64]);
}

tomozosantomozosan

Rustのテスト書いているときにResult型の返すErrorを特定したいとなったが...

この記事を見るにかなり大変 💦
結局むりやり unwrapでパニックをおこしてエラーメッセージを補足するようなやり方が手軽そうではある.
なんかいい方法ないのかな?
https://zhauniarovich.com/post/2021/2021-01-testing-errors-in-rust/

#[test]
#[should_panic(expected="kind: InvalidDigit")]
fn test_zero_division() {
    let number_str = "10 ";
    number_str.parse::<i32>() // Result<i32, ParseIntError>
       .unwrap(); // ParseIntError({ kind: InvalidDigit }) 

}
tomozosantomozosan

pub(crate) の意味

pub(crate)はRustのアクセス修飾子で、その要素は同じcrate(ライブラリやモジュールの集合)内からのみアクセス可能です。つまり、他のcrateからはアクセスできないが、同じcrate内からはアクセスできるという意味です。このように、crate内部のアクセス制限を設定することで、crateのインターフェイスを隠蔽し、実装の詳細を隠すことができます。
上記の例で言うと、 Config struct は、外部のモジュールからはアクセスできないが、同じcrate内部ではアクセスできる、という意味になる。