群論入門2章

群論入門2章の勉強メモ。

2.1 部分群

キーワード

事項

  • 群Gの部分群H1,H2,…,Hnの共通部分はGの部分群である
  • A⊂Gのとき、Gの部分群でAを含むもの全ての共通集合Hを\lt A\gtと書く
  • このとき、AがHを生成するといい、AはHの生成系である
  • \lt A \gt=\{a_{1}^{\epsilon_{1}}...a_{n}^{\epsilon_{n}}|a_{i} \in A, \epsilon_{i} = \pm 1, 1 \le i \le n, n = 1, 2, ...\}
  • 群Gが1つの元aによって生成されるとき(G=\lt a \gt)、Gを巡回群という
  • n次の交代群A_{n}は、n次の対称群S_{n}のうち偶置換全体の集合である

2.2 部分群による類別

キーワード

  • (左|右)剰余類
  • (左|右)類別

事項

  • a≡b(mod H)⇔b^{-1}a∈Hと定義すると、これは同値関係である
  • よって、群Gはその部分群Hによって類別できる(左剰余類)
  • Hを部分群とすると、各剰余類は、aHである。(aは剰余類の代表元)
  • 各剰余類の位数は等しい

2.3 正規部分群と剰余群

キーワード

事項

  • 任意のa∈Gに対し、aHa^{-1}=Hであるとき、HはGの正規部分群である
  • NがGの正規部分群であるとき、\overline{G}=G/Nは(C_{a}C_{b}=C_{ab}という演算の下で)群をなす
  • これを剰余群(商群)という

群Gを正規部分群Nで割った結果が剰余群G/Nである。

2.4 部分加群

  • 加群は可換群
  • b^{-1}a=ab^{-1}より、部分加群による剰余類は左右の区別が無くなる(一致する)
  • したがって、部分加群正規部分群である

vimの正規表現

vim正規表現このページにまとめてあり、大変参考になる。
vimでプログラムを編集する際に注意していることをメモしておく。

角カッコ[]

対応している角カッコがあると正規表現として扱われる。
角カッコそのものを書くときはエスケープする。
対応するカッコ閉じはエスケープしなくていいようだ。

:s/[3]/[4]/g
before: int a[3]
 after: int a[[4]]

:s/\[3]/[4]/g
before: int a[3]
 after: int a[4]
後方参照

丸カッコを後方参照で使うときはエスケープしなければならない。
エスケープされた丸カッコで括った内容を、\1や\2などで参照できる。

:s/(\(.*\))/\1/g
before: "Snow (Hey Oh)"
 after: "Snow Hey Oh"
non-greedyなマッチング

*を使うと0回以上の繰り返しの最大マッチになる。
non-greedyにするには0回以上の繰り返しの最小マッチ\{-}を用いる。

:s/(3.*)/3/g
before: (1 2 (3 nil nil) 4)
 after: (1 2 3

:s/(3.\{-})/3/g
before: (1 2 (3 nil nil) 4)
 after: (1 2 3 4)
便利な記法

\<で単語の最初にマッチする。

:s/king/man/g
before: "The king is streaking."
 after: "The man is streaman."

:s/\<king/man/g
before: "The king is streaking."
 after: "The man is streaking."

Perl正規表現が書けるeregex.vimを使ったほうが良いかもしれない。

vimで操作の記録・再生(キーボードマクロ)

vimで操作の記録・再生を行うには次のようにする。

  1. 記録する操作の名前を決める(英数字1文字、ここではaとする)
  2. ノーマルモードでqaと入力する(aは1.で決めた文字)
  3. 記録したい操作を行う(この間、最下部にrecordingと表示される)
  4. ノーマルモードでqと入力して、操作の記録を終了する
  5. ノーマルモードで@a(aは1.で決めた文字)と入力して、現在のバッファに対して操作を適用する

ただし、操作名の大文字小文字は区別されない。

同じ操作を複数の対象に適用したいときに、これを使うのと使わないのでは効率がかなり違ってくる。
カーソル移動コマンド(ggや検索)と一緒に使うと良さそうだ。
初歩的な機能だが、今まであまり使っていなかった。

lazy val

Scalaで結構嵌ったこと。

trait A { val a: Int }
trait B extends A { val b: Int; val a = b }
object C extends B { val c = 3; val b = c }

こういう風に定義すると、

scala> C.a
res17: Int = 0

となる。しかし、C.a=3となってほしい。
コップ本第20章「抽象メンバー」に答えが書いてあった。ポイントは、スーパークラスから順番に初期化されるということ。
trait Bでval a = bとした時点では、bはデフォルト値0をとるからa=0になるようだ。
正解は、次のようにする。

trait A { val a: Int }
trait B extends A { val b: Int; lazy val a = b }
object C extends B { val c = 3; val b = c }

スーパークラスから継承したフィールドを初期化する際にlazyをつける。これで、

scala> C.a
res20: Int = 3

となり、期待する動作になる。lazyをつけると、定義時ではなく初めて参照される時点で初期化される。
結論は、traitまたはabstract classで他の値を参照してvalを初期化する際はlazyをつけること。

第20章では他にも、抽象型、パス依存型、構造的サブ型という重要な概念が紹介されている。
コップ本、ちゃんと読まなきゃね・・・