Browse code

Implemented algorithms

Cinan Rakosnik authored on 08/04/2018 at 15:36:15
Showing 20 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,90 @@
0
+import {
1
+  addIndex,
2
+  findIndex,
3
+  find,
4
+  map,
5
+  propEq,
6
+  reduce,
7
+  sort,
8
+  range,
9
+  concat,
10
+  filter,
11
+  reverse,
12
+  prop,
13
+  flatten,
14
+  uniq,
15
+  reject,
16
+  contains,
17
+  omit,
18
+  equals,
19
+  update,
20
+  times,
21
+  add,
22
+  pluck,
23
+  last
24
+} from 'rambda';
25
+import type { JobId } from '../../types';
26
+import { max, min, remove, slice } from 'ramda';
27
+import { createSchedule as johnson, updateCTime } from '../johnson';
28
+
29
+type JobOperations = {
30
+  jobId: JobId,
31
+  operations: Array<{ t: number }>
32
+};
33
+
34
+type JobOperationsWithC = {
35
+  jobId: JobId,
36
+  operations: Array<{ t: number, c: number }>
37
+};
38
+
39
+export const createSchedule = (jobsOperations: JobOperations[], processorsCount: number): JobOperationsWithC[] => {
40
+  const allSchedules = map(k => {
41
+    const jobsOperationsForK = map((jobsOperation: JobOperations) => {
42
+      const t1 = reduce((acc, i) => acc + jobsOperation.operations[i].t, 0, range(0, k));
43
+      const t2 = reduce((acc, i) => acc + jobsOperation.operations[i].t, 0, range(processorsCount - k, processorsCount));
44
+
45
+      const operations = [
46
+        { t: t1 },
47
+        { t: t2 }
48
+      ];
49
+      const newJobsOperations = { jobId: jobsOperation.jobId, operations };
50
+      return newJobsOperations;
51
+    }, jobsOperations);
52
+
53
+    const jobsOperationsOrderTemplate = johnson(jobsOperationsForK);
54
+
55
+    const mapWithIndex = addIndex(map);
56
+    const jobsOperationsReordered = mapWithIndex((jobOperationTemplate, i) => {
57
+      const { operations } = find(propEq('jobId', jobOperationTemplate.jobId), jobsOperations);
58
+      return {
59
+        jobId: jobOperationTemplate.jobId,
60
+        operations
61
+      };
62
+    }, jobsOperationsOrderTemplate);
63
+
64
+    const jobsOperationsReorderedWithC = updateCTime(jobsOperationsReordered, processorsCount);
65
+
66
+    return jobsOperationsReorderedWithC;
67
+  }, range(1, processorsCount));
68
+
69
+  const bestSchedule = reduce((acc, schedule) => {
70
+    const cmaxAcc = last(last(acc).operations).c;
71
+    const cmax = last(last(schedule).operations).c;
72
+
73
+    return (cmax < cmaxAcc) ? schedule : acc;
74
+  }, [{ operations: [{ c: Infinity }] }], allSchedules);
75
+
76
+  return bestSchedule;
77
+};
78
+
79
+export default (jobsOperations: JobOperations[], processorsCount: number) => {
80
+  const schedule = createSchedule(jobsOperations, processorsCount);
81
+
82
+  return times(i =>
83
+    map((jobTime: JobOperationsWithC) => ({
84
+      processor: i + 1,
85
+      startTime: jobTime.operations[i].c - jobTime.operations[i].t,
86
+      endTime: jobTime.operations[i].c,
87
+    }), schedule)
88
+  , processorsCount);
89
+};
0 90
\ No newline at end of file
1 91
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobsWithOperations = [
4
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
5
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
6
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
7
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
8
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
9
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
10
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
11
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
12
+  ];
13
+
14
+  const schedule = createSchedule(jobsWithOperations, 3);
15
+
16
+  expect(schedule.length).toBe(8);
17
+  expect(schedule[0]).toEqual({ jobId: 5, operations: [ { t: 4, c: 4 }, { t: 4, c: 8 }, { t: 20, c: 28 } ] });
18
+  expect(schedule[1]).toEqual({ jobId: 8, operations: [ { t: 10, c: 14 }, { t: 2, c: 16 }, { t: 25, c: 53 } ] });
19
+  expect(schedule[2]).toEqual({ jobId: 6, operations: [ { t: 3, c: 17 }, { t: 12, c: 29 }, { t: 13, c: 66 } ] });
20
+  expect(schedule[3]).toEqual({ jobId: 2, operations: [ { t: 6, c: 23 }, { t: 13, c: 42 }, { t: 19, c: 85 } ] });
21
+  expect(schedule[4]).toEqual({ jobId: 4, operations: [ { t: 16, c: 39 }, { t: 7, c: 49 }, { t: 21, c: 106 } ] });
22
+  expect(schedule[5]).toEqual({ jobId: 3, operations: [ { t: 15, c: 54 }, { t: 10, c: 64 }, { t: 18, c: 124 } ] });
23
+  expect(schedule[6]).toEqual({ jobId: 1, operations: [ { t: 12, c: 66 }, { t: 8, c: 74 }, { t: 11, c: 135 } ] });
24
+  expect(schedule[7]).toEqual({ jobId: 7, operations: [ { t: 17, c: 83 }, { t: 6, c: 89 }, { t: 8, c: 143 } ] });
25
+});
26
+
27
+test('create gantt', () => {
28
+  const jobsWithOperations = [
29
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
30
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
31
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
32
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
33
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
34
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
35
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
36
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
37
+  ];
38
+
39
+  const template = createGantt(jobsWithOperations, 3);
40
+
41
+  expect(template.length).toBe(3);
42
+  expect(template[0].length).toBe(8);
43
+  expect(template[1].length).toBe(8);
44
+  expect(template[2].length).toBe(8);
45
+
46
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 4 });
47
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 4, endTime: 14 });
48
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 14, endTime: 17 });
49
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 17, endTime: 23 });
50
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 23, endTime: 39 });
51
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 39, endTime: 54 });
52
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 54, endTime: 66 });
53
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 66, endTime: 83 });
54
+
55
+  expect(template[1][0]).toEqual({ processor: 2, startTime: 4, endTime: 8 });
56
+  expect(template[1][1]).toEqual({ processor: 2, startTime: 14, endTime: 16 });
57
+  expect(template[1][2]).toEqual({ processor: 2, startTime: 17, endTime: 29 });
58
+  expect(template[1][3]).toEqual({ processor: 2, startTime: 29, endTime: 42 });
59
+  expect(template[1][4]).toEqual({ processor: 2, startTime: 42, endTime: 49 });
60
+  expect(template[1][5]).toEqual({ processor: 2, startTime: 54, endTime: 64 });
61
+  expect(template[1][6]).toEqual({ processor: 2, startTime: 66, endTime: 74 });
62
+  expect(template[1][7]).toEqual({ processor: 2, startTime: 83, endTime: 89 });
63
+
64
+  expect(template[2][0]).toEqual({ processor: 3, startTime: 8, endTime: 28 });
65
+  expect(template[2][1]).toEqual({ processor: 3, startTime: 28, endTime: 53 });
66
+  expect(template[2][2]).toEqual({ processor: 3, startTime: 53, endTime: 66 });
67
+  expect(template[2][3]).toEqual({ processor: 3, startTime: 66, endTime: 85 });
68
+  expect(template[2][4]).toEqual({ processor: 3, startTime: 85, endTime: 106 });
69
+  expect(template[2][5]).toEqual({ processor: 3, startTime: 106, endTime: 124 });
70
+  expect(template[2][6]).toEqual({ processor: 3, startTime: 124, endTime: 135 });
71
+  expect(template[2][7]).toEqual({ processor: 3, startTime: 135, endTime: 143 });
72
+});
0 73
\ No newline at end of file
1 74
new file mode 100644
... ...
@@ -0,0 +1,175 @@
0
+// import {
1
+//   addIndex,
2
+//   findIndex,
3
+//   find,
4
+//   map,
5
+//   propEq,
6
+//   reduce,
7
+//   sort,
8
+//   range,
9
+//   concat,
10
+//   filter,
11
+//   reverse,
12
+//   prop,
13
+//   flatten,
14
+//   uniq,
15
+//   reject,
16
+//   contains,
17
+//   omit,
18
+//   equals,
19
+//   update,
20
+//   times,
21
+//   add,
22
+//   pluck,
23
+//   last, forEach
24
+// } from 'rambda';
25
+// import type { JobId } from '../../types';
26
+// import { max, min, remove, slice } from 'ramda';
27
+// import { createSchedule as johnson, updateCTime } from '../johnson';
28
+//
29
+// type JobTime = {
30
+//   jobId: JobId,
31
+//   t: number,
32
+//   succ: JobId[],
33
+//   processor: number
34
+// };
35
+//
36
+// type JobTimeWithZK = JobTime | {
37
+//   z: number,
38
+//   k: number
39
+// };
40
+//
41
+// const noAncJobs = (jobTimes: JobTime[]) => {
42
+//   const allSuccesors = flatten(map(prop('succ'), jobTimes));
43
+//   return reject((jobTime: JobTime) => contains(jobTime.jobId, allSuccesors), jobTimes);
44
+// };
45
+//
46
+// const ancestors = (id: JobId, jobTimes: JobTime[]) =>
47
+//   filter(({ succ }) => contains(id, succ), jobTimes);
48
+//
49
+// const updateZK = (jobTimes: JobTimeWithZK[], allJobTimes: JobTimeWithZK) =>
50
+//   map((jobTime: JobTimeWithZK) => {
51
+//     // const allSuccesors = map(prop('succ'), jobTimes);
52
+//     const ancestors = filter(aJob => contains(jobTime.jobId, aJob.succ), allJobTimes);
53
+//
54
+//     let z = reduce((acc, job) => max(acc, job.k), -Infinity, ancestors);
55
+//     z = max(z, jobTime.t);
56
+//
57
+//     return {
58
+//       ...jobTime,
59
+//       z,
60
+//       k: z + jobTime.t
61
+//     };
62
+//   }, jobTimes);
63
+//
64
+// export const createSchedule = (jobTimes: JobTime[], processorsCount: number) => {
65
+//   let k = 0;
66
+//   let Pk = [];
67
+//
68
+//   let jobTimesWithZK: JobTimeWithZK[] = map((jobTime: JobTime) => ({
69
+//       ...jobTime,
70
+//       z: 0,
71
+//       k: 0 + jobTime.t
72
+//     }), jobTimes);
73
+//
74
+//   let Sk = noAncJobs(jobTimesWithZK);
75
+//   let mStar;
76
+//
77
+//   const processorC = [0, 0, 0, 0];
78
+//
79
+//   // while (Sk.length) {
80
+//   while (k < 4) {
81
+//     // if (k === 2) {
82
+//     //   console.log(processorC);
83
+//     // }
84
+//     // console.log(processorC);
85
+//     let kStar = reduce((acc: JobTimeWithZK, jobTime: JobTimeWithZK) => {
86
+//       // console.log(jobTime.jobId, jobTime.t + processorC[jobTime.processor]);
87
+//
88
+//       const anc = ancestors(jobTime.jobId, jobTimes)[0];
89
+//       // let z = processorC[jobTime.processor];
90
+//
91
+//       // console.log(jobTime, anc);
92
+//
93
+//       if (anc) {
94
+//         jobTime.k = jobTime.t + anc.k;
95
+//       } else {
96
+//         jobTime.k = jobTime.t;
97
+//       }
98
+//
99
+//         jobTimes.forEach(j => {
100
+//           if (j.jobId === jobTime.jobId) {
101
+//             j.k = jobTime.k
102
+//           }
103
+//         });
104
+//
105
+//         // if (k === 2) {
106
+//         //   console.log(jobTime, anc);
107
+//         // }
108
+//
109
+//       return jobTime.k < acc.k ? jobTime : acc;
110
+//     }
111
+//       // jobTime.t < acc.t ? jobTime : acc
112
+//       // jobTime.k < acc.k ? jobTime : acc
113
+//     , { k: Infinity }, Sk).k;
114
+//
115
+//     if (k === 3)
116
+//       console.log(kStar);
117
+//
118
+//     let oStar = find((jobTime: JobTimeWithZK) => jobTime.k === kStar, Sk);
119
+//     // console.log(oStar);
120
+//     mStar = oStar.processor;
121
+//
122
+//     // processorC[oStar.processor] += oStar.t;
123
+//     // const p = pluck('processor', map(succ => find(propEq('jobId', succ), jobTimes), oStar.succ));
124
+//     // forEach(processor => {
125
+//     //   if (processor !== oStar.processor) {
126
+//     //     return processorC[processor] += oStar.t;
127
+//     //   }
128
+//     // }, p);
129
+//
130
+//     let morePk = filter((jobTime: JobTimeWithZK) =>
131
+//       jobTime.processor === oStar.processor && (jobTime.k - jobTime.t) < kStar
132
+//     , Sk);
133
+//     morePk = updateZK(morePk, jobTimesWithZK);
134
+//
135
+//     Pk = concat(Pk, morePk);
136
+//     let PkIds = pluck('jobId', Pk);
137
+//     let rejectedFromSk = filter((jobTime: JobTimeWithZK) => contains(jobTime.jobId, PkIds), Sk);
138
+//     let rejectedSuccessors = flatten(
139
+//       map(jobTime => map(jobId => find(propEq('jobId', jobId), jobTimesWithZK), jobTime.succ), rejectedFromSk)
140
+//     );
141
+//     // rejectedSuccessors = updateZK(rejectedSuccessors, jobTimesWithZK);
142
+//
143
+//     // Sk = reject(jobTime => jobTime.jobId === oStar.jobId, Sk);
144
+//     Sk = reject((jobTime: JobTimeWithZK) => contains(jobTime.jobId, PkIds), Sk);
145
+//     Sk = concat(Sk, rejectedSuccessors);
146
+//
147
+//     Sk = sort((a, b) => a.jobId > b.jobId, Sk);
148
+//
149
+//     // if (k === 1) {
150
+//     //   console.log(Sk);
151
+//     // }
152
+//
153
+//     k++;
154
+//   }
155
+//
156
+//   // const jobTimesExtended = map((jobTime: JobTime) => {
157
+//   //   return ({
158
+//   //     ...jobTime,
159
+//   //
160
+//   //   })
161
+//   // }, jobTimes);
162
+// };
163
+//
164
+// export default (jobsOperations: JobOperations[], processorsCount: number) => {
165
+//   const schedule = createSchedule(jobsOperations, processorsCount);
166
+//
167
+//   return times(i =>
168
+//     map((jobTime: JobOperationsWithC) => ({
169
+//       processor: i + 1,
170
+//       startTime: jobTime.operations[i].c - jobTime.operations[i].t,
171
+//       endTime: jobTime.operations[i].c,
172
+//     }), schedule)
173
+//   , processorsCount);
174
+// };
0 175
\ No newline at end of file
1 176
new file mode 100644
... ...
@@ -0,0 +1,53 @@
0
+import { map, reduce, sort, range, omit, times } from 'rambda';
1
+import type { JobId } from '../../types';
2
+import { updateCTime } from '../johnson';
3
+import { min } from 'ramda';
4
+
5
+type JobOperations = {
6
+  jobId: JobId,
7
+  operations: Array<{ t: number }>
8
+};
9
+
10
+type JobOperationsWithC = {
11
+  jobId: JobId,
12
+  operations: Array<{ t: number, c: number }>
13
+};
14
+
15
+export const createSchedule = (jobsOperations: JobOperations[], processorsCount: number): JobOperationsWithC[] => {
16
+  const jobsOperationsWithKoefs = map((jobsOperation: JobOperations) => {
17
+    const ej = jobsOperation.operations[0].t < jobsOperation.operations[processorsCount - 1].t
18
+      ? 1 : -1;
19
+    const daco = reduce(
20
+      (acc, i) => min(jobsOperation.operations[i-1].t + jobsOperation.operations[i].t, acc),
21
+      Infinity,
22
+      range(1, processorsCount)
23
+    );
24
+
25
+    const koef = ej / daco;
26
+
27
+    return { ...jobsOperation, koef };
28
+  }, jobsOperations);
29
+
30
+  let sortedJobsOperations = sort(
31
+    (a: JobOperations, b: JobOperations) => {
32
+      return b.koef - a.koef;
33
+    },
34
+    jobsOperationsWithKoefs
35
+  );
36
+
37
+  sortedJobsOperations = map(omit('koef'), sortedJobsOperations);
38
+
39
+  return updateCTime(sortedJobsOperations, processorsCount);
40
+};
41
+
42
+export default (jobsOperations: JobOperations[], processorsCount: number) => {
43
+  const schedule = createSchedule(jobsOperations, processorsCount);
44
+
45
+  return times(i =>
46
+    map((jobTime: JobOperationsWithC) => ({
47
+      processor: i + 1,
48
+      startTime: jobTime.operations[i].c - jobTime.operations[i].t,
49
+      endTime: jobTime.operations[i].c,
50
+    }), schedule)
51
+  , processorsCount);
52
+};
0 53
\ No newline at end of file
1 54
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobsWithOperations = [
4
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
5
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
6
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
7
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
8
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
9
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
10
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
11
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
12
+  ];
13
+
14
+  const schedule = createSchedule(jobsWithOperations, 3);
15
+
16
+  expect(schedule.length).toBe(8);
17
+  expect(schedule[0]).toEqual({ jobId: 5, operations: [ { t: 4, c: 4 }, { t: 4, c: 8 }, { t: 20, c: 28 } ] });
18
+  expect(schedule[1]).toEqual({ jobId: 8, operations: [ { t: 10, c: 14 }, { t: 2, c: 16 }, { t: 25, c: 53 } ] });
19
+  expect(schedule[2]).toEqual({ jobId: 6, operations: [ { t: 3, c: 17 }, { t: 12, c: 29 }, { t: 13, c: 66 } ] });
20
+  expect(schedule[3]).toEqual({ jobId: 2, operations: [ { t: 6, c: 23 }, { t: 13, c: 42 }, { t: 19, c: 85 } ] });
21
+  expect(schedule[4]).toEqual({ jobId: 4, operations: [ { t: 16, c: 39 }, { t: 7, c: 49 }, { t: 21, c: 106 } ] });
22
+  expect(schedule[5]).toEqual({ jobId: 3, operations: [ { t: 15, c: 54 }, { t: 10, c: 64 }, { t: 18, c: 124 } ] });
23
+  expect(schedule[6]).toEqual({ jobId: 1, operations: [ { t: 12, c: 66 }, { t: 8, c: 74 }, { t: 11, c: 135 } ] });
24
+  expect(schedule[7]).toEqual({ jobId: 7, operations: [ { t: 17, c: 83 }, { t: 6, c: 89 }, { t: 8, c: 143 } ] });
25
+});
26
+
27
+test('create gantt', () => {
28
+  const jobsWithOperations = [
29
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
30
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
31
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
32
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
33
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
34
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
35
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
36
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
37
+  ];
38
+
39
+  const template = createGantt(jobsWithOperations, 3);
40
+
41
+  expect(template.length).toBe(3);
42
+  expect(template[0].length).toBe(8);
43
+  expect(template[1].length).toBe(8);
44
+  expect(template[2].length).toBe(8);
45
+
46
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 4 });
47
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 4, endTime: 14 });
48
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 14, endTime: 17 });
49
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 17, endTime: 23 });
50
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 23, endTime: 39 });
51
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 39, endTime: 54 });
52
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 54, endTime: 66 });
53
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 66, endTime: 83 });
54
+
55
+  expect(template[1][0]).toEqual({ processor: 2, startTime: 4, endTime: 8 });
56
+  expect(template[1][1]).toEqual({ processor: 2, startTime: 14, endTime: 16 });
57
+  expect(template[1][2]).toEqual({ processor: 2, startTime: 17, endTime: 29 });
58
+  expect(template[1][3]).toEqual({ processor: 2, startTime: 29, endTime: 42 });
59
+  expect(template[1][4]).toEqual({ processor: 2, startTime: 42, endTime: 49 });
60
+  expect(template[1][5]).toEqual({ processor: 2, startTime: 54, endTime: 64 });
61
+  expect(template[1][6]).toEqual({ processor: 2, startTime: 66, endTime: 74 });
62
+  expect(template[1][7]).toEqual({ processor: 2, startTime: 83, endTime: 89 });
63
+
64
+  expect(template[2][0]).toEqual({ processor: 3, startTime: 8, endTime: 28 });
65
+  expect(template[2][1]).toEqual({ processor: 3, startTime: 28, endTime: 53 });
66
+  expect(template[2][2]).toEqual({ processor: 3, startTime: 53, endTime: 66 });
67
+  expect(template[2][3]).toEqual({ processor: 3, startTime: 66, endTime: 85 });
68
+  expect(template[2][4]).toEqual({ processor: 3, startTime: 85, endTime: 106 });
69
+  expect(template[2][5]).toEqual({ processor: 3, startTime: 106, endTime: 124 });
70
+  expect(template[2][6]).toEqual({ processor: 3, startTime: 124, endTime: 135 });
71
+  expect(template[2][7]).toEqual({ processor: 3, startTime: 135, endTime: 143 });
72
+});
0 73
\ No newline at end of file
1 74
new file mode 100644
... ...
@@ -0,0 +1,104 @@
0
+import {
1
+  addIndex, findIndex, find, map, propEq, reduce, sort, range, concat,
2
+  filter, reverse, prop, flatten, uniq, reject, contains, omit, equals, update, times
3
+} from 'rambda';
4
+import type { JobId } from '../../types';
5
+import { max, min, remove, slice } from 'ramda';
6
+
7
+type JobOperations = {
8
+  jobId: JobId,
9
+  operations: Array<{ t: number }>
10
+};
11
+
12
+type JobOperationsWithC = {
13
+  jobId: JobId,
14
+  operations: Array<{ t: number, c: number }>
15
+};
16
+
17
+const findMinT = (operations) =>
18
+  reduce(
19
+    (t1, t2) => t1.t < t2.t ? t1 : t2,
20
+    { t: Infinity },
21
+    operations
22
+  );
23
+
24
+const findMinJob = (jobsOperations: JobOperations[]): JobOperations =>
25
+  reduce(
26
+    (minJob: JobOperations, jobOperations: JobOperations) => {
27
+      const minJobT = findMinT(minJob.operations);
28
+      const jobOperationsT = findMinT(jobOperations.operations);
29
+
30
+      return minJobT.t < jobOperationsT.t ? minJob : jobOperations;
31
+    },
32
+    { operations: [ { t: Infinity }, { t: Infinity } ] },
33
+    jobsOperations
34
+  );
35
+
36
+export const updateCTime = (jobsOperations: JobOperations[], processorCount: number): JobOperationsWithC[] => {
37
+  let prev = 0;
38
+  const cj = [];
39
+
40
+  cj[0] = map((jobTime: JobOperations) => {
41
+    prev += jobTime.operations[0].t;
42
+    const operationC = { ...jobTime.operations[0], c: prev };
43
+    const operations = update(0, operationC, jobTime.operations);
44
+
45
+    return { ...jobTime, operations };
46
+  }, jobsOperations);
47
+
48
+  if (processorCount > 1) {
49
+    times(i => {
50
+      const processorI = i + 1;
51
+      prev = cj[0][0].operations[0].c;
52
+
53
+      cj[processorI] = map((jobTime: JobOperations) => {
54
+        const conflicts = filter(({ c }) => prev < c, jobTime.operations);
55
+        if (conflicts.length) {
56
+          const maxConflict = sort((a, b) => b.c - a.c, conflicts)[0];
57
+          prev = maxConflict.c;
58
+        }
59
+
60
+        prev += jobTime.operations[processorI].t;
61
+
62
+        const operationC = { ...jobTime.operations[processorI], c: prev };
63
+        const operations = update(processorI, operationC, jobTime.operations);
64
+
65
+        return { ...jobTime, operations };
66
+      }, cj[i]);
67
+    }, processorCount - 1);
68
+  }
69
+
70
+  return cj[processorCount - 1];
71
+};
72
+
73
+export const createSchedule = (jobsOperations: JobOperations[]): JobOperationsWithC[] => {
74
+  let I = jobsOperations;
75
+  let L = [[], []];
76
+
77
+  while (I.length) {
78
+    const minTJob = findMinJob(I);
79
+
80
+    const { t: minT } = findMinT(minTJob.operations);
81
+    const operationIndex = findIndex(o => o.t === minT, minTJob.operations);
82
+    const minTJobIndex = findIndex(equals(minTJob), I);
83
+
84
+    L[operationIndex].push(minTJob);
85
+    I = remove(minTJobIndex, 1, I);
86
+  }
87
+
88
+  const LFinal = concat(L[0], reverse(L[1]));
89
+
90
+  return updateCTime(LFinal, 2);
91
+};
92
+
93
+export default (jobsOperations: JobOperations[]) => {
94
+  const schedule = createSchedule(jobsOperations);
95
+
96
+  return times(i =>
97
+    map((jobTime: JobOperationsWithC) => ({
98
+      processor: i + 1,
99
+      startTime: jobTime.operations[i].c - jobTime.operations[i].t,
100
+      endTime: jobTime.operations[i].c,
101
+    }), schedule)
102
+  , 2);
103
+};
0 104
\ No newline at end of file
1 105
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobsWithOperations = [
4
+    { jobId: 1, operations: [ { t: 15 }, { t: 11 } ] },
5
+    { jobId: 2, operations: [ { t: 20 }, { t: 15 } ] },
6
+    { jobId: 3, operations: [ { t: 35 }, { t: 5 } ] },
7
+    { jobId: 4, operations: [ { t: 10 }, { t: 31 } ] },
8
+    { jobId: 5, operations: [ { t: 18 }, { t: 16 } ] },
9
+    { jobId: 6, operations: [ { t: 17 }, { t: 26 } ] },
10
+    { jobId: 7, operations: [ { t: 9 }, { t: 32 } ] },
11
+    { jobId: 8, operations: [ { t: 44 }, { t: 6 } ] },
12
+    { jobId: 9, operations: [ { t: 29 }, { t: 18 } ] },
13
+    { jobId: 10, operations: [ { t: 21 }, { t: 22 } ] },
14
+  ];
15
+
16
+  const schedule = createSchedule(jobsWithOperations);
17
+
18
+  expect(schedule.length).toBe(10);
19
+  expect(schedule[0]).toEqual({ jobId: 7, operations: [ { t: 9, c: 9 }, { t: 32, c: 41 } ] });
20
+  expect(schedule[1]).toEqual({ jobId: 4, operations: [ { t: 10, c: 19 }, { t: 31, c: 72 } ] });
21
+  expect(schedule[2]).toEqual({ jobId: 6, operations: [ { t: 17, c: 36 }, { t: 26, c: 98 } ] });
22
+  expect(schedule[3]).toEqual({ jobId: 10, operations: [ { t: 21, c: 57 }, { t: 22, c: 120 } ] });
23
+  expect(schedule[4]).toEqual({ jobId: 9, operations: [ { t: 29, c: 86 }, { t: 18, c: 138 } ] });
24
+  expect(schedule[5]).toEqual({ jobId: 5, operations: [ { t: 18, c: 104 }, { t: 16, c: 154 } ] });
25
+  expect(schedule[6]).toEqual({ jobId: 2, operations: [ { t: 20, c: 124 }, { t: 15, c: 169 } ] });
26
+  expect(schedule[7]).toEqual({ jobId: 1, operations: [ { t: 15, c: 139 }, { t: 11, c: 180 } ] });
27
+  expect(schedule[8]).toEqual({ jobId: 8, operations: [ { t: 44, c: 183 }, { t: 6, c: 189 } ] });
28
+  expect(schedule[9]).toEqual({ jobId: 3, operations: [ { t: 35, c: 218 }, { t: 5, c: 223 } ] });
29
+});
30
+
31
+test('create gantt', () => {
32
+  const jobsWithOperations = [
33
+    { jobId: 1, operations: [ { t: 15 }, { t: 11 } ] },
34
+    { jobId: 2, operations: [ { t: 20 }, { t: 15 } ] },
35
+    { jobId: 3, operations: [ { t: 35 }, { t: 5 } ] },
36
+    { jobId: 4, operations: [ { t: 10 }, { t: 31 } ] },
37
+    { jobId: 5, operations: [ { t: 18 }, { t: 16 } ] },
38
+    { jobId: 6, operations: [ { t: 17 }, { t: 26 } ] },
39
+    { jobId: 7, operations: [ { t: 9 }, { t: 32 } ] },
40
+    { jobId: 8, operations: [ { t: 44 }, { t: 6 } ] },
41
+    { jobId: 9, operations: [ { t: 29 }, { t: 18 } ] },
42
+    { jobId: 10, operations: [ { t: 21 }, { t: 22 } ] },
43
+  ];
44
+
45
+  const template = createGantt(jobsWithOperations);
46
+
47
+  expect(template.length).toBe(2);
48
+  expect(template[0].length).toBe(10);
49
+  expect(template[1].length).toBe(10);
50
+
51
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 9 });
52
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 9, endTime: 19 });
53
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 19, endTime: 36 });
54
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 36, endTime: 57 });
55
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 57, endTime: 86 });
56
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 86, endTime: 104 });
57
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 104, endTime: 124 });
58
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 124, endTime: 139 });
59
+  expect(template[0][8]).toEqual({ processor: 1, startTime: 139, endTime: 183 });
60
+  expect(template[0][9]).toEqual({ processor: 1, startTime: 183, endTime: 218 });
61
+
62
+  expect(template[1][0]).toEqual({ processor: 2, startTime: 9, endTime: 41 });
63
+  expect(template[1][1]).toEqual({ processor: 2, startTime: 41, endTime: 72 });
64
+  expect(template[1][2]).toEqual({ processor: 2, startTime: 72, endTime: 98 });
65
+  expect(template[1][3]).toEqual({ processor: 2, startTime: 98, endTime: 120 });
66
+  expect(template[1][4]).toEqual({ processor: 2, startTime: 120, endTime: 138 });
67
+  expect(template[1][5]).toEqual({ processor: 2, startTime: 138, endTime: 154 });
68
+  expect(template[1][6]).toEqual({ processor: 2, startTime: 154, endTime: 169 });
69
+  expect(template[1][7]).toEqual({ processor: 2, startTime: 169, endTime: 180 });
70
+  expect(template[1][8]).toEqual({ processor: 2, startTime: 183, endTime: 189 });
71
+  expect(template[1][9]).toEqual({ processor: 2, startTime: 218, endTime: 223 });
72
+});
0 73
\ No newline at end of file
1 74
new file mode 100644
... ...
@@ -0,0 +1,86 @@
0
+import {
1
+  addIndex, findIndex, find, map, propEq, reduce, sort, range, concat,
2
+  filter, reverse, prop, flatten, uniq, reject, contains, omit
3
+} from 'rambda';
4
+import type { JobId } from '../../types';
5
+import { max, remove, slice } from 'ramda';
6
+
7
+type JobTime = {
8
+  jobId: JobId,
9
+  t: number,
10
+  d: number,
11
+  c: number,
12
+  w: number,
13
+  anc: JobId[],
14
+};
15
+
16
+const findMaxTJob = (jobTimes: JobTime[]) =>
17
+  reduce(
18
+    (maxTJob: JobTime, jobTime: JobTime) => maxTJob.t >= jobTime.t ? maxTJob : jobTime,
19
+    { t: -Infinity },
20
+    jobTimes
21
+  );
22
+
23
+const findMinJob = (fi: number, jobTimes: JobTime[]) =>
24
+  reduce(
25
+    (minJob: JobTime, jobTime: JobTime) => {
26
+      const minJobU = minJob.w * max(fi - minJob.d, 0);
27
+      const jobTimeU = jobTime.w * max(fi - jobTime.d, 0);
28
+
29
+      return minJobU < jobTimeU ? minJob : jobTime;
30
+    },
31
+    { w: Infinity },
32
+    jobTimes
33
+  );
34
+
35
+const updateCTime = (jobTimes: JobTime[]) => {
36
+  let prev = 0;
37
+
38
+  const cj = map((jobTime: JobTime) => {
39
+    prev += jobTime.t;
40
+
41
+    return { ...jobTime, c: prev };
42
+  }, jobTimes);
43
+
44
+  return cj;
45
+};
46
+
47
+export const createSchedule = (jobs: JobTime[]) => {
48
+  let fi = reduce((sum, job: JobTime) => sum + job.t, 0, jobs);
49
+  let jobsD = jobs;
50
+  let R = [];
51
+
52
+  while (fi > 0) {
53
+    const allAcc = uniq(flatten(
54
+      map(prop('anc'), jobsD)
55
+    ));
56
+
57
+    const G = reject((jobTime: JobTime) => contains(jobTime.jobId, allAcc), jobsD);
58
+
59
+    if (!G.length) return null;
60
+
61
+    const minJob = findMinJob(fi, G);
62
+    const minJobIndex = findIndex(propEq('jobId', minJob.jobId), jobsD);
63
+
64
+    jobsD = remove(minJobIndex, 1, jobsD);
65
+    fi -= minJob.t;
66
+
67
+    R.push(minJob);
68
+  }
69
+
70
+  const withC = updateCTime(reverse(R));
71
+
72
+  return map(omit(['w', 'anc']), withC);
73
+};
74
+
75
+export default (jobs: JobTime[]) => {
76
+  const schedule = createSchedule(jobs);
77
+
78
+  const normalizedSchedule = map((jobTime: JobTime) => ({
79
+    processor: 1,
80
+    startTime: jobTime.c - jobTime.t,
81
+    endTime: jobTime.c,
82
+  }), schedule);
83
+
84
+  return [normalizedSchedule];
85
+};
0 86
\ No newline at end of file
1 87
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobs = [
4
+    { jobId: 1, t: 8, d: 11, anc: [], w: 1 },
5
+    { jobId: 2, t: 5, d: 9, anc: [], w: 1 },
6
+    { jobId: 3, t: 6, d: 10, anc: [], w: 3 },
7
+    { jobId: 4, t: 5, d: 14, anc: [1], w: 2 },
8
+    { jobId: 5, t: 9, d: 19, anc: [1], w: 1 },
9
+    { jobId: 6, t: 3, d: 14, anc: [2, 3, 4], w: 1 },
10
+    { jobId: 7, t: 9, d: 36, anc: [2, 3, 4], w: 2 },
11
+    { jobId: 8, t: 5, d: 39, anc: [2, 3, 4], w: 2 },
12
+    { jobId: 9, t: 8, d: 31, anc: [5, 6], w: 1 },
13
+    { jobId: 10, t: 5, d: 59, anc: [7], w: 2 },
14
+    { jobId: 11, t: 5, d: 61, anc: [8], w: 3 },
15
+  ];
16
+
17
+  const schedule = createSchedule(jobs);
18
+
19
+  expect(schedule.length).toBe(11);
20
+  expect(schedule[0]).toEqual({ jobId: 3, t: 6, d: 10, c: 6 });
21
+  expect(schedule[1]).toEqual({ jobId: 1, t: 8, d: 11, c: 14 });
22
+  expect(schedule[2]).toEqual({ jobId: 4, t: 5, d: 14, c: 19 });
23
+  expect(schedule[3]).toEqual({ jobId: 2, t: 5, d: 9, c: 24 });
24
+  expect(schedule[4]).toEqual({ jobId: 6, t: 3, d: 14, c: 27 });
25
+  expect(schedule[5]).toEqual({ jobId: 5, t: 9, d: 19, c: 36 });
26
+  expect(schedule[6]).toEqual({ jobId: 7, t: 9, d: 36, c: 45 });
27
+  expect(schedule[7]).toEqual({ jobId: 8, t: 5, d: 39, c: 50 });
28
+  expect(schedule[8]).toEqual({ jobId: 9, t: 8, d: 31, c: 58 });
29
+  expect(schedule[9]).toEqual({ jobId: 11, t: 5, d: 61, c: 63 });
30
+  expect(schedule[10]).toEqual({ jobId: 10, t: 5, d: 59, c: 68 });
31
+});
32
+
33
+test('create gantt', () => {
34
+  const jobs = [
35
+    { jobId: 1, t: 8, d: 11, anc: [], w: 1 },
36
+    { jobId: 2, t: 5, d: 9, anc: [], w: 1 },
37
+    { jobId: 3, t: 6, d: 10, anc: [], w: 3 },
38
+    { jobId: 4, t: 5, d: 14, anc: [1], w: 2 },
39
+    { jobId: 5, t: 9, d: 19, anc: [1], w: 1 },
40
+    { jobId: 6, t: 3, d: 14, anc: [2, 3, 4], w: 1 },
41
+    { jobId: 7, t: 9, d: 36, anc: [2, 3, 4], w: 2 },
42
+    { jobId: 8, t: 5, d: 39, anc: [2, 3, 4], w: 2 },
43
+    { jobId: 9, t: 8, d: 31, anc: [5, 6], w: 1 },
44
+    { jobId: 10, t: 5, d: 59, anc: [7], w: 2 },
45
+    { jobId: 11, t: 5, d: 61, anc: [8], w: 3 },
46
+  ];
47
+
48
+  const template = createGantt(jobs);
49
+
50
+  expect(template.length).toBe(1);
51
+  expect(template[0].length).toBe(11);
52
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 6 });
53
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 6, endTime: 14 });
54
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 14, endTime: 19 });
55
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 19, endTime: 24 });
56
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 24, endTime: 27 });
57
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 27, endTime: 36 });
58
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 36, endTime: 45 });
59
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 45, endTime: 50 });
60
+  expect(template[0][8]).toEqual({ processor: 1, startTime: 50, endTime: 58 });
61
+  expect(template[0][9]).toEqual({ processor: 1, startTime: 58, endTime: 63 });
62
+  expect(template[0][10]).toEqual({ processor: 1, startTime: 63, endTime: 68 });
63
+});
0 64
\ No newline at end of file
1 65
new file mode 100644
... ...
@@ -0,0 +1,86 @@
0
+import {
1
+  addIndex, findIndex, find, map, propEq, reduce, sort, range, concat,
2
+  filter, reverse, prop, flatten, uniq, reject, contains, omit, times
3
+} from 'rambda';
4
+import type { JobId } from '../../types';
5
+import { groupBy, max, remove, slice } from 'ramda';
6
+
7
+type JobTime = {
8
+  jobId: JobId,
9
+  t: number
10
+};
11
+
12
+type JobTimeAssigned = JobTime | {
13
+  processor: number,
14
+};
15
+
16
+type JobTimeAssignedWithC = JobTimeAssigned | {
17
+  c: number,
18
+};
19
+
20
+export const updateCTime = (jobTimes: JobTimeAssigned[]) => {
21
+  let prev = 0;
22
+  let prevProcessor = 0;
23
+
24
+  const cj = map((jobTime: JobTimeAssigned) => {
25
+    if (jobTime.processor !== prevProcessor) {
26
+      prev = 0;
27
+    }
28
+
29
+    prev += jobTime.t;
30
+    prevProcessor = jobTime.processor;
31
+
32
+    return { ...jobTime, c: prev };
33
+  }, jobTimes);
34
+
35
+  return cj;
36
+};
37
+
38
+export const createSchedule = (jobs: JobTime[], processorCount: number): JobTimeAssignedWithC[] => {
39
+  let G = jobs;
40
+  const sumT = reduce((acc, job) => acc + job.t, 0, G);
41
+  const maxT = reduce((acc, job) => max(acc, job.t), -Infinity, G);
42
+  const K = max(Math.ceil(sumT / processorCount), maxT);
43
+  const R = [];
44
+
45
+  let processorC = times(() => 0, processorCount + 1);
46
+  let activeProcessor = 1;
47
+
48
+  let i = 0;
49
+
50
+  while (G.length) {
51
+    if (processorC[activeProcessor] + G[0].t <= K) {
52
+      processorC[activeProcessor] += G[0].t;
53
+      R.push({ ...G[0], processor: activeProcessor });
54
+      [, ...G] = G;
55
+
56
+      if (processorC[activeProcessor] === K) {
57
+        activeProcessor++;
58
+      }
59
+    } else {
60
+      const tDiff = processorC[activeProcessor] + G[0].t - K;
61
+
62
+      R.push({ ...G[0], t: G[0].t - tDiff, processor: activeProcessor });
63
+      G[0].t = tDiff;
64
+
65
+      activeProcessor++;
66
+    }
67
+
68
+    i++;
69
+  }
70
+
71
+  const withC = updateCTime(R);
72
+  return withC;
73
+};
74
+
75
+export default (jobs: JobTime[], processorCount: number) => {
76
+  const schedule = createSchedule(jobs, processorCount);
77
+
78
+  const grouped = Object.values(groupBy(jobTime => jobTime.processor, schedule));
79
+
80
+  return map(map((job: JobTimeAssignedWithC) => ({
81
+    processor: job.processor,
82
+    startTime: job.c - job.t,
83
+    endTime: job.c
84
+  })), grouped);
85
+};
0 86
\ No newline at end of file
1 87
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobs = [
4
+    { jobId: 1, t: 3 },
5
+    { jobId: 2, t: 9 },
6
+    { jobId: 3, t: 5 },
7
+    { jobId: 4, t: 7 },
8
+    { jobId: 5, t: 6 },
9
+  ];
10
+
11
+  const schedule = createSchedule(jobs, 3);
12
+
13
+  expect(schedule.length).toBe(7);
14
+  expect(schedule[0]).toEqual({ jobId: 1, t: 3, c: 3, processor: 1 });
15
+  expect(schedule[1]).toEqual({ jobId: 2, t: 7, c: 10, processor: 1 });
16
+  expect(schedule[2]).toEqual({ jobId: 2, t: 2, c: 2, processor: 2 });
17
+  expect(schedule[3]).toEqual({ jobId: 3, t: 5, c: 7, processor: 2 });
18
+  expect(schedule[4]).toEqual({ jobId: 4, t: 3, c: 10, processor: 2 });
19
+  expect(schedule[5]).toEqual({ jobId: 4, t: 4, c: 4, processor: 3 });
20
+  expect(schedule[6]).toEqual({ jobId: 5, t: 6, c: 10, processor: 3 });
21
+});
22
+
23
+test('create gantt', () => {
24
+  const jobs = [
25
+    { jobId: 1, t: 3 },
26
+    { jobId: 2, t: 9 },
27
+    { jobId: 3, t: 5 },
28
+    { jobId: 4, t: 7 },
29
+    { jobId: 5, t: 6 },
30
+  ];
31
+
32
+  const template = createGantt(jobs, 3);
33
+
34
+  expect(template.length).toBe(3);
35
+  expect(template[0].length).toBe(2);
36
+  expect(template[1].length).toBe(3);
37
+  expect(template[2].length).toBe(2);
38
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 3 });
39
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 3, endTime: 10 });
40
+  expect(template[1][0]).toEqual({ processor: 2, startTime: 0, endTime: 2 });
41
+  expect(template[1][1]).toEqual({ processor: 2, startTime: 2, endTime: 7 });
42
+  expect(template[1][2]).toEqual({ processor: 2, startTime: 7, endTime: 10 });
43
+  expect(template[2][0]).toEqual({ processor: 3, startTime: 0, endTime: 4 });
44
+  expect(template[2][1]).toEqual({ processor: 3, startTime: 4, endTime: 10 });
45
+});
0 46
\ No newline at end of file
1 47
new file mode 100644
... ...
@@ -0,0 +1,76 @@
0
+import { addIndex, findIndex, find, map, propEq, reduce, sort, range, concat } from 'rambda';
1
+import type { JobId } from '../../types';
2
+import { remove, slice } from 'ramda';
3
+
4
+type JobTime = {
5
+  jobId: JobId,
6
+  t: number,
7
+  d: number,
8
+  c: number
9
+};
10
+
11
+const mapWithIndex = addIndex(map);
12
+
13
+// const byAsc = (a: JobTime, b: JobTime) => a.time - b.time;
14
+
15
+const findJobById = (jobId: JobId, jobTimes: JobTime[]): JobTime =>
16
+  find(propEq('jobId', jobId), jobTimes);
17
+
18
+const findLateJob = (jobTimes: JobTime[]) =>
19
+  find(({ c, d }: JobTime) => c > d, jobTimes);
20
+
21
+const findMaxTJob = (jobTimes: JobTime[]) =>
22
+  reduce(
23
+    (maxTJob: JobTime, jobTime: JobTime) => maxTJob.t > jobTime.t ? maxTJob : jobTime,
24
+    { t: -Infinity },
25
+    jobTimes
26
+  );
27
+
28
+const updateCTime = (jobTimes: JobTime[]) => {
29
+  let prev = 0;
30
+
31
+  const cj = map((jobTime: JobTime) => {
32
+    prev += jobTime.t;
33
+
34
+    return { ...jobTime, c: prev };
35
+  }, jobTimes);
36
+
37
+  return cj;
38
+};
39
+
40
+export const createSchedule = (jobs: JobTime[]) => {
41
+  const F = sort((a: JobTime, b: JobTime) => a.d - b.d, jobs);
42
+  const L = [];
43
+
44
+  let cj = updateCTime(F);
45
+  let lateJob;
46
+
47
+  while (lateJob = findLateJob(cj)) {
48
+    const lateJobIndex = findIndex(propEq('jobId', lateJob.jobId), cj);
49
+    const jobsBeforeLateJob = slice(0, lateJobIndex + 1, cj);
50
+
51
+    const maxTJob = findMaxTJob(jobsBeforeLateJob);
52
+    const maxTJobIndex = findIndex(propEq('jobId', maxTJob.jobId), cj);
53
+
54
+    cj = remove(maxTJobIndex, 1, cj);
55
+    cj = updateCTime(cj);
56
+
57
+    L.push(maxTJob);
58
+  }
59
+
60
+  const schedule = concat(cj, L);
61
+
62
+  return updateCTime(schedule);
63
+};
64
+
65
+export default (jobs: JobTime[]) => {
66
+  const schedule = createSchedule(jobs);
67
+
68
+  const normalizedSchedule = map((jobTime: JobTime) => ({
69
+    processor: 1,
70
+    startTime: jobTime.c - jobTime.t,
71
+    endTime: jobTime.c,
72
+  }), schedule);
73
+
74
+  return [normalizedSchedule];
75
+};
0 76
\ No newline at end of file
1 77
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobs = [
4
+    { jobId: 1, t: 6, d: 10 },
5
+    { jobId: 2, t: 8, d: 25 },
6
+    { jobId: 3, t: 4, d: 20 },
7
+    { jobId: 4, t: 6, d: 18 },
8
+    { jobId: 5, t: 7, d: 20 },
9
+    { jobId: 6, t: 4, d: 40 },
10
+    { jobId: 7, t: 3, d: 35 },
11
+    { jobId: 8, t: 6, d: 42 },
12
+    { jobId: 9, t: 5, d: 25 },
13
+  ];
14
+
15
+  const schedule = createSchedule(jobs);
16
+
17
+  expect(schedule.length).toBe(9);
18
+  expect(schedule[0]).toEqual({ t: 6, d: 10, c: 6, jobId: 1 });
19
+  expect(schedule[1]).toEqual({ t: 6, d: 18, c: 12, jobId: 4 });
20
+  expect(schedule[2]).toEqual({ t: 4, d: 20, c: 16, jobId: 3 });
21
+  expect(schedule[3]).toEqual({ t: 5, d: 25, c: 21, jobId: 9 });
22
+  expect(schedule[4]).toEqual({ t: 3, d: 35, c: 24, jobId: 7 });
23
+  expect(schedule[5]).toEqual({ t: 4, d: 40, c: 28, jobId: 6 });
24
+  expect(schedule[6]).toEqual({ t: 6, d: 42, c: 34, jobId: 8 });
25
+  expect(schedule[7]).toEqual({ t: 7, d: 20, c: 41, jobId: 5 });
26
+  expect(schedule[8]).toEqual({ t: 8, d: 25, c: 49, jobId: 2 });
27
+});
28
+
29
+test('create gantt', () => {
30
+  const jobs = [
31
+    { jobId: 1, t: 6, d: 10 },
32
+    { jobId: 2, t: 8, d: 25 },
33
+    { jobId: 3, t: 4, d: 20 },
34
+    { jobId: 4, t: 6, d: 18 },
35
+    { jobId: 5, t: 7, d: 20 },
36
+    { jobId: 6, t: 4, d: 40 },
37
+    { jobId: 7, t: 3, d: 35 },
38
+    { jobId: 8, t: 6, d: 42 },
39
+    { jobId: 9, t: 5, d: 25 },
40
+  ];
41
+
42
+  const template = createGantt(jobs);
43
+
44
+  expect(template.length).toBe(1);
45
+  expect(template[0].length).toBe(9);
46
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 6 });
47
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 6, endTime: 12 });
48
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 12, endTime: 16 });
49
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 16, endTime: 21 });
50
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 21, endTime: 24 });
51
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 24, endTime: 28 });
52
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 28, endTime: 34 });
53
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 34, endTime: 41 });
54
+  expect(template[0][8]).toEqual({ processor: 1, startTime: 41, endTime: 49 });
55
+});
0 56
\ No newline at end of file
1 57
new file mode 100644
... ...
@@ -0,0 +1,51 @@
0
+import {
1
+  addIndex, findIndex, find, map, propEq, reduce, sort, range, concat,
2
+  filter, reverse, prop, flatten, uniq, reject, contains, omit, equals, update, times
3
+} from 'rambda';
4
+import type { JobId } from '../../types';
5
+import { updateCTime } from '../johnson';
6
+
7
+type JobOperations = {
8
+  jobId: JobId,
9
+  operations: Array<{ t: number }>
10
+};
11
+
12
+type JobOperationsWithC = {
13
+  jobId: JobId,
14
+  operations: Array<{ t: number, c: number }>
15
+};
16
+
17
+export const createSchedule = (jobsOperations: JobOperations[], processorsCount: number): JobOperationsWithC[] => {
18
+  const jobsOperationsWithKoefs = map(jobsOperation => {
19
+    const koef = reduce(
20
+      (acc, i) => acc + Math.abs(processorsCount - 2 * i + 1) * jobsOperation.operations[i-1].t,
21
+      0,
22
+      range(1, processorsCount + 1)
23
+    );
24
+
25
+    return { ...jobsOperation, koef };
26
+  }, jobsOperations);
27
+
28
+  let sortedJobsOperations = sort(
29
+    (a: JobOperations, b: JobOperations) => {
30
+      return b.koef - a.koef;
31
+    },
32
+    jobsOperationsWithKoefs
33
+  );
34
+
35
+  sortedJobsOperations = map(omit('koef'), sortedJobsOperations);
36
+
37
+  return updateCTime(sortedJobsOperations, processorsCount);
38
+};
39
+
40
+export default (jobsOperations: JobOperations[], processorsCount: number) => {
41
+  const schedule = createSchedule(jobsOperations, processorsCount);
42
+
43
+  return times(i =>
44
+    map((jobTime: JobOperationsWithC) => ({
45
+      processor: i + 1,
46
+      startTime: jobTime.operations[i].c - jobTime.operations[i].t,
47
+      endTime: jobTime.operations[i].c,
48
+    }), schedule)
49
+  , processorsCount);
50
+};
0 51
\ No newline at end of file
1 52
new file mode 100644
... ...
@@ -0,0 +1,73 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobsWithOperations = [
4
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
5
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
6
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
7
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
8
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
9
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
10
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
11
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
12
+  ];
13
+
14
+  const schedule = createSchedule(jobsWithOperations, 3);
15
+
16
+  expect(schedule.length).toBe(8);
17
+  expect(schedule[0]).toEqual({ jobId: 4, operations: [ { t: 16, c: 16 }, { t: 7, c: 23 }, { t: 21, c: 44 } ] });
18
+  expect(schedule[1]).toEqual({ jobId: 8, operations: [ { t: 10, c: 26 }, { t: 2, c: 28 }, { t: 25, c: 69 } ] });
19
+  expect(schedule[2]).toEqual({ jobId: 3, operations: [ { t: 15, c: 41 }, { t: 10, c: 51 }, { t: 18, c: 87 } ] });
20
+  expect(schedule[3]).toEqual({ jobId: 2, operations: [ { t: 6, c: 47 }, { t: 13, c: 64 }, { t: 19, c: 106 } ] });
21
+  expect(schedule[4]).toEqual({ jobId: 7, operations: [ { t: 17, c: 64 }, { t: 6, c: 70 }, { t: 8, c: 114 } ] });
22
+  expect(schedule[5]).toEqual({ jobId: 5, operations: [ { t: 4, c: 68 }, { t: 4, c: 74 }, { t: 20, c: 134 } ] });
23
+  expect(schedule[6]).toEqual({ jobId: 1, operations: [ { t: 12, c: 80 }, { t: 8, c: 88 }, { t: 11, c: 145 } ] });
24
+  expect(schedule[7]).toEqual({ jobId: 6, operations: [ { t: 3, c: 83 }, { t: 12, c: 100 }, { t: 13, c: 158 } ] });
25
+});
26
+
27
+test('create gantt', () => {
28
+  const jobsWithOperations = [
29
+    { jobId: 1, operations: [ { t: 12 }, { t: 8 }, { t: 11 } ] },
30
+    { jobId: 2, operations: [ { t: 6 }, { t: 13 }, { t: 19 } ] },
31
+    { jobId: 3, operations: [ { t: 15 }, { t: 10 }, { t: 18 } ] },
32
+    { jobId: 4, operations: [ { t: 16 }, { t: 7 }, { t: 21 } ] },
33
+    { jobId: 5, operations: [ { t: 4 }, { t: 4 }, { t: 20 } ] },
34
+    { jobId: 6, operations: [ { t: 3 }, { t: 12 }, { t: 13 } ] },
35
+    { jobId: 7, operations: [ { t: 17 }, { t: 6 }, { t: 8 } ] },
36
+    { jobId: 8, operations: [ { t: 10 }, { t: 2 }, { t: 25 } ] },
37
+  ];
38
+
39
+  const template = createGantt(jobsWithOperations, 3);
40
+
41
+  expect(template.length).toBe(3);
42
+  expect(template[0].length).toBe(8);
43
+  expect(template[1].length).toBe(8);
44
+  expect(template[2].length).toBe(8);
45
+
46
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 16 });
47
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 16, endTime: 26 });
48
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 26, endTime: 41 });
49
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 41, endTime: 47 });
50
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 47, endTime: 64 });
51
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 64, endTime: 68 });
52
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 68, endTime: 80 });
53
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 80, endTime: 83 });
54
+
55
+  expect(template[1][0]).toEqual({ processor: 2, startTime: 16, endTime: 23 });
56
+  expect(template[1][1]).toEqual({ processor: 2, startTime: 26, endTime: 28 });
57
+  expect(template[1][2]).toEqual({ processor: 2, startTime: 41, endTime: 51 });
58
+  expect(template[1][3]).toEqual({ processor: 2, startTime: 51, endTime: 64 });
59
+  expect(template[1][4]).toEqual({ processor: 2, startTime: 64, endTime: 70 });
60
+  expect(template[1][5]).toEqual({ processor: 2, startTime: 70, endTime: 74 });
61
+  expect(template[1][6]).toEqual({ processor: 2, startTime: 80, endTime: 88 });
62
+  expect(template[1][7]).toEqual({ processor: 2, startTime: 88, endTime: 100 });
63
+
64
+  expect(template[2][0]).toEqual({ processor: 3, startTime: 23, endTime: 44 });
65
+  expect(template[2][1]).toEqual({ processor: 3, startTime: 44, endTime: 69 });
66
+  expect(template[2][2]).toEqual({ processor: 3, startTime: 69, endTime: 87 });
67
+  expect(template[2][3]).toEqual({ processor: 3, startTime: 87, endTime: 106 });
68
+  expect(template[2][4]).toEqual({ processor: 3, startTime: 106, endTime: 114 });
69
+  expect(template[2][5]).toEqual({ processor: 3, startTime: 114, endTime: 134 });
70
+  expect(template[2][6]).toEqual({ processor: 3, startTime: 134, endTime: 145 });
71
+  expect(template[2][7]).toEqual({ processor: 3, startTime: 145, endTime: 158 });
72
+});
0 73
\ No newline at end of file
1 74
new file mode 100644
... ...
@@ -0,0 +1,68 @@
0
+import {
1
+  addIndex, findIndex, find, map, propEq, reduce, sort, range, concat,
2
+  filter, reverse
3
+} from 'rambda';
4
+import type { JobId } from '../../types';
5
+import { remove, slice } from 'ramda';
6
+
7
+type JobTime = {
8
+  jobId: JobId,
9
+  t: number,
10
+  d: number,
11
+  c: number
12
+};
13
+
14
+const findMaxTJob = (jobTimes: JobTime[]) =>
15
+  reduce(
16
+    (maxTJob: JobTime, jobTime: JobTime) => maxTJob.t >= jobTime.t ? maxTJob : jobTime,
17
+    { t: -Infinity },
18
+    jobTimes
19
+  );
20
+
21
+const updateCTime = (jobTimes: JobTime[]) => {
22
+  let prev = 0;
23
+
24
+  const cj = map((jobTime: JobTime) => {
25
+    prev += jobTime.t;
26
+
27
+    return { ...jobTime, c: prev };
28
+  }, jobTimes);
29
+
30
+  return cj;
31
+};
32
+
33
+export const createSchedule = (jobs: JobTime[]) => {
34
+  let fi = reduce((sum, job: JobTime) => sum + job.t, 0, jobs);
35
+  let jobsD = jobs;
36
+  let R = [];
37
+
38
+  while (fi > 0) {
39
+    const G = filter((jobTime: JobTime) => jobTime.d >= fi, jobsD);
40
+
41
+    if (!G.length) return null;
42
+
43
+    const maxTJob = findMaxTJob(G);
44
+    const maxTJobIndex = findIndex(propEq('jobId', maxTJob.jobId), jobsD);
45
+
46
+    jobsD = remove(maxTJobIndex, 1, jobsD);
47
+    fi -= maxTJob.t;
48
+
49
+    R.push(maxTJob);
50
+  }
51
+
52
+  const withC = updateCTime(reverse(R));
53
+
54
+  return withC;
55
+};
56
+
57
+export default (jobs: JobTime[]) => {
58
+  const schedule = createSchedule(jobs);
59
+
60
+  const normalizedSchedule = map((jobTime: JobTime) => ({
61
+    processor: 1,
62
+    startTime: jobTime.c - jobTime.t,
63
+    endTime: jobTime.c,
64
+  }), schedule);
65
+
66
+  return [normalizedSchedule];
67
+};
0 68
\ No newline at end of file
1 69
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+import createGantt, { createSchedule } from './index';
1
+
2
+test('create schedule', () => {
3
+  const jobs = [
4
+    { jobId: 1, t: 4, d: 10 },
5
+    { jobId: 2, t: 6, d: 25 },
6
+    { jobId: 3, t: 4, d: 20 },
7
+    { jobId: 4, t: 6, d: 18 },
8
+    { jobId: 5, t: 7, d: 40 },
9
+    { jobId: 6, t: 4, d: 50 },
10
+    { jobId: 7, t: 3, d: 35 },
11
+    { jobId: 8, t: 2, d: 52 },
12
+    { jobId: 9, t: 6, d: 46 },
13
+    { jobId: 10, t: 7, d: 28 },
14
+    { jobId: 11, t: 1, d: 50 },
15
+  ];
16
+
17
+  const schedule = createSchedule(jobs);
18
+
19
+  expect(schedule.length).toBe(11);
20
+  expect(schedule[0]).toEqual({ jobId: 11, t: 1, d: 50, c: 1 });
21
+  expect(schedule[1]).toEqual({ jobId: 3, t: 4, d: 20, c: 5 });
22
+  expect(schedule[2]).toEqual({ jobId: 1, t: 4, d: 10, c: 9 });
23
+  expect(schedule[3]).toEqual({ jobId: 4, t: 6, d: 18, c: 15 });
24
+  expect(schedule[4]).toEqual({ jobId: 2, t: 6, d: 25, c: 21 });
25
+  expect(schedule[5]).toEqual({ jobId: 10, t: 7, d: 28, c: 28 });
26
+  expect(schedule[6]).toEqual({ jobId: 8, t: 2, d: 52, c: 30 });
27
+  expect(schedule[7]).toEqual({ jobId: 7, t: 3, d: 35, c: 33 });
28
+  expect(schedule[8]).toEqual({ jobId: 5, t: 7, d: 40, c: 40 });
29
+  expect(schedule[9]).toEqual({ jobId: 9, t: 6, d: 46, c: 46 });
30
+  expect(schedule[10]).toEqual({ jobId: 6, t: 4, d: 50, c: 50 });
31
+});
32
+
33
+test('create gantt', () => {
34
+  const jobs = [
35
+    { jobId: 1, t: 4, d: 10 },
36
+    { jobId: 2, t: 6, d: 25 },
37
+    { jobId: 3, t: 4, d: 20 },
38
+    { jobId: 4, t: 6, d: 18 },
39
+    { jobId: 5, t: 7, d: 40 },
40
+    { jobId: 6, t: 4, d: 50 },
41
+    { jobId: 7, t: 3, d: 35 },
42
+    { jobId: 8, t: 2, d: 52 },
43
+    { jobId: 9, t: 6, d: 46 },
44
+    { jobId: 10, t: 7, d: 28 },
45
+    { jobId: 11, t: 1, d: 50 },
46
+  ];
47
+
48
+  const template = createGantt(jobs);
49
+
50
+  expect(template.length).toBe(1);
51
+  expect(template[0].length).toBe(11);
52
+  expect(template[0][0]).toEqual({ processor: 1, startTime: 0, endTime: 1 });
53
+  expect(template[0][1]).toEqual({ processor: 1, startTime: 1, endTime: 5 });
54
+  expect(template[0][2]).toEqual({ processor: 1, startTime: 5, endTime: 9 });
55
+  expect(template[0][3]).toEqual({ processor: 1, startTime: 9, endTime: 15 });
56
+  expect(template[0][4]).toEqual({ processor: 1, startTime: 15, endTime: 21 });
57
+  expect(template[0][5]).toEqual({ processor: 1, startTime: 21, endTime: 28 });
58
+  expect(template[0][6]).toEqual({ processor: 1, startTime: 28, endTime: 30 });
59
+  expect(template[0][7]).toEqual({ processor: 1, startTime: 30, endTime: 33 });
60
+  expect(template[0][8]).toEqual({ processor: 1, startTime: 33, endTime: 40 });
61
+  expect(template[0][9]).toEqual({ processor: 1, startTime: 40, endTime: 46 });
62
+  expect(template[0][10]).toEqual({ processor: 1, startTime: 46, endTime: 50 });
63
+});
0 64
\ No newline at end of file
1 65
new file mode 100644
... ...
@@ -0,0 +1,134 @@
0
+import {
1
+  addIndex,
2
+  findIndex,
3
+  find,
4
+  map,
5
+  propEq,
6
+  reduce,
7
+  sort,
8
+  range,
9
+  concat,
10
+  filter,
11
+  reverse,
12
+  prop,
13
+  flatten,
14
+  uniq,
15
+  reject,
16
+  contains,
17
+  omit,
18
+  equals,
19
+  update,
20
+  times,
21
+  add,
22
+  pluck,
23
+  last, forEach, all
24
+} from 'rambda';
25
+import type { JobId } from '../../types';
26
+import { groupBy, max, min, remove, slice } from 'ramda';
27
+import { updateCTime } from '../mcnaught';
28
+
29
+type JobTime = {
30
+  jobId: JobId,
31
+  t: number,
32
+  anc: JobId[]
33
+};
34
+
35
+const noSuccJobs = (jobTimes: JobTime[]) => {
36
+  const allAnc = flatten(map(jobTime => jobTime.ignore ? [] : jobTime.anc, jobTimes));
37
+  return reject(jobTime => jobTime.ignore || contains(jobTime.jobId, allAnc), jobTimes);