summaryrefslogtreecommitdiff
path: root/job_scheduling/generate-jobscheduling.py
blob: 5cf9b04c1bb5d76302328c6151245f2a11d95287 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python
# Usage for 3a (first argument is the deadline):
#   $0 -1 | z3 -smt -in
# Usage for 3b:
#   $0 90 b | z3 -smt -in

import sys

# Deadline
deadline = int(sys.argv[1])
is_b = len(sys.argv) >= 3 and sys.argv[2] == 'b'


# Number of jobs
n = 12

# For i: (j, ...), job i must not start before jobs j have ended.
job_dependencies_ended = {
    3:  (1, 2),
    5:  (3, 4),
    7:  (3, 4, 6),
    9:  (5, 8),
    11: (10,),
    12: (9, 11),
}

job_dependencies_started = {
    8: (5,),
}

job_durations = {
    i: i + 5 for i in range(1, n + 1)
}


def fillin(cases, template_vars):
    if type(cases) == str:
        return cases.format(**template_vars)
    return [template.format(**template_vars) for template in cases]

literals = []
preds = []

# Start time of all jobs
# and their duration
for i in range(1, n + 1):
    literals += fillin([
        "t{i}",
        "d{i}",
    ], vars())
    # times must be positive and
    # all jobs must finish before the deadline.
    preds += fillin([
        "(>= t{i} 0)",
        "(<= (+ t{i} d{i}) {deadline})",
    ], vars())

# Define duration
for i, duration in job_durations.items():
    preds += fillin([
        "(= d{i} {duration})"
    ], vars())

# Job i may not start before job(s) j have *ended*. Or:
# for all j: t_j + d_j <= t_i
for i, deps in job_dependencies_ended.items():
    for j in deps:
        preds += fillin([
            "(<= (+ t{j} d{j}) t{i})"
        ], vars())

# Job i may not start before job(s) j have *started*. Or:
# for all j: t_j <= t_i
for i, deps in job_dependencies_started.items():
    for j in deps:
        preds += fillin([
            "(<= t{j} t{i})"
        ], vars())

# Jobs 5, 7 en 10 require a special equipment of which only one copy is
# available, so no two of these jobs may run at the same time.
# Or:
# There must exist a pair of jobs (i, j) s.t. one starts after another ended:
# t_i + d_i <= t_j
jobs_max2_for_3 = (5, 7, 10)
altpreds = []
for i in jobs_max2_for_3:
    for j in jobs_max2_for_3:
        if i == j:
            continue
        altpreds += fillin([
            "(<= (+ t{i} d{i}) t{j})"
        ], vars())

preds += ["(or %s)" % " ".join(altpreds)]

# Begin generator
s = """(benchmark test.smt
:logic QF_UFLIA
:extrafuns
(
"""
s += "\n".join("(%s Int)" % x for x in literals)
s += """
)
:formula
(and
"""
s += "\n".join(preds)
s += """
))
"""

try:
    import sys
    print(s)
    # Hack to avoid printing a ugly error in case stdin of next pipe is closed.
    sys.stdout.flush()
    sys.stdout.close()
except BrokenPipeError:
    pass