2020年11月30日月曜日

英語サイト

 What is Schedule NurseⅢ (nurse-scheduling-software.com)

(日本語だとリダイレクトされます)

英語マニュアル


Video

英語マニュアルは、シフトは、プロの翻訳者の成果物をさらに、Grammerlyで書き直したものです。やはり、Passive構文の指摘が結構あり、正しい指摘に思えるものは直感的に直しました。
ユーザとPythonについては、プロの翻訳者に頼らず、DeepLとGrammerlyで作ったものです。以前にそういったツールなしにつくったものよりは良いような気がします。
また、日本の恥さらしになるかもしれないのですが、世界に問うてみたい気持ちの方が強いです。以前と違うのは、大手メーカの後追いではないということです。ニッチではあっても世界で唯一であることがささやかな誇りです。

2020年11月28日土曜日

インストール場所

 MSIXのインストール場所は、通常フォルダと異なり、書き込みをすることができません。

(作者である私自身もどこにインストールされたか分かりません。)

そうすると、problem.jsonの受け渡し、サンプルフォルダでのWriteが出来ないので、基点フォルダ別に設け

AppData→sugawara-systems→schedule_nurse→1.0.0.0

にしています。なので、インストール最初のフォルダは、ここになります。さらに、

英語版と日本語版でサンプルが異なりますので、上からさらに

Samples→Japanese→プロジェクトサンプル

でようやくサンプル場所に辿りつきます。

なお、AppDataは、通常隠しフォルダとなっているので、本来的に保存する場所ではないと思います。そのため、サンプルを保存する場合は、ドキュメントフォルダに移して保存してください。更新時に、名前を変えていても消去されるのではないかと思います。また、アンインストール時は、このフォルダは、消去されると思います。(未確認)




2020年11月27日金曜日

Hugoでサイトを構築

 https://www.wangchucheng.com/en/docs/eureka/

というテーマを拝借して構築しています。最初マークダウンをtyporaで記述するようなイメージを持っていたのですが、

hugo server

で、ローカルに起動中に、mdファイルを書き換えると、即差にupdateされることが分かりtyporaを使用する必要はありません。単純にテキストエディタで記述しながら、画面表示を確認できます。

製作中のSnapshotです。



2020年11月26日木曜日

.htaccessでリダイレクト

 日本語ブラウザを検出してリダイレクトするようにしました。

リダイレクトされないようにするには、ブラウザを日本語以外にするか、OSの言語設定を日本語以外にします。

以下で、切り替えています。



RewriteEngine On

  RewriteCond %{HTTP:Accept-Language} ^ja [NC]
  RewriteRule ^$ https://japanese.nurse-scheduling-software.com/ [L,R=301]



2020年11月25日水曜日

Githubで1MB以上のファイルが読み取れない

 1MBしか読み取れないのは、GetRawContentの仕様のようです。

blobsを使うと100MBまで出来るようになるよ、というご丁寧なエラーメッセージが出てきます。

.net core - How to retrieve and update a file > 1MB from/to master GitHub using Octokit.Net Git Data API within c# - Stack Overflow


131Cで問題を修正しました。


private Dictionary SHA_MAP = new Dictionary();
        
        public async void read_hiearachy()
        {
            try
            {
                SHA_MAP.Clear();
                var github = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("IshisakaSample"));
                
                string owner = richTextBox1.Text.Trim();
                string repo = richTextBox2.Text.Trim();


               
                treeView1.Nodes.Clear();
                TreeNode rootNode = new TreeNode(repo);
                treeView1.Nodes.Add(rootNode); // ルート・ノードの追加

                
                string branch_str = richTextBox3.Text.Trim();
                var branch = await github.Repository.Branch.Get(owner, repo, branch_str);// "master");
                var contents = await github.Git.Tree.GetRecursive(owner, repo, branch.Commit.Sha);
                foreach (var v in contents.Tree)
                {
                    if (v.Path.Contains(".nurse3"))
                    {
                        if (v.Size >= 1024 * 1024)
                        {
                            SHA_MAP[v.Path] = v.Sha;
                        }
						if (Thread.CurrentThread.CurrentUICulture.DisplayName.Contains("日本語")){
                            if (v.Path.Contains("Japanese"))
                            {
                                rootNode.Nodes.Add(v.Path);
                            }
                        }else if (v.Path.Contains("English")){
                        	rootNode.Nodes.Add(v.Path);

                        }
                    }
                    Debug.WriteLine(v.Path, v.Type);
                }
                rootNode.Expand();
            }
            catch(Exception ex)
            {
                MessageBox.Show(ex.Message);
            }

        }

        private void button1_Click(object sender, EventArgs e)
        {
            read_hiearachy();
        }

        
        private async void read(string filepath)
        {
            var github = new Octokit.GitHubClient(new Octokit.ProductHeaderValue("IshisakaSample"));
            string owner = richTextBox1.Text.Trim();
            string repo = richTextBox2.Text.Trim();
            if (SHA_MAP.ContainsKey(filepath))
            {
                string sha = SHA_MAP[filepath];
                var b64 = await github.Git.Blob.Get(owner, repo, sha);
                
                byte[] file=Convert.FromBase64String(b64.Content);
                
                form1.deserialize(file);

            }
            else
            {
                var file = await github.Repository.Content.GetRawContent(owner, repo, filepath);
                form1.deserialize(file);
            }

        }

2020年11月24日火曜日

appinstaller Webでの記載のしかた

そのまま、貼り付けるとXMLファイルとしてブラウザが認識してしまって上手くいきませんでした。

 https://docs.microsoft.com/en-us/windows/msix/app-installer/installing-windows10-apps-web

のようにすると、インストーラとして認識してくれるようです。downloadのページに貼り付けていますが、未だテスト中です。




2020年11月22日日曜日

英語プロジェクトと日本語プロジェクト

 日本語環境とそれ以外の環境で、作ったプロジェクト間では、互換がありません。プロジェクトが日本語由来かどうかは、作成時に決まります。その後、国を変更するということは想定していません。

これは、Date関係の定義を変えているために起きる現象です。例えば、日 →Sun、今月→ThisMonth と言った具体にDate表現が異なり、それをベースにDay集合を定義しているためで、基本的には、日本語環境で作ったプロジェクトを英語圏に持っていっても動きません。Pythonを使っていれば、確実にエラーとなるので、分りやすいですが、使っていなければ一見動いているように見えるプロジェクトも多いです。

無用なトラブルを避けるために、Githubサンプルも英語と日本語に分けて、参照できないようにしています。英語環境では、Englishフォルダ下しか見えません


日本語環境では、Japaneseフォルダ下しか見えません。


となります。



2020年11月21日土曜日

時間制約のVector化

 行制約時間制約についてVector化記述に対応しました。


時間制約は、ソフト制約がありません。ハード制約しかない唯一の制約になります。また、原因解析でも時間制約が原因とすることは、現状ありません。性能上も整数制約に比べれば、一概には言えないのですが、理屈的には、数倍以上遅くなることがありえます。

従い、

■出来る限り、整数制約を使って頂く

■ソフト制約化は、整数制約を併用する

といった対応が必要になります。

2020年11月20日金曜日

ZOOM MEETING 廃止

 諸事情によりZOOM MEETINGを廃止しました。また、購入ページをリニューアルしました。実質的には、何も変わっていませんが、有償・無償との違いを分かりやすくしました。

2020年11月19日木曜日

ConstraintEnableの改善

 例えば、月で制約を切り替えるとします。通常月は、


Special月は、

という制約にしたとします。この場合、OffDaysという名前がどちらにもありますが、一方のグループしかOnにしていないために、GUIには、一つの名前しか現れません。

<改善前>
Pythonで制約を切り替えた場合、GUIが把握しているOn/Offとは異なることがありえます。
その場合、GUIが把握しているOn/Offとソルバーのそれと齟齬が生じ赤マーキングになってしまうことがありました。

<改善後>
Pythonを使用した場合、Solverが認識しているOn/OffをGUIに返すようにして、SolverとGUIの認識を一致させるようにしました。その結果、赤マーキングはなくなりました。





2020年11月18日水曜日

数独問題の作成方法4x4 から100x100まで

 勤務表ソフトではありますが、数独を汎用的にプログラムできれば、GUIを拡張できる能力の強力な証明になるので、搭載pythonで汎用的に書き直してみました。100x100までは、動作を確認しました。GUIでは、100x100結果は、表示しきれないので、ExcelにExportさせた結果が以下です。簡易的ですが、一応各行列の和が各々5050になっていることを確認しました。

∵ n(n+1)/2=5050




Pythonソースは、以下が全ソースです。このソースは、数独サイズに依存しません。4x4でも、100x100でも同じソースでOKです。では、どうやってサイズを可変するかというと、GUI上で、スタッフ数、Day数、シフト数をGUIで定義しなおせばよいです。例えば、4x4の場合は、4人、4Days,4シフトを定義します。

<オリジナル問題の作り方>
1)ブランク状態(解が存在するなら適度な数字が入っていてもよい)で解を求めます。
2)解を予定に送ります。
3)適当な箇所をブランクにします。
4)解を求め2解目が存在しないことを確認します。
5)3)4)を気力が続く限り続け、2解目が存在するときに諦めて、その前の状態を問題として終了します。



数独の条件としては、1解しか存在しないことが条件となります。例えば、100x100で1ブランクでも作れば、1解しか存在しないので、超巨大ではあるけれども超簡単な数独問題となります。1解しか存在しない証明は難しいですが、スケジュールナースを活用すれば、簡単にチェック出来ます。

import sc3
import math

if math.sqrt(len(AllDays)) !=math.sqrt(len(shiftdef)):
    raise ValueError("AllDays and shiftdef are inconsistent")
blocks=int(math.sqrt(len(AllDays)))

for day in AllDays: #column
	for shift in shiftdef.keys():
		V=[]
		for person in A_Member_in_All:
			V.append(sc3.GetShiftVar(person,day,shift))
		sc3.AddHard(sc3.SeqLE(1,1,V),'')
for person in A_Member_in_All: #row
	for  shift in shiftdef.keys():
		V=[]
		for  day in AllDays:
			V.append(sc3.GetShiftVar(person,day,shift))
		sc3.AddHard(sc3.SeqLE(1,1,V),'')
for person in range(0,len(A_Member_in_All),blocks): #block
	for shift in shiftdef.keys():
		for  day in range(0,len(AllDays),blocks):
			V=[]
			for  i  in range(blocks):
				for  j in range(blocks):
					V.append(sc3.GetShiftVar(person+i,day+j,shift))
			sc3.AddHard(sc3.SeqLE(1,1,V),'')


2020年11月17日火曜日

年始年末の実装

 

今月が通常月の場合、今月の定義は以下になります。


このときSecondMonth(次月)は、空集合になります。


今月が年始を含む場合、今月の定義は、


このとき、SecondMonthは、


となります。thisyearsdatesは、上記に関わらず以下となり、


ThisYearsThisMonthを以下のように取得できます。



これを従来の制約上のThisMonthと置き換えれば、年末年始に依存しない期間とすることができ、メンテナンスフリーの実装とすることができます。Pythonによるコントロール切り替えも不要です。




2020年11月15日日曜日

Dr.Planning

 https://dmcommunity.org/challenge/challenge-apr-2020/

In a hospital, there has to be a doctor present at all times. In order to make sure this is the case, a planning is made for the next 7 days, starting on a monday. Each day consists of three shifts: an early shift, a late shift and a night shift.


Every shift needs to be assigned to a doctor. In total there are 5 doctors: every doctor has a list of available days, and some have special requirements. In general, the following rules apply:


■A doctor can only work one shift per day.

■A doctor should always be available for his shift (see table below)

■If a doctor has the night shift, they either get the next day off, or the night shift again.

■A doctor either works both days of the weekend, or none of the days.

■A planning should be made in which every requirement is fulfilled.


Name Available

Fleming Friday, Saturday, Sunday

Freud Every day early or late, never night

Heimlich Every day but neven the night shift on weekends

Eustachi Every day, every shift

Golgi Every day, every shift but at max 2 night shifts

という問題を解いてみます。

まずは、上の条件から、スタッフ数5人、シフト数 Early,Late,Night,PaidHolidayの4つ、

月曜から始まる1週間を考えればよいことが分かります。

■A doctor can only work one shift per day.

スケジュールナースは、Default状態でそうなっているので、何も記述する必要がありません。

■A doctor should always be available for his shift (see table below)

意味不明ですが、多分、Dr.毎、シフトは、条件があるのだと思います。テーブル参照。

■If a doctor has the night shift, they either get the next day off, or the night shift again.

Nightの後は、Nightかオフ(PaidHoliday)なので、その他のシフトを禁止すればよいことが分かります。他のシフトは、EarlyかLateしかないので、

Night→Early

Night→Late

を禁止すれば十分です。

■A doctor either works both days of the weekend, or none of the days.

週末の定義が不明ですが、土日と仮定すると、土日のうちの1日だけ働くことを禁止すればよいです。これは、排他的論理和(XOR)ですね。土曜日に働いたら日曜日禁止、日曜日に働いたら、土曜日禁止すれば、よいです。

■A planning should be made in which every requirement is fulfilled.

多分、全てのシフトで、1人以上(or 1人?)が必要だ、ということでしょう。列制約になります。

次にテーブル条件について考えます。

■Fleming Friday, Saturday, Sunday

金土日以外をPaidHolidayで予定を埋めてしまえばよいことが分かります。

■Freud Every day early or late, never night

夜勤以外というラベルを作って、全日予定を埋めます。

■Heimlich Every day but neven the night shift on weekends

夜勤以外というラベルを土日に埋め込みます。

■Golgi Every day, every shift but at max 2 night shifts

Nightシフト数を2以下に制限すればOKです。

非常に簡単なロジックで、実際的には、全然足りてないですが、スケジュールナースで行えば、多分世界最速で、モデル記述とグラフィック10解を得ることが出来ます。初見11分でした。(この文章を書いている時間の方が長い)


動画はこちら

https://youtu.be/pHYFd5IE0U0


2020年11月14日土曜日

競合調査

国際環境で、AWS LAMBDAで同じような機能を提供するVendorはいるのでしょうか?いるとすれば、競合になります。二つヒットしました。

https://www.optaplanner.org/

https://openrules.wordpress.com/2020/04/22/building-a-live-worker-scheduler/

OptaPlannerは、私が開発を始めたころからありました。100%JAVAで書かれているメタヒューリスティクスがベースになっています。ベルギーのGeoffrey De SmetさんがLeadであり論文や動画の投稿も沢山あります。オープンソースのビジネスモデルであり、RedHatがスポンサーのようです。

Openrulesは、毛色が変わっていますが、発想が面白いです。

2020年11月13日金曜日

言及されています

 日本の論文での言及は初めてではないかと思います。

https://www.jstage.jst.go.jp/article/pjsai/JSAI2020/0/JSAI2020_4Rin129/_pdf/-char/ja

スケジュールナースの目指している方向は、

1)求解速度

最適な解を求めるには、会話的に管理者の思いと、解の状況を見ながら、重みを調整します。そのためには、すぐに解が出ることが必要です。できれば、数秒、遅くても数十秒以内に実用的な解を提示できることが必要です。

2)超汎用性・柔軟性

 どのようなルールも記述できること。少なくとも、人間が作り出し運用しているルールを記述できない、ということがないこと。大体はGUIベースで、非常にレアな制約でもPythonで記述可能です。

3)ルール化・モデル化支援

Integer Programmingのリテラシーが有るならモデル化してMIPに落とせるでしょう。しかし、毎月制約は変化するのが常です。しかも、モデルをつくり運用するのは、IT技術者でもITリテラシーに通じた人でもありません。制約の世界では、モデル化とメンテナンスの時間の方が、解を求める時間よりはるかにかかります。本来は、生産性向上が目的なのですが、

■自動化コスト=モデル化(ルール記述・開発)+求解時間+メンテナンスコスト

■手書きコスト=求解時間(作成時間)

フェアな比較では、モデル化とメンテナンスコストを論ずるべきと思いますが、そのような論文は、見たことがありません。実際、SC3の開発においては、この部分に多くの時間を注きました。https://patents.google.com/patent/JP6364638B1/ja


4)アカデミックとのGapを埋めること

http://www.econ.upf.edu/~ramalhin/Referencias/Kellog_2007.pdf

5)ベンチマークでトップ性能を維持すること

https://www.nurse-scheduling-software.com/tutorial/benchmarks.htm

こちらプレスリリースをご覧ください。

開発から7年、上記の目的は、ほぼ達成できたと考えます。今後は、国際的にも主要な地位を目指すことを目標にしたいと思います。

そこで、次の二つの方向性を考えたいと思います。

1)デスクトップアプリのフリー化

 ソフト自体にコストはかかりません。勤務表作成と月々のメンテナンスのみ有償になります。

2)特定業務・形態に絞ったアプリ化

 企業向けにスケジューリングソルバ(AWS LAMBDA FUNCTION)を提供

国・分野を絞ることで、汎用性・柔軟性をなるべく維持しながら、より簡便なGUIを装備していただき自動最適化を実現。


2020年11月12日木曜日

年末年始対応の構想

年末年始は、次月にはなりますが、年始期間まで含んで休みを設定するところが多いと思います。

 年末年始をPythonを使ってダイナミックに記述するのは、良いアイデアですが、年始の期間を新たに定義しなければいけないのが、どうも美しくない、と思いました。そこで、次月(SecondMonth)というのをPredifineすることにしました。


こうすると、制約終了日が決まれば、「次月」は、自動的に決まります。(通常月は、空集合になります。)今月部であって AND 次月部でない 部分が通常月の制約に対応します。これは、ユーザ定義で、集合演算で求めます。

こうすると、

1)年末年始では、制約終了日がSpecial

2)年末年始期間を絶対定義

以上の2点だけが、通常月と変わる部分で、後は、PythonがDynamicに制約を切り替えるので、面倒な部分を隠蔽してくれます。



2020年11月10日火曜日

スタッフ名の空白

 は、今まで除去してきたのですが、英語環境では、さすがにまずいという結論となり、空白を許容することにしました。スタッフ名以外は、空白を除去しているのは従来通りです。



2020年11月8日日曜日

Hyper-Vでテスト

 Windows Sandboxを導入して拡張子msix/msibundleのテストを行いたかったのですが拡張子を認識してくれませんでした。仕方なく、Windows10 1903ISOを持ってきて(VisualStudio OS付ライセンス)Hyper-Vでテストすることにしましました。しかし、OSインストールが、動きませんでした。

同じ現象で、はまった方がおられましたので、その通りにしたら動きました。

https://qiita.com/saeki4n/items/b712cd5c9359f3b54dae

Hyper-Vの良いところは、Snapshotを取って、任意の時点に戻れることです。OS起動状態でスナップショットを取っておけば、何時でもCleanインストール状態から再現できます。


インストーラの拡張子は、見慣れないmsix/msibundleになります。Win10では、ダブルクリックするとインストーラが起動します。

下図は、Hyper-V上でのインストール時のスナップショットですが、デジタル著名が効いて、あの忌まわしいウィルスまがいのメッセージが出てきません。スケジュールナースでのサポートは、Windows10 x64のみVersion 1903以降になります。(現在は2004です。)


インストール後の起動は、デスクトップアイコンはありません。さ行のメニューからの起動となります。

英語化が11月一杯かかるので、リリースは、11月Endを予定しています。




2020年11月7日土曜日

Signing Tool Error 0x8007000B

対処方法 

https://docs.microsoft.com/en-us/windows/msix/package/signing-known-issues

  • Run Eventvwr.msc
  • Open the event log: Event Viewer (Local) -> Applications and Services Logs -> Microsoft -> Windows -> AppxPackagingOM -> Microsoft-Windows-AppxPackaging/Operational
  • Find the most recent error event


2020年11月6日金曜日

Code Signing Certificateを取得しました

 取得までの流れ

1)DUNS NUMBERの取得

2)代理店の選択

メールでいくつか英語を使う場面はありましたが、コールバックも日本語選択可能ですし、

英語メールに抵抗なければ、最安でも問題ないと思います。

3)Sectigoとのやり取り 日本語でした

法人番号を提示の依頼がありましたが、個人業者なのでない、と回答しました。

4)コールバック 日本語を選択

 コンピュータによる自動コールバックで、6桁の数字を記します。

5)ORDER #xxxx - Your Code Signing Certificate is ready!

 が着ます。リンクアドレスをインストールするPC上で、IEを起動します。

SHA128/256を選択します。期限は、下のように2年です。(26400円代理店で異なる)

How to Export Your Code Signing Certificate

に従ってExportします。

注意事項
1)ドメイン情報は結局使いませんでした。
2)Win10上でもIEが必要です。Edgeや、Cromeでは動作しません。IEは、WIN10の中に多分defaultでありました。
3)心配していたコールバックも、日本語を選択し、CallNowを選択すれば、すぐかかってきます。
4)DUNS NUMBERの取得で、東京商工リサーチで登録済みでも海外サイトに反映するには、2週間位かっかってしまうとのことで、直接海外にReflectしてくれるように指示(代理店)がありました。メールを送ると、すぐ登録したよ、とのReplyがありました。
5)更新の概念はないそうです。2年を選択したので、2年経つまえに再度取得する必要があります。
6)一番時間がかかった壁は、DUNS NUMBER取得と海外でのReflectです。DUNS NUMBER取得済みであるならば、1週間で可能と思いますが、取得していない場合は、1ヶ月見る必要があると思います。

以上、個人業者がコードサイニング証明書を取得する でした。






て、以下の手順で、pcxをExport

2020年11月5日木曜日

DeepLとGrammarly

 マニュアルの英文化を進めています。基本的には、DEEPLで日本文、DEEPL出力をGrammerlyに入力して校正していきます。全体で300ページ位あり、最初は、プロの翻訳者にお願いしていたのですが、上記方法に落ち着きました。DEEPL、翻訳者原稿どちらをGrammarlyに入力しても、受動態(PassiveVoice)の指摘が多いです。しっくりしないときは、自分で書き直して、再度Grammarlyにかけたり、元々の日本文から手直しします。Grammarlyは、有償版です。DeepLとGrammarlyの組み合わせが最強と実感しています。

以上の手順をもっと厳格に進めている方もおられました。

https://qiita.com/doikoji/items/d3b818dc2937bc34d579


2020年11月4日水曜日

Copt 1.43の評価

BarrirerSolver(内点法)を実装したとのことで評価してみました。

WSL1では、MACアドレスは、変わらなかったのですが、今回環境はWSL2になっており、前回のMAC ADDRESSとは見かけ上異なるものとなり、ライセンスで弾かれてしまいました。

しかたなくWindowsVersionでの評価です。WindowsVersionでは、コマンドラインで_Underbarがスキップされてしまうので、これも仕方なくファイル名を手動で変更しました。結果は、こちらです。

確かに、大規模インスタンスでは、顕著に速くなっていることが分かります。ただし、Defaultでマルチスレッドになるらしくスレッド数は、4です。また、内点法では、Simplexみたいに、Resolveで速くなることもないのでその辺は割り引いて考える必要があります。