2025年2月20日木曜日

Q.遅勤務1(休遅)は、月1回が上限

 Ans.

「月1回が上限」のニュアンスは、ハード制約だと思います。ただし、スタッフによっては、月2回までやってもよい、という方もおられるかもしれません。そういった要求に対する実装です。


いつものように、スタッフプロパティシートで、希望上限回数を指定します。


行制約で、制約します。ソフトレベル1に着目してください。

行制約レベル1の許容エラー数を1にします。

こうすると、スタッフプロパティシートで、0を指定しているとすると、

0+1=1回までは、ソフトエラー範囲であり、同時に1回以下がハード制約となります。

つまり、2回という解を許容しませんので題意を実現できます。

また、あるスタッフがスタッフプロパティシートに1回と記述すると

1+1=2回までは、ソフトエラー範囲であり、ハード制約でもあります。3回という解は許容しません(存在しません)

このように、題意の要求以上に、将来の変更を予想して記述しておくとメンテナンス性がよくなるでしょう


なお、行制約レベル1には、他の制約も(5連休禁止)あるのですが、不等式制約ではないので、何ら影響はありません。



2025年2月19日水曜日

Q.休日、準夜(準)の職員がいる場合は、日勤の看護師4名をA及びBチームから同数程度を割り当てる 。休日で準夜(準)の職員がいない場合は、日勤の看護師3名をA及びBチームから同数程度を割り当てる

 Ans.

居る場合と居ない場合で記述されています。この場合、

日勤看護師4+準夜1==5

日勤看護師3+準夜0==4

となっていて、同じ値にはならないので、列制約では記述できないように見えます。

ただし、この他に

■準夜(準)がいる場合、長日勤(長日)をA及びBチームに各1名、夜勤(夜)をA及びBチームに各1名割当てる

■準夜(準)がいない場合、長日勤(長日)をA及びBチームに1又は2名合計3名、夜勤(夜)をA及びBチームに1名又は2名合計3名割当てる

という制約があり、
長日2+準夜1==3 夜勤2+準夜1==3
長日3+準夜0==3 夜勤3+準夜0==3

となっています。
これを勘案すると、

準夜1:長日2+休日日勤4==6
準夜0:長日3+ 休日日勤3==6

と、見事に同じ数になっています。本質的な意図は、むしろこちらの方ではないでしょうか? これで、ペア制約ではなく、列制約で記述出来ます。

これを実装すると、以下のようになります。
シフト集合は、



次に、A/Bチームの割り当てです。常に成立するのは、A/Bチームから1名以上という制約です。

一方、
準夜1:日勤4名:Aチーム2名、Bチーム2名以上
準夜0:日勤3名:Aチーム1名以上、Bチーム1名以上

となっています。これより、

    Aチーム人数日勤者数==準夜+1

となっている関係であることが分かります。こういう等式がある場合は、リニアペア制約が使えますが、今回は、列制約とペア制約を用いて記述しました。

■休日A/Bチームから1名以上 :列制約
■休日準夜が居るならば、Aチームは、2名 :ペア制約

Aチーム2名とすることで、自動的にBチームも2名になりますから、上の記述だけで十分です。必ず出来るかは、分かりませんのでペア制約は、ソフト制約としています。1名以上は、mustでしょうからハード制約としています。










2025年2月18日火曜日

Q.準夜(準)がいる場合、長日勤(長日)をA及びBチームに各1名、夜勤(夜)をA及びBチームに各1名割当てる 。準夜(準)がいない場合、長日勤(長日)をA及びBチームに1又は2名合計3名、夜勤(夜)をA及びBチームに1名又は2名合計3名割当てる

 Q.

■準夜(3交代準)がいる場合、長日勤(長日)をA及びBチームに各1名、夜勤(夜)をA及びBチームに各1名割当てる

■準夜(3交代準)がいない場合、長日勤(長日)をA及びBチームに1又は2名合計3名、夜勤(夜)をA及びBチームに1名又は2名合計3名割当てる


Ans.

上の仕様を式で表現すると、以下の関係になっています。

長日2+準夜1==3 、夜勤2+準夜1==3
長日3+準夜0==3 、夜勤3+準夜0==3

つまり、足すと常に3です。こういう関係は、ペア制約ではなく列制約で記述した方がベターです。

シフト集合は、以下で合成します。


2025年2月17日月曜日

Q平日の日勤は9名以上が望ましく、A及びBチームから同数程度を割り当てたい

Ans.

「日勤9名以上」は、そのまま列制約で記述すれば良いのですが、「望ましい」とあることから、ソフト制約とします。

「A及びBチームから同数程度」は、9/2=4. 5 ですので、Aチームから4名以上、Bチームから4名以上とすればよいでしょう。

 






2025年2月15日土曜日

AI技術サーベイ

 目標としているのは、モデリングの代行をAIに行わせることはできないか?ということです。似たようなこととして、プログラミング言語または、独自言語を生成AIで生成させること、または、学習すること、その視点でサーベイしてみました。

https://qiita.com/jovyan/items/6767c9fd944a636fdf88

https://note.com/k_ishi_ai/n/n2897a12f917c

https://note.com/k_ishi_ai/n/n475c804f3195

https://zenn.dev/knowledgesense/articles/110a81646806e6

最終目標は、

日本語 ⇒ 構造化JSON ⇒ プロジェクトファイル 

とすることです。AIが日本語から、構造化JSONを出力させることが出来れば、自動的にプロジェクトファイルには、出来ると思います。そしてそれが正しいかどうか?チェックもまた可能だろうと思います。

問題は、如何にして、それを学習させるかがポイントになると考えられます。
ローカルでDeepSeekをファインチューニングさせることが出来れば、遊べるようになると思います。

下記論文に着目しています。Native Language(英語)とCHAT GPTを用いて、Gurobi等のソルバを呼び出すようです。


NL4Optは、ORとAIの合同チームによるモデリングCompetitionです。ここでもファーウェイが主導しているようです。


こちらは、今後も注目していきたいと思います。現在は、全てChatGPTによるものですが、今後は、DeepSeekを使った報告も出てくるだろうと思います。



現時点で言えるのは、当面モデリングエキスパートの需要はなくならない、ということだろうと思います。言語から簡単にモデリングというのは、現時点においては幻想です。暗黙知の他に、ときに、本人も言葉で出来ない制約があります。その職場に固有の事情や知識も必要となります。加えて言葉の外にある制約や、意図、心理等、を全て学習しない限り、100%の精度で制約には変換できないと思います。エラーが存在する⇒そこにエキスパートが必要だと思います。




Q.変則2交代に3交代が混在、準夜が居た場合に翌日深夜、深夜が居た場合前日準夜

 前回から引き続き、

■3交代、準夜が居た場合、同じチームで、翌日深夜が居ること

■3交代、深夜が居た場合に、同じチームで、前日に準夜が居ること

この要件は、3交代の勤務を考えた場合、必然となります。日勤を除く時間帯16時間を誰かが埋めないといけない、ということです。

この職場の場合、チームは、A/Bの2チームで、3交代が各々1名居ります。なので、

■Aチーム3交代準夜が居れば、翌日Aチーム2交代深夜が居ること

■Bチーム3交代準夜が居れば、翌日Bチーム2交代深夜がいること

になります。同様に、

■Aチーム3交代深夜が居れば、前日Aチーム2交代準夜が居ること

■Bチーム3交代深夜が居れば、前日Bチーム2交代準夜がいること

が、制約になります。



「居ること」の真意は、「少なくとも一人居ること」ですから、ORで、演算子「または」を用いて実装できます。(具体的な深夜準夜人数については、列制約で制約しています。)

また、「前日」が必要ですから、「制約開始日1日前から」を使えば、先月からの流れも問題ありません。翌日に対しては、+1、前日に対しては、ー1を「日オフセット」で指定すればOKです。

以上を実装したのが、次になります。



「AならばB」で気を付けること

「AならばB」制約は、難しいので、使わないで済むならば、使いたくはないです。
今回の場合のように、使わなくては記述できないので、使わざるを得ないのですが、その際、気を付けることがあります。それは、

「Aでないときは、何も制約していない」

ということです。言葉通り、Aならば、Bになるのですが、その反対の、Aでないならば、
の状態のとき、Bがどうなるかは、何も制約されていないということです。

今回の例で言えば、3交代深夜が居ないときに、2交代準夜が居てもおかしくない、ということが起きてしまいます。
つまり、茶色枠の制約だけでは、上の事象が起きてしまう可能性があります。本当は、どういう風にしたいかというと、

■Aチーム3交代準夜が居ないならば、翌日Aチーム2交代深夜が居ない

という風にしたい訳です。なので、茶色枠の4つの制約に対して、さらに4つの制約を加えています。これで初めて、意図した動きになると思います。本質的な意図は、

準夜人数==翌日深夜人数

ということなので、AならばBを使うと、両方向から制約する必要がある、ということです。(多分、リニアペア制約を使えば、上の制約をダイレクトに制約出来ると思います。)

まとめとして、

「AならばB」制約では、Aでないときどうしたいか?も考える

ということがポイントになります。フリーで良いならば片方向でよく、フリーではまずいということであれば、両方向で制約する必要があります。

結構難しい制約です。今回は、Aチーム、Bチーム一人づつの3交代での記述になるのですが、この条件が崩れた場合は、また記述しなおす必要があります。これをメンテナンスしていくのは、なかなか大変そう..と思います。

全員が同じ変則2交代に移行してくれれば、上のような面倒な制約は、必要ありません。
特殊な事例ですが、このような例は、他の地方公立病院でもありそうな話ではあると思います。



2025年2月14日金曜日

Q.変則2交代に3交代が混在

 Q.

■準夜(準)がいる場合、長日勤(長日)をA及びBチームに各1名、夜勤(夜)をA及びBチームに各1名割当てる

■準夜(準)がいない場合、長日勤(長日)をA及びBチームに1又は2名合計3名、夜勤(夜)をA及びBチームに1名又は2名合計3名割当てる

■準夜(準)を1名割当てた場合、翌日に準夜(準)と同じチームの1名を深夜(深)に割当てる

■準夜(準)及び深夜(深)の割当ては、3交替制の職員を優先して行う

Ans.

言葉にして言うと難しいです。図にしてみましょう。

今3交代勤務者が深夜準夜の勤務をしたとすると、準夜の後深夜を誰かが行う必要があります。ところが、同じチームに3交代勤務者は一人のため、2交代勤務者が深夜勤務を代行する必要があります。本来は、2交代勤務者は、長夜明だけなのですが、3交代勤務者のサポートのために、深夜・準夜もシフトをこなす必要が出てきます。皆が一斉に変則2交代に移行すれば、必要ないのですが、なかなか簡単には行かない事情があるようです。

また、準夜が居れば、長日・夜勤者は、2名でよい、居なければ3名必要ということになります。




つまり、

    準夜+長日==3名
    準夜+夜勤==3名

という制約式になります。==は、C言語表記で、等しい という意味です。
これを列制約で記述します。準夜+長日は、シフト集合で合成します。準夜+夜勤も同じく
シフト集合で合成します。
マウスホイールボタンを押すと、下のように、シフト集合の場合は、その要素が表示されます。




準夜が居た場合に翌日深夜
深夜が居た場合に前日準夜

は、ペア制約による記述となります。

2025年2月12日水曜日

Q.サブスク試用について

Q. スケジュールナースを1週間試用版をお願いしたく、一旦、私個人でのカード登録で、試用版からサブスクでも使用させて頂ければ、別カードでの申し込みをしたいと考えています。事務処理のやり方を教えてください。

Ans.サブスクは、マイクロソフトアカウントに紐づいています。

A)1週間試用して、

B)本使用では、別なクレジットカードで使用したい、

ということでしょうか?

それでしたら、A)で、約1週間、課金される前にキャンセル処理を行うことで課金されません。確実に課金されないためには、1週間より前、5日後にキャンセル処理されることをお勧めします。

https://www.nurse-scheduling-software.com/japanese/service/pausing_subscription/


B)同じアカウント名では、課金なしには、もはや使用できません。なので、別なアカウント名にすればよいです。

https://www.nurse-scheduling-software.com/japanese/service/create_microsoft_acount/

(ただし、この方法で未来永劫に無料で使うことができる、ということではないようです。1日に登録できるマイクロソフトアカウント個数は限られているためです。)

そうすれば、また無料試用期間から始められる筈です。このとき、別なクレジットカードを使うようにすれば、そのクレジットカードに1週間後、課金が始まります。

いずれにいたしましても、1週間で判断は、かなり難しいと思います。

個人の持ち出し(480@/月)になってしまいますが、一月間、不明な実装方法については、サポートを活用して、試してみたら如何でしょうか?

https://www.nurse-scheduling-software.com/japanese/constraints_faqs/

https://www.nurse-scheduling-software.com/japanese/constraints_faqs/chapter23/



2025年2月10日月曜日

Q.買い切り版で、登録していただいたアカウントを変更はできますでしょうか?

 Ans.

アカウント名の変更ということでしたら承ります。

お手数ですが、以下の手順となります。


手順

1)お客さまは、新しく登録したいアカウント名1個を送って頂く

2)1)を受けて、菅原システムズは、1)アカウント名をマイクロソフトサーバに登録します。

3)2)を受けて、お客さまは、登録したいアカウント名で、スケジュールナースの動作を確認出来たら、菅原システムズにその旨連作します。

4)3)を受けて、菅原システムズは、1)アカウント名をマイクロソフトサーバから削除します。

これにより、旧アカウント名では、スケジュールナースを使用できなくなるのでご注意ください。


2025年2月9日日曜日

Q. ストア買い取り版 追加インストール希望

 Q.放射線部の勤務表作成を複数人で行う準備をしてるところです。2台分の追加インストールを行いたいです。

Ans.

恐れ入ります。原則的に一つのライセンスについて一つのマイクロソフトアカウントとしております。 一つのライセンスで、一つの部署が原則です。同じアカウント名で、同時に十台まで使用できるので、同じ部署の複数人が自宅・職場等で使用する分には、それで足りると思います。

また、xxx様以外の部署で新たなアカウントが必要ということになると、新たにお買い求め頂くことになってしまいます。

2025年2月8日土曜日

GPUによるPDLPの評価

GPU P1000とRTX4060TI 16GBを比較してみました。

P1000 (640CUDA  1.3GHz)→4060TI(4352CUDA 2.5GHz)

にすれば、GPU性能上、

4352/640*2.5/1.3 ≒13

13倍程度の高速化が期待されたのですが、現実は2倍以下の場合もあります。このままでは、使いものになりません。仮にもっとCUDA数の大きなGPUを使ったとしても、現在の伸びでは期待できません。

cPDLPCPU  cuPDLP(Quadro P1000)  CLP  cuPDLP(RTX4060TI16GB)

n080w8_2_0-4-0-9-1-9-6-2  47.7sec   14.3sec 76sec        9sec
instance19 46.7sec    21.6sec 2.6sec               5sec
instance20 14.8sec    6.7sec 9.6sec               1sec
instance21 41.5sec   16.2sec 78sec                1sec

傾向としては、
■Iteration数がバラつく。試行毎でもバラつきます。
■規模が大きくなるにつれて、改善傾向(高速化度)が強まる
■大規模問題(instance21)での結果は、期待通り

GPUクロックが固定されていないためか?と一瞬思ったのですが、固定してやっても結果は変わりませんでした。

NVIDIA のGPUのクロックを固定する方法 - pyopyopyo - Linuxとかプログラミングの覚え書き -








D:\test\test_cudaLinear>test

D:\test\test_cudaLinear>nvidia-smi -q -d CLOCK

==============NVSMI LOG==============

Timestamp                                 : Sat Feb  8 04:26:08 2025
Driver Version                            : 571.96
CUDA Version                              : 12.8

Attached GPUs                             : 1
GPU 00000000:01:00.0
    Clocks
        Graphics                          : 2805 MHz
        SM                                : 2805 MHz
        Memory                            : 9001 MHz
        Video                             : 2190 MHz
    Applications Clocks
        Graphics                          : N/A
        Memory                            : N/A
    Default Applications Clocks
        Graphics                          : N/A
        Memory                            : N/A
    Deferred Clocks
        Memory                            : N/A
    Max Clocks
        Graphics                          : 3105 MHz
        SM                                : 3105 MHz
        Memory                            : 9001 MHz
        Video                             : 2415 MHz
    Max Customer Boost Clocks
        Graphics                          : N/A
    SM Clock Samples
        Duration                          : Not Found
        Number of Samples                 : Not Found
        Max                               : Not Found
        Min                               : Not Found
        Avg                               : Not Found
    Memory Clock Samples
        Duration                          : Not Found
        Number of Samples                 : Not Found
        Max                               : Not Found
        Min                               : Not Found
        Avg                               : Not Found
    Clock Policy
        Auto Boost                        : N/A
        Auto Boost Default                : N/A


D:\test\test_cudaLinear>cudalinear -fname n080w8_2_0-4-0-9-1-9-6-2BG2.mps -nIterLim 500000 -ifPre 1 -dPrimalTol 1e-5
num threads= 1
--------------------------------------------------
reading file...
        n080w8_2_0-4-0-9-1-9-6-2BG2.mps
--------------------------------------------------
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
--------------------------------------------------
running presolve
--------------------------------------------------
Presolving model
11734 rows, 20786 cols, 215656 nonzeros  0s
11734 rows, 20693 cols, 215563 nonzeros  0s
Presolve status: Reduced
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
Minimize
No obj offset
--------------------------------------------------
running scaling
- use Ruiz scaling
- use PC scaling
--------------------------------------------------
--------------------------------------------------
enter main solve loop
--------------------------------------------------

  ____ _   _ ____  ____  _     ____
 / ___| | | |  _ \|  _ \| |   |  _ \
| |   | | | | |_) | | | | |   | |_) |
| |___| |_| |  __/| |_| | |___|  __/
 \____|\___/|_|   |____/|_____|_|

Cuda runtime 12060
Cuda driver 12080
cuSparse 12504
Cuda device 0: NVIDIA GeForce RTX 4060 Ti


--------------------------------------------------
CUPDHG Parameters:
--------------------------------------------------

    nIterLim:          500000
    dTimeLim (sec):    3600.00
    ifScaling:         1
    ifRuizScaling:     1
    ifL2Scaling:       0
    ifPcScaling:       1
    eLineSearchMethod: 2
    dPrimalTol:        1.0000e-05
    dDualTol:          1.0000e-04
    dGapTol:           1.0000e-04
    dFeasTol:          1.0000e-08
    eRestartMethod:    1

--------------------------------------------------

     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    1.03e+02  0.00e+00   0.01s [L]
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    1.03e+02  0.00e+00   0.01s [A]
Termination check: 1.032666e+02|1.042666e-03  0.000000e+00|2.920578e+00  0.000000e+00|1.000000e-04
Termination check: 1.032666e+02|1.042666e-03  0.000000e+00|2.920578e+00  0.000000e+00|1.000000e-04
Last restart was iter 0: average
Last restart was iter 1: average
Last restart was iter 2: average
Last restart was iter 4: average
Last restart was iter 7: current
Last restart was iter 40: average
Last restart was iter 80: average
Last restart was iter 160: average
Last restart was iter 280: average
Last restart was iter 400: current
Last restart was iter 480: average
Last restart was iter 760: average
Last restart was iter 1120: average
Last restart was iter 1600: average
Last restart was iter 1880: current
Last restart was iter 2160: average
Last restart was iter 2600: average
Last restart was iter 2880: average
Last restart was iter 3160: average
Last restart was iter 3280: current
Last restart was iter 3640: current
Last restart was iter 3880: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     4000  +3.38816992e+03  +3.38118002e+03  +6.99e+00    3.30e-01  1.65e-02   0.73s [L]
     4000  +3.38779443e+03  +3.38934372e+03  -1.55e+00    9.24e-02  7.53e-04   0.73s [A]
Termination check: 3.298630e-01|1.042666e-03  1.650873e-02|2.920578e+00  1.032428e-03|1.000000e-04
Termination check: 9.244807e-02|1.042666e-03  7.527463e-04|2.920578e+00  2.285719e-04|1.000000e-04
Last restart was iter 3960: current
Last restart was iter 6200: current
Last restart was iter 6440: current
Last restart was iter 6560: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     8000  +3.41615033e+03  +3.41508172e+03  +1.07e+00    1.75e-02  1.02e-04   1.41s [L]
     8000  +3.41329596e+03  +3.41716699e+03  -3.87e+00    1.18e-02  9.91e-05   1.41s [A]
Termination check: 1.747635e-02|1.042666e-03  1.018131e-04|2.920578e+00  1.564065e-04|1.000000e-04
Termination check: 1.178435e-02|1.042666e-03  9.914102e-05|2.920578e+00  5.666482e-04|1.000000e-04
Last restart was iter 6800: average
Last restart was iter 10640: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    12000  +3.42440093e+03  +3.42183563e+03  +2.57e+00    6.01e-03  7.29e-05   2.09s [L]
    12000  +3.42179821e+03  +3.42244885e+03  -6.51e-01    4.98e-03  3.66e-05   2.09s [A]
Termination check: 6.008872e-03|1.042666e-03  7.291813e-05|2.920578e+00  3.746476e-04|1.000000e-04
Termination check: 4.978544e-03|1.042666e-03  3.658292e-05|2.920578e+00  9.504995e-05|1.000000e-04
Last restart was iter 10840: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    16000  +3.42948919e+03  +3.42399978e+03  +5.49e+00    2.48e-03  5.15e-05   2.75s [L]
    16000  +3.42739936e+03  +3.42399246e+03  +3.41e+00    1.35e-03  3.87e-05   2.75s [A]
Termination check: 2.482076e-03|1.042666e-03  5.146503e-05|2.920578e+00  8.008492e-04|1.000000e-04
Termination check: 1.350319e-03|1.042666e-03  3.872877e-05|2.920578e+00  4.971842e-04|1.000000e-04
Last restart was iter 12520: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    20000  +3.42816896e+03  +3.42516766e+03  +3.00e+00    2.66e-03  3.41e-05   3.43s [L]
    20000  +3.42828181e+03  +3.42525346e+03  +3.03e+00    1.99e-03  2.41e-05   3.43s [A]
Termination check: 2.655098e-03|1.042666e-03  3.410679e-05|2.920578e+00  4.378692e-04|1.000000e-04
Termination check: 1.987844e-03|1.042666e-03  2.405062e-05|2.920578e+00  4.418021e-04|1.000000e-04
Last restart was iter 19600: current
Last restart was iter 21160: current
Last restart was iter 23240: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    24000  +3.42643584e+03  +3.42605686e+03  +3.79e-01    4.21e-02  2.07e-05   4.10s [L]
    24000  +3.42637363e+03  +3.42612232e+03  +2.51e-01    5.40e-03  4.17e-06   4.10s [A]
Termination check: 4.210707e-02|1.042666e-03  2.069015e-05|2.920578e+00  5.529809e-05|1.000000e-04
Termination check: 5.401254e-03|1.042666e-03  4.166442e-06|2.920578e+00  3.666811e-05|1.000000e-04
Last restart was iter 23720: average
Last restart was iter 24240: current
Last restart was iter 24440: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    28000  +3.42565192e+03  +3.42648533e+03  -8.33e-01    8.06e-03  1.51e-06   4.79s [L]
    28000  +3.42622676e+03  +3.42650881e+03  -2.82e-01    7.13e-03  1.47e-06   4.79s [A]
Termination check: 8.056111e-03|1.042666e-03  1.512344e-06|2.920578e+00  1.216096e-04|1.000000e-04
Termination check: 7.130953e-03|1.042666e-03  1.469720e-06|2.920578e+00  4.115273e-05|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    32000  +3.42568942e+03  +3.42657068e+03  -8.81e-01    7.60e-03  2.20e-06   5.46s [L]
    32000  +3.42592677e+03  +3.42661118e+03  -6.84e-01    6.52e-03  1.21e-06   5.46s [A]
Termination check: 7.600765e-03|1.042666e-03  2.195129e-06|2.920578e+00  1.285898e-04|1.000000e-04
Termination check: 6.523763e-03|1.042666e-03  1.213275e-06|2.920578e+00  9.986266e-05|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    36000  +3.42595291e+03  +3.42657121e+03  -6.18e-01    4.57e-03  3.24e-06   6.13s [L]
    36000  +3.42538203e+03  +3.42667066e+03  -1.29e+00    5.51e-03  6.04e-07   6.13s [A]
Termination check: 4.571100e-03|1.042666e-03  3.235627e-06|2.920578e+00  9.021589e-05|1.000000e-04
Termination check: 5.511004e-03|1.042666e-03  6.042666e-07|2.920578e+00  1.880368e-04|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    40000  +3.42722460e+03  +3.42661804e+03  +6.07e-01    2.70e-03  1.28e-06   6.80s [L]
    40000  +3.42583599e+03  +3.42669722e+03  -8.61e-01    3.91e-03  4.80e-07   6.80s [A]
Termination check: 2.699920e-03|1.042666e-03  1.278393e-06|2.920578e+00  8.848638e-05|1.000000e-04
Termination check: 3.905445e-03|1.042666e-03  4.796320e-07|2.920578e+00  1.256628e-04|1.000000e-04
Last restart was iter 26240: average
Last restart was iter 41000: current
Last restart was iter 41080: current
Last restart was iter 41280: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    44000  +3.42547714e+03  +3.42643168e+03  -9.55e-01    3.96e-03  6.86e-06   7.48s [L]
    44000  +3.42564450e+03  +3.42657412e+03  -9.30e-01    4.58e-03  3.11e-06   7.48s [A]
Termination check: 3.963274e-03|1.042666e-03  6.856812e-06|2.920578e+00  1.392908e-04|1.000000e-04
Termination check: 4.578061e-03|1.042666e-03  3.113830e-06|2.920578e+00  1.356470e-04|1.000000e-04
Last restart was iter 42760: current
Last restart was iter 44960: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    48000  +3.42722966e+03  +3.42653605e+03  +6.94e-01    1.96e-03  2.07e-06   8.16s [L]
    48000  +3.42690306e+03  +3.42656473e+03  +3.38e-01    1.63e-03  1.62e-06   8.16s [A]
Termination check: 1.956777e-03|1.042666e-03  2.065282e-06|2.920578e+00  1.011859e-04|1.000000e-04
Termination check: 1.627761e-03|1.042666e-03  1.617831e-06|2.920578e+00  4.935833e-05|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    52000  +3.42717924e+03  +3.42656103e+03  +6.18e-01    1.57e-03  2.70e-06   8.83s [L]
    52000  +3.42732935e+03  +3.42665984e+03  +6.70e-01    1.07e-03  3.31e-07   8.83s [A]
Termination check: 1.567878e-03|1.042666e-03  2.698537e-06|2.920578e+00  9.018737e-05|1.000000e-04
Termination check: 1.069825e-03|1.042666e-03  3.313637e-07|2.920578e+00  9.766843e-05|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    52400  +3.42691858e+03  +3.42656166e+03  +3.57e-01    1.59e-03  2.21e-06   8.92s [L]
    52400  +3.42731388e+03  +3.42666552e+03  +6.48e-01    1.04e-03  3.29e-07   8.92s [A]

Solving information:        Optimal average solution.
          Primal objective: +3.42731388e+03
            Dual objective: +3.42666552e+03
   Primal infeas (abs/rel): 1.04e-03 / 1.00e-05
     Dual infeas (abs/rel): 3.29e-07 / 1.13e-11
     Duality gap (abs/rel): 6.48e-01 / 9.46e-05
      Number of iterations: 52400

Timing information:
    Total solver time 9.013000e+00 in 52400 iterations
           Solve time 8.916000e+00 in 52400 iterations
        Iters per sec 5.877075e+03
         Scaling time 1.200000e-02
        Presolve time 8.500000e-02
                   Ax 1.045000e+00 in 53734 calls
                  Aty 1.156000e+00 in 53734 calls
     ComputeResiduals 0.000000e+00 in 0 calls
       UpdateIterates 6.884000e+00 in 52400 calls

GPU Timing information:
          CudaPrepare 1.040000e-01
Alloc&CopyMatToDevice 4.000000e-03
      CopyVecToDevice 0.000000e+00
     DeviceMatVecProd 2.190000e+00
        CopyVecToHost 0.000000e+00
--------------------------------
--- saving to ./solution-sum.json
--------------------------------
  Free Device memory 1.000000e-03

D:\test\test_cudaLinear>cudalinear -fname instance19.mps -nIterLim 500000 -ifPre 1 -dPrimalTol 1e-5
num threads= 1
--------------------------------------------------
reading file...
        instance19.mps
--------------------------------------------------
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
--------------------------------------------------
running presolve
--------------------------------------------------
Presolving model
459 rows, 6083 cols, 254040 nonzeros  0s
459 rows, 6083 cols, 254040 nonzeros  0s
Presolve status: Reduced
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
Minimize
Has obj offset 300.000000
--------------------------------------------------
running scaling
- use Ruiz scaling
- use PC scaling
--------------------------------------------------
--------------------------------------------------
enter main solve loop
--------------------------------------------------

  ____ _   _ ____  ____  _     ____
 / ___| | | |  _ \|  _ \| |   |  _ \
| |   | | | | |_) | | | | |   | |_) |
| |___| |_| |  __/| |_| | |___|  __/
 \____|\___/|_|   |____/|_____|_|

Cuda runtime 12060
Cuda driver 12080
cuSparse 12504
Cuda device 0: NVIDIA GeForce RTX 4060 Ti


--------------------------------------------------
CUPDHG Parameters:
--------------------------------------------------

    nIterLim:          500000
    dTimeLim (sec):    3600.00
    ifScaling:         1
    ifRuizScaling:     1
    ifL2Scaling:       0
    ifPcScaling:       1
    eLineSearchMethod: 2
    dPrimalTol:        1.0000e-05
    dDualTol:          1.0000e-04
    dGapTol:           1.0000e-04
    dFeasTol:          1.0000e-08
    eRestartMethod:    1

--------------------------------------------------

     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
        0  +3.00000000e+02  +1.20000000e+01  +2.88e+02    1.03e+02  0.00e+00   0.00s [L]
        0  +3.00000000e+02  +1.20000000e+01  +2.88e+02    1.03e+02  0.00e+00   0.00s [A]
Termination check: 1.026158e+02|1.036158e-03  0.000000e+00|2.070235e-01  9.201278e-01|1.000000e-04
Termination check: 1.026158e+02|1.036158e-03  0.000000e+00|2.070235e-01  9.201278e-01|1.000000e-04
Last restart was iter 0: average
Last restart was iter 1: average
Last restart was iter 2: average
Last restart was iter 4: current
Last restart was iter 7: current
Last restart was iter 9: average
Last restart was iter 40: average
Last restart was iter 80: average
Last restart was iter 160: average
Last restart was iter 280: current
Last restart was iter 440: average
Last restart was iter 640: current
Last restart was iter 720: current
Last restart was iter 1040: current
Last restart was iter 1200: current
Last restart was iter 1720: average
Last restart was iter 1800: average
Last restart was iter 2120: current
Last restart was iter 2560: average
Last restart was iter 3000: current
Last restart was iter 3120: average
Last restart was iter 3240: current
Last restart was iter 3320: current
Last restart was iter 3360: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     4000  +3.13156582e+03  +3.14485627e+03  -1.33e+01    1.92e-01  1.00e-03   0.79s [L]
     4000  +3.13510013e+03  +3.14558144e+03  -1.05e+01    1.75e-01  2.23e-04   0.79s [A]
Termination check: 1.918230e-01|1.036158e-03  1.002731e-03|2.070235e-01  2.117183e-03|1.000000e-04
Termination check: 1.753267e-01|1.036158e-03  2.229571e-04|2.070235e-01  1.668550e-03|1.000000e-04
Last restart was iter 3440: average
Last restart was iter 4480: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     8000  +3.15424115e+03  +3.14737552e+03  +6.87e+00    1.92e-02  1.30e-04   1.51s [L]
     8000  +3.15309039e+03  +3.14731850e+03  +5.77e+00    1.60e-02  3.07e-05   1.51s [A]
Termination check: 1.924401e-02|1.036158e-03  1.297241e-04|2.070235e-01  1.089329e-03|1.000000e-04
Termination check: 1.595192e-02|1.036158e-03  3.073819e-05|2.070235e-01  9.159682e-04|1.000000e-04
Last restart was iter 7000: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    12000  +3.14754575e+03  +3.14742372e+03  +1.22e-01    6.13e-03  1.18e-05   2.19s [L]
    12000  +3.14850105e+03  +3.14743339e+03  +1.07e+00    2.89e-03  7.55e-06   2.19s [A]
Termination check: 6.131199e-03|1.036158e-03  1.181000e-05|2.070235e-01  1.938108e-05|1.000000e-04
Termination check: 2.888755e-03|1.036158e-03  7.552550e-06|2.070235e-01  1.695513e-04|1.000000e-04
Last restart was iter 8840: current
Last restart was iter 12040: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    16000  +3.14770410e+03  +3.14746170e+03  +2.42e-01    4.13e-03  4.47e-06   2.82s [L]
    16000  +3.14659655e+03  +3.14746318e+03  -8.67e-01    1.94e-03  4.05e-06   2.82s [A]
Termination check: 4.129900e-03|1.036158e-03  4.469477e-06|2.070235e-01  3.849848e-05|1.000000e-04
Termination check: 1.944635e-03|1.036158e-03  4.050609e-06|2.070235e-01  1.376682e-04|1.000000e-04
Last restart was iter 12240: average
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    20000  +3.14823809e+03  +3.14746977e+03  +7.68e-01    7.36e-03  4.14e-06   3.50s [L]
    20000  +3.14774868e+03  +3.14747355e+03  +2.75e-01    2.13e-03  2.26e-06   3.50s [A]
Termination check: 7.359316e-03|1.036158e-03  4.136498e-06|2.070235e-01  1.220189e-04|1.000000e-04
Termination check: 2.129193e-03|1.036158e-03  2.259238e-06|2.070235e-01  4.369881e-05|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    24000  +3.14813795e+03  +3.14748888e+03  +6.49e-01    5.32e-03  3.67e-06   4.17s [L]
    24000  +3.14844821e+03  +3.14748980e+03  +9.58e-01    3.85e-03  1.14e-06   4.17s [A]
Termination check: 5.322694e-03|1.036158e-03  3.667634e-06|2.070235e-01  1.030817e-04|1.000000e-04
Termination check: 3.854022e-03|1.036158e-03  1.136330e-06|2.070235e-01  1.522019e-04|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    28000  +3.14744877e+03  +3.14749012e+03  -4.14e-02    2.09e-03  1.31e-06   4.82s [L]
    28000  +3.14800194e+03  +3.14749394e+03  +5.08e-01    2.98e-03  5.80e-07   4.82s [A]
Termination check: 2.086090e-03|1.036158e-03  1.307150e-06|2.070235e-01  6.568466e-06|1.000000e-04
Termination check: 2.975282e-03|1.036158e-03  5.795401e-07|2.070235e-01  8.067989e-05|1.000000e-04
Last restart was iter 19160: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
    30240  +3.14769267e+03  +3.14749172e+03  +2.01e-01    1.01e-03  1.14e-06   5.17s [L]
    30240  +3.14773743e+03  +3.14749297e+03  +2.44e-01    1.10e-03  8.47e-07   5.17s [A]

Solving information:        Optimal current solution.
          Primal objective: +3.14769267e+03
            Dual objective: +3.14749172e+03
   Primal infeas (abs/rel): 1.01e-03 / 9.74e-06
     Dual infeas (abs/rel): 1.14e-06 / 5.50e-10
     Duality gap (abs/rel): 2.01e-01 / 3.19e-05
      Number of iterations: 30240

Timing information:
    Total solver time 5.227000e+00 in 30240 iterations
           Solve time 5.172000e+00 in 30240 iterations
        Iters per sec 5.846868e+03
         Scaling time 1.400000e-02
        Presolve time 4.100000e-02
                   Ax 5.310000e-01 in 31698 calls
                  Aty 7.340000e-01 in 31698 calls
     ComputeResiduals 0.000000e+00 in 0 calls
       UpdateIterates 3.976000e+00 in 30240 calls

GPU Timing information:
          CudaPrepare 8.600000e-02
Alloc&CopyMatToDevice 3.000000e-03
      CopyVecToDevice 0.000000e+00
     DeviceMatVecProd 1.261000e+00
        CopyVecToHost 0.000000e+00
--------------------------------
--- saving to ./solution-sum.json
--------------------------------
  Free Device memory 1.000000e-03

D:\test\test_cudaLinear>cudalinear -fname instance20.mps -nIterLim 500000 -ifPre 1 -dPrimalTol 1e-5
num threads= 1
--------------------------------------------------
reading file...
        instance20.mps
--------------------------------------------------
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
--------------------------------------------------
running presolve
--------------------------------------------------
Presolving model
1142 rows, 6249 cols, 426542 nonzeros  0s
1142 rows, 6249 cols, 426542 nonzeros  0s
Presolve status: Not reduced
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
Minimize
No obj offset
--------------------------------------------------
running scaling
- use Ruiz scaling
- use PC scaling
--------------------------------------------------
--------------------------------------------------
enter main solve loop
--------------------------------------------------

  ____ _   _ ____  ____  _     ____
 / ___| | | |  _ \|  _ \| |   |  _ \
| |   | | | | |_) | | | | |   | |_) |
| |___| |_| |  __/| |_| | |___|  __/
 \____|\___/|_|   |____/|_____|_|

Cuda runtime 12060
Cuda driver 12080
cuSparse 12504
Cuda device 0: NVIDIA GeForce RTX 4060 Ti


--------------------------------------------------
CUPDHG Parameters:
--------------------------------------------------

    nIterLim:          500000
    dTimeLim (sec):    3600.00
    ifScaling:         1
    ifRuizScaling:     1
    ifL2Scaling:       0
    ifPcScaling:       1
    eLineSearchMethod: 2
    dPrimalTol:        1.0000e-05
    dDualTol:          1.0000e-04
    dGapTol:           1.0000e-04
    dFeasTol:          1.0000e-08
    eRestartMethod:    1

--------------------------------------------------

     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    1.59e+02  0.00e+00   0.01s [L]
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    1.59e+02  0.00e+00   0.01s [A]
Termination check: 1.587199e+02|1.597199e-03  0.000000e+00|3.319796e-01  0.000000e+00|1.000000e-04
Termination check: 1.587199e+02|1.597199e-03  0.000000e+00|3.319796e-01  0.000000e+00|1.000000e-04
Last restart was iter 0: average
Last restart was iter 1: average
Last restart was iter 2: average
Last restart was iter 4: current
Last restart was iter 7: current
Last restart was iter 9: average
Last restart was iter 40: average
Last restart was iter 80: average
Last restart was iter 160: average
Last restart was iter 280: current
Last restart was iter 360: current
Last restart was iter 600: current
Last restart was iter 920: current
Last restart was iter 1000: current
Last restart was iter 1160: average
Last restart was iter 1240: average
Last restart was iter 1760: current
Last restart was iter 2200: current
Last restart was iter 2760: average
Last restart was iter 3120: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     4000  +4.79820895e+03  +4.75850224e+03  +3.97e+01    1.21e-01  4.64e-03   0.77s [L]
     4000  +4.81498430e+03  +4.75654113e+03  +5.84e+01    6.00e-02  2.47e-03   0.77s [A]
Termination check: 1.207468e-01|1.597199e-03  4.636336e-03|3.319796e-01  4.154416e-03|1.000000e-04
Termination check: 6.000623e-02|1.597199e-03  2.468643e-03|3.319796e-01  6.105302e-03|1.000000e-04
Last restart was iter 3320: current
Last restart was iter 4280: current
Last restart was iter 4320: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     7000  +4.76875256e+03  +4.76890483e+03  -1.52e-01    7.64e-03  5.89e-05   1.27s [L]
     7000  +4.76922200e+03  +4.76896552e+03  +2.56e-01    9.15e-04  1.47e-05   1.27s [A]

Solving information:        Optimal average solution.
          Primal objective: +4.76922200e+03
            Dual objective: +4.76896552e+03
   Primal infeas (abs/rel): 9.15e-04 / 5.73e-06
     Dual infeas (abs/rel): 1.47e-05 / 4.44e-09
     Duality gap (abs/rel): 2.56e-01 / 2.69e-05
      Number of iterations: 7000

Timing information:
    Total solver time 1.367000e+00 in 7000 iterations
           Solve time 1.275000e+00 in 7000 iterations
        Iters per sec 5.490196e+03
         Scaling time 1.800000e-02
        Presolve time 7.400000e-02
                   Ax 1.210000e-01 in 7214 calls
                  Aty 1.380000e-01 in 7214 calls
     ComputeResiduals 0.000000e+00 in 0 calls
       UpdateIterates 9.700000e-01 in 7000 calls

GPU Timing information:
          CudaPrepare 7.600000e-02
Alloc&CopyMatToDevice 5.000000e-03
      CopyVecToDevice 0.000000e+00
     DeviceMatVecProd 2.570000e-01
        CopyVecToHost 0.000000e+00
--------------------------------
--- saving to ./solution-sum.json
--------------------------------
  Free Device memory 0.000000e+00

D:\test\test_cudaLinear>cudalinear -fname instance21.mps -nIterLim 500000 -ifPre 1 -dPrimalTol 1e-5
num threads= 1
--------------------------------------------------
reading file...
        instance21.mps
--------------------------------------------------
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
--------------------------------------------------
running presolve
--------------------------------------------------
Presolving model
1556 rows, 9235 cols, 603232 nonzeros  0s
1556 rows, 9235 cols, 603232 nonzeros  0s
Presolve status: Not reduced
Running HiGHS 1.9.0 (git hash: n/a): Copyright (c) 2025 HiGHS under MIT licence terms
Minimize
No obj offset
--------------------------------------------------
running scaling
- use Ruiz scaling
- use PC scaling
--------------------------------------------------
--------------------------------------------------
enter main solve loop
--------------------------------------------------

  ____ _   _ ____  ____  _     ____
 / ___| | | |  _ \|  _ \| |   |  _ \
| |   | | | | |_) | | | | |   | |_) |
| |___| |_| |  __/| |_| | |___|  __/
 \____|\___/|_|   |____/|_____|_|

Cuda runtime 12060
Cuda driver 12080
cuSparse 12504
Cuda device 0: NVIDIA GeForce RTX 4060 Ti


--------------------------------------------------
CUPDHG Parameters:
--------------------------------------------------

    nIterLim:          500000
    dTimeLim (sec):    3600.00
    ifScaling:         1
    ifRuizScaling:     1
    ifL2Scaling:       0
    ifPcScaling:       1
    eLineSearchMethod: 2
    dPrimalTol:        1.0000e-05
    dDualTol:          1.0000e-04
    dGapTol:           1.0000e-04
    dFeasTol:          1.0000e-08
    eRestartMethod:    1

--------------------------------------------------

     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    2.36e+02  0.00e+00   0.00s [L]
        0  +0.00000000e+00  +0.00000000e+00  +0.00e+00    2.36e+02  0.00e+00   0.00s [A]
Termination check: 2.360339e+02|2.370339e-03  0.000000e+00|3.955477e-01  0.000000e+00|1.000000e-04
Termination check: 2.360339e+02|2.370339e-03  0.000000e+00|3.955477e-01  0.000000e+00|1.000000e-04
Last restart was iter 0: average
Last restart was iter 1: average
Last restart was iter 2: average
Last restart was iter 4: current
Last restart was iter 7: current
Last restart was iter 8: current
Last restart was iter 9: average
Last restart was iter 40: average
Last restart was iter 80: average
Last restart was iter 160: current
Last restart was iter 280: average
Last restart was iter 360: current
Last restart was iter 440: current
Last restart was iter 600: current
Last restart was iter 920: current
Last restart was iter 1120: current
Last restart was iter 1360: current
Last restart was iter 1520: average
Last restart was iter 1600: current
Last restart was iter 2520: current
Last restart was iter 2640: current
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     4000  +2.11357849e+04  +2.11302185e+04  +5.57e+00    2.96e-02  2.64e-04   0.83s [L]
     4000  +2.11404979e+04  +2.11299275e+04  +1.06e+01    5.08e-03  2.09e-04   0.83s [A]
Termination check: 2.963712e-02|2.370339e-03  2.640344e-04|3.955477e-01  1.316966e-04|1.000000e-04
Termination check: 5.084463e-03|2.370339e-03  2.088359e-04|3.955477e-01  2.500615e-04|1.000000e-04
     Iter       Primal.Obj         Dual.Obj        Gap  Primal.Inf  Dual.Inf    Time
     4440  +2.11156665e+04  +2.11305657e+04  -1.49e+01    2.21e-02  1.84e-04   0.91s [L]
     4440  +2.11333909e+04  +2.11305333e+04  +2.86e+00    2.30e-03  1.61e-04   0.91s [A]

Solving information:        Optimal average solution.
          Primal objective: +2.11333909e+04
            Dual objective: +2.11305333e+04
   Primal infeas (abs/rel): 2.30e-03 / 9.70e-06
     Dual infeas (abs/rel): 1.61e-04 / 4.06e-08
     Duality gap (abs/rel): 2.86e+00 / 6.76e-05
      Number of iterations: 4440

Timing information:
    Total solver time 1.056000e+00 in 4440 iterations
           Solve time 9.140000e-01 in 4440 iterations
        Iters per sec 4.857768e+03
         Scaling time 2.600000e-02
        Presolve time 1.160000e-01
                   Ax 7.600000e-02 in 4668 calls
                  Aty 7.900000e-02 in 4668 calls
     ComputeResiduals 0.000000e+00 in 0 calls
       UpdateIterates 6.920000e-01 in 4440 calls

GPU Timing information:
          CudaPrepare 8.600000e-02
Alloc&CopyMatToDevice 8.000000e-03
      CopyVecToDevice 0.000000e+00
     DeviceMatVecProd 1.550000e-01
        CopyVecToHost 0.000000e+00
--------------------------------
--- saving to ./solution-sum.json
--------------------------------
  Free Device memory 0.000000e+00

D:\test\test_cudaLinear>

原因として考えられるのは、CPU-GPU間の転送部です。GPUのプログラムは、経験がないので良くわからないのですが、cuPDLPの本体記述によるものと、考えています。現在の実装の中規模以下では、頻繁にCPUと通信することがボトルネックになっていると推察されます。(Google版(CPU版)も見たのですが、cpPDLP(COPT版)の方に歩があると見ています。)

恐らく、超大規模問題では、GPU演算の時間が相対的に主体なので、CPU-GPU転送時間がボトルナックにはならないのではないでしょうか?現在のPDLPのトピックは、超大規模問題であり、Nvidiaもプロモートしています。

NVIDIA cuOpt で大規模な線形計画問題を加速する - NVIDIA 技術ブログ

ちなみに配送最適化問題については、こちらが詳しい

運搬経路問題(配送最適化問題,Vehicle Routing Problem) をPuLPで解く #Python - Qiita


しかし、我々の主な関心は、中大規模問題であり、主に商用のISMソルバの置き換えにあります。商用ISMソルバを使いたくても使えない庶民向けのソルバです。

よって、GPUの力を最大限発揮させるには、cuPDLP本体を記述し直しなおすしかない、という結論になります。

もう一つの問題は、WarmStartのサポートです。Simplexでは、WarmStartの恩恵があるのですが、FirstOrderにおいても、これは可能な筈です。これも現在のcuPDLPは、サポートされていないので、実装を検討する必要があります。

以上2点の実装を行う必要があります。

Highs ISMも組み込んでみたのですが、現在のスケジュールナースの速度の倍程度遅く、仮に将来マルチスレッド化されても、期待の改善度を上回ることはない、と判断しました。一方、FirstOrderは、高精度は、期待できないものの、WarmStartが魅力であり、GPUのスケーラビリティを生かせる可能性もあり、将来性があります。

以上より、Unresolved instances,INRC2 8weeks 2instancesとScheduling Benchmarks 2instances を解く為には、cuPDLPの実装し直しが必要であると結論しました。

Highs Teamが以上の要件を満足するように再実装してくれることを期待したいのですが、待っていられないし、COPTが率先して実装することもあり得ないと思うので、自分で行うことにしました。

Q.サブスク見積りについて

 Ans.

申し訳ありませんが、サブスクについては、マイクロソフト社による販売となるため、菅原システムズでは、お見積りすることが出来ません。サブスクは、クレジットカード必須となりますので、国公立病院においては、買い切り版にてお見積りをお願いしております。ご理解の上、ご検討頂きたくお願いします。



なお、サブスクの販売価格については、菅原システムズが価格決定権を持ちます。当面、1年程度は、現行価格480円/月を維持します。それ以降については、未定です。


2025年2月7日金曜日

Performance comparison between Highs MIP solver and Schedule Nurse

 We compared Highs MIP solver and Schedule Nurse, using instances of Nurse Rostering Benchmarks site. Actually algorithm 2 in Schedule Nurse  is Highs MIP solver ,and algorithm 3 in Schedule Nurse is mathematical solver for nurse rostering benchmark use. Therefore we can fairly compare the performance under the all the same condition.


What is surprising is the significant improvement of the MIP solver in Highs. I think that Instance 8 was not solved in the previous test (two years ago), but it was solved this time. That is better than SCIP. As it has not yet been multi-threaded, we can expect further performance improvements in the future.











2025年2月6日木曜日

OsiHighsSolverInterface

 For the first time in two years I have updated the Highs interface in Schedule Nurse. Two years ago there was an implementation of the trumpet OsiHighsSolverInterface, but in version 1.9.0 it was gone. There was no other choice, so I wrote it myself.

The MIP solver interface in Highs has also been updated and it is now possible to have a callback when the value of the objective function changes. This means that even if you abort the solution in the middle, you can still keep the best solution up to that point.

2025年2月5日水曜日

Instance15 modeling bug analysis

 There is a bug in the modelling of Scheduling Benchmark instance 15. In this article, we will report on the problem and explain how to analyze the bug.

Modelling bug:

In the coverage constraint section, there is a bug where a soft constraint with a Max value of 0 is interpreted as a hard constraint.

<Bug section>


Marked portions should be as follows.


Bug Analysis:

<Load instance15.ros>




As shown in the figure below, you can see that the Max 0 part of the coverage constraint is actually a hard constraint, when it should be a soft constraint with a weight of 1.

<Bug workaround>

Change them to  soft constraints with a weight index of 1, as shown in the figure below.


<Checking the bug fix>

Export the schedule to Excel as follows.


Colored portions are soft constraints


<Replace with UB3829 solution>

Using the format above, replace the data to  UB3829 solution (text format) which was obtained by asking the administrator of the benchmark site.


<Import the UB3829 solution above in another Schedule Nurse>


Schedules are replaced by the operation above.


<Lock all schedules on the first Schedule Nurse>

We preserve the scheduling soft constraints as is.



<Copy and paste the second Scheduler solution>



<Lock all the schedule on the first Schedule Nurse>




<Fill with Day Offs on the schedules in the first Schedule Nurse>


<Solve it!>

We obtained the repeated result of UB3829.


If you use Algorithm 1, please take care allowable errors on column constraints as follows.


<Summary>

Incorrect modeling causes missing the 3829UB solution. In this state, we never get the 3829UB. After workarounds, we obtained the repeated result of 3829UB.





2025年2月4日火曜日

The new solution we submitted for instance15

 The new solution we submitted for instance15 was accepted!

Changes



This solution was obtained using Schedule Nurse under development and took 128,000 seconds on a Ryzen9700x 32GB PC.



As it is single-threaded, the CPU is running at 5.2GHz. At this rate, it will probably take a few more days to prove the optimal solution, but we are busy with INRC2 for the moment, so we will plan this separately.

Another approach is to use multi-threading. In this case, multi-threading is possible, since there is still room in the 3rd level cache (32MB), there is a possibility of getting results faster. This will also be planned separately.


2025年2月3日月曜日

New Record Report for Instance15 in scheduling benchmarks

Thanks to the UB3829 solution you sent me, I was able to find a bug in my modeling. When the Max value of the cover constraint was 0, soft constraints were being interpreted as  hard constraints. This was a bug I made when automatically converting the .ros file. Accordingly, I apologize for the incorrect reports I have made so far regarding the instance 15 LB value. (There is no effect on other instances.)


I have now fixed the bug and discovered new LB and UB values for instance 15, so I would like to report them.

LB: 3827

UB: 3828


I think you can check the UB value in the attached data.


Incumbent LB=2826.36 

Root LB=2823.64

2025年2月2日日曜日

Q.学校時間割作成について

 Q.

公立中学校の教頭をしております。

来年度の時間割作成をするためのアプリ等を探しております。

御社のサービスの使用料金など、教えていただけますでしょうか。

概算で結構です。


Ans.

<中学校の時間割作成の難易度>

問題としての難易度は、ナーススケジューリング問題に比べれば、遥かに容易です。なので、フリーの最適化ソルバ(CBCやHIGHS等)で解くことが出来ます。一方、ナーススケジューリング問題は、フリーは勿論、商用ソルバでも完璧に解くのはとても難しいです。そういった難しい問題にスケジュールナースを使うことは意味がありますが、中学校の時間割作成は、容易な問題の範疇であるので、敢えて有償のスケジュールナースを使う必要性はないと思います。


<Pythonで記述する方法>

数理最適化による時間割作成 #Python - Qiita

この記事に倣って、Pythonで記述します。Pythonへの理解が必要となりますが、コストはかかりません。Pythonを知っている方が居れば、この記事に倣って作成が可能ではないかと思います。

<スケジュールナースサブスクを使って記述する方法>

作成月の1カ月分だけ、サブスクで作成する方法です。480円/月かかります。

https://schedule-nurse.blogspot.com/2025/02/q_2.html

スケジュールナースのサンプルプロジェクトは、

時間割作成問題

です。こちらを自力で改変することが出来れば、480円で済みます。何かご質問があれば、

制約FAQs

のように、一般のユーザサポートの一環として受けつけています。

<プロジェクトファイル作成サービス>

上記では、面倒で学習時間の方が勿体ない、とにかく面倒なしで作って欲しい場合のサービスになります。

ストア買い切り版

で、ストア買い切り版+プロジェクト作成サービス 11万円

となります。


以上、安い順に記述しましたが、情報関係の先生ならば、Pythonで記述できるのでは?

と思います。







Q. サブスク試用版について

Q.

スケジュールナースを試用したいのですが、

まずは、480円のサブスクリプションでしか試用版はないでしょうか?


Ans.

サブスクでは、1週間程度、無料で使用が可能ですが、クレジットカード登録が必要となります。申し訳ありませんが、試用版の提供は、サブスク以外では行っていません。


Q.副看護師長の長日勤(長日)及び夜勤(夜)は、月3回までが望ましい

Ans.

各スタッフ毎に夜勤回数を指定する方式にします。

こうすることで、

■主任看護師及び看護師の長日勤(長日)及び夜勤(夜)は、月4回までが上限

■副看護師長の長日勤(長日)及び夜勤(夜)は、月3回までが望ましい

■新人及び準新人の看護師の長日勤(長日)及び夜勤(夜)は、月3回までが上限

といった仕様も、同様に取り扱い可能となります。

また他に、

■休日は、早出(早勤務2(早2))を2交替職員又は3交替関連追加シフトのある看護師1名に割当てる

といった集合の仕様では、暗黙にそれ以外のスタッフの早出を禁止している、ということがあります。この場合、そのスタッフの最大早番数を0に設定すれば事足ります。

つまり、種々の仕様はありますが、個別に制約を記述するよりも、スタッフ定義(スタッフプロパティシート)のページで一元管理した方がメンテナンス上ベターです。


まずは、グループ集合定義で、あり得る回数を指定します。


次に、スタッフ定義で値を指定します。
ブランクは制約なし、最大0指定で禁止 の意味になります。

後は、行制約で上で定義したグループ集合を呼び出して、完了です。




2025年2月1日土曜日

Q.サンプルプログラムの所在

 Q.

サンプルプログラムから作成したいと思うのですが、どこにあるかが分かりません。。。

クリニックのスタッフ用なので難しくないとは思うのですが、イチからつくるのは大変そうなので。

どこからダウンロードできるでしょうか??


Ans.

https://www.nurse-scheduling-software.com/japanese/manuals/user_manuals/chapter15/


で、色々あるので眺めてみてください。

これらは、

■チュートリアル チュートリアル

■Kindle本 自動勤務表: これからはじめる | 菅原孝幸 | 工学 | Kindleストア | Amazon

■制約Faqs 制約FAQs

■ユーザご提供 GitHub、オープンソース文化

によるプロジェクトファイル群です。

GitHub上のサーバにあり英語版も含めると数百個のサンプルプロジェクトファイルがあります。

ダウンロードするには、ネットに接続している必要があります。

近いのが見つからない場合、サポートまでご相談ください。