●実現したい仕様
新人であるスタッフQが2月から夜勤のシフトが始まる。
夜勤は通常2名体制だが、スタッフQが初夜勤時は新人以外2名、新人1名の計3名で組みたい。

この3名の特別体制は月1回まで、それ以降は新人も含めた2名体制になる。
※初夜勤の日は仮で2/15(木)と設定し、スタッフQの2/14(水)までの勤務は日勤(-)または休み(×)のいずれかのみに設定(予定入力上で設定済)

●ご教示頂きたいこと 
・今回は仮で2/15(木)を特別体制の日に指定しましたが、
これを2/13~2/16のいずれかに設定、という形で幅をもたせることは可能ですか?

・Pythonによる制約までは対応できません。一応、特別体制の日を指定すれば、上記の制約で対応はできているため、無理に複雑な制約を組み合わせる必要はないとも考えています。目的の実装のために多くの時間を割いてしまうのは、スケジュールナースのアプリを利用する上で本末転倒になってしまうため、簡便に実装できるのであれば設定したいという考えです。


おっしゃる通りです。
何もかも制約化するというのは、間違いです。
「将来も含めたトータルの作業量に対して、メリットの方が大きいときだけ制約化する」が原則となります。
ご要求仕様に対して、Pythonを使わずに実装することは可能です。
リニアペア制約やマクロ等、最近の版で実装した部分の理解が必要となるので、技術的なハードルは高くなりますが、それらを駆使すれば、スマートに書けます。



新人初回夜勤区間の設定

2月15日の単日に対して、2月13-16日の区間を新たに設定しました。今回は、この区間に対して制約を加えていきます。



区間以外の定義

上で定義した区間を基に列制約用とペア制約用で、区間を整形します。

区間 適用 制約
新人初回夜勤区間でない今月 通常時制約  列制約
新人初回夜勤区間今月 今月だけ ペア制約







どちらの集合も排他的(=交わりがない、ANDは空集合)であり、集合の足し算をすると、「今月」集合に合致します。 このように漏れのないように定義することが重要です。

列制約の変更

初回夜勤区間以外の区間を制約します。新人初回夜勤区間が定義されていない場合(空集合時)は、この区間は、今月に一致します。
つまり、この区間は、通常時の区間です。 最大・最小は、後述するマクロで定義しています。



行制約の追加

初回夜勤区間の新人の夜勤回数、最小値をマクロで指定しています。要求仕様では、初回のみの短い区間を想定していますが、長い区間で複数回を行う場合も考慮しています。
最小値をマクロにしていることに注意してください。これが固定値だと、初回夜勤区間が空集合のときにソフトエラーが発生します。しかしマクロ化することによって、空集合時は、最小値を0にすることが出来、無用なエラーを回避できます。



ペア制約追加

「新人初回夜勤区間今月」でのみ、作用する制約です。
リニアペア制約、「等しい」オペレータを使用しています。この制約は、次のように制約します。今回、係数は全て1なので、

ΣA ==ΣB+数値オフセット

数値オフセットtは、今回、マクロで記述し、通常時の夜勤回数で、-2になります。つまり、上式は、

新人夜勤回数==全員夜勤回数-2

となるので、以下のように制約されます。

新人者数 全夜勤者数
0 2
1 3
2 4

固有のスタッフ名ではなく、「新人」で抽象化した集合で作用することに注意してください。「新人」が空集合でも問題なく動きます。 また、新人は1名に限定されることはありません。

また、制約上、-2を設定する必要がありますが、使用者に、「ここはマイナスを設定してください」では、訳が分からなくなってしまうので、 やはり、ここは、マクロで定義し、マイナス値が暗黙のうちに設定されるようにします。



マクロ設定

マクロ化することで、関連する定数変更を、関係を保ったまま一気に行えます。また、制約箇所を探して値変更する必要もなくなるので、メンテナンス性が向上します。





初回夜勤区間の日数を数えて、空集合なら0、それ以外は、設定値D3にしています。 これは、空集合時は、行制約を制約しないようにするためです。

使用法

また、使い方等や、製作者からのメッセージを記すことが出来ます。



プロジェクト

プロジェクトは、以下です。

ダウンロード して、実装の参考にしてください。