Paper
Interval Scheduling with Eligible Machine Sets
6 pages · 23 marked passages · pdflatex · download PDF · lax-888481
-
The Word RAM
-
Interval Scheduling with Eligible Machine Sets
An instance consists of jobs and identical parallel machines. Job has a processing time , a deadline , a weight , and a set of eligible machines. Each job is an interval: job , if scheduled, occupies exactly , so a schedule chooses only which machine runs a job, never when.
A schedule assigns to every job either an eligible machine or nothing. It is feasible if no machine is assigned two jobs whose intervals overlap. Its weight is the total weight of the jobs it schedules. The optimization problem asks for a feasible schedule of maximum weight; the decision problem asks whether weight is attainable.
1 import Mathlib.Algebra.BigOperators.Fin 2 import Mathlib.Data.Finset.Lattice.Fold 3 … module docstring, 38 lines 42 43 namespace Lax888481.Scheduling 44 45 /-- An instance of interval scheduling with eligible machine sets: `jobs` jobs on 46 `machines` machines, each job with a processing time, a deadline, a weight, and the set 47 of machines allowed to run it. -/ 48 structure Instance where 49 /-- The number `n` of jobs. -/ 50 jobs : ℕ 51 /-- The number `m` of machines. -/ 52 machines : ℕ 53 /-- The processing time `p j` of job `j`. -/ 54 p : Fin jobs → ℕ 55 /-- The deadline `d j` of job `j`. -/ 56 d : Fin jobs → ℕ 57 /-- The weight `w j` of job `j`. -/ 58 w : Fin jobs → ℕ 59 /-- The machines eligible to run job `j`. -/ 60 eligible : Fin jobs → Finset (Fin machines) 61 /-- Every job takes at least one time unit. -/ 62 p_pos : ∀ j, 0 < p j 63 /-- Every job fits before its deadline. -/ 64 p_le_d : ∀ j, p j ≤ d j 65 66 namespace Instance 67 68 variable (I : Instance) 69 70 /-- The time at which job `j` starts, namely `d j - p j`: a job occupies exactly the 71 interval `[d j - p j, d j)`. -/ 72 def start (j : Fin I.jobs) : ℕ := I.d j - I.p j 73 74 /-- Jobs `j` and `j'` *overlap*: their half-open intervals meet. -/ 75 def Overlap (j j' : Fin I.jobs) : Prop := 76 I.start j < I.d j' ∧ I.start j' < I.d j 77 78 /-- A schedule assigns each job an eligible machine, or nothing. -/ 79 abbrev Schedule := Fin I.jobs → Option (Fin I.machines) 80 81 variable {I} 82 83 /-- A schedule is *feasible* if it places every scheduled job on an eligible machine and 84 never places two overlapping jobs on the same machine. -/ 85 def Feasible (σ : I.Schedule) : Prop := 86 (∀ j i, σ j = some i → i ∈ I.eligible j) ∧ 87 (∀ j j' i, j ≠ j' → I.Overlap j j' → σ j = some i → σ j' ≠ some i) 88 89 /-- A schedule is *complete* if it rejects no job. -/ 90 def Complete (σ : I.Schedule) : Prop := ∀ j, σ j ≠ none 91 92 /-- The weight of a schedule: the total weight of the jobs it schedules. -/ 93 def weight (σ : I.Schedule) : ℕ := ∑ j, (σ j).elim 0 fun _ => I.w j 94 95 variable (I) 96 97 /-- `I` admits a feasible schedule of weight at least `W`. -/ 98 def HasWeight (W : ℕ) : Prop := ∃ σ : I.Schedule, Feasible σ ∧ W ≤ weight σ 99 100 /-- `I` admits a feasible schedule that rejects no job. -/ 101 def AllSchedulable : Prop := ∃ σ : I.Schedule, Feasible σ ∧ Complete σ 102 103 /-- The largest processing time in `I`, and `0` if there are no jobs. -/ 104 def pmax : ℕ := Finset.univ.sup I.p 105 106 end Instance 107 108 end Lax888481.Scheduling 109 -
Word Encoding of a Scheduling Instance
A scheduling instance is handed to a word random access machine as a word of numbers: the number of jobs, the number of machines, then the processing times, the deadlines, the weights, then offsets and a target array listing, for each job in turn, the machines eligible to run it. The offsets say where each job's block of eligible machines begins, the first being and the last the length of the target array. A decision instance appends the threshold as a final entry.
1 import Lax888481.Scheduling 2 … module docstring, 38 lines 41 42 namespace Lax888481.InstanceEncoding 43 44 open Lax888481.Scheduling 45 46 /-- The number of jobs declared by a word: its first entry. -/ 47 def jobCount (x : List ℕ) : ℕ := x.getD 0 0 48 49 /-- The number of machines declared by a word: its second entry. -/ 50 def machineCount (x : List ℕ) : ℕ := x.getD 1 0 51 52 /-- The processing time of job `j`: the processing times follow the two header 53 entries. -/ 54 def proc (x : List ℕ) (j : ℕ) : ℕ := x.getD (2 + j) 0 55 56 /-- The deadline of job `j`: the deadlines follow the processing times. -/ 57 def due (x : List ℕ) (j : ℕ) : ℕ := x.getD (2 + jobCount x + j) 0 58 59 /-- The weight of job `j`: the weights follow the deadlines. -/ 60 def wt (x : List ℕ) (j : ℕ) : ℕ := x.getD (2 + 2 * jobCount x + j) 0 61 62 /-- The `i`-th offset: the `n+1` offsets follow the weights. -/ 63 def offset (x : List ℕ) (i : ℕ) : ℕ := x.getD (2 + 3 * jobCount x + i) 0 64 65 /-- The `t`-th entry of the target array, which follows the offsets. -/ 66 def target (x : List ℕ) (t : ℕ) : ℕ := x.getD (3 + 4 * jobCount x + t) 0 67 68 /-- The word `x` encodes the instance `I`. -/ 69 structure EncodesInstance (x : List ℕ) (I : Instance) : Prop where 70 /-- The word declares `I`'s jobs. -/ 71 jobCount_eq : jobCount x = I.jobs 72 /-- The word declares `I`'s machines. -/ 73 machineCount_eq : machineCount x = I.machines 74 /-- The word consists of the two header entries, the three arrays of one number per 75 job, the `n+1` offsets, and a target array as long as the last offset says. -/ 76 length_eq : x.length = 3 + 4 * I.jobs + offset x I.jobs 77 /-- The processing times are `I`'s. -/ 78 proc_eq : ∀ j : Fin I.jobs, proc x j = I.p j 79 /-- The deadlines are `I`'s. -/ 80 due_eq : ∀ j : Fin I.jobs, due x j = I.d j 81 /-- The weights are `I`'s. -/ 82 wt_eq : ∀ j : Fin I.jobs, wt x j = I.w j 83 /-- The block of the first job begins at the start of the target array. -/ 84 offset_zero : offset x 0 = 0 85 /-- The offsets are nondecreasing, so they cut the target array into one block per 86 job. -/ 87 offset_mono : ∀ j < I.jobs, offset x j ≤ offset x (j + 1) 88 /-- Every entry of the target array is a machine. -/ 89 target_lt : ∀ t < offset x I.jobs, target x t < I.machines 90 /-- The block of a job lists exactly its eligible machines. -/ 91 eligible_iff : ∀ (j : Fin I.jobs) (i : Fin I.machines), 92 i ∈ I.eligible j ↔ ∃ t, offset x j ≤ t ∧ t < offset x (j + 1) ∧ target x t = i 93 94 /-- The word `x` presents the instance `I` together with the threshold `W`: an instance 95 block followed by the single entry `W`. -/ 96 def EncodesDecisionInstance (x : List ℕ) (I : Instance) (W : ℕ) : Prop := 97 ∃ y, x = y ++ [W] ∧ EncodesInstance y I 98 99 /-- The words that encode a decision instance. -/ 100 def DecisionInstances : Set (List ℕ) := 101 {x | ∃ I W, EncodesDecisionInstance x I W} 102 103 /-- The words that encode an instance, with no threshold. -/ 104 def Instances : Set (List ℕ) := {x | ∃ I, EncodesInstance x I} 105 106 end Lax888481.InstanceEncoding 107 -
Binary Encoding of a Scheduling Instance
A scheduling instance as a binary word, the representation classical complexity measures running time against. A number is written as its binary digits preceded by its length in unary, which makes the encoding self-delimiting; an instance is the number of jobs, the number of machines, the three arrays of processing times, deadlines and weights, and the eligibility matrix, in that order.
1 import Lax888481.Scheduling 2 import Lax434930.PolynomialTime 3 import Mathlib.Data.List.FinRange 4 import Mathlib.Data.Nat.Bits 5 … module docstring, 37 lines 43 44 namespace Lax888481.BinaryEncoding 45 46 open Lax888481.Scheduling Lax434930.PolynomialTime 47 48 /-- A natural number as a binary word: its digits, least significant first, preceded by 49 their number in unary. The unary prefix makes the code self-delimiting. -/ 50 def encodeNat (n : ℕ) : Word := 51 List.replicate n.bits.length true ++ [false] ++ n.bits 52 53 /-- An instance as a binary word: the two counts, the processing times, the deadlines, 54 the weights, and the eligibility matrix in row order. -/ 55 def encodeInstance (I : Instance) : Word := 56 encodeNat I.jobs ++ encodeNat I.machines ++ 57 (List.finRange I.jobs).flatMap (fun j => encodeNat (I.p j)) ++ 58 (List.finRange I.jobs).flatMap (fun j => encodeNat (I.d j)) ++ 59 (List.finRange I.jobs).flatMap (fun j => encodeNat (I.w j)) ++ 60 (List.finRange I.jobs).flatMap 61 (fun j => (List.finRange I.machines).map fun i => decide (i ∈ I.eligible j)) 62 63 end Lax888481.BinaryEncoding 64 -
The Scheduling Problems, Parameterized
Interval scheduling with eligible machine sets, as parameterized problems on words: the decision problem "is weight attainable?" parameterized by the number of machines, the same problem parameterized by , and the problem "can every job be scheduled?" parameterized by .
The three theorems of this submission are about these three problems: the first is W[1]-hard, the second is fixed-parameter tractable, and the third is NP-hard already when its parameter is bounded by an absolute constant.
1 import Lax888481.InstanceEncoding 2 import Lax888481.ParameterizedComplexity 3 … module docstring, 31 lines 35 36 namespace Lax888481.SchedulingProblems 37 38 open Lax888481.Scheduling Lax888481.InstanceEncoding Lax888481.ParameterizedComplexity 39 open Lax808846.Ram Lax808846.RamComputes 40 41 /-- The largest processing time declared by a word: the largest of the `n` entries of 42 its processing-time block. -/ 43 def pmaxOf (x : List ℕ) : ℕ := 44 ((List.range (jobCount x)).map (proc x)).foldr max 0 45 46 /-- **Interval scheduling with eligible machine sets**, parameterized by the number of 47 machines. -/ 48 def byMachines : Problem where 49 Domain := DecisionInstances 50 Yes x := ∃ I W, EncodesDecisionInstance x I W ∧ I.HasWeight W 51 param x := machineCount x 52 53 /-- The same problem, parameterized by the number of machines together with the largest 54 processing time. -/ 55 def byMachinesAndPmax : Problem where 56 Domain := DecisionInstances 57 Yes x := ∃ I W, EncodesDecisionInstance x I W ∧ I.HasWeight W 58 param x := machineCount x + pmaxOf x 59 60 /-- **Scheduling every job**: is there a feasible schedule that rejects no job? 61 Parameterized by the largest processing time. Instances carry no threshold. -/ 62 def allSchedulableByPmax : Problem where 63 Domain := Instances 64 Yes x := ∃ I, EncodesInstance x I ∧ I.AllSchedulable 65 param x := pmaxOf x 66 67 /-- **The parameter is computed by a word RAM program in linear time.** One program and 68 one constant `c` such that, at every word length, on every decision instance whose 69 entries fit, the program halts within `c · (|x| + 1)` instructions having written the 70 largest processing time. 71 72 A parameterized problem whose parameter no machine can read is not one a machine can be 73 handed, and the parameter of the second and third problems above is not an entry of the 74 word but a maximum over a block of it. This says that reading it costs a single pass, 75 so that nothing in the running time of the third theorem is hidden in obtaining the 76 parameter it is stated in terms of. -/ 77 axiom pmaxOf_computesInTime : 78 ∃ (prog : Program) (c : ℕ), ∀ w : ℕ, 79 ComputesInTime w prog 80 {x | x ∈ DecisionInstances ∧ Fits c w x} 81 (fun x => [pmaxOf x]) 82 (fun x => c * (x.length + 1)) 83 84 end Lax888481.SchedulingProblems 85 -
Parameterized Problems and FPT-Reductions on a Word RAM
A parameterized problem is a set of admissible input words, a yes-instance predicate on them, and a parameter read off the word. It is fixed-parameter tractable if one word RAM program decides it, on every admissible word of parameter , within instructions for a constant and a function of the parameter alone.
An fpt-reduction from to is a map on words that sends admissible words to admissible words, preserves and reflects yes-instances, raises the parameter by at most a function of it, and is computed by one word RAM program within the same kind of bound. Fpt-reductions compose, and together with gives .
1 import Lax808846.RamComputes 2 … module docstring, 56 lines 59 60 namespace Lax888481.ParameterizedComplexity 61 62 open Lax808846.Ram Lax808846.RamComputes 63 64 /-- A parameterized problem: the words that encode an instance, which of them are 65 yes-instances, and the parameter each one carries. -/ 66 structure Problem where 67 /-- The words that encode an instance. A program may do anything on the others. -/ 68 Domain : Set (List ℕ) 69 /-- The yes-instances. -/ 70 Yes : List ℕ → Prop 71 /-- The parameter, read off the word. -/ 72 param : List ℕ → ℕ 73 74 /-- The word `x` fits at word length `w`, with room for `c` times its length: every 75 entry `v` of `x` satisfies `c * (x.length + v + 1) ≤ 2 ^ w`. -/ 76 def Fits (c w : ℕ) (x : List ℕ) : Prop := ∀ v ∈ x, c * (x.length + v + 1) ≤ 2 ^ w 77 78 open Classical in 79 /-- At every word length, the program decides `P` on every admissible word that fits, 80 within `c * g k * (|x| + 1)` instructions, where `k` is the word's parameter. It writes 81 `1` for a yes-instance and `0` for a no-instance. -/ 82 def Decides (P : Problem) (prog : Program) (c : ℕ) (g : ℕ → ℕ) : Prop := 83 ∀ w : ℕ, ComputesInTime w prog 84 {x | x ∈ P.Domain ∧ Fits c w x} 85 (fun x => if P.Yes x then [1] else [0]) 86 (fun x => c * g (P.param x) * (x.length + 1)) 87 88 /-- `P` is **fixed-parameter tractable**: one program and one constant decide it within 89 `c * g k * (|x| + 1)` instructions, for some function `g` of the parameter alone. -/ 90 def FPT (P : Problem) : Prop := ∃ (prog : Program) (c : ℕ) (g : ℕ → ℕ), Decides P prog c g 91 92 /-- The map `f` is an fpt-reduction from `P` to `Q`, computed by `prog` within 93 `c * g k * (|x| + 1)` instructions and raising the parameter by at most `h`. -/ 94 structure IsFptReduction (P Q : Problem) (f : List ℕ → List ℕ) (prog : Program) 95 (c : ℕ) (g h : ℕ → ℕ) : Prop where 96 /-- The image of an admissible word is admissible. -/ 97 maps_domain : ∀ x ∈ P.Domain, f x ∈ Q.Domain 98 /-- Yes-instances go to yes-instances, and no-instances to no-instances. -/ 99 correct : ∀ x ∈ P.Domain, (P.Yes x ↔ Q.Yes (f x)) 100 /-- The new parameter is bounded by a function of the old one alone. -/ 101 param_le : ∀ x ∈ P.Domain, Q.param (f x) ≤ h (P.param x) 102 /-- At every word length, the program computes `f` on every admissible word that fits 103 and whose image fits, within the stated bound. -/ 104 time : ∀ w : ℕ, ComputesInTime w prog 105 {x | x ∈ P.Domain ∧ Fits c w x ∧ Fits c w (f x)} 106 f (fun x => c * g (P.param x) * (x.length + 1)) 107 108 /-- `P` **fpt-reduces** to `Q`. -/ 109 def FptReduces (P Q : Problem) : Prop := 110 ∃ (f : List ℕ → List ℕ) (prog : Program) (c : ℕ) (g h : ℕ → ℕ), 111 IsFptReduction P Q f prog c g h 112 113 @[inherit_doc] infix:50 " ≤fpt " => FptReduces 114 115 end Lax888481.ParameterizedComplexity 116 -
NP-Hardness of a Scheduling Problem, and on a Class of Instances
A scheduling problem is NP-hard if every language in NP has a polynomial-time many-one reduction to it, the reduction's output being an instance in the binary encoding.
It is NP-hard on a class of instances if such a reduction exists whose output always lies in . When is a slice on which some parameter is bounded by an absolute constant, this is para-NP-hardness for that parameter: it rules out an algorithm running in time for every function , unless — a stronger and unconditional-in- conclusion than W[1]-hardness, which rules out fixed-parameter tractability only under .
1 import Lax888481.BinaryEncoding 2 import Lax434930.NondeterministicPolynomialTime 3 … module docstring, 34 lines 38 39 namespace Lax888481.NPHardness 40 41 open Lax888481.Scheduling Lax888481.BinaryEncoding 42 open Lax434930.PolynomialTime Lax434930.NondeterministicPolynomialTime 43 44 /-- A property of scheduling instances: a decision problem on them. -/ 45 abbrev Problem := Instance → Prop 46 47 /-- `Q` is **NP-hard**: every language in NP reduces to it in polynomial time. -/ 48 def NPHard (Q : Problem) : Prop := 49 ∀ A : Language, A ∈ NP → 50 ∃ f : Word → Instance, 51 Nonempty (Turing.TM2ComputableInPolyTime id encodeInstance f) ∧ 52 ∀ x, x ∈ A ↔ Q (f x) 53 54 /-- `Q` is **NP-hard on `C`**: every language in NP reduces to it in polynomial time by a 55 reduction all of whose outputs lie in `C`. -/ 56 def NPHardOn (Q : Problem) (C : Instance → Prop) : Prop := 57 ∀ A : Language, A ∈ NP → 58 ∃ f : Word → Instance, 59 Nonempty (Turing.TM2ComputableInPolyTime id encodeInstance f) ∧ 60 ∀ x, C (f x) ∧ (x ∈ A ↔ Q (f x)) 61 62 end Lax888481.NPHardness 63 -
Polynomial-Time Many-One Reductions on the Word RAM
A polynomial-time many-one reduction from one set of words to another is a map on words, computable by a word RAM program in time polynomial in the bit-size of its input, that preserves and reflects membership. A reduction whose image additionally lies in a given class witnesses hardness on that class.
1 import Lax759944.RamPolytime 2 … module docstring, 27 lines 30 31 namespace Lax888481.PolynomialReduction 32 33 /-- `P` reduces to `Q` in polynomial time on the word RAM. -/ 34 def PolyReduces (P Q : Set (List ℕ)) : Prop := 35 ∃ f : List ℕ → List ℕ, 36 Lax759944.RamPolytime.RamPolytime f ∧ ∀ x, (x ∈ P ↔ f x ∈ Q) 37 38 /-- `P` reduces to `Q` in polynomial time by a reduction whose image lies in `C`. -/ 39 def PolyReducesOn (P Q : Set (List ℕ)) (C : List ℕ → Prop) : Prop := 40 ∃ f : List ℕ → List ℕ, 41 Lax759944.RamPolytime.RamPolytime f ∧ (∀ x, C (f x)) ∧ ∀ x, (x ∈ P ↔ f x ∈ Q) 42 43 end Lax888481.PolynomialReduction 44 -
Multicoloured Clique
An instance is a graph on vertices together with a colouring of its vertices by colours, in which adjacent vertices always receive different colours. It is a yes-instance if the graph contains a clique with one vertex of each colour — necessarily of size .
Parameterized by the number of colours, this problem is W[1]-complete. It is the standard starting point for parameterized hardness proofs, because a reduction from it may assume the vertices of a solution are distinguishable in advance, one per colour.
1 import Lax271696.GraphEncoding 2 import Lax888481.ParameterizedComplexity 3 … module docstring, 43 lines 47 48 namespace Lax888481.MulticolouredClique 49 50 /-- An instance of Multicoloured Clique: a graph whose vertices are coloured so that 51 adjacent vertices differ in colour. -/ 52 structure Instance where 53 /-- The number `k` of colours, the parameter. -/ 54 colours : ℕ 55 /-- The number `n` of vertices. -/ 56 vertices : ℕ 57 /-- The graph. -/ 58 graph : SimpleGraph (Fin vertices) 59 /-- The colour of each vertex. -/ 60 colour : Fin vertices → Fin colours 61 /-- Adjacent vertices differ in colour. -/ 62 adj_colour_ne : ∀ u v, graph.Adj u v → colour u ≠ colour v 63 64 /-- `G` contains a multicoloured clique: one vertex of each colour, pairwise adjacent. -/ 65 def Instance.HasMulticolouredClique (G : Instance) : Prop := 66 ∃ f : Fin G.colours → Fin G.vertices, 67 (∀ c, G.colour (f c) = c) ∧ ∀ c c', c ≠ c' → G.graph.Adj (f c) (f c') 68 69 /-- The word `x` presents the instance `G`: a compressed sparse row block encoding the 70 graph, with each adjacency list strictly increasing, followed by one entry per vertex 71 giving its colour, followed by the number of colours. -/ 72 def EncodesInstance (x : List ℕ) (G : Instance) : Prop := 73 ∃ g, x = g ++ (List.ofFn fun v => (G.colour v : ℕ)) ++ [G.colours] ∧ 74 Lax271696.GraphEncoding.EncodesGraph g G.vertices G.graph ∧ 75 ∀ u < G.vertices, ∀ t, Lax271696.GraphEncoding.offset g u ≤ t → 76 t + 1 < Lax271696.GraphEncoding.offset g (u + 1) → 77 Lax271696.GraphEncoding.target g t < Lax271696.GraphEncoding.target g (t + 1) 78 79 /-- The words that encode an instance. -/ 80 def Instances : Set (List ℕ) := {x | ∃ G, EncodesInstance x G} 81 82 /-- **Multicoloured Clique**, parameterized by the number of colours. The parameter is 83 the last entry of the word. -/ 84 def problem : ParameterizedComplexity.Problem where 85 Domain := Instances 86 Yes x := ∃ G, EncodesInstance x G ∧ G.HasMulticolouredClique 87 param x := x.getLast? |>.getD 0 88 89 end Lax888481.MulticolouredClique 90 -
Construction 1
The scheduling instance built from a Multicoloured Clique instance. There is one edge selection machine for each of the pairs of colours and one validation machine, so the number of machines depends on the number of colours alone — so the reduction is a parameterized one.
Vertices are laid out along the time axis in an order that refines the colour order, each vertex owning a window of length . A vertex contributes one job of processing time for its own colour, eligible only on the validation machine, and one unit job for each other colour , eligible also on the edge selection machine of . An edge with contributes one job on the edge selection machine of that colour pair, spanning from just after 's window to just before 's. Each colour pair also gets two colour combination jobs per vertex, which fill the rest of that machine's timeline so that exactly one edge job can be selected on it.
The weights are chosen in three tiers, , so that a schedule of the target weight is forced to select one edge per colour pair, and then forced to have those edges agree on one vertex per colour — which is the clique.
- def✓
Lax888481.Construction1(1st statement) - def✓
Lax888481.Construction1(2nd statement) - def✓
Lax888481.Construction1(3rd statement) - def✓
Lax888481.Construction1(4th statement) - def✓
Lax888481.Construction1(5th statement) - def✓
Lax888481.Construction1(6th statement)
1 import Lax888481.MulticolouredClique 2 import Lax888481.Scheduling 3 import Lax888481.InstanceEncoding 4 import Mathlib.Data.Nat.Choose.Basic 5 … module docstring, 76 lines 82 83 namespace Lax888481.Construction1 84 85 open Lax888481.MulticolouredClique 86 87 variable (G : MulticolouredClique.Instance) 88 89 /-- The number of vertices. -/ 90 abbrev nVert : ℕ := G.vertices 91 92 /-- The number of colours, the parameter. -/ 93 abbrev nCol : ℕ := G.colours 94 95 /-- The paper's order `<π`, as the position it assigns: vertices ranked by colour, ties 96 broken by index, counting from one. -/ 97 noncomputable def rank (v : Fin G.vertices) : ℕ := 98 1 + (Finset.univ.filter fun u : Fin G.vertices => 99 (G.colour u : ℕ) < (G.colour v : ℕ) ∨ 100 ((G.colour u : ℕ) = (G.colour v : ℕ) ∧ (u : ℕ) < (v : ℕ))).card 101 102 /-- The window length `K = k + 2` each vertex occupies. -/ 103 abbrev K : ℕ := G.colours + 2 104 105 /-- `c₁ = n + 1`: the weight of a vertex job for a colour other than its own. -/ 106 def c1 : ℕ := G.vertices + 1 107 108 /-- `c₂ = (k-1)·n·c₁ + n + 1`: above the total weight of every vertex job together. -/ 109 def c2 : ℕ := (G.colours - 1) * G.vertices * c1 G + G.vertices + 1 110 111 /-- `c₃ = (kn + k²n)·n·c₂ + 1`: above the total weight of every colour combination job 112 together. -/ 113 def c3 : ℕ := (G.colours * G.vertices + G.colours ^ 2 * G.vertices) * G.vertices * c2 G + 1 114 115 /-- The machine of the colour pair `{a, b}` with `a < b`: its position `b(b-1)/2 + a` in 116 the enumeration of pairs by larger element, then smaller, written with the binomial 117 coefficient it is. -/ 118 def pairIdx (a b : ℕ) : ℕ := b.choose 2 + a 119 120 /-- The validation machine. -/ 121 abbrev validation : ℕ := G.colours.choose 2 122 123 /-- One machine per colour pair, plus the validation machine. -/ 124 def nMach : ℕ := G.colours.choose 2 + 1 125 126 /-- The vertex jobs: one per vertex and colour. -/ 127 abbrev nVJob : ℕ := G.vertices * G.colours 128 129 /-- The colour combination slots: one per ordered colour pair and vertex. -/ 130 abbrev nCJob : ℕ := G.colours * G.colours * G.vertices 131 132 open Classical in 133 /-- The oriented edges of the graph, smaller colour first, in lexicographic order. This 134 is the enumeration the edge jobs are indexed by. There is one slot per edge and not one 135 per pair of vertices, because the word the reduction is handed lists the edges and a 136 reduction running in time linear in it cannot afford a slot for every pair. -/ 137 noncomputable def edgeList : List (Fin G.vertices × Fin G.vertices) := 138 ((List.finRange G.vertices) ×ˢ (List.finRange G.vertices)).filter 139 fun p => decide ((G.colour p.1 : ℕ) < (G.colour p.2 : ℕ) ∧ G.graph.Adj p.1 p.2) 140 141 /-- The edge slots: one per oriented edge. -/ 142 noncomputable abbrev nEJob : ℕ := (edgeList G).length 143 144 /-- The jobs of the construction. -/ 145 noncomputable def nJobs : ℕ := nVJob G + nCJob G + nEJob G 146 147 variable {G} 148 149 /-- The colour of vertex number `v`, as a number, and `0` when `v` is out of range. -/ 150 noncomputable def col (v : ℕ) : ℕ := 151 if h : v < G.vertices then (G.colour ⟨v, h⟩ : ℕ) else 0 152 153 /-- The position of vertex number `v`, and `0` when `v` is out of range. -/ 154 noncomputable def pos (v : ℕ) : ℕ := 155 if h : v < G.vertices then rank G ⟨v, h⟩ else 0 156 157 variable (G) 158 159 -- A job index below `n·k` is a vertex job; the next `k²n` are colour combination slots 160 -- and the rest, one per edge, are edge slots. 161 162 /-- The vertex of vertex job `j`. -/ 163 def vjVert (j : ℕ) : ℕ := j / G.colours 164 165 /-- The colour of vertex job `j`. -/ 166 def vjCol (j : ℕ) : ℕ := j % G.colours 167 168 /-- The smaller colour of colour combination slot `q`. -/ 169 def cjA (q : ℕ) : ℕ := q / G.vertices / G.colours 170 171 /-- The larger colour of colour combination slot `q`. -/ 172 def cjB (q : ℕ) : ℕ := q / G.vertices % G.colours 173 174 /-- The vertex of colour combination slot `q`. -/ 175 def cjZ (q : ℕ) : ℕ := q % G.vertices 176 177 /-- The first endpoint of edge slot `q`. -/ 178 noncomputable def ejU (q : ℕ) : ℕ := (((edgeList G)[q]?).map fun p => (p.1 : ℕ)).getD 0 179 180 /-- The second endpoint of edge slot `q`. -/ 181 noncomputable def ejV (q : ℕ) : ℕ := (((edgeList G)[q]?).map fun p => (p.2 : ℕ)).getD 0 182 183 /-- A colour combination slot carries a job when its pair is ordered and its vertex has 184 one of the two colours. -/ 185 def CJobOk (q : ℕ) : Prop := 186 cjA G q < cjB G q ∧ cjB G q < G.colours ∧ cjZ G q < G.vertices ∧ 187 (col (G := G) (cjZ G q) = cjA G q ∨ col (G := G) (cjZ G q) = cjB G q) 188 189 /-- An edge slot carries a job when it names one of the enumerated edges. Every slot of 190 the edge block does, so the block has no inert slots; the condition is here because the 191 accessors below are total functions on slot numbers. -/ 192 noncomputable def EJobOk (q : ℕ) : Prop := q < (edgeList G).length 193 194 -- The raw formulas below are the paper's, with the edge job one unit shorter and colours 195 -- from zero, as the notes above say. An inert slot is given a unit job with no eligible 196 -- machine; on every admissible slot the clamp is inactive. 197 198 open Classical in 199 /-- The paper's processing time of job `j`, before clamping. -/ 200 noncomputable def rawProc (j : ℕ) : ℕ := 201 if j < nVJob G then 202 (if vjCol G j = col (G := G) (vjVert G j) then K G else 1) 203 else if j < nVJob G + nCJob G then 204 let q := j - nVJob G 205 if CJobOk G q then 206 (if col (G := G) (cjZ G q) = cjA G q 207 then K G * pos (G := G) (cjZ G q) - cjB G q - 2 208 else K G * (G.vertices - pos (G := G) (cjZ G q)) + cjA G q + 2) 209 else 1 210 else 211 let q := j - nVJob G - nCJob G 212 if EJobOk G q then 213 K G * (pos (G := G) (ejV G q) - pos (G := G) (ejU G q)) 214 - col (G := G) (ejU G q) + col (G := G) (ejV G q) - 1 215 else 1 216 217 open Classical in 218 /-- The paper's deadline of job `j`, before clamping. -/ 219 noncomputable def rawDue (j : ℕ) : ℕ := 220 if j < nVJob G then 221 (if vjCol G j = col (G := G) (vjVert G j) 222 then K G * pos (G := G) (vjVert G j) + 1 223 else K G * pos (G := G) (vjVert G j) - vjCol G j) 224 else if j < nVJob G + nCJob G then 225 let q := j - nVJob G 226 if CJobOk G q then 227 (if col (G := G) (cjZ G q) = cjA G q 228 then K G * pos (G := G) (cjZ G q) - cjB G q - 1 229 else K G * G.vertices + 2) 230 else 1 231 else 232 let q := j - nVJob G - nCJob G 233 if EJobOk G q then 234 K G * pos (G := G) (ejV G q) - col (G := G) (ejU G q) - 1 235 else 1 236 237 /-- The processing time of job `j`, clamped so that `0 < p ≤ d` holds outright. -/ 238 noncomputable def procOf (j : ℕ) : ℕ := max 1 (min (rawProc G j) (rawDue G j)) 239 240 /-- The deadline of job `j`, clamped so that `0 < p ≤ d` holds outright. -/ 241 noncomputable def dueOf (j : ℕ) : ℕ := max 1 (rawDue G j) 242 243 open Classical in 244 /-- The weight of job `j`. An inert slot has weight zero. -/ 245 noncomputable def wtOf (j : ℕ) : ℕ := 246 if j < nVJob G then 247 (if vjCol G j = col (G := G) (vjVert G j) then 1 else c1 G) 248 else if j < nVJob G + nCJob G then 249 let q := j - nVJob G 250 if CJobOk G q then 251 (if col (G := G) (cjZ G q) = cjA G q 252 then c2 G * pos (G := G) (cjZ G q) 253 else c2 G * (G.vertices - pos (G := G) (cjZ G q))) 254 else 0 255 else 256 let q := j - nVJob G - nCJob G 257 if EJobOk G q then 258 c2 G * (pos (G := G) (ejV G q) - pos (G := G) (ejU G q)) + c3 G 259 else 0 260 261 open Classical in 262 /-- The machines eligible to run job `j`, as a list of machine numbers. An inert slot has 263 none, so no feasible schedule can place it. -/ 264 noncomputable def eligOf (j : ℕ) : List ℕ := 265 if j < nVJob G then 266 (if vjCol G j = col (G := G) (vjVert G j) then [validation G] 267 else [validation G, 268 pairIdx (min (vjCol G j) (col (G := G) (vjVert G j))) 269 (max (vjCol G j) (col (G := G) (vjVert G j)))]) 270 else if j < nVJob G + nCJob G then 271 let q := j - nVJob G 272 if CJobOk G q then [pairIdx (cjA G q) (cjB G q)] else [] 273 else 274 let q := j - nVJob G - nCJob G 275 if EJobOk G q then 276 [pairIdx (col (G := G) (ejU G q)) (col (G := G) (ejV G q))] 277 else [] 278 279 lemma procOf_pos (j : ℕ) : 0 < procOf G j := by 280 simp only [procOf]; omega 281 282 lemma procOf_le_dueOf (j : ℕ) : procOf G j ≤ dueOf G j := by 283 simp only [procOf, dueOf]; omega 284 285 open Classical in 286 /-- **Construction 1.** The scheduling instance built from the Multicoloured Clique 287 instance `G`. -/ 288 noncomputable def inst : Scheduling.Instance where 289 jobs := nJobs G 290 machines := nMach G 291 p j := procOf G j 292 d j := dueOf G j 293 w j := wtOf G j 294 eligible j := Finset.univ.filter fun i : Fin (nMach G) => (i : ℕ) ∈ eligOf G j 295 p_pos j := procOf_pos G j 296 p_le_d j := procOf_le_dueOf G j 297 298 @[simp] lemma inst_jobs : (inst G).jobs = nJobs G := rfl 299 @[simp] lemma inst_machines : (inst G).machines = nMach G := rfl 300 301 /-- **The threshold `W` of Lemmas 1 and 2.** -/ 302 def targetWeight : ℕ := 303 G.colours.choose 2 * c3 G + G.colours.choose 2 * (G.vertices * c2 G) + 304 (G.colours - 1) * G.vertices * c1 G + G.colours 305 306 /-- Where job `j`'s block of eligible machines begins. -/ 307 noncomputable def offOf (j : ℕ) : ℕ := 308 ((List.range j).map fun i => (eligOf G i).length).sum 309 310 /-- The processing-time block. -/ 311 noncomputable def procBlock : List ℕ := (List.range (nJobs G)).map (procOf G) 312 313 /-- The deadline block. -/ 314 noncomputable def dueBlock : List ℕ := (List.range (nJobs G)).map (dueOf G) 315 316 /-- The weight block. -/ 317 noncomputable def wtBlock : List ℕ := (List.range (nJobs G)).map (wtOf G) 318 319 /-- The offset block, one entry per job and one more. -/ 320 noncomputable def offBlock : List ℕ := (List.range (nJobs G + 1)).map (offOf G) 321 322 /-- The target block: the eligible machines of each job in turn. -/ 323 noncomputable def tgtBlock : List ℕ := (List.range (nJobs G)).flatMap (eligOf G) 324 325 /-- **The word Construction 1 emits**: the instance, followed by the threshold. -/ 326 noncomputable def emit : List ℕ := 327 ([nJobs G, nMach G] ++ procBlock G ++ dueBlock G ++ wtBlock G ++ offBlock G ++ tgtBlock G) 328 ++ [targetWeight G] 329 330 /-- **The emitted word presents the constructed instance and its threshold.** -/ 331 axiom emit_encodes (G : MulticolouredClique.Instance) : 332 Lax888481.InstanceEncoding.EncodesDecisionInstance (emit G) (inst G) (targetWeight G) 333 334 /-- **The machine count.** The constructed instance has one machine per pair of colours 335 and one more, so its number of machines depends on the parameter alone. -/ 336 axiom machines_eq (G : MulticolouredClique.Instance) : (inst G).machines = G.colours.choose 2 + 1 337 338 /-- **Construction 1 is correct.** The graph has a multicoloured clique exactly when the 339 constructed instance admits a feasible schedule of weight at least `W`. -/ 340 axiom correct (G : MulticolouredClique.Instance) : 341 G.HasMulticolouredClique ↔ (inst G).HasWeight (targetWeight G) 342 343 -- The construction as a map on words. 344 345 /-- The word a malformed input is sent to: one job of weight one, no machine to run it 346 on, and the threshold one. No schedule reaches the threshold, so the word is a 347 no-instance, as the source problem says of a word that is not a graph. -/ 348 def noWord : List ℕ := [1, 0, 1, 1, 1, 0, 0, 1] 349 350 open Classical in 351 /-- **Construction 1 as a total map on words.** A word that does not encode a 352 Multicoloured Clique instance is sent to a fixed decision instance no schedule can 353 satisfy. A reduction is a function on all words, and the machine that computes it has to 354 decide which case it is in; making the diversion part of the map rather than a side 355 condition is what keeps the statements below free of hypotheses. 356 357 The case split is on a proposition rather than on a decision procedure, and the instance 358 the word is read as is chosen rather than computed, so the map is `noncomputable` in 359 Lean. Nothing is lost on either count: a word determines its instance up to everything 360 the construction looks at, so the correctness statement below does not mention the choice; 361 what has to be computable is the machine program. -/ 362 noncomputable def reduce (x : List ℕ) : List ℕ := 363 if h : ∃ G, MulticolouredClique.EncodesInstance x G then emit h.choose else noWord 364 365 /-- **The reduction lands in the domain of the scheduling problem.** Every word it emits 366 presents an instance together with a threshold. -/ 367 axiom reduce_maps (x : List ℕ) : 368 reduce x ∈ Lax888481.InstanceEncoding.DecisionInstances 369 370 /-- **The reduction is correct.** A word encodes a graph with a multicoloured clique 371 exactly when the word it is sent to presents an instance meeting its threshold. 372 373 No well-formedness hypothesis is needed: a word that encodes no graph satisfies neither 374 side, the left because there is no graph to have a clique and the right because the word 375 it is sent to has a job it cannot run. -/ 376 axiom reduce_correct (x : List ℕ) : 377 (∃ G, MulticolouredClique.EncodesInstance x G ∧ G.HasMulticolouredClique) ↔ 378 ∃ I W, Lax888481.InstanceEncoding.EncodesDecisionInstance (reduce x) I W ∧ 379 I.HasWeight W 380 381 /-- **The reduction raises the parameter by a function of it alone.** The number of 382 machines of the image is , where — the parameter of the source — is 383 the last entry of the word. This is the inequality that makes the reduction a 384 parameterized one rather than merely a correct one. -/ 385 axiom reduce_param (x : List ℕ) : 386 Lax888481.InstanceEncoding.machineCount (reduce x) ≤ (x.getLast?.getD 0).choose 2 + 1 387 388 end Lax888481.Construction1 389 - def✓
-
no assumptions
Section 3 of the paper, joined to the archive's shapes.
The argument itself — Observation 3, Lemma 1 and Lemma 2 — is the paper's, proved over the paper's own presentation: an abstract finite vertex type, and jobs and machines named structurally as sums and subtypes. Three translations carry it to the numbered instance the concept builds. is the instance shape, and on it the two notions of multicoloured clique are the same proposition. is the order , which the paper assumes exists and the concept fixes by ranking vertices by colour and breaking ties by index. And is the numbering: the machines correspond exactly, the jobs embed, and the slots outside that embedding carry inert jobs — weight zero and no eligible machine at all, so feasibility alone forces a schedule to reject them and they change neither side.
The padding is the cost of indexing by all ordered pairs. A closed-form job index is two divisions, where enumerating only the edges of the graph would be a search; the cost is edge slots of which only the edges are jobs, and is where it is paid.
-
Interval Scheduling Is W[1]-Hard for the Number of Machines
Multicoloured Clique, parameterized by the number of colours, fpt-reduces to interval scheduling with eligible machine sets, parameterized by the number of machines.
Multicoloured Clique is W[1]-complete (Fellows, Hermelin, Rosamond and Vialette 2009), so this says that interval scheduling with eligible machine sets is W[1]-hard for . It is therefore fixed-parameter tractable only if , which is not believed: no algorithm solves it in time unless the hierarchy collapses. The third theorem of this submission shows that adding to the parameter does make the problem tractable, so the two results together locate the boundary.
The reduction turns an instance with colours into a scheduling instance on machines — one for each pair of colours, which selects an edge between those two colour classes, and one validation machine. The parameter of the image depends on the parameter of the source alone, so the reduction is an fpt-reduction and not merely a correct one.
1 import Lax888481.MulticolouredClique 2 import Lax888481.SchedulingProblems 3 … module docstring, 41 lines 45 46 namespace Lax888481.Theorem1 47 48 open Lax888481.ParameterizedComplexity 49 50 /-- **Theorem 1.** Multicoloured Clique fpt-reduces to interval scheduling with eligible 51 machine sets, parameterized by the number of machines. -/ 52 axiom mcc_fptReduces_byMachines : 53 MulticolouredClique.problem ≤fpt SchedulingProblems.byMachines 54 55 end Lax888481.Theorem1 56 -
(3,4)-Satisfiability
(3,4)-SAT is satisfiability restricted to formulas in which every clause contains exactly three literals and every variable occurs at most four times. Tovey proved that it is NP-hard; it is the starting point of the second theorem of this submission, because the bounded number of occurrences is what keeps the processing times of the scheduling instance the reduction builds bounded by an absolute constant.
1 import Lax429075.Reductions 2 import Lax429075.Satisfiability 3 import Lax888481.NPHardness 4 … module docstring, 20 lines 25 26 namespace Lax888481.SatVariant 27 28 open Lax429075.CNF Lax434930.PolynomialTime 29 30 /-- The number of occurrences of the variable `i` in the formula `F`. -/ 31 def occurrences (F : Formula) (i : ℕ) : ℕ := 32 (F.flatMap fun C => C.filter fun l => l.index == i).length 33 34 /-- The variables occurring in `F`. -/ 35 def occurringVars (F : Formula) : List ℕ := (F.flatMap id).map Literal.index 36 37 /-- `F` is a *(3,4)* formula: every clause has exactly three literals, and every variable 38 occurs at most four times. -/ 39 def Exact34 (F : Formula) : Prop := 40 (∀ C ∈ F, C.length = 3) ∧ ∀ i ∈ occurringVars F, occurrences F i ≤ 4 41 42 /-- **(3,4)-SAT** as a language: the encodings of satisfiable (3,4) 43 formulas. -/ 44 def SAT34 : Language := 45 {w | ∃ F : Formula, Lax429075.Encoding.encodeCNF F = w ∧ Exact34 F ∧ Satisfiable F} 46 47 /-- **Tovey's theorem.** (3,4)-SAT is NP-hard. 48 49 Tovey, *A simplified NP-complete satisfiability problem*, Discrete Applied Mathematics 8 50 (1984) 85–89. -/ 51 axiom sat34_npHard : 52 ∀ A : Language, A ∈ Lax434930.NondeterministicPolynomialTime.NP → 53 Lax429075.Reductions.ManyOne A SAT34 54 55 end Lax888481.SatVariant 56 -
Word Encoding of a (3,4) Formula
A formula is handed to a word random access machine as a word of numbers: the number of variables, the number of clauses, then three blocks of three numbers per clause, one block per literal, giving the variable it mentions, whether the occurrence is positive, and which of the four occurrences of that variable it is.
1 import Lax888481.ParameterizedComplexity 2 … module docstring, 35 lines 38 39 namespace Lax888481.Exact34Encoding 40 41 /-- The number of variables declared by a word: its first entry. -/ 42 def varCount (x : List ℕ) : ℕ := x.getD 0 0 43 44 /-- The number of clauses declared by a word: its second entry. -/ 45 def clauseCount (x : List ℕ) : ℕ := x.getD 1 0 46 47 /-- The variable of literal `h` of clause `c`. -/ 48 def litVar (x : List ℕ) (c h : ℕ) : ℕ := x.getD (2 + 9 * c + 3 * h) 0 49 50 /-- The sign of literal `h` of clause `c`: `1` when the occurrence is positive. -/ 51 def litSign (x : List ℕ) (c h : ℕ) : ℕ := x.getD (2 + 9 * c + 3 * h + 1) 0 52 53 /-- Which of the four occurrences of its variable literal `h` of clause `c` is. -/ 54 def litApp (x : List ℕ) (c h : ℕ) : ℕ := x.getD (2 + 9 * c + 3 * h + 2) 0 55 56 /-- The word `x` is a `(3,4)` formula: two header entries followed by nine 57 numbers per clause, every variable in range, every appearance index below four, 58 distinct occurrences of one variable carrying distinct appearance indices, and no more 59 variables declared than there are literal slots to hold them. -/ 60 structure WellFormed (x : List ℕ) : Prop where 61 /-- The word consists of the header and three numbers per literal. -/ 62 length_eq : x.length = 2 + 9 * clauseCount x 63 /-- Every literal mentions a declared variable. -/ 64 var_lt : ∀ c < clauseCount x, ∀ h < 3, litVar x c h < varCount x 65 /-- Every appearance index is one of four. -/ 66 app_lt : ∀ c < clauseCount x, ∀ h < 3, litApp x c h < 4 67 /-- Every declared variable occurs in some clause. There are `3C` literal slots, so a 68 formula in which every variable occurs has at most `3C` of them. -/ 69 var_le : varCount x ≤ 3 * clauseCount x 70 /-- Distinct occurrences of one variable carry distinct appearance indices. -/ 71 app_inj : ∀ c < clauseCount x, ∀ h < 3, ∀ c' < clauseCount x, ∀ h' < 3, 72 litVar x c h = litVar x c' h' → litApp x c h = litApp x c' h' → c = c' ∧ h = h' 73 74 /-- The assignment `τ` satisfies the formula `x`: every clause owns a literal whose sign 75 agrees with `τ`. -/ 76 def Satisfies (x : List ℕ) (τ : ℕ → Bool) : Prop := 77 ∀ c < clauseCount x, ∃ h < 3, (litSign x c h = 1) = τ (litVar x c h) 78 79 /-- The words encoding a `(3,4)` formula. -/ 80 def Formulas : Set (List ℕ) := {x | WellFormed x} 81 82 /-- **(3,4)-SAT**, as a set of words. -/ 83 def Satisfiable : Set (List ℕ) := {x | WellFormed x ∧ ∃ τ, Satisfies x τ} 84 85 end Lax888481.Exact34Encoding 86 -
Construction 2
The scheduling instance built from a formula. Each variable gets two machines, one for each truth value, and one job spanning a fixed window of length . Each clause gets three machines, and each of its three literal occurrences gets three jobs: a unit job whose deadline records which occurrence of its variable it is and which literal of its clause, flanked by two jobs filling the rest of the window.
The window is what makes the construction work. A variable job overlaps every job of every occurrence of its variable, so a schedule that places all of them must put the variable job on one of the two machines of its variable, and that choice is the truth value. The bounded number of occurrences of a variable is what keeps the window, and with it every processing time, bounded by an absolute constant.
- def✓
Lax888481.Construction2(1st statement) - def✓
Lax888481.Construction2(2nd statement) - def✓
Lax888481.Construction2(3rd statement) - def✓
Lax888481.Construction2(4th statement) - def✓
Lax888481.Construction2(5th statement) - def✓
Lax888481.Construction2(6th statement) - def✓
Lax888481.Construction2(7th statement) - def✓
Lax888481.Construction2(8th statement)
1 import Lax888481.Exact34Encoding 2 import Lax888481.InstanceEncoding 3 import Lax759944.RamPolytime 4 import Mathlib.Data.Finset.Lattice.Fold 5 … module docstring, 36 lines 42 43 namespace Lax888481.Construction2 44 45 open Lax888481.Scheduling Lax888481.Exact34Encoding 46 47 variable (x : List ℕ) 48 49 /-- The number of variables the word declares. -/ 50 abbrev nVar : ℕ := varCount x 51 52 /-- The number of clauses the word declares. -/ 53 abbrev nCla : ℕ := clauseCount x 54 55 /-- One job per variable and nine per clause. -/ 56 def nJobs : ℕ := nVar x + 9 * nCla x 57 58 /-- Two machines per variable and three per clause. -/ 59 def nMach : ℕ := 2 * nVar x + 3 * nCla x 60 61 /-- The deadline of the literal job of occurrence `h` of clause `c`, clamped to the 62 range `[2, 24]` it already lies in on a well-formed word. -/ 63 def dl (c h : ℕ) : ℕ := min 24 (max 2 (2 * (litApp x c h + 1) + 8 * h)) 64 65 lemma dl_ge (c h : ℕ) : 2 ≤ dl x c h := by 66 simp only [dl]; omega 67 68 lemma dl_le (c h : ℕ) : dl x c h ≤ 24 := by 69 simp only [dl]; omega 70 71 /-- On a well-formed word the clamp is inactive: the deadline is the formula's own 72 `2(k+1) + 8h`. -/ 73 lemma dl_eq_of_lt {c h : ℕ} (happ : litApp x c h < 4) (hh : h < 3) : 74 dl x c h = 2 * (litApp x c h + 1) + 8 * h := by 75 simp only [dl]; omega 76 77 variable {x} 78 79 /-- The clause of job index `i` counted from the first clause job. -/ 80 def cOf (i : ℕ) : ℕ := i / 9 81 82 /-- The literal of job index `i` counted from the first clause job. -/ 83 def hOf (i : ℕ) : ℕ := i % 9 / 3 84 85 /-- The slot of job index `i` counted from the first clause job. -/ 86 def sOf (i : ℕ) : ℕ := i % 3 87 88 variable (x) 89 90 /-- The processing time of job `j`. -/ 91 def procOf (j : ℕ) : ℕ := 92 if j < nVar x then 25 93 else 94 match sOf (j - nVar x) with 95 | 0 => 1 96 | 1 => dl x (cOf (j - nVar x)) (hOf (j - nVar x)) - 1 97 | _ => 25 - dl x (cOf (j - nVar x)) (hOf (j - nVar x)) 98 99 /-- The deadline of job `j`. -/ 100 def dueOf (j : ℕ) : ℕ := 101 if j < nVar x then 25 102 else 103 match sOf (j - nVar x) with 104 | 0 => dl x (cOf (j - nVar x)) (hOf (j - nVar x)) 105 | 1 => dl x (cOf (j - nVar x)) (hOf (j - nVar x)) - 1 106 | _ => 25 107 108 /-- The machines eligible to run job `j`, as a list of machine numbers. -/ 109 def eligOf (j : ℕ) : List ℕ := 110 if j < nVar x then [2 * j, 2 * j + 1] 111 else 112 let i := j - nVar x 113 let base := 2 * nVar x + 3 * cOf i 114 match sOf i with 115 | 0 => [base + 1, base + 2, 116 2 * litVar x (cOf i) (hOf i) + (if litSign x (cOf i) (hOf i) = 1 then 0 else 1)] 117 | _ => [base, base + 1, base + 2] 118 119 lemma procOf_pos (j : ℕ) : 0 < procOf x j := by 120 unfold procOf 121 split 122 · omega 123 · have h1 := dl_ge x (cOf (j - nVar x)) (hOf (j - nVar x)) 124 have h2 := dl_le x (cOf (j - nVar x)) (hOf (j - nVar x)) 125 match hs : sOf (j - nVar x) with 126 | 0 => simp 127 | 1 => simp <;> omega 128 | (k + 2) => simp <;> omega 129 130 lemma procOf_le_dueOf (j : ℕ) : procOf x j ≤ dueOf x j := by 131 unfold procOf dueOf 132 split 133 · omega 134 · have h1 := dl_ge x (cOf (j - nVar x)) (hOf (j - nVar x)) 135 have h2 := dl_le x (cOf (j - nVar x)) (hOf (j - nVar x)) 136 match hs : sOf (j - nVar x) with 137 | 0 => simp <;> omega 138 | 1 => simp 139 | (k + 2) => simp <;> omega 140 141 lemma procOf_le_25 (j : ℕ) : procOf x j ≤ 25 := by 142 unfold procOf 143 split 144 · omega 145 · have h1 := dl_ge x (cOf (j - nVar x)) (hOf (j - nVar x)) 146 have h2 := dl_le x (cOf (j - nVar x)) (hOf (j - nVar x)) 147 match hs : sOf (j - nVar x) with 148 | 0 => simp 149 | 1 => simp <;> omega 150 | (k + 2) => simp <;> omega 151 152 /-- **Construction 2.** The scheduling instance built from the word `x`. -/ 153 def inst : Instance where 154 jobs := nJobs x 155 machines := nMach x 156 p j := procOf x j 157 d j := dueOf x j 158 w _ := 1 159 eligible j := Finset.univ.filter fun i : Fin (nMach x) => (i : ℕ) ∈ eligOf x j 160 p_pos j := procOf_pos x j 161 p_le_d j := procOf_le_dueOf x j 162 163 @[simp] lemma inst_jobs : (inst x).jobs = nJobs x := rfl 164 @[simp] lemma inst_machines : (inst x).machines = nMach x := rfl 165 @[simp] lemma inst_p (j : Fin (nJobs x)) : (inst x).p j = procOf x j := rfl 166 @[simp] lemma inst_d (j : Fin (nJobs x)) : (inst x).d j = dueOf x j := rfl 167 168 169 /-- Where job `j`'s block of eligible machines begins. -/ 170 def offOf (j : ℕ) : ℕ := 171 if j ≤ nVar x then 2 * j else 2 * nVar x + 3 * (j - nVar x) 172 173 /-- The processing-time block. -/ 174 def procBlock : List ℕ := (List.range (nJobs x)).map (procOf x) 175 176 /-- The deadline block. -/ 177 def dueBlock : List ℕ := (List.range (nJobs x)).map (dueOf x) 178 179 /-- The weight block: every job has weight one. -/ 180 def wtBlock : List ℕ := List.replicate (nJobs x) 1 181 182 /-- The offset block, one entry per job and one more. -/ 183 def offBlock : List ℕ := (List.range (nJobs x + 1)).map (offOf x) 184 185 /-- The target block: the eligible machines of each job in turn. -/ 186 def tgtBlock : List ℕ := (List.range (nJobs x)).flatMap (eligOf x) 187 188 /-- **The word Construction 2 emits.** -/ 189 def emit : List ℕ := 190 [nJobs x, nMach x] ++ procBlock x ++ dueBlock x ++ wtBlock x ++ offBlock x ++ tgtBlock x 191 192 /-- The word a malformed input is sent to: one job, no machine, so its only job cannot 193 be scheduled. -/ 194 def noWord : List ℕ := [1, 0, 1, 1, 1, 0, 0] 195 196 /-- **Construction 2 as a total map on words.** A word that is not a well-formed formula 197 is sent to a fixed instance that cannot schedule every job. A reduction is a function on 198 all words, and the machine that computes it has to decide which case it is in; making the 199 diversion part of the map rather than a side condition is what keeps the statement below 200 free of hypotheses. 201 202 The case split is on a proposition rather than on a decision procedure, so the map is 203 `noncomputable` in Lean. Nothing is lost: what has to be computable is the machine 204 program, and the statement that one computes this map is `reduce_computesInTime`. -/ 205 noncomputable def reduce (x : List ℕ) : List ℕ := 206 open Classical in 207 if Lax888481.Exact34Encoding.WellFormed x then emit x else noWord 208 209 /-- Every weight of the constructed instance is `1`. -/ 210 axiom weights_one (x : List ℕ) (j : Fin (inst x).jobs) : (inst x).w j = 1 211 212 /-- Every processing time of the constructed instance is at most `25`. -/ 213 axiom pmax_le (x : List ℕ) : (inst x).pmax ≤ 25 214 215 /-- **Construction 2 is correct.** A well-formed `(3,4)` formula is satisfiable 216 exactly when every job of the instance it builds can be scheduled. -/ 217 axiom correct (x : List ℕ) (hwf : Lax888481.Exact34Encoding.WellFormed x) : 218 (∃ τ, Lax888481.Exact34Encoding.Satisfies x τ) ↔ (inst x).AllSchedulable 219 220 /-- **The emitted word encodes the constructed instance.** -/ 221 axiom emit_encodes (x : List ℕ) (hwf : Lax888481.Exact34Encoding.WellFormed x) : 222 Lax888481.InstanceEncoding.EncodesInstance (emit x) (inst x) 223 224 /-- **The reduction is correct.** A word is a satisfiable `(3,4)` formula exactly 225 when the instance it is sent to can schedule every job. -/ 226 axiom reduce_correct (x : List ℕ) : 227 x ∈ Lax888481.Exact34Encoding.Satisfiable ↔ 228 ∃ I, Lax888481.InstanceEncoding.EncodesInstance (reduce x) I ∧ I.AllSchedulable 229 230 /-- **The reduction lands in the bounded slice.** Every instance it emits has processing 231 times at most `25` and unit weights. -/ 232 axiom reduce_slice (x : List ℕ) : 233 ∃ I, Lax888481.InstanceEncoding.EncodesInstance (reduce x) I ∧ 234 I.pmax ≤ 25 ∧ ∀ j, I.w j = 1 235 236 open Lax759944.RamPolytime in 237 /-- **The reduction runs in polynomial time.** One word RAM program computes the map on 238 every word — well-formed or not — within a polynomial number of instructions in the bit 239 size of its input. 240 241 This is the running-time half of the reduction, and it is the half the hardness 242 statements need, so it is stated in their currency: `Lax759944.RamPolytime` measures the 243 input by its bit size rather than by the number of entries, hands the machine the input 244 preceded by its length, and is proved in that submission to be interchangeable with 245 polynomial time on a Turing machine. The statement about the emitter alone, 246 `emit_computesInTime`, is the same claim in the archive's word-RAM currency and on 247 well-formed input only; it is the part of this one that does the work, and deciding 248 well-formedness is what the rest of it adds. 249 250 Deciding well-formedness is not a formality. The condition that distinct occurrences of 251 one variable carry distinct appearance indices is a disjointness condition on `3C` 252 pairs, and it is decidable in one pass only because the pairs live in a universe of size 253 `4V`: an occurrence is bucketed at `4v + k`, and a bucket claimed twice refutes it. -/ 254 axiom reduce_ramPolytime : RamPolytime reduce 255 256 open Lax808846.Ram Lax808846.RamComputes Lax888481.ParameterizedComplexity in 257 /-- **Construction 2 runs in linear time.** One word RAM program and one constant `c` 258 such that, at every word length, on every well-formed formula whose entries fit, the 259 program halts within `c · (|x| + 1)` instructions having written `emit x`. -/ 260 axiom emit_computesInTime : 261 ∃ (prog : Program) (c : ℕ), ∀ w : ℕ, 262 ComputesInTime w prog 263 {y | Lax888481.Exact34Encoding.WellFormed y ∧ Fits c w y} 264 emit (fun y => c * (y.length + 1)) 265 266 end Lax888481.Construction2 267 - def✓
-
no assumptions
The two halves of the paper's Section 4. From a satisfying assignment, builds the schedule: each variable job goes on the machine opposing its value, freeing the agreeing machine for the selected literal of every clause that variable satisfies, and the remaining jobs of a clause are distributed over its own three machines by the transposition exchanging the selected literal with the first.
Conversely reads the assignment off a schedule. first shows that the two wrapper jobs of each literal share a machine — all three wrappers of one side pairwise overlap, so they are spread bijectively over the clause's machines, and the evenness of the deadlines forces that bijection to be the identity. Machine of the clause is then blocked for two literals, and the third literal job has nowhere to go but its variable machine, which pins the variable job to the opposite one.
-
Scheduling Every Job Is Hard for Constant Processing Times and Unit Weights
Deciding whether every job of an interval scheduling instance can be scheduled is NP-hard, and remains so on instances in which every processing time is at most and every weight is .
The bound on the processing times is absolute: it does not grow with the instance. So the problem is para-NP-hard for the parameter , and no algorithm running in time can exist for any function unless . Together with the third theorem, which is fixed-parameter tractable for , this shows that neither half of that combined parameter can be dropped.
The reduction is from -satisfiability. It gives each variable two machines, one for each truth value, and each clause three; each occurrence of a variable in a clause becomes a unit job flanked by two jobs filling the rest of a fixed window of length , and each variable becomes one job spanning that whole window. The bounded number of occurrences of a variable is what keeps the window, and with it every processing time, bounded by a constant.
- thm✓
Lax888481.Theorem2(1st statement) - thm✓
Lax888481.Theorem2(2nd statement) - thm✓
Lax888481.Theorem2(3rd statement)
1 import Lax888481.Exact34Encoding 2 import Lax888481.PolynomialReduction 3 import Lax888481.SatVariant 4 import Lax888481.SchedulingProblems 5 … module docstring, 46 lines 52 53 namespace Lax888481.Theorem2 54 55 open Lax888481.Scheduling Lax888481.NPHardness Lax888481.PolynomialReduction 56 57 /-- The words encoding an instance in which every processing time is at most `25` and 58 every weight is `1`. -/ 59 def BoundedSlice (y : List ℕ) : Prop := 60 ∃ I : Instance, InstanceEncoding.EncodesInstance y I ∧ 61 I.pmax ≤ 25 ∧ ∀ j, I.w j = 1 62 63 /-- **Construction 2.** `(3,4)`-satisfiability reduces in polynomial time to 64 scheduling every job, by a reduction whose every output has processing times at most 65 `25` and unit weights. -/ 66 axiom sat34_polyReducesOn_allSchedulable : 67 PolyReducesOn Exact34Encoding.Satisfiable 68 {y | ∃ I, InstanceEncoding.EncodesInstance y I ∧ I.AllSchedulable} 69 BoundedSlice 70 71 /-- **Theorem 2.** Deciding whether every job can be scheduled is NP-hard. -/ 72 axiom npHard_allSchedulable : NPHard Instance.AllSchedulable 73 74 /-- **Theorem 2, on the bounded slice.** Deciding whether every job can be scheduled is 75 NP-hard already on instances whose processing times are at most `25` and whose weights 76 are all `1` — so the problem is para-NP-hard for the parameter `p_max`. -/ 77 axiom npHardOn_allSchedulable_pmax_le : 78 NPHardOn Instance.AllSchedulable 79 fun I => I.pmax ≤ 25 ∧ ∀ j, I.w j = 1 80 81 end Lax888481.Theorem2 82 - thm✓
-
Preprocessing an Interval Scheduling Instance Down to a Bounded Number of Live Jobs
The step that makes the dynamic program fixed-parameter tractable. Two jobs with the same processing time and the same deadline occupy the same interval, so on any one machine they are interchangeable; of the jobs sharing an interval and eligible on a given machine, only the heaviest can ever be useful, because a schedule places at most of them at once and a lighter one can always be exchanged for a heavier unused one. Keeping, for each machine, the best jobs of each interval eligible there, and discarding the rest, leaves the optimum unchanged.
What the step buys is a bound independent of the number of jobs. A job alive at time has a deadline in and a processing time in , so there are at most intervals it could occupy; each interval keeps at most jobs per machine and there are machines. So at most surviving jobs are alive at any one instant — a bound in the parameter alone. Fed into the state-space bound of the dynamic program, this makes the table's size a function of and .
1 import Lax888481.DynamicProgram 2 … module docstring, 38 lines 41 42 namespace Lax888481.Preprocessing 43 44 open Lax888481.Scheduling Lax888481.Scheduling.Instance Lax888481.DynamicProgram 45 46 variable (I : Instance) 47 48 /-- `j` is strictly better than `j'`: heavier, or equally heavy and earlier in index 49 order. -/ 50 def Better (j j' : Fin I.jobs) : Prop := 51 I.w j' < I.w j ∨ (I.w j' = I.w j ∧ (j : ℕ) < (j' : ℕ)) 52 53 instance (j j' : Fin I.jobs) : Decidable (Better I j j') := 54 inferInstanceAs (Decidable (_ ∨ _)) 55 56 /-- The jobs occupying the interval `[dd - pp, dd)` that are eligible on machine `i`. -/ 57 def slotOf (i : Fin I.machines) (dd pp : ℕ) : Finset (Fin I.jobs) := 58 Finset.univ.filter fun j => I.d j = dd ∧ I.p j = pp ∧ i ∈ I.eligible j 59 60 /-- The jobs occupying the same interval as `j` that are eligible on machine `i`. -/ 61 def sameSlot (i : Fin I.machines) (j : Fin I.jobs) : Finset (Fin I.jobs) := 62 slotOf I i (I.d j) (I.p j) 63 64 /-- How many jobs of `j`'s slot on machine `i` beat `j`. -/ 65 def rank (i : Fin I.machines) (j : Fin I.jobs) : ℕ := 66 ((sameSlot I i j).filter fun j' => Better I j' j).card 67 68 /-- **The preprocessing step.** Keep a job when, for some machine it is eligible on, it 69 is among the `m` best jobs of its interval there. -/ 70 def keep : Finset (Fin I.jobs) := 71 Finset.univ.filter fun j => ∃ i ∈ I.eligible j, rank I i j < I.machines 72 73 /-- The best weight achievable by a feasible schedule that uses only jobs from `K`. -/ 74 def optimumOn (K : Finset (Fin I.jobs)) : ℕ := 75 (Finset.univ.filter fun σ : I.Schedule => Feasible σ ∧ ∀ j, σ j ≠ none → j ∈ K).sup 76 weight 77 78 /-- **Lemma 5.** Preprocessing does not change the optimum: the best weight achievable 79 using only the kept jobs is the optimum of the whole instance. -/ 80 axiom optimumOn_keep (I : Instance) : optimumOn I (keep I) = optimum I 81 82 /-- **Observation 5.** At most `p_max ^ 2 * m ^ 2` kept jobs are alive at any one 83 instant — a bound in the parameter alone, with no dependence on the number of jobs. -/ 84 axiom card_keep_alive_le (I : Instance) (t : ℕ) : 85 ((keep I).filter fun j => Active t j).card ≤ I.pmax * I.pmax * (I.machines * I.machines) 86 87 end Lax888481.Preprocessing 88 -
no assumptions
One inequality is immediate, since a schedule using only kept jobs is a schedule. The other is the exchange argument: any feasible schedule can be rewritten, one discarded job at a time, into one of no smaller weight that uses only kept jobs.
-
no assumptions
The kept jobs alive at are covered by the intervals with and , and each such interval keeps at most jobs per machine.
-
The Dynamic Program for Interval Scheduling, and Its State Space
The algorithm behind the third theorem. It sweeps the time axis, carrying at each instant a state — which job, if any, occupies each machine — and the best total weight of the jobs started so far that is consistent with that state. A state at time may follow a state at time when every job still running continues on its own machine and every job appearing at that had already started was already there.
Writing for the best weight of jobs started by time over the feasible schedules whose occupancy at is exactly , the recursion is
with the weight of the jobs starts. At the horizon every machine is idle and the value is the optimum of the instance.
The number of states at any instant is at most , where is the number of jobs alive then: a state chooses, for each of the machines, one job alive at or nothing. This is where fixed-parameter tractability comes from — the table is indexed by the parameter, not by the instance — and it is why the preprocessing step, which bounds by a function of and alone, completes the argument.
- def✓
Lax888481.DynamicProgram(1st statement) - def✓
Lax888481.DynamicProgram(2nd statement) - def✓
Lax888481.DynamicProgram(3rd statement)
1 import Lax888481.Scheduling 2 import Mathlib.Algebra.Order.Monoid.WithTop 3 … module docstring, 43 lines 47 48 namespace Lax888481.DynamicProgram 49 50 open Lax888481.Scheduling Lax888481.Scheduling.Instance 51 52 variable (I : Instance) 53 54 /-- A snapshot of the machines at one instant: which job, if any, occupies each. -/ 55 abbrev State : Type := Fin I.machines → Option (Fin I.jobs) 56 57 variable {I} 58 59 /-- Job `j` is running at time `t`, that is `t ∈ [d j - p j, d j)`. -/ 60 def Active (t : ℕ) (j : Fin I.jobs) : Prop := I.start j ≤ t ∧ t < I.d j 61 62 instance (t : ℕ) (j : Fin I.jobs) : Decidable (Active t j) := 63 inferInstanceAs (Decidable (_ ∧ _)) 64 65 instance (j j' : Fin I.jobs) : Decidable (I.Overlap j j') := 66 inferInstanceAs (Decidable (_ ∧ _)) 67 68 instance (σ : I.Schedule) : Decidable (Feasible σ) := 69 inferInstanceAs (Decidable (_ ∧ _)) 70 71 variable (I) 72 73 /-- The value of an optimal schedule. -/ 74 def optimum : ℕ := (Finset.univ.filter fun σ : I.Schedule => Feasible σ).sup weight 75 76 /-- The time horizon: every job has finished by then. -/ 77 def horizon : ℕ := Finset.univ.sup I.d 78 79 /-- The total weight of the scheduled jobs that have started by time `t`. -/ 80 def weightStarted (σ : I.Schedule) (t : ℕ) : ℕ := 81 ∑ j, if σ j ≠ none ∧ I.start j ≤ t then I.w j else 0 82 83 /-- The total weight of the jobs a state shows as *beginning* at time `t`. -/ 84 def freshWeight (t : ℕ) (s : State I) : ℕ := 85 ∑ j, if (∃ i, s i = some j) ∧ I.start j = t then I.w j else 0 86 87 /-- A state that could be the machine occupancy at time `t`: every occupant is eligible 88 and active, and no job occupies two machines. -/ 89 def ValidState (t : ℕ) (s : State I) : Prop := 90 (∀ i j, s i = some j → i ∈ I.eligible j ∧ Active t j) ∧ 91 (∀ i i' j, s i = some j → s i' = some j → i = i') 92 93 instance (t : ℕ) (s : State I) : Decidable (ValidState I t s) := 94 inferInstanceAs (Decidable (_ ∧ _)) 95 96 /-- The transition relation: state `s` at time `t` may be followed by state `s'` at time 97 `t + 1`. A job still running continues on its machine, and a job appearing at `t + 1` 98 that had already started must have been there at `t`. -/ 99 def Step (t : ℕ) (s s' : State I) : Prop := 100 ValidState I (t + 1) s' ∧ 101 (∀ i j, s i = some j → t + 1 < I.d j → s' i = some j) ∧ 102 (∀ i j, s' i = some j → I.start j ≤ t → s i = some j) 103 104 instance (t : ℕ) (s s' : State I) : Decidable (Step I t s s') := 105 inferInstanceAs (Decidable (_ ∧ _)) 106 107 variable {I} 108 109 /-- The machine occupancy at time `t` of the schedule `σ`. -/ 110 noncomputable def runOf (σ : I.Schedule) (t : ℕ) : State I := fun i => 111 if h : ∃ j, σ j = some i ∧ Active t j then some h.choose else none 112 113 variable (I) 114 115 /-- The best total weight of jobs started by time `t`, over the feasible schedules whose 116 machine occupancy at time `t` is exactly `s`. `⊥` when there is no such schedule. -/ 117 noncomputable def optAt (t : ℕ) (s : State I) : WithBot ℕ := 118 open Classical in 119 (Finset.univ.filter fun σ : I.Schedule => Feasible σ ∧ runOf σ t = s).sup 120 fun σ => (weightStarted I σ t : WithBot ℕ) 121 122 /-- **The dynamic program.** A recursion on the time index: the value of a state at 123 `t + 1` is the best value of a predecessor, plus the weight of the jobs beginning then. -/ 124 def dp : ℕ → State I → WithBot ℕ 125 | 0, s => if ValidState I 0 s then (freshWeight I 0 s : WithBot ℕ) else ⊥ 126 | t + 1, s' => 127 ((Finset.univ.filter fun s => Step I t s s').sup fun s => dp t s) 128 + (freshWeight I (t + 1) s' : WithBot ℕ) 129 130 /-- The value the algorithm returns: the table at the horizon, with every machine idle. -/ 131 def solve : WithBot ℕ := dp I (horizon I) fun _ => none 132 133 /-- The number of jobs alive at time `t`. -/ 134 def aliveCount (t : ℕ) : ℕ := (Finset.univ.filter fun j => Active (I := I) t j).card 135 136 /-- **Lemma 6.** The recursion computes the specification: at every instant and every 137 state, the dynamic program's value is the best weight of jobs started by then over the 138 feasible schedules with that occupancy. -/ 139 axiom dp_eq_optAt (I : Instance) (t : ℕ) (s : State I) : dp I t s = optAt I t s 140 141 /-- **Theorem 3, algorithmic half.** The dynamic program returns the optimum of the 142 instance. -/ 143 axiom solve_eq_optimum (I : Instance) : solve I = (optimum I : WithBot ℕ) 144 145 /-- **The state-space bound.** At any instant there are at most `(a_t + 1) ^ m` valid 146 states, where `a_t` is the number of jobs alive then. -/ 147 axiom card_validState_le (I : Instance) (t : ℕ) : 148 (Finset.univ.filter fun s : State I => ValidState I t s).card 149 ≤ (aliveCount I t + 1) ^ I.machines 150 151 end Lax888481.DynamicProgram 152 - def✓
-
no assumptions
Lemma 6, by induction on the time index: the base case is , which realises a state at time zero by the schedule that places exactly its occupants, and the step is , which matches each predecessor state against the schedules extending it.
-
Interval Scheduling Is Fixed-Parameter Tractable for the Machines and the Largest Processing Time
Interval scheduling with eligible machine sets is fixed-parameter tractable for the combined parameter . There are one word RAM program and one constant such that, at every word length admitting the input and the configuration table, the program halts within
instructions and writes if a feasible schedule of weight at least exists and if none does.
The algorithm sweeps the time axis. At each point it records, for every machine, how much longer that machine stays busy (a vector of numbers, each at most ) and the best weight achieving that configuration. A preprocessing step first discards all but a bounded number of jobs per starting time, so the number of jobs alive at any moment, and hence the number of reachable configurations, is bounded by a function of the parameter alone.
Together with the first theorem, which rules out fixed-parameter tractability for alone unless , and the second, which rules it out for alone unless , this locates the problem: the combined parameter is tractable and neither half of it is.
1 import Lax888481.SchedulingProblems 2 … module docstring, 53 lines 56 57 namespace Lax888481.Theorem3 58 59 open Lax808846.Ram Lax808846.RamComputes 60 open Lax888481.InstanceEncoding Lax888481.SchedulingProblems Lax888481.ParameterizedComplexity 61 62 open Classical in 63 /-- **Theorem 3.** One word RAM program decides interval scheduling with eligible machine 64 sets within `c * (m * p_max + 1) ^ (2 * m) * (m + 1) * (|x| + 1)` instructions, at every 65 word length admitting the instance and a table indexed by machine configurations. 66 67 The paper states the bound as `O((m · p_max)^{2m} · m · n)`. Written with an explicit 68 constant, the product needs the `+1`s: with no machines, or with no jobs, `(m · p_max)^{2m} · m` 69 is zero, and no program answers in zero instructions. Apart from those terms, the bound differs 70 from the paper's in measuring the input by `|x|` instead of `n`. -/ 71 axiom fptTime_byMachinesAndPmax : 72 ∃ (prog : Program) (c : ℕ), ∀ w : ℕ, 73 ComputesInTime w prog 74 {x | x ∈ DecisionInstances ∧ Fits c w x ∧ 75 c * (machineCount x * pmaxOf x + 1) ^ (2 * machineCount x) ≤ 2 ^ w} 76 (fun x => if byMachinesAndPmax.Yes x then [1] else [0]) 77 (fun x => c * (machineCount x * pmaxOf x + 1) ^ (2 * machineCount x) * 78 (machineCount x + 1) * (x.length + 1)) 79 80 /-- **Theorem 3**, in the general form: the problem parameterized by `m + p_max` is 81 fixed-parameter tractable. 82 83 It does not follow from the explicit bound by weakening the function of the parameter, 84 because `FPT` asks for an answer on every word whose entries fit, and there the table need not 85 be addressable. Where it is not, the proof tries every schedule, and the function of the 86 parameter is much larger than `(m · p_max)^{2m}`. -/ 87 axiom fpt_byMachinesAndPmax : FPT byMachinesAndPmax 88 89 end Lax888481.Theorem3 90
Loading the paper…