-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
293 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Google.OrTools.LinearSolver; | ||
using System; | ||
|
||
namespace TaskAssigner | ||
{ | ||
public class Assigner | ||
{ | ||
private readonly Solver solver_; | ||
|
||
public Assigner(Solver solver) | ||
{ | ||
this.solver_ = solver ?? throw new ArgumentNullException(nameof(solver)); | ||
} | ||
|
||
public AssignmentDescription Solve(AssignmentDescription assignment) | ||
{ | ||
if (assignment is null) | ||
{ | ||
throw new ArgumentNullException(nameof(assignment)); | ||
} | ||
|
||
var assignerCore = new AssignerCore(this.solver_, assignment); | ||
return assignerCore.Run(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
using Google.OrTools.LinearSolver; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
|
||
namespace TaskAssigner | ||
{ | ||
public class AssignerCore | ||
{ | ||
private readonly Solver solver_; | ||
private readonly AssignmentDescription assignment_; | ||
private readonly int[,] costs_; | ||
private readonly Variable[,] variables_; | ||
|
||
// TODO(zhangshuai.ds): Pass in 3 policies. | ||
public AssignerCore(Solver solver, AssignmentDescription assignment) | ||
{ | ||
this.solver_ = solver ?? throw new ArgumentNullException(nameof(solver)); | ||
this.assignment_ = assignment ?? throw new ArgumentNullException(nameof(assignment)); | ||
this.costs_ = this.ComputeCosts(assignment); | ||
this.variables_ = this.solver_.MakeBoolVarMatrix(assignment.Nodes.Count, assignment.Tasks.Count); | ||
} | ||
|
||
public AssignmentDescription Run() | ||
{ | ||
this.AddObjective(); | ||
this.AddConstraints(); | ||
|
||
Solver.ResultStatus status = this.solver_.Solve(); | ||
if (status == Solver.ResultStatus.OPTIMAL) | ||
{ | ||
var result = new AssignmentDescription(); | ||
|
||
foreach (NodeDescription n in this.assignment_.Nodes) | ||
{ | ||
result.Nodes.Add(n); | ||
} | ||
|
||
foreach (TaskDescription t in this.assignment_.Tasks) | ||
{ | ||
result.Tasks.Add(t); | ||
} | ||
|
||
for (int i = 1; i < this.assignment_.Nodes.Count; i++) | ||
{ | ||
for (int j = 0; j < this.assignment_.Tasks.Count; j++) | ||
{ | ||
if (this.variables_[i, j].SolutionValue() > 0) | ||
{ | ||
if (!result.Assignments.TryGetValue(i, out ISet<int> tasks)) | ||
{ | ||
tasks = new HashSet<int>(); | ||
result.Assignments.Add(i, tasks); | ||
} | ||
tasks.Add(j); | ||
Console.WriteLine($"Task {j} assigned to node {i} with cost {this.costs_[i, j]}."); | ||
} | ||
} | ||
} | ||
Console.WriteLine($"Total cost is {this.solver_.Objective().Value()}"); | ||
|
||
return result; | ||
} | ||
|
||
throw new NotImplementedException($"Not implemented for status: {status}"); | ||
} | ||
|
||
protected int[,] ComputeCosts(AssignmentDescription assignment) | ||
{ | ||
int[,] costs = new int[assignment.Nodes.Count, assignment.Tasks.Count]; | ||
for (int j = 0; j < assignment.Tasks.Count; j++) | ||
{ | ||
costs[0, j] = 500; // UNASSIGNED cost | ||
if (assignment.Assignments[0].Contains(j)) // Not assigned yet. | ||
{ | ||
for (int i = 1; i < assignment.Nodes.Count; i++) | ||
{ | ||
costs[i, j] = 0; // No fee for assignment. | ||
} | ||
} | ||
else | ||
{ | ||
for (int i = 1; i < assignment.Nodes.Count; i++) | ||
{ | ||
if (assignment.Assignments[i].Contains(j)) | ||
{ | ||
costs[i, j] = 0; // Don't move. | ||
} | ||
else | ||
{ | ||
costs[i, j] = 200; // Moving cost. | ||
} | ||
} | ||
} | ||
} | ||
return costs; | ||
} | ||
|
||
protected void AddObjective() | ||
{ | ||
var movingCosts = new LinearExpr(); | ||
for (int i = 0; i < this.assignment_.Nodes.Count; i++) | ||
{ | ||
for (int j = 0; j < this.assignment_.Tasks.Count; j++) | ||
{ | ||
movingCosts += this.costs_[i, j] * this.variables_[i, j]; | ||
} | ||
} | ||
|
||
// TODO(zhangshuai.ds): Computes it. | ||
var imbalanceCosts = new LinearExpr(); | ||
|
||
// TODO(zhangshuai.ds): Add coefficients for the two costs. | ||
this.solver_.Minimize(movingCosts + imbalanceCosts); | ||
} | ||
|
||
protected void AddConstraints() | ||
{ | ||
// Each task is assigned to exactly one node (including UNASSIGNED virtual node). | ||
for (int j = 0; j < this.assignment_.Tasks.Count; j++) | ||
{ | ||
LinearExpr expr = Enumerable.Range(0, this.assignment_.Nodes.Count) | ||
.Select(i => this.variables_[i, j]) | ||
.ToArray() | ||
.Sum(); | ||
this.solver_.Add(expr == 1); | ||
} | ||
|
||
// Each worker cannot exceed its capacity. | ||
for (int i = 0; i < this.assignment_.Nodes.Count; i++) | ||
{ | ||
var cpuCores = new LinearExpr(); | ||
var memoryMiB = new LinearExpr(); | ||
|
||
for (int j = 0; j < this.assignment_.Tasks.Count; j++) | ||
{ | ||
cpuCores += this.variables_[i, j] * this.assignment_.Tasks[j].CpuCores; | ||
memoryMiB += this.variables_[i, j] * this.assignment_.Tasks[j].MemoryMiB; | ||
} | ||
|
||
this.solver_.Add(cpuCores <= this.assignment_.Nodes[i].CpuCores); | ||
this.solver_.Add(memoryMiB <= this.assignment_.Nodes[i].MemoryMiB); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace TaskAssigner | ||
{ | ||
public class AssignmentDescription | ||
{ | ||
// Nodes[0] means UNASSIGNED | ||
public IList<NodeDescription> Nodes { get; } = new List<NodeDescription>(); | ||
|
||
public IList<TaskDescription> Tasks { get; } = new List<TaskDescription>(); | ||
|
||
public IDictionary<int /* nodeIndex */, ISet<int /* taskIndex */>> Assignments { get; } = | ||
new Dictionary<int, ISet<int>>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace TaskAssigner | ||
{ | ||
public class NodeDescription | ||
{ | ||
public int Id { get; set; } | ||
|
||
public int CpuCores { get; set; } | ||
|
||
public int MemoryMiB { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
using Google.OrTools.LinearSolver; | ||
using System.Collections.Generic; | ||
|
||
namespace TaskAssigner | ||
{ | ||
class Program | ||
{ | ||
static void Main() | ||
{ | ||
using var solver = Solver.CreateSolver( | ||
"SimpleMipProgram", | ||
"CBC_MIXED_INTEGER_PROGRAMMING"); | ||
|
||
var assigner = new Assigner(solver); | ||
|
||
var assignment = new AssignmentDescription(); | ||
assignment.Nodes.Add(new NodeDescription | ||
{ | ||
Id = 0, | ||
CpuCores = int.MaxValue, | ||
MemoryMiB = int.MaxValue, | ||
}); | ||
for (int i = 1; i <= 3; i++) | ||
{ | ||
assignment.Nodes.Add(new NodeDescription | ||
{ | ||
Id = i, | ||
CpuCores = 48, | ||
MemoryMiB = 64 << 10, // 64 GiB | ||
}); | ||
} | ||
for (int i = 0; i < 13; i++) | ||
{ | ||
assignment.Tasks.Add(new TaskDescription | ||
{ | ||
Id = i, | ||
CpuCores = 8, | ||
MemoryMiB = 32 << 10, // 32 GiB, CPU:MEM=1:4 | ||
}); | ||
} | ||
for (int i = 0; i < 17; i++) | ||
{ | ||
assignment.Tasks.Add(new TaskDescription | ||
{ | ||
Id = 13 + i, | ||
CpuCores = 16, | ||
MemoryMiB = 32 << 10, // 16 GiB, CPU:MEM=1:2 | ||
}); | ||
} | ||
assignment.Assignments[0] = new HashSet<int>(); | ||
for (int i = 0; i < assignment.Tasks.Count; i++) | ||
{ | ||
assignment.Assignments[0].Add(i); | ||
} | ||
for (int i = 1; i < assignment.Nodes.Count; i++) | ||
{ | ||
assignment.Assignments[i] = new HashSet<int>(); | ||
} | ||
|
||
assignment = assigner.Solve(assignment); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<OutputType>Exe</OutputType> | ||
<TargetFramework>$(NetfxCurrentTargetFramework)</TargetFramework> | ||
<Platforms>x64</Platforms> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Google.OrTools" Version="7.6.7691" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
namespace TaskAssigner | ||
{ | ||
public class TaskDescription | ||
{ | ||
public int Id { get; set; } | ||
|
||
public int CpuCores { get; set; } | ||
|
||
public int MemoryMiB { get; set; } | ||
} | ||
} |