/* g++ -g seat4.cpp -o seat4 */ /* 「上司の帰宅が遅れると、部下の帰宅も遅れる」の仮説検証プログラム */ #include <stdio.h> #include <stdlib.h> #include <math.h> // 共通関数 double max(double a){ return a; } double max(double a, double b){ if (a > b) return a; else return b; }; double max(double a, double b, double c ){ return max(max(a,b), max(b,c)); }; double max(double a, double b, double c, double d ){ return max(max(a,b,c), d); }; double min(double a){ return a; } double min(double a, double b){ if (b > a) return a; else return b; }; double min(double a, double b, double c ){ return min(min(a,b), min(b,c)); }; double min(double a, double b, double c, double d ){ return min(min(a,b,c), d); }; // ファジィ表現 typedef enum scale {LESSLESS, LESS, ZERO, MORE, MOREMORE} SCALE; // 前件部メンバーシップ関数(山3つ)クラス class condition_MF3 { private: double center; double width; SCALE express; public: condition_MF3(double _center, double _witdth, SCALE _express){ center = _center; width = _witdth; express = _express; // 使用できないファジィ表現を使った場合は止める if ((express == LESSLESS) || (express == MOREMORE)){ printf("wrong expression used \n"); exit(0); } }; double func(double _x); }; double condition_MF3::func(double _x) { // x,yは、メンバーシップ関数上の座標を示す double x = _x; double y = 0.0; // yの値は、必ず0以上1以下になる if (express == LESS){ if (x <= center - width){ y = 1.0; } else if (x <= center){ y = - 1.0 / width * (x - center); } else{ y = 0.0; } } else if (express == ZERO){ if (x <= center - width){ y = 0.0; } else if (x <= center){ y = 1.0 / width * (x - center) + 1.0; } else if (x <= center + width){ y = -1.0 / width * (x - center) + 1.0; } else{ y = 0.0; } } else if (express == MORE){ if (x <= center){ y = 0.0; } else if (x <= center + width){ y = 1.0 / width * (x - center); } else{ y = 1.0; } } else { printf("wrong expression\n"); exit(1); } return y; }; // 前件部メンバーシップ関数(山5つ)クラス class condition_MF5 { private: double center; double width; SCALE express; public: condition_MF5(double _center, double _witdth, SCALE _express){ center = _center; width = _witdth; express = _express; }; double func(double _x); }; double condition_MF5::func(double _x) { // x,yは、メンバーシップ関数上の座標を示す double x = _x; double y = 0.0; // yの値は、必ず0以上1以下になる if (express == LESSLESS){ if (x <= center - 2.0 * width){ y = 1.0; } else if (x <= center - width){ y = - 1.0 / width * (x - (center - 2.0 * width)) + 1.0; } else{ y = 0.0; } } else if (express == LESS){ if (x <= center - 2.0 * width){ y = 0.0; } else if (x <= center - width){ y = 1.0 / width * (x - (center - width)) + 1.0; } else if (x <= center){ y = -1.0 / width * (x - (center - width)) + 1.0; } else{ y = 0.0; } } else if (express == ZERO){ if (x <= center - width){ y = 0.0; } else if (x <= center){ y = 1.0 / width * (x - center) + 1.0; } else if (x <= center + width){ y = -1.0 / width * (x - center) + 1.0; } else{ y = 0.0; } } else if (express == MORE){ if (x <= center){ y = 0.0; } else if (x <= center + width){ y = 1.0 / width * (x - (center + width)) + 1.0; } else if (x <= center + 2.0 * width){ y = -1.0 / width * (x - (center + width)) + 1.0; } else{ y = 0.0; } } else if (express == MOREMORE){ if (x <= center + width){ y = 0.0; } else if (x <= center + 2.0 * width){ y = 1.0 / width * (x - (center + 2.0 * width)) + 1.0; } else{ y = 1.0; } } return y; }; // 後件部メンバーシップ関数(山3つ)クラス class action_MF3 { private: double center; double width; SCALE express; double x; double y; public: action_MF3(double _center, double _witdth, SCALE _express){ y = 0.0; // yの値は、必ず0以上1以下になる center = _center; width = _witdth; express = _express; if (express == LESS){ x = center - width; } else if (express == ZERO){ x = center; } else if (express == MORE){ x = center + width; } else{ printf("wrong scale expression\n"); exit(0); } }; // Y座標の値を最大値で更新する void func_Max(double b){ y = max(b, y); }; // Y座標の値をリセット(y=0)する void func_Reset(){ y = 0.0; }; // X座標を返す double func_X(void){ return x; }; // (最大値で更新された、最後の)Y座標を返す double func_Y(){ return y; }; }; // 後件部メンバーシップ関数(山5つ)クラス class action_MF5 { private: double center; double width; SCALE express; double x; double y; public: action_MF5(double _center, double _witdth, SCALE _express){ y = 0.0; // yの値は、必ず0以上1以下になる center = _center; width = _witdth; express = _express; if (express == LESSLESS){ x = center - 2.0 * width; } else if (express == LESS){ x = center - width; } else if (express == ZERO){ x = center; } else if (express == MORE){ x = center + width; } else if (express == MOREMORE){ x = center + 2.0 * width; } else{ printf("wrong scale expression\n"); exit(-1); // 強制終了 } }; // Y座標の値を最大値で更新する void func_Max(double b){ y = max(b, y); }; // Y座標の値をリセット(y=0)する void func_Reset(){ y = 0.0; }; // X座標を返す double func_X(void){ return x; }; // (最大値で更新された、最後の)Y座標を返す double func_Y(){ return y; }; }; typedef enum post{ HEAD = 1, // 部長 CHIEF = 2, // 課長 STAFF = 3 // 平社員 } POST; typedef struct person{ int absences; // 0:帰宅、 1:残業 char name[10]; int section; int number; POST post; double p_x; double p_y; double expected_return_time; // 17.5(17:30)から、21.0(21:00)までの時間) double going_home_ratio; } PERSON; const int SECTION = 6; const int MEMBER = 8; const int ALL_PERSON_COUNTER = 49; // 6つの課、それぞれ8人と部長 PERSON person[] = { {1,"部長",-1,-1, HEAD, 0.0, 0.0}, {1,"社員", 0, 0, STAFF, 3.5 + 0.0 + 0.0, -4.4 + 0.0 + 0.0}, {1,"社員", 0, 1, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 0.0 + 0.0}, {1,"社員", 0, 2, STAFF, 3.5 + 0.0 + 2.4, -4.4 + 0.0 + 0.0}, {1,"社員", 0, 3, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 0.0 + 0.0}, {1,"課長", 0, 4, CHIEF, 3.5 + 0.0 + 0.0, -4.4 + 0.0 + 2.0}, {1,"社員", 0, 5, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 0.0 + 2.0}, {1,"社員", 0, 6, STAFF, 3.5 + 0.0 + 2.4, -4.4 + 0.0 + 2.0}, {1,"社員", 0, 7, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 0.0 + 2.0}, {1,"社員", 1, 0, STAFF, 3.5 + 4.8 + 0.0, -4.4 + 0.0 + 0.0}, {1,"社員", 1, 1, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 0.0 + 0.0}, {1,"社員", 1, 2, STAFF, 3.5 + 4.8 + 2.4, -4.4 + 0.0 + 0.0}, {1,"課長", 1, 3, CHIEF, 3.5 + 4.8 + 3.6, -4.4 + 0.0 + 0.0}, {1,"社員", 1, 4, STAFF, 3.5 + 4.8 + 0.0, -4.4 + 0.0 + 2.0}, {1,"社員", 1, 5, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 0.0 + 2.0}, {1,"社員", 1, 6, STAFF, 3.5 + 4.8 + 2.4, -4.4 + 0.0 + 2.0}, {1,"社員", 1, 7, STAFF, 3.5 + 4.8 + 3.6, -4.4 + 0.0 + 2.0}, {1,"社員", 2, 0, STAFF, 3.5 + 0.0 + 0.0, -4.4 + 3.4 + 0.0}, {1,"社員", 2, 1, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 3.4 + 0.0}, {1,"課長", 2, 2, CHIEF, 3.5 + 0.0 + 2.4, -4.4 + 3.4 + 0.0}, {1,"社員", 2, 3, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 3.4 + 0.0}, {1,"社員", 2, 4, STAFF, 3.5 + 0.0 + 0.0, -4.4 + 3.4 + 2.0}, {1,"社員", 2, 5, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 3.4 + 2.0}, {1,"社員", 2, 6, STAFF, 3.5 + 0.0 + 2.4, -4.4 + 3.4 + 2.0}, {1,"社員", 2, 7, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 3.4 + 2.0}, {1,"社員", 3, 0, STAFF, 3.5 + 4.8 + 0.0, -4.4 + 3.4 + 0.0}, {1,"社員", 3, 1, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 3.4 + 0.0}, {1,"社員", 3, 2, STAFF, 3.5 + 4.8 + 2.4, -4.4 + 3.4 + 0.0}, {1,"社員", 3, 3, STAFF, 3.5 + 4.8 + 3.6, -4.4 + 3.4 + 0.0}, {1,"社員", 3, 4, STAFF, 3.5 + 4.8 + 0.0, -4.4 + 3.4 + 2.0}, {1,"社員", 3, 5, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 3.4 + 2.0}, {1,"課長", 3, 6, CHIEF, 3.5 + 4.8 + 2.4, -4.4 + 3.4 + 2.0}, {1,"社員", 3, 7, STAFF, 3.5 + 4.8 + 3.6, -4.4 + 3.4 + 2.0}, {1,"課長", 4, 0, CHIEF, 3.5 + 0.0 + 0.0, -4.4 + 6.8 + 0.0}, {1,"社員", 4, 1, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 6.8 + 0.0}, {1,"社員", 4, 2, STAFF, 3.5 + 0.0 + 2.4, -4.4 + 6.8 + 0.0}, {1,"社員", 4, 3, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 6.8 + 0.0}, {1,"社員", 4, 4, STAFF, 3.5 + 0.0 + 0.0, -4.4 + 6.8 + 2.0}, {1,"社員", 4, 5, STAFF, 3.5 + 0.0 + 1.2, -4.4 + 6.8 + 2.0}, {1,"社員", 4, 6, STAFF, 3.5 + 0.0 + 2.4, -4.4 + 6.8 + 2.0}, {1,"社員", 4, 7, STAFF, 3.5 + 0.0 + 3.6, -4.4 + 6.8 + 2.0}, {1,"社員", 5, 0, STAFF, 3.5 + 4.8 + 0.0, -4.4 + 6.8 + 0.0}, {1,"社員", 5, 1, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 6.8 + 0.0}, {1,"社員", 5, 2, STAFF, 3.5 + 4.8 + 2.4, -4.4 + 6.8 + 0.0}, {1,"社員", 5, 3, STAFF, 3.5 + 4.8 + 3.6, -4.4 + 6.8 + 0.0}, {1,"課長", 5, 4, CHIEF, 3.5 + 4.8 + 0.0, -4.4 + 6.8 + 2.0}, {1,"社員", 5, 5, STAFF, 3.5 + 4.8 + 1.2, -4.4 + 6.8 + 2.0}, {1,"社員", 5, 6, STAFF, 3.5 + 4.8 + 2.4, -4.4 + 6.8 + 2.0}, {1,"社員", 5, 7, STAFF, 3.5 + 4.8 + 3.6, -4.4 + 6.8 + 2.0}, }; double distance(PERSON* person1, PERSON* person2) { double d = 0.0; d = pow((person1->p_x - person2->p_x),2.0); d += pow((person1->p_y - person2->p_y),2.0); d = sqrt(d); if ((person1->absences == 0) || (person2->absences == 0) ) d = 99999.9; // どちらかが不在であれば、非常に大きい距離になる return d; } int main() { PERSON* cheif[SECTION+1]; // 初期状態 (最初は個人の帰宅時間は、乱数で設定) for (int i = 0; i < ALL_PERSON_COUNTER; i++){ // 各個人の帰宅時間を設定 person[i].expected_return_time = 17.5 + (21.0 -17.5) * rand()/ (1.0 + RAND_MAX); //person[i].expected_return_time = 18.5; // 各課の課長を選定(後で探すのが面倒なので) if (person[i].post == CHIEF){ cheif[person[i].section] = &person[i]; } } person[0].expected_return_time = 22.0; /* for (int i = 0; i < ALL_PERSON_COUNTER; i++){ printf("%d, expected_return_time = %f\n",i, person[i].expected_return_time); printf("%d, expected_return_time = %d\n",i, person[i].absences); } */ // 残業時間 condition_MF3 OverTime_Short(1.0, 1.0, LESS); // 1時間 condition_MF3 OverTime_Middle(1.0, 1.0, ZERO); // 2時間 condition_MF3 OverTime_Long(1.0, 1.0, MORE); // 3時間 // 部長からの距離 condition_MF5 DistanceFrom_HEAD_NearNear(5.0, 5.0, LESSLESS); // 5メートル condition_MF5 DistanceFrom_HEAD_Near(5.0, 5.0, LESS); // 10メートル condition_MF5 DistanceFrom_HEAD_Middle(5.0, 5.0, ZERO); // 15メートル condition_MF5 DistanceFrom_HEAD_Far(5.0, 5.0, MORE); // 20メートル condition_MF5 DistanceFrom_HEAD_FarFar(5.0, 5.0, MOREMORE); // 25メートル // 課長からの距離 condition_MF5 DistanceFrom_CHIEF_NearNear(1.0, 1.0, LESSLESS); // 1メートル condition_MF5 DistanceFrom_CHIEF_Near(1.0, 1.0, LESS); // 2メートル condition_MF5 DistanceFrom_CHIEF_Middle(1.0, 1.0, ZERO); // 3メートル condition_MF5 DistanceFrom_CHIEF_Far(1.0, 1.0, MORE); // 4メートル condition_MF5 DistanceFrom_CHIEF_FarFar(1.0, 1.0, MOREMORE); // 5メートル // 残っている課の人数 condition_MF3 Staying_COUNT_Less(2, 2, LESS); // 2人 condition_MF3 Staying_COUNT_Middle(2, 2, ZERO); // 4人 condition_MF3 Staying_COUNT_Many(2, 2, MORE); // 6人 // 帰宅度数 action_MF3 GoingHome_Hard(0.5, 0.5, LESS);// 帰宅度数 0.0 → 帰宅できない action_MF3 GoingHome_Middle(0.5, 0.5, ZERO);// 帰宅度数 0.5 → 迷う action_MF3 GoingHome_Easy(0.5, 0.5, MORE);// 帰宅度数 1.0 → 帰宅できる double present_time =17.5; while (present_time < 24.0){ present_time += 0.1; // 一番後ろで加算すると忘れそうなので // printf("present_time = %f\n", present_time); // 部の中の課の全体状況の把握 if (person[0].expected_return_time < present_time){ // 部長は特別あつかい person[0].absences = 0; } int staying_count[SECTION] ={}; // 各課(Section)で残っている人数を格納(最初はゼロリセット) int staying_all = 0; for (int i = 0; i < ALL_PERSON_COUNTER; i++){ if (person[i].absences == 1){ staying_count[person[i].section] += 1; // (Section)に一人追加 staying_all += 1; } } printf("%f,%d,%d,%d,%d,%d,%d,%d\n", present_time, staying_count[0], staying_count[1], staying_count[2], staying_count[3], staying_count[4], staying_count[5], staying_all); for (int i = 1; i < ALL_PERSON_COUNTER; i++){ // person[0]の部長は神様→誰からも影響を受けない(とする) #if 1 if (person[i].absences == 0) // 帰った人間はどーでも良い continue; if (person[i].expected_return_time > present_time) // 仕事中は帰らない continue; #endif if (person[i].post == STAFF){ // (ヒラ)社員の場合の付加条件 /* ルール3 課長が残っている場合、課長から1.5m以内のメンバは、帰宅度数0.0 課長から3.0m以内のメンバは、帰宅度数0.5 課長から4.5m以内のメンバは、帰宅度数0.7 */ double dis = distance(cheif[person[i].section], &person[i]); /////////////// double r11 = min(DistanceFrom_CHIEF_NearNear.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r11); double r12 = min(DistanceFrom_CHIEF_Near.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r12); double r13 = min(DistanceFrom_CHIEF_Middle.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r13); double r14 = min(DistanceFrom_CHIEF_Far.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r14); double r15 = min(DistanceFrom_CHIEF_FarFar.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r15); /////////////// /////////////// double r21 = min(DistanceFrom_CHIEF_NearNear.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r21); double r22 = min(DistanceFrom_CHIEF_Near.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r22); double r23 = min(DistanceFrom_CHIEF_Middle.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r23); double r24 = min(DistanceFrom_CHIEF_Far.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r24); double r25 = min(DistanceFrom_HEAD_FarFar.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r25); /////////////// /////////////// double r31 = min(DistanceFrom_CHIEF_NearNear.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r31); double r32 = min(DistanceFrom_CHIEF_Near.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r32); double r33 = min(DistanceFrom_CHIEF_Middle.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r33); double r34 = min(DistanceFrom_CHIEF_Far.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r34); double r35 = min(DistanceFrom_CHIEF_FarFar.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r34); /////////////// } if (person[i].post == CHIEF){ // 課長の場合の付加条件 /* ルール2 部長が残っている場合、部長から5m以内の課長は、帰宅度数0.0 5m~10m以内の課長は、帰宅度数0.5 10m以上の課長は、帰宅度数1.0 */ double dis = distance(&person[0], &person[i]); /////////////// double r11 = min(DistanceFrom_HEAD_NearNear.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r11); double r12 = min(DistanceFrom_HEAD_Near.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r12); double r13 = min(DistanceFrom_HEAD_Middle.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r13); double r14 = min(DistanceFrom_HEAD_Far.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r14); double r15 = min(DistanceFrom_HEAD_FarFar.func(dis), OverTime_Short.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r15); /////////////// /////////////// double r21 = min(DistanceFrom_HEAD_NearNear.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r21); double r22 = min(DistanceFrom_HEAD_Near.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r22); double r23 = min(DistanceFrom_HEAD_Middle.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r23); double r24 = min(DistanceFrom_HEAD_Far.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r24); double r25 = min(DistanceFrom_HEAD_FarFar.func(dis), OverTime_Middle.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r25); /////////////// /////////////// double r31 = min(DistanceFrom_HEAD_NearNear.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Hard.func_Max(r31); double r32 = min(DistanceFrom_HEAD_Near.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Middle.func_Max(r32); double r33 = min(DistanceFrom_HEAD_Middle.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r33); double r34 = min(DistanceFrom_HEAD_Far.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r34); double r35 = min(DistanceFrom_HEAD_FarFar.func(dis), OverTime_Long.func(person[i].expected_return_time - present_time)); GoingHome_Easy.func_Max(r34); /////////////// } #if 0 /* ルール4 同じ課のメンバのの人数が、6人以上残っている場合は、帰宅度数0.3 4人残っている場合は、帰宅度数0.6 2人以下の場合は、帰宅度数1.0 */ int num = staying_count[person[i].section]; double r41 = min(Staying_COUNT_Less.func((double)num)); GoingHome_Easy.func_Max(r41); double r42 = min(Staying_COUNT_Middle.func((double)num)); GoingHome_Middle.func_Max(r42); double r43 = min(Staying_COUNT_Many.func((double)num)); GoingHome_Hard.func_Max(r43); #endif /* ルールに振れない場合は、min-max重心法の分母がゼロになり、 ゼロ割が発生する場合がある為、それを回避する */ double denominator = // 分母 GoingHome_Easy.func_Y() + GoingHome_Middle.func_Y() + GoingHome_Hard.func_Y(); double numerator = // 分子 GoingHome_Easy.func_X() * GoingHome_Easy.func_Y() + GoingHome_Middle.func_X() * GoingHome_Middle.func_Y() + GoingHome_Hard.func_X() * GoingHome_Hard.func_Y(); // 推論結果 (分母がゼロの場合は、推論結果は前回と同値とする) if ( denominator != 0.0){ person[i].going_home_ratio = numerator / denominator ; /* if ((present_time >= 18.5) && (present_time < 18.52)){ printf("%d: person[i].going_home_ratio=%f\n",i, person[i].going_home_ratio); } */ } if (person[i].going_home_ratio > 0.75){ person[i].absences = 0; // 0:帰宅、 1:残業 } // 後件部メンバーシップ関数のリセット(ループさせる時は必ずリセットする) GoingHome_Easy.func_Reset(); GoingHome_Middle.func_Reset(); GoingHome_Hard.func_Reset(); } } /* for (int i = 0; i < ALL_PERSON_COUNTER; i++){ printf("%d, absences = %d\n",i, person[i].absences); } */ return 0; }