trsing’s diary

勉強、読んだ本、仕事で調べたこととかのメモ。

EFFECTIVE C# 6.0/7.0 読書メモ 項目12、13

項目12 メンバには割り当て演算子よりもオブジェクト初期化子を使用すること

オブジェクト初期化子を使用するメリット
  • コンストラクタに関わらずメンバ変数を確実に初期化することができる
  • 将来新しいコンストラクタを追加した場合でも、メンバ変数の初期化忘れを防ぐことができる

通常、複数のコンストラクタが用意される。コンストラクタでメンバ変数を初期化する場合、初期化し忘れ、整合性が取れなくなる、手間がかかるといったデメリットが生じる。

オブジェクト初期化子を使うべきでないケース
  • オブジェクトを0またはnullに初期化するケース

システム規定の初期化処理では、コードを実行する前にすべての値が0に初期化される(メモリブロック全体が0に設定される)。独自のコードを追加すると0を再設定することになり無駄。

  • 同一のオブジェクトに対して複数回の初期化を行うケース

オブジェクト初期化子を使用し、コンストラクタでも初期化すると、オブジェクト初期化子で作成したオブジェクトは即座にガベージになる。対策方法は項目14を参照。

  • 初期化時における例外処理に対応させるケース

初期化コードはtryブロックで囲うことができない。例外が生じるとオブジェクトの外側へ伝搬される。初期化コードをコンストラクタ内に移動させて、例外を適切に処理するような復旧用コードを作成すること。

オブジェクト初期化子が実行されるタイミング

すべてのコンストラクタ(親クラスのコンストラクタ含む)よりも先に実行される。初期化子が記述された順序で実行される。
※詳細は項目14参照

13 staticメンバを適切に初期化すること

  • staticメンバ変数は、型のインスタンスが作成されるよりも前に初期化される(staticメンバ初期化子、staticコンストラクタ)
  • staticコンストラクタは1つのみ定義可能。引数を取ることはできない。
  • staic変数初期化子、staticコンストラクタ以外の方法でstaticメンバ変数を初期化すべきではない。
  • 例外が出る可能性がある場合はstaticコンストラクタを使用するべき。
例外について

staticコンストラクタはCLRから呼び出される。staticコンストラクタ内で発生した例外が処理されない場合、CLRは例外をスローしてプログラムを停止させる。この例外を呼び出し元が処理できたとしても、staticコンストラクタによる初期化がされていない状態になる。

static変数初期化子だと、発生した例外をクラス自身で処理することはできない。staticコンストラクタの場合にはクラス内での例外処理が可能。

EFFECTIVE C# 6.0/7.0 読書メモ 項目11

11 .NETのリソース管理を理解する

優れた開発者となるには、実行環境におけるメモリやその他主要なリソースの管理方法を理解する必要がある。.NETの場合、メモリ管理やガーベジコレクタを理解すること。

ガベージコレクタ
マネージヒープにおけるメモリを管理する。メモリリーク、参照されていない未開放のポインタ、未初期化ポインタ、その他多くのメモリ管理における問題のほとんどを扱う。このためメモリリークやポインタ関連の問題もはや開発者の責任ではない。
※その他のシステムリソース(非マネージリソース)に対しては開発者自身が後処理を実装する

ガベージコレクタはアプリケーション内で生存中のオブジェクトからエンティティが到達可能かを把握でき、到達不可能なオブジェクトをガベージとみなす。ガベージコレクタが実行されるたびに使用されなくなったメモリ(ガベージ)を解放し、オブジェクトの再配置を行ってメモリの集約及び未使用メモリの領域の最大化を行う。

非マネージリソースの管理
開発者が責任を負う。非マネージリソース生存期間を開発者が制御できるようにするメカニズム、ファイナライザとIDisposableインターフェイスを用いる。ファイナライザには多くの欠点があるため、IDisposableインターフェイスも併せて実装するとよい。

・ファイナライザ
ファイナライザは、非マネージリソースが最終的には解放されるということを保証するための方法。オブジェクトがガベージとなった後、不特定のタイミングでガベージコレクタによって呼び出される。
※タイミングが不特定のため、なるべくファイナライザに頼らないような設計あるいはコーディングを行うべき。

・ファイナライザによるパフォーマンスの低下
ファイナライザを使用すると解放されるのが遅くなるため、世代が上がり、長命なオブジェクトとみなされてさらに余計に生存することになる。 この問題を回避するためにはIDisposableインターフェイスと一般的なDisposeパターンを使用するとよい。

EFFECTIVE C# 6.0/7.0 読書メモ 項目6~項目10

項目6 文字列指定のAPIを使用しないこと

文字列ベースのAPIやライブラリのデメリット
・型の安全性が損なわれる
・ツールによるサポートもなくなる
・静的型付け言語における多数の利点を失う

シンボル名が必要な時はnameof()式を利用するとよい。メリットは、
・シンボル名の変更が反映される。
・静的解析ツールを使用すれば、引数の名前が間違った位置で使用されている場合に、間違いや不整合を検出できる。

nameof演算子は型や変数、インターフェイス名前空間に対して機能する。修飾されていない名前、完全修飾名のいずれであっても機能し、常にローカル名を返す。これにより一貫性が保たれている。

> nameof(System.Int32.MaxValue)
"MaxValue"
> nameof(Int32.MaxValue)
"MaxValue"

ジェネリック型定義に対しては、クローズジェネリック型(型パラメータが指定されている)に対してのみ機能する。

> class MyClassG<T> { }
> nameof(MyClassG)//オープン
(1,8): error CS0305: ジェネリック 種類 'MyClassG<T>' を使用するには、1 型引数が必要です。
> nameof(MyClassG<int>)//クローズ
"MyClassG"

7 デリゲートを使用してコールバックを表現する

デリゲートを用いてコールバックを実装するメリット
・クライアント側で必要となる条件が比較的単純
・デリゲートの対象は実行時に決定できる
・複数のクライアントを対象としたデリゲートを用意することができる

デリゲートはメソッドへの参照を持ったオブジェクト(Cの関数ポインタみたいなもの)。一つのデリゲートに複数のメソッドを登録することができ(マルチキャストデリゲート)、すべてのメソッドが一回の呼び出しに集約される。

注意点
・例外に対して安全ではない
デリゲートは例外をキャッチしないため実行中のメソッドが例外をスローした場合、その時点で終了する(残りのメソッドは実行されない)。

・返り値は最後に実行されたメソッドの返り値になる
デリゲートに複数登録した場合、最後に登録されたメソッドの返り値になる。
各メソッドの返り値を確認したい場合、各メソッドを明示的に呼び出すコードを使用する。

foreach(Func<bool>pr in cp.GetInvocationList())//デリゲートに登録されたメソッドのリストから各メソッドを取得
    bContinue &= pr();//各メソッドの返り値を確認

項目8 イベントの呼び出し時にnull条件演算子を用意すること

null条件演算子を使用するとイベントの呼び出しがスレッドセーフで簡潔になる。

イベントを呼び出す方法
1.そのままつかう

private EventHandler<int> Updated;
Updated(this);

Updatedイベントにアタッチされたイベントハンドラがない状態(null)ではNullReferenceException例外がスローされる

2.nullチェックする

if(Updated != null)
    Updated(this);

nullチェックとイベント呼び出しとの間に別のスレッドが実行され、Updatedが変更される可能性がある。登録解除された場合ハンドラはnullになるのでNullRefereneException例外がスローされる(見つけづらい上に修正しづらいバグ)。

3.ハンドラをローカル変数に割り当て、割り当てたローカル変数に対してnullチェックし、実行する。

var handler = Updated;
if(handler != null)
    handler(this);

スレッドセーフ (ローカル変数にはUpdatedが参照しているすべての元のハンドラを参照するマルチキャストデリゲートが格納される。別スレッドによりイベントからハンドラが登録解除されても、ローカル変数には影響がない)。 しかし可読性が悪く、書く量も多い。

4.null条件演算子を使用する。

Updated?.Invoke(this);

正解。スレッドセーフで簡潔。
※?.演算子の直後に括弧を続ける事ができないのでInvokeメソッドを呼び出す必要がある

項目9 ボックス化およびボックス化解除を最小限に抑える

ボックス化とボックス化解除は望んでいない場所でコピーを作成することがあり、それにより不具合が起こることがある。 ボックス化、ボックス化解除ではヒープの確保やコピーが生じるためパフォーマンスの低下を招く。

ボックス化、ボックス化解除

.NET FrameworkはSystem.Objectという、すべてのオブジェクトの親である参照型を定義している
・値型はデータを保持するコンテナであり、多態性を持たない型
ボックス化、ボックス化解除はこのギャップを埋めるために用意された機能。

ボックス化
値型を参照型に変換する。ボックスをヒープ上に確保し、値型のコピーを格納する。

ボックス化解除
ボックス化された値型のコピーを作成して返す。ボックスの中身にアクセスする際は毎回コピーされた新しい値が返される

注意点
System.Objectを引数に取る場合はボックス化、ボックス化解除が発生する。
補完文字列はSystem.Objectへの参照の配列を使用して作成される。そのため、値型を使うとボックス化が生じる。
また、ボックス内のオブジェクトに対してToString()を呼び出してボックス内の値にアクセスするため、アンボックス化が起こる。 補完文字列を繰り返し使用する場合などはパフォーマンスに注意すること。これを回避するにはToStringであらかじめ文字列インスタンスへ変換しておくとよい。

不具合の例
.NET 1.xのコレクションに格納する場合、System.Objectインスタンスへの参照が保持される。つまり値型をコレクションに追加すると、ボックス化が行われる。このコレクションからオブジェクトを取り出すとコピーが作成される。このコピーに変更を行ってもコレクション内のオブジェクトに影響はない。

項目10 親クラスの変更に応じる場合のみnew修飾子を使用すること

new修飾子を使用して非virtualメソッドを再定義すると型の挙動が曖昧になる。

非virtualメソッドは静的に結び付けられている(コンパイル時の型により規定される)。
実行時の型が派生クラスでも、型が元クラスであれば元クラスのものが実行され、型が派生クラスなら派生クラスのものが実行される。

> public class MyClass { public void MagicMethod() { Console.WriteLine("MyClass"); } }
> public class MyOtherClass : MyClass { public new void MagicMethod() { Console.WriteLine("MyOtherClass"); } }
> object c = new MyOtherClass() as object;
> ((MyClass)c).MagicMethod();
MyClass
> ((MyOtherClass)c).MagicMethod();
MyOtherClass

メソッドにnewを使用すべき場面
派生クラスですでに使用済みのメソッド名が新しいバージョンの親クラスに定義されたメンバと競合した場合。
この場合の解決策としては、
・派生クラスのメソッド名を変更する。
・new修飾子を使用して再定義する。
メソッドを使用するすべてのコードを変更できるなら前者のほうが良い(長期運用に耐えられるだろう)。 そうでないならnew修飾子を使用する(一時しのぎだが)。

基本的にnew修飾子は使用すべきでない。使う場合も十分検討すること。

EFFECTIVE C# 6.0/7.0 読書メモ 項目1~項目5

項目1 ローカル変数の方をなるべく暗黙的に指定すること

ローカル変数の型を宣言する場合はなるべくvarを使う。 コンパイラが型を宣言する。

メリット

  • ローカル変数の型という細部を気にせずに済み、コードの意味に注力できる。
  • 型を自分で選択するよりコンパイラに選択させたほうが良い場合が多々ある(IQueryableとIEnumerable)

注意点

  • コードから型を判断できるならvar。できないなら型を明記する。数値型も型を使用した方が良い。
  • varは動的型付けではない。コンパイル時の型と実行時の型が異なる場合、コンパイル時の型が優先される。

良い例

var foo = new MyType();//型が明確

悪い例

var foo = sumeObject.DoSomeWork();//返り値の型が明確でない。
//型を明記するか、変数名を工夫してわかりやすくする。

項目2 constよりもreadonlyを使用すること

constはコンパイル時に値が利用可能でなければいけない場合(属性の引数、switch caseのラベル、enumの定義)にのみ使用すべき。 ほかはreadonlyを使用したほうが高い柔軟性を得られる。

const(コンパイル時定数)はオブジェクトコード内の定数値に置き換えられる。次の二つは同じコードが出力される。

if(myDateTime.Year == Millennium)//public const int Millennium = 2000;
if(myDateTime.Year == 2000)

constはメソッド内でも宣言できる。

readonly(実行時定数)は実行時に値が割り当てられるのでより柔軟な対応が可能。ILはreadonly変数を参照するものになる。
readonlyはメソッド内では宣言できない。

アセンブリを超えた場合も同様。
例)
アプリケーションアセンブリがInfrastructureという別のアセンブリを参照しているとする。 Infrastructureのconstについては値に置き換えられる。readonlyの値は実行時に解決される。
・Infrastractureのconstが変更になった場合、アプリケーション側の再コンパイルが必要。
・readonlyの場合、アプリケーション側の再コンパイルは不要。

注意点
constは実行時測度が若干有利だが、柔軟性を損なってまで効率性を揚げる必要があるかよく検討すること。実行速度を理由にconstを使用する場合先にパフォーマンスの測定もするべき。

項目3 キャストにはisまたはasを使用すること

as演算子のほうが安全で、実行時の効率も優れる。 キャスト演算の場合、予想もしない副作用が起こったり、思いがけないタイミングで成功あるいは失敗することがある。

as、is演算子
ユーザー定義の変換を行わず、実行時の型のチェックのみ。実行時の型が要求された型と一致する場合にのみ成功する。指定の型ではない、指定の型から派生した型でない場合には変換に失敗する。
※ボックス化された値型をボックス化解除されたnull許容型へと変換する場合、新しい型を作成する

キャスト
指定の型への変換演算子を利用できる。

キャストだと文脈で振る舞いが変わる例)
SecondTypeからMyTypeへのユーザー定義の変換演算子が存在する場合、

object st = Factory.Getobject();//SecondType型を返す
t = (MyType)st;

上記は失敗するが、

SecondType st = Factory.Getobject();

と宣言していれば成功する。

コンパイラコンパイル時におけるstの型を基準とするため、前者ではstはobject型。objectからMyTypeに変換するユーザー定義の変換演算子はない。そのため、コンパイラはoの実行時の型がMyTypeかどうかをチェックするコードを生成。oはMyTypeではないため失敗。(実行時における実際の型がMyType型に変換できるかチェックするわけではない)

その他注意点

  • as演算子は参照型またはNull許容型で使用すること。
  • foreachステートメントはキャスト演算子を使用している。値型と参照型の両方をサポートする必要があるため。(IEnumerable.CurrentはSystem.Objectで変換演算子を持たないため対象となる型によらず同じ挙動)
  • 変換可能かではなく厳密な型を知りたい場合はGetType()メソッド。オブジェクトの実行時における型を返す。

項目4 string.Format()を補完文字列に置き換える

可読性が大幅に向上する。置換される式が簡単に把握できる。結果の確認も簡単。引数のインデックスを間違えることもない。

注意点

  • 三項演算子を使用する場合は式を括弧で囲む(:を見つけると書式指定文字列の解質店だと判断するため)。
  • 文字列補完によりコンピュータに読み取らせる文字列(SQLコマンドなど)を生成する場合、それによって発生しうるリスクを考慮すること。(作成されるのは単一の文字列。想定しない文字列になってない?)
  • パフォーマンスに注意
Console.WriteLine($"円周率の値は{Math.PI}")

という補完文字列があったとする。値型をobject型と強制するため、ボックス化が起こる。このコードが繰り返し呼ばれる場合、パフォーマンスに重大な影響を与える。

項目5 カルチャ固有の文字列よりもFormattableStringを使用すること

特定のカルチャが必要な場合、文字列補間を明示的にFormattableStringとして作成してから、特定のカルチャを使用して文字列に変換すると楽。

暗黙的な型指定を使用すると、文字列補完は文字列になる。

> var third = $"今日は{DateTime.Now.Month}月{DateTime.Now.Day}日です";
> third.GetType().Name
"String"

指定するとFormattableStringから派生したオブジェクトを作成できる

> FormattableString second = $"今日は{DateTime.Now.Month}月{DateTime.Now.Day}日です";
> second.GetType().Name
"ConcreteFormattableString"
> second.Format
"今日は{0}月{1}日です"
> second.GetArguments()
object[2] { 3, 30 }

注意点
文字列とFormattableString両方を受け付けるオーバーロードがある場合、 $"" リテラルを渡すと、文字列引数のメソッドが優先される。

> string ToFrenchCanada(FormattableString src)
. {
.     return string.Format( System.Globalization.CultureInfo.CreateSpecificCulture("fr-CA"), src.Format, src.GetArguments());
. }
> ToFrenchCanada($"{5.5}")
"5,5"
> string ToUs(FormattableString src)
. {
.     return string.Format(System.Globalization.CultureInfo.CreateSpecificCulture("en-US"), src.Format, src.GetArguments());
. }
> ToUs($"{5.5}")
"5.5"

Formatの一つ目の引数(null)いらんかった。

読書 スラスラわかるC# 第2版

スラスラわかるC# 第2版

スラスラわかるC# 第2版

C#はかなり昔に入門本を読んでそれ以来必要になった箇所だけ適当につまみ食い。そんなのでも使う頻度は低くやることもちょっとした改修程度だったので困りませんでしたが、最近業務でがっつり使う必要が出てきました。

それでまじめに復習しておきたいなーと思ってたところ、ググったらだいたい出てくるHPの人が著者の本があるということで買いました。
使えるレベルで各機能が紹介されており、つまみ食いだった部分をちゃんと整理することができました。基礎として必要な部分がしっかり載っています。とはいえ深堀はしていないので手の込んだことをしようと思うなら別途調べる必要があります。

C#の復習をしたい人のほか、C#に手を出そうと思ってるほかの言語経験者にとっても良い本になると思います。プログラム初心者にとってはどうだろ?スラスラとはいかないかも。

Visual StudioC#インタラクティブをお供に読み進めるとよいと思います。REPL実行できるので本に書いてあるちょっとしたコードを確認するのにすごく便利。 f:id:trsing:20190328223127p:plain
f:id:trsing:20190328223152p:plain

覚えてた方がよさそうなもの適当にメモ
  • @をつけるとキーワードを変数名として使うことができる
  • スコープが異なる、同じ名前の変数は認められない
    ※メンバーとローカル変数は共存可
{
    {int x = 2;}
    int x = 5;
}
(1,9): error CS0136: ローカルまたはパラメーター 'x' は、その名前が外側のローカルのスコープでローカルやパラメーターの定義に使用されているため、このスコープでは宣言できません。
  • 多次元配列[a,b](要素がaxb個)と配列の配列[a][b](要素が配列である)は別物
  • 匿名型は、他のクラスのプロパティを初期化子に渡す場合にはプロパティ名を省略できる
 class User { 
    public int Id { get; } = 19; 
    public string Name { get; } = "abc"; 
}
 var usr = new User();
 var ukusr = new { usr.Id, usr.Name };
> ukusr
<>f__AnonymousType0#56<int, string>(\{ Id = 19, Name = "abc" })
  • 匿名型は型を明示して書くことはできない
> var u = new { int Level = 12, string Title = "AA" };
(1,15): error CS1525: 'int' は無効です。
(1,19): error CS1003: 構文エラーです。',' が必要です。
(1,31): error CS1525: 'string' は無効です。
(1,38): error CS1003: 構文エラーです。',' が必要です。
> var u = new {  Level = 12,  Title = "AA" };
  • 匿名型コンパイル時には自動的にクラスへと展開される。そのため、dynamicのように動的に実行時にプロパティ名の解決を行うような場合でも、正しく実行することができる
static void OutputTitle(dynamic item)
{ Console.WriteLine(item.Title); }
var x = new { Title = "A", Level = 12 };
OutputTitle(x);
>A
  • tupleはコンパイル時にValueTupleという型へと展開される。このときフィールド名はなくなる。そのため、dynamicのように動的に実行時にプロパティ名の解決を行うような場合、まず動作しない(Item1などにすれば動作する)。
static void OutputTitle(dynamic item)
{
    Console.WriteLine(item.Title);
    //Console.WriteLine(item.Item2);
}
static void Main(string[] args)
{
    (int level, string Title) p = (12, "A");
    Console.WriteLine(p.Title);
    OutputTitle(p); //NG。'Title'の定義がありません。Item2ならOK
}
  • C#7.0以降に追加された新しい文法、_がそのスコープから利用可能な識別子として存在しない場合、アンダースコアを値の破棄として使うことができる
var (w,_,_,z) = (10,20,30,40);
  • オーバーロード呼び出しの優先順位は
    オプションなし>オプションあり>可変長引数
  • readonly:クラスのフィールドでのみ宣言可。staticの有無を変えられる。コンストラクター内で値を書き換え可能。new可能。コンパイル結果は変数と同様。
    const:ローカル変数でも宣言可。常にstatic扱い。宣言時のみ初期化可能。インスタンスをnewで生成するものには使えない。コンパイル結果はリテラルと同様。

  • 静的な型はtypeof(クラス名)。静的とはコンパイル時に型が確定するという意味。
    動的な型は変数名.GetType()。動的とはコンパイル時には型が確定せず、実行時に変化する可能性があるもの。

> class Base { }
> class Derived : Base { }
> Base a = new Base();
> a.GetType()
[Submission#3+Base]
> Base b = new Derived();
> b.GetType()
[Submission#4+Derived]
  • コンストラクタが呼ばれる順番は基底→継承
    ※呼び出される基底クラスのコンストラクターは引数なしのコンストラクター。引数付きのコンストラクターを呼び出すためには、明示的に基底クラスのコンストラクターを呼び出す必要がある。
  • キャスト式:型変換できない場合は例外を返す
    as演算子:型変換ができない場合には結果がnullになる
    is演算子:左辺の変数が右辺の型にキャスト可能ならばtrue、不可ならばfalseを返す
  • 既定値default(T) 値型:0、参照型:null
  • IEnumerableインターフェイスを使う場合:データを全件取得した上で、プログラム中で加工(データ全件分の通信量)
    IQueryableインターフェイスを使う場合:データを外部のシステムにデータの加工まで依頼し、必要なデータのみ取得(加工済みデータ分の通信量)

チャットツール導入に失敗した話

結構前の話だけど反省も込めて。

失敗した話その1

経緯

新しいおもちゃほしい。

情報共有の問題を解決。とまではいかなくともマシにはしたかった。

一つの案件に対して複数のグループ(ソフト屋さんやら機械屋さんやら)で対応しておりますが。 グループ内ではそれなりに情報が共有されるけどグループ間となるとさっぱり。 設計の変更はもちろん酷いときは動作仕様もいつの間にか変わってたりする。 悪意があって隠しているわけではなくいちいち伝える必要が無いと考えている模様。

言って改善されるというものでもなさそうなので チャットツール導入してそこでのやり取りが増えればその分は可視化されるのでましになるだろう、と。

選んだツール。

Rocket.Chat。

流行ってるしSlack使いたいなーと思ったけど社外のサービスになるから申請とか必要でめんどくさい。 目的が「情報共有」だけでは申請理由として弱いし。 社内でなんかできるのないかなーと探すとRocket.Chatというのが良さそう。

自PCにDocker入れて必要なコンテナ引っ張ってくれば良い、と。 Window7でもちょいと手間は増えるけど問題なし。 Dockerとか触ってみたかったし丁度いいですねー。 MongoDBも使う、と。いわゆるNoSQLとかいうの触ってみたかったし(ry。 たいして時間かからずサクサクっとできた。うーん便利。

使ってみて

まずは使ってくれそうな数名に声をかけて試してみた。 ログが追える、必要なときに資料投げ込めると使い勝手よし。 場面によっては直接面合わせてやり取りするより効果的かも。

駄目だったよ

効果ありそうだし他の人にも広めよう。 というとこで管理職に嗅ぎつけられた。結果、使ってないサーバあるのでそれ使って良いよとなりました。やったぜ。 良い管理職デスネー。 ついでにメンバー全員にチャットツール導入してみたので使ってネ!と連絡。

と、ここまでは良かったのだけど。 まずサーバがボロい。 1日で落ちる。エラー見るとメモリ不足のせいのようだったので不要なの止めたりしたけどそれでも3日で落ちる。 立ち上がりも遅い。5分以上かかる。だるい。

そして利用者が増えたかというとそうでもなく。 まあ連絡の仕方が悪かった。いきなり使ってねと言っただけではね…。 んで管理職参入を機に使ってた人も居なくなったんですよ。 とても不思議。ナンデダロ?

利用者おらず管理もめんどい。 私のモチベーションと共に消滅しましたよと。

反省点

  • どんなものか、どう使えるか、どう使いたいかをちゃんと説明しよう
    これ使ってーといきなりわけのわからんもん投げられても使う人少ないですわなー。
  • まともな道具を使おう
    数日に1回10分程度でも意外とモチベーション下がる。めんどい。

その2

経緯

情報共有の問題は悪化していた。もうどうにでもな~れ。 取引先で情報収集・実験するために何人か長期出張に行くことになったけど、 その人達とのやり取りがままならない。

これはチャンスでは?ボブは訝しんだ

外部との情報共有。これはSlack導入の名目になる。
※メール投げても返ってこねえみたいな状況(それくらい忙しいらしい)なのでSlack導入したとこでどうなるもんでもない

実際に問題が改善するかどうかはさておき。問題点および改善する手段として適切(たぶん)。後はそれっぽい資料をでっち上げれば作成すれば許可でるんじゃね?と思った。目的や使い方がはっきりしており自分でメンテなどする必要もなし(簡単な説明書くらいは作る必要はあるし、導入したらしたでなんか色々出てくるかもしれないけど)とその1の反省点も踏まえてよい感じ。

上司も参加してる打ち合わせで適当に話題を誘導、出張組と情報共有の問題があると上司が発言したところで

Slackを導入すれば…
・問題解決の一助になる
・費用は機能制限はかかるが無料プランがある
・セキュリティはISOのほにゃららを取得している
・日系大手の使用実績あり
ダイマ。どうなるかなー。

やっぱり駄目だったよ

上司殿曰く
「自分で調べて判断する」
あーこれ駄目なやつですね。 念の為翌日聞いてみると
「調べた結果セキュリティに難あるので不許可」
ですって。諦めた。

反省点

・話す相手は選ぼう
この上司「新しいツールをどんどん導入しよう」とか言ってたんですがねー。 その1の管理職に話してれば違った結果だったかも。

振り返ってみて

こうやって書き出してみるともっと良いやりようがいくらでもあったように思う。立ち回り下手やなあ…。

PRML 5章演習問題 5.38~5.41

5.38

wの周辺ガウス分布 
q(w|D,\alpha)=N(w|w_{MAP},A^{-1})
wが与えられた時のtの条件付きガウス分布 
p(t|x,w,\beta)\simeq N(t|y(x,w_{MAP})-g^{T}w_{MAP}+g^{T}w,\beta^{-1})
より
\mu=w_{MAP},\,\Delta^{-1}=A^{-1},\,A=g^{T},\,b=y(x,w_{MAP})-g^{T}w_{MAP},\,L^{-1}=\beta^{-1} として(2.115)より
f:id:trsing:20190316124217p:plain

5.39

ラプラス近似により
f:id:trsing:20190316130737p:plain よって
f:id:trsing:20190316130822p:plain
Aについて

\ln p(D|w,\beta)P(w|\alpha)=
\ln \left|\frac{\beta}{2\pi}\right|^{N/2}+
\ln \left|\frac{\alpha}{2\pi}\right|^{W/2}-
\frac{\beta}{2}\sum(y(x_{n},w)-t_{n})^{2} -\frac{\alpha}{2}w^{T}w=(5.165)
これと(4.132)よりAは(5.166)

5.40

Kクラスニューラルネットワークに対して、尤度関数は
$$ \prod_{n}^{N}\prod_{k}^{K}y_{k}(x_{n},w)^{t_{nk}} $$ となる。 これに対応する誤差関数は(5.24)。

事後確率に対し、重みについてラプラス近似を適用する。 ここで、(5.166)のヘッセ行列Hに対応するものは(5.24)から求められる。 (\nabla \nabla \sum\sum t_{nk}\ln y_{k}(x_{n},w_{MAP}))

同様に、(5.24)は正則化誤差関数(5.184)のバイナリ交差誤差の項 (-\sum\{t_{n}\ln y_{n}+(1-t_{n})\ln (1-y_{n})\}) を置き換える。

周辺化の結果は解析的ではないため、 新しいパターンに対する予測分布を近似する必要がある。 しかしながら、2クラス問題とは対照的に、ギブスが変わりの近似について議論したにもかかわらずこの近似の明確な候補はない。

5.41

ラプラス近似により
f:id:trsing:20190316140232p:plain
よって f:id:trsing:20190316140438p:plain
Aについて

\ln p(D|w)P(w|\alpha)=
\ln p(D|w)+
\ln \left|\frac{\alpha}{2\pi}\right|^{W/2} -\frac{\alpha}{2}w^{T}w\\
A=-\nabla_{w}\nabla_{w}\ln p(D|w)P(w|\alpha)|_{w=w_{MAP}}\\
=\alpha I -\nabla_{w}\nabla_{w}\ln p(D|w)|_{w=w_{MAP}}