ゆくゆくは有へと

おかゆ/彼ノ∅有生 の雑記

Disjoint set を勉強した AOJ #2512222 - Python編

Disjoint Set: Union Find Tree | Aizu Online Judge

AOJの解説とは異なり、root が自身へのポインタではなく、その木の集合を持つようにしてある。

当たり前ながら、破壊的更新ができるなら冗長な構造ですけど、ちょっと先のことも踏まえてこうした。

Pythonの集合はたしかハッシュセットなので、そこまで極端に速度落ちないことを期待する。

あと、競プロにありがちなデータ入力が毎回打つのダルすぎて、Stdinクラスに関数をまとめた。

パターンマッチ使いて~~~~~~~~~~~~~~~~~~~~~~~

Aizu #2512222

勉強がてら二分木をつくった回

純粋関数型データ構造

純粋関数型データ構造

今これ↑を読んでて、二分木の実装を練習がてらRustでしてみようと思ったのがきっかけ。

BTreeを実装しようとした

下の木をムーブしないようにmatchref 付けまわるのがたいへんでした(小並感)

やってて気づいたけど、この本にあるように、下の木を共有するの、Rustじゃデフォでできんや~ん

純粋だからこそ共有できるんやね(あたりまえのことをじっかんする)。

〈じゅんすいかんすう型でーたこうぞう〉の二分木をつくるなら、Rc使えばよさそうですね:

純粋な二分木

たぶん

追記 8/24 3:00

RustのBTreeMapはどうなってるんだろうと思ってソース見てみた:

doc.rust-lang.org

んんっ、なんだこのnodeモジュールとやらはっ ソースどこにあるんだろわからん

指定文字消すのどうすればいいんや

abc002.contest.atcoder.jp

“The Rust Programming Language” の第二版を最終章除いて読み終わったので、Atcoderでぽちぽちコード書く練習してるんだけど、 API全然知らないのでもうわっかんな~い(へらへら)

ありがたい………

qiita.com

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = buffer.trim().to_string();
    for ch in "aeiou".chars() {
        word = word.split(ch).collect::<Vec<_>>().concat();
    }
    println!("{}", word);
}

効率的な文字の消し方が分からんかったので、各母音字でsplitして集めてを繰り返すという微妙なやりかたをした。

調べてて気づいたが、collect::<Vec<_>>().concat() でなく、collect::<String>()にしたほうが賢いね。
collectFromIteratorトレイトのメソッドで、charイテレータStringにコレクトできるので。

というようなことを考えてると、for文消したくなるね。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word = buffer.trim().to_string();
    let word = "aeiou".chars().fold(word, |w, c| w.split(c).collect::<String>());
    println!("{}", word);
}

畳み込めばいいよね!ってことで畳み込んだ。

もう少し素朴なやりかた。containsStringpushをおぼえた。

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let mut word = String::new();
    for c in buffer.trim().chars() {
        if !['a', 'e', 'i', 'o', 'u'].contains(&c) {
            word.push(c)
        }
    }

    println!("{}", word);
}

&strcharの配列なりスライスではないので、if !['a', 'e', 'i', 'o', 'u'].contains(&c)と書かないといけないのがPythonマンのおかゆには厳しさがある。

if !"aeiou".chars().collect<Vec<_>>.contains(&c)とすればいけるけど。もっと簡単な書き方あるのかな~。

と色々書いてて思いついたけど、filter使えばいいのでは……?

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .chars()
                             .filter(|c| !['a', 'e', 'i', 'o', 'u'].contains(&c))
                             .collect();
    println!("{}", word);
}

やっぱイテレータ触るならチェーンやで……!といわんばかりのチェーン 単語を文字のイテレータにして、子音だけパスしてコレクト。リストの内包表記こそ使えないものの、それにいちばん近いのは今までの中ならこれかな?

Pythonでなら、多分こう書くもんな:

word = "".join([c for c in word if c not in "aeiou"])
print(word)

f:id:waraby0ginger:20170807012446j:plain

追記(2017/8/7/20:05):replace あるやんけ

use std::io;

fn main() {
    let mut buffer = String::new();
    io::stdin().read_line(&mut buffer).unwrap();

    let word: String = buffer.trim()
                             .replace(&['a', 'e', 'i', 'o', 'u'][..], "");
    println!("{}", word);
}

あれからstrのこと調べてると、スライスとstrcontains, starts_with, ends_with, find, split系の引数が違うらしいことを知った。

strでは、要素1つの代わりにパターン(Patternトレイトを実装している型)を取るらしい:

  • &String
  • &[char]
  • char
  • FnMut(char) -> bool
  • &&str
  • &str

文字1文字はもちろんのこと、部分文字列やら、char.is_numericといった関数も与えれるので、結構柔軟にパターンが作れるらしい。

特に、&[char]論理和(って言い方であってんのか)なので便利…。

ちなみにおかゆは .replace(&['a', 'e', 'i', 'o', 'u'], "") ってして「&[char; 5]はダメっぷ~~~~ww」ってコンパイラに言われてキレてたんですけど、
ジェネリクスのトレイトバウンドの箇所では諸々の型強制(今回だとunsize coercion)が効かないの忘れてた(てへぺろ

Coercions -

こういう場面で型強制効かないのって安全のため?なんだろうけど、トレイトバウンドに使うときに融通の効くトレイトを作るのって結構大変そうだね。

人工言語学Wikiの「関与原理」へのコメント

ja.conlinguistics.wikia.com

コメントがあって、コメントしようとしたらなぜかこの記事にだけログインできない謎に遭遇してコメントできなかったので、ここに書いておきます。


はじめまして、おかゆです。

Yuhrさんの「格標示に比べれば関与は暗黙的ですが、そもそも、発話されている(言語形式としてそこに存在している)というだけでとんでもない明示と言えるでしょう。」という説明のほうが、本記事よりも関与原理についてよりよく的確に説明しているように感じます。関与原理のエッセンスというのは、言語形式としてそこに存在することの甚大な有標性だと思います。

本記事では、「関与原理」は意味役割の理論の中で説明しようとされていますが、実のところ、関与原理のいう「関与」は種々の意味役割よりも根本・原始にあると思います。

なぜ意味役割と同じ領域の中で「関与原理」を説明しようとしたのか、その動機はちょっと失念してしまいました。ただ、格体系のデザインの話になると、(特に工学言語の分野だとありがちですが)意味役割を格の形式として網羅的に分離しきりたいだとか、動詞のもつ意味役割の体系を完全に明示したいというような、意味役割体系における網羅性・完全性の強迫に駆られることがしばしばありますが、そもそも意味役割云々以前の問題として「言及したい対象について、そこで言い表している」という事実にはたいへん大きな価値があって、多くの語りたいことにとっては、その「言い表しによる有標化」だけで(意味役割を表示することなく)十分なんじゃないか、というようなことを考えて私は「関与原理」などと言い始めたような気がします(そうであれば、意味役割と紐付けて関与原理を説明しようとした動機にもある程度察しがつきます)。「関与原理」自体は「話者は、言いたいことを言い表している(あるいは言い表そうとできる)」というような至極当たり前のようなことに名前をつけただけに過ぎないと考えることもできます(なので私は「原理」と呼んでいるわけですが)。

拙い返事ですみませんが、これで。


Rustのmoduleの話

`mod` and the Filesystem - The Rust Programming Language

mod client {            //
    fn connect(){}      // -> client.rs
}                       //

mod network {           //
    fn connect(){}      //  ------ -> network/mod.rs
                        // |
    mod server {        // |
        fn connect(){}  // | -> network/server.rs
    }                   //  ------
}                       //

Rustのメモ

“ownership” について

「所有権」と訳されているけれど、"ownership" のニュアンスを完全に捉えきれてるのかよく分からない。

英辞郎を引いてみると

  1. 所有権、所有、所有者[持ち主]であること
  2. 責任感、当事者意識

とあり、1の意義はOKとして、2の意義って「所有権」って語から察せるものなんだろうか?おかゆが単に世間知らずで、「所有権」にそういうニュアンスを感じることができないだけ?

“ownership” で大事なニュアンスはむしろ 2 のほうなんじゃないかって理解が浅いながら思うのだけど、つまり、「メモリ解放の責任をもつ」ってことかなって。ムーブは「責任の押し付け」で、借用はその責任を被らずに値を使わせていただくことのできる仕組みということかなって。

特に訳さず、「オーナーシップ」でいいような気もする。「ムーブ」もムーブだし。

IntoIterator

Python だと Iterable で、for .. in .. にぶち込むと勝手に iter してくれてるのが懐かしく思える。

このあたりのムーブセマンティクスの挙動は勉強しないとなあ

ライフタイム

どうでもいいんだけど、"ownership" は訳して、"lifetime" は「ライフタイム」なんやね。

ライフタイムよく分かんね~~

ライフタイムより:

struct Foo<'a> {
    x: &'a i32,
}

fn main() {
    let x;                    // -+ xがスコープに入る
                              //  |
    {                         //  |
        let y = &5;           // ---+ yがスコープに入る
        let f = Foo { x: y }; // ---+ fがスコープに入る
        x = &f.x;             //  | | ここでエラーが起きる
    }                         // ---+ fとyがスコープから出る
                              //  |
    println!("{}", x);        //  |
}                             // -+ xがスコープから出る

エラーが起きるのは分かるけど、ライフタイム明記せなコンパイラちゃんは認識できんの?と思ってライフタイム指定消してみよ:

struct Foo {
    x: &i32,
}

fn main() {
    let x;                    // -+ xがスコープに入る
                              //  |
    {                         //  |
        let y = &5;           // ---+ yがスコープに入る
        let f = Foo { x: y }; // ---+ fがスコープに入る
        x = &f.x;             //  | | ここでエラーが起きる
    }                         // ---+ fとyがスコープから出る
                              //  |
    println!("{}", x);        //  |
}                             // -+ xがスコープから出る

にしてみたら、

error[E0106]: missing lifetime specifier
 --> src\main.rs:2:8
  |
2 |     x: &i32,
  |        ^ expected lifetime parameter

error: aborting due to previous error
error: Could not compile `practice`.

あ、なるほど、指定子ないぞ!って怒られるのか。

内部構造にどっかの参照(借用)をもってるから、ってことかしら…。まあそうだろうけど…。

コンパイラちゃんはどこを見て指定子が必要なところかどうかを見極めるんだろ?
「内部構造に借用の型を持ってたら」かな?「外側(ガワ)にライフタイムを伝播」させるために、ライフタイム指定子が必要?

関数アノテーションでのライフタイム省略については、「ライフタイムの関わる出力は、大抵入力のライフタイムと関連あるやろ(鼻ホジ」ってことでしょう…。

“mutablity” について

ミュータビリティ

一方で、Rustで「イミュータブル(immutable)」について言及するとき、変更不可能であることを意味しない: 「外側のミュータビリティ(exterior mutability)」を表します。例として、Arc を考えます:

うーん。原文は

However, when we say something is ‘immutable’ in Rust, that doesn’t mean that it’s not able to be changed: we are referring to its ‘exterior mutability’ that in this case is immutable. Consider, for example, Arc:

「しかしながら、Rustで私たちが「あるモノがイミュータブル(immutable)だ」と言うとき、別にそれが変化し得ないと言っているわけではありません。そうではなく、「外側のミュータビリティ」に関してイミュータブルだと言っているわけです。」

これくらいの意味だろう…。

主成分分析に関するメモ

多変量解析入門(C・チャットフィールド, A・J・コリンズ)4.4 p.69あたり

「例えば、1つの変数がすべての他の変数よりもずっと大きい分散を持っていると、相関構造がどのようなものであっても、その変数が共分散行列の第1主成分の中で際立った重みを持つことになる。反面、すべての変数が単位分散を持つように尺度化されていると、第1主成分は全く違った性質を示すであろう。このような事情から、一般論として、例えばすべての変数が百分率である場合とか、すべて同一の座標系で測られている場合とかのように、すべての変数が「大体似通った」分散を持っているのでなければ、PCAを実行することはほとんど意味がないと言えよう。」

「この尺度構成の問題を処理するために、通常共分散行列ではなく”相関”行列を分析する方法が行われている。…(中略)…。この返還によってすべての変数が単位分散を持つように尺度化され、一応重要度に差異がなくなる。しかしこの尺度構成の手順は、ある程度任意性を持っており、データいかんに左右され、しかも尺度化の問題を解決するものというよりも回避するためのものといえる。すべての変数が同等に重要であると考えられない場合には、相関行列の分析はやらないほうがよい。また相関行列を分析した場合、2つ以上の標本についてのPCAの結果の比較がより困難になる。」

「相関行列の主成分は、変数をもとの座標系に変換しなおすと直交しなくなるであろう。これはp空間で直交する2直線の線形変換が、一般には新しい直交する2直線を与えないからであって、これも尺度構成がなによりも重要であることを示唆している。」

「成分は変数の線形変換の不変量ではない。」

化学者のための多変量解析(尾崎幸洋ほか)

3.3.2 p.51あたり

「旧来の定量化法においては、それぞれの成分に対して代表的なピークを選定し、その吸収強度の時系列変化と対応する濃度推移(目的変量)を使って検量を行う。また各成分に特徴的なピークを複数個選択し、MLRを用いて検量を行うこともできるが、着目した波長以外での情報の欠落や、選択したピークと他のピークとのオーバーラップなど、しばしばやっかいな問題に遭遇する。PLSではPCRの場合と同様に、全波長のスペクトルあるいは一定波長域のスペクトルを用いて回帰を行う。PLSの特徴は、説明変量X側と目的変量Y側の双方に主成分分析(PCA)による直交分解を適用することにある。」

※ PLS: Partial Least Squares

簡単には、多次元の説明変量で、多次元の目的変量を説明(回帰)する1つの方法で、それぞれの空間で主成分軸を決定してしまって、それぞれの主成分スコアを座標として回帰を行う方法らしい。

(いちほ)