これはなに?
おれにもよくわからない。それだけは最初に言っておく。
ポエム
何をやったか?
MathWorksはSystem Composerという、システム構成図、アーキテクチャを記述できるツールを提供している。
これはMBSE:Model Based Systems EngineeringとMBD:Model Based Designの領域を繋ぐという目的で開発されたSimulinkのオプションToolboxだそうだ。
MBSEとか、アーキテクチャとか色々webページに書いてるが
今回私はそんな本来ツールが担うべきミッションや利用目的を一切無視して、このツールで家族の家事割当てを表現してみようと思う。
ちなみに、これだけは言えるが、これはMBSEではないことは確かだ。
菜箸に墨つけて水墨画を書いてるようなものだ。まともな使い方ではない。MBSEを雑に扱おうと意図はなく、あくまでツールで遊んでみただけであることはここで明言しておく。
ただこのツールに対しては雑に扱っているという点は否めない。一応というか私もMathWorks社員だが身内に怒られないか心配だ。
Step1.家族をモデリングする
さっそくSystem Composerで家族をモデリングしてみた。
マイキーという名前に特段意味はないので気にしないでいただきたい。
見た目、SimulinkっぽいがSystem Composerはあくまでアーキテクチャ記述をするものらしく、Simulinkみたいに実行可能なロジックをもったモデルはかけないらしい。
ただ、ある階層より下を直接Simulinkレイヤーにすることができるので、そこでロジックをかけば直接Simulinkとつながるわけだ。それがSystem Composerの特徴の一つと言える。
だが当然今回はその特徴と言える機能とか無視するので使わない。
逆を行ってこそMATLAB芸人なのだ。
もう一つSystem Composerで特徴的なのは「ステレオタイプ」と呼ばれるメタ情報をユーザが定義し、それをモデルやポートなどのモデル要素に割り当てることができるということだ。
こちらの「プロファイルエディタ」では
プロファイルと呼ばれるxml形式のファイルに、ステレオタイプ、そしてステレオタイプが持つ要素であるプロパティを定義することができる。
この定義をモデルにInportという操作で読み込ませると、
モデルが持つ要素にこのステレオタイプを割り当てることができる。
お察しの良い皆さんならおわかりのことだと思うが、
今回Adult、大人を赤色に、Child、子供を青色にした。
Step2.タスクをモデリングする
こんな感じだ。
タスクもステレオタイプで同じタイプのタスクは色分けしてみた。
System ComposerにはView機能とかいうのが備わっており、
ステレオタイプが同じコンポーネントのみを表示させたり、モデルから別のダイアグラムを生成することができる。
モデルから生成されたダイアグラムはViewというが、
これはモデルの情報と同期しているので二重管理になることはない。
現状はシンプルすぎるモデルで、全然機能を活用できていない気がする。
だが今は芸をやっているのだ。許してくれ。
ギターを使って芸をする芸人がたまにいるが、音楽やギターをアート以外に使ってはいけないというわけではないってのと同じだ
すなわち、それがMATLAB芸人なのだ。
Step3.割り当てる
System Composerは割り当てエディタというものがあり、
2つのモデルファイルの要素同士でリンクをつくることができる。
ご覧の通り、家族をタスクに割り当ててるわけだ。
これで誰がどのタスクを担当してるのかを表をクリックすることで割り当てることができる。
複数の割り当てパターン(シナリオ)を定義することもできるみたいだが、
とりあえず一つだけで良いだろう。
複数の割り当てパターンを作ると、例えば
お母さんに負荷が多いパターンと、お父さんが負荷が多いパターン等色々ためしてみて、
最終的にバランスを決めるということができるかもしれない。
しかし、割り当て結果を眺めていてもなんだかつまらん。
なんかしら負荷的なものを計算で求めることができんのだろうか。
Step4.解析する
できるみたいだ。
このリンク先の動画では家族ごとに割り当て先のタスクコンポーネントが持っている
ステレオタイプのプロパティ値(タスクにかかる時間)を計算して、
それぞれどれぐらい家事に時間をつかってるかを解析するスクリプトをまわしている。
アロケート先のコンポーネント情報を集めたい時はどうやらAPIが用意されているらしく、
サクッと取ることができて便利だった。
getAllocatedToという関数らしい。
ヘルプ検索すると逆向き、つまり割り付けられてる方から割り付け元を集約させるgetAllocatedFromってのもあるらしい。
以下解析関数コードである。
function AllScenariosTaskData = FamilyTaskAnalysis()
%% 解析用の前準備
%アロケーション(割り当て)の情報をAllocationDataファイルから読み込む
allocation = 'HouseWorkTask';
allocationSet = systemcomposer.allocation.load(allocation);
%シナリオを取り込む
allocationScenarios = allocationSet.Scenarios;
%アロケーションデータで関連付けられているコンポーネントのうち
%Human(人間)のステレオタイプがついているやつだけを取り出す。
%そうすることで、家族の構成を列挙することになる
[~, FamilyMember] = allocationSet.SourceModel.find(...
systemcomposer.query.HasStereotype(...
systemcomposer.query.IsStereotypeDerivedFrom("Family.Human")));
%重複を排除する
FamilyMember = unique(FamilyMember);
%シナリオごとの解析データ格納用Cell
AllScenariosTaskData = cell(length(allocationScenarios));
%% 家族ごとに割り当てられているタスクを取得する
%シナリオごとにループ
for scenarioIdx = 1:length(allocationScenarios)
Scenario = allocationScenarios(scenarioIdx);
%タスク情報格納用Cell作成
FamilyTaskNames = cell(1,length(FamilyMember));
%家族のメンバーごとにループ
for familyIdx = 1:length(FamilyMember)
disp("======================================");
%% 処理1:タスクの集約と表示
Member = FamilyMember(familyIdx);
disp(['■' Member.Name 'のタスク'])
%メンバーに割り当てられているタスクコンポーネントを集める
%このアロケート先の要素を集めてくれるAPIがアツかった
Tasks = Scenario.getAllocatedTo(Member);
%タスク名だけを取り出す
FamilyTaskNames{familyIdx} = {Tasks(:).Name};
%タスク名を表示する
disp(string(FamilyTaskNames{familyIdx}))
newline();
%% 処理2:タスクにかかる合計時間を算出
HouseworkTimePerDay = 0;
for TaskIdx = 1:length(Tasks)
HouseworkTimePerDay = HouseworkTimePerDay + Tasks(TaskIdx).getEvaluatedPropertyValue("TaskType.Task.TimeForTask");
end
%メンバーのステレオタイプに合計家事時間を反映する
Member.setProperty("Family.Human.HouseworkTimePerDay",num2str(HouseworkTimePerDay),"hour")
disp(['合計家事時間は' num2str(HouseworkTimePerDay) '時間です'])
end
disp("======================================");
%タスク情報をテーブルに変換
FamilyTaskTable = cell2table(FamilyTaskNames,"VariableNames",{FamilyMember(:).Name});
%シナリオごとにデータに格納
AllScenariosTaskData{scenarioIdx} = FamilyTaskTable;
end
end
終わり
以上とりあえずつくってみたものを紹介してみた。
しかし・・・
・・・・俺は一体何を作っていたんだ・・・
わからない・・・・