Skip to content

Commit 6bd4dd1

Browse files
committed
New example: Cloud Balancing
1 parent 2eec8f2 commit 6bd4dd1

17 files changed

+550
-0
lines changed

examples/object_oriented/cloud_balancing/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
3+
4+
class CotComputer():
5+
6+
def __init__(self, computer_id, cpu_power, memory_size, network_bandwidth, cost):
7+
8+
self.computer_id = computer_id
9+
self.cpu_power = cpu_power
10+
self.memory_size = memory_size
11+
self.network_bandwidth = network_bandwidth
12+
self.cost = cost
13+
14+
def build_from_domain_computer(domain_computer):
15+
16+
cot_computer = CotComputer(
17+
domain_computer.computer_id,
18+
domain_computer.cpu_power,
19+
domain_computer.memory_size,
20+
domain_computer.network_bandwidth,
21+
domain_computer.cost,
22+
)
23+
24+
return cot_computer
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
3+
4+
class CotProcess():
5+
6+
def __init__(self, process_id, cpu_power_req, memory_size_req, network_bandwidth_req, computer_id):
7+
8+
self.process_id = process_id
9+
self.cpu_power_req = cpu_power_req
10+
self.memory_size_req = memory_size_req
11+
self.network_bandwidth_req = network_bandwidth_req
12+
self.computer_id = computer_id
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
4+
from greyjack.cotwin.CotwinBase import CotwinBase
5+
6+
class CotScheduleCB( CotwinBase ):
7+
8+
def __init__(self):
9+
super().__init__()
10+
11+
pass

examples/object_oriented/cloud_balancing/cotwin/__init__.py

Whitespace-only changes.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
3+
4+
class Computer():
5+
6+
def __init__(self, computer_id, cpu_power, memory_size, network_bandwidth, cost):
7+
8+
self.computer_id = computer_id
9+
self.cpu_power = cpu_power
10+
self.memory_size = memory_size
11+
self.network_bandwidth = network_bandwidth
12+
self.cost = cost
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
3+
4+
class Process():
5+
6+
def __init__(self, process_id, cpu_power_req, memory_size_req, network_bandwidth_req, computer_id):
7+
8+
self.process_id = process_id
9+
self.cpu_power_req = cpu_power_req
10+
self.memory_size_req = memory_size_req
11+
self.network_bandwidth_req = network_bandwidth_req
12+
self.computer_id = computer_id
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
3+
4+
class ScheduleCB():
5+
6+
def __init__(self, computers, processes):
7+
8+
self.computers = computers
9+
self.processes = processes
10+
11+
12+
def print_metrics(self):
13+
14+
used_resources_map = {}
15+
for process in self.processes:
16+
process_id = process.process_id
17+
cpu_power_req = process.cpu_power_req
18+
memory_size_req = process.memory_size_req
19+
network_bandwidth_req = process.network_bandwidth_req
20+
computer_id = process.computer_id
21+
22+
if computer_id not in used_resources_map:
23+
used_resources_map[computer_id] = {
24+
"processes": [],
25+
"cpu": 0,
26+
"memory": 0,
27+
"network": 0
28+
}
29+
30+
used_resources_map[computer_id]["processes"].append(process_id)
31+
used_resources_map[computer_id]["cpu"] += cpu_power_req
32+
used_resources_map[computer_id]["memory"] += memory_size_req
33+
used_resources_map[computer_id]["network"] += network_bandwidth_req
34+
35+
total_violations = 0
36+
computer_ids = list(sorted(list(used_resources_map.keys())))
37+
for computer_id in computer_ids:
38+
computer_info = self.computers[computer_id]
39+
40+
if used_resources_map[computer_id]["cpu"] > computer_info.cpu_power:
41+
total_violations += 1
42+
if used_resources_map[computer_id]["memory"] > computer_info.memory_size:
43+
total_violations += 1
44+
if used_resources_map[computer_id]["network"] > computer_info.network_bandwidth:
45+
total_violations += 1
46+
47+
print("Computer {} utilization: ".format(computer_id))
48+
print(" CPU: {} / {} | RAM: {} / {} | NTWRK: {} / {}".format(
49+
used_resources_map[computer_id]["cpu"], computer_info.cpu_power,
50+
used_resources_map[computer_id]["memory"], computer_info.memory_size,
51+
used_resources_map[computer_id]["network"], computer_info.network_bandwidth,
52+
))
53+
print(" PIDs: {}".format(", ".join(str(pid) for pid in used_resources_map[computer_id]["processes"])))
54+
print()
55+
print()
56+
57+
print("Total violations: {}".format(total_violations))
58+
print("Computers used: {}".format(len(computer_ids)))
59+
print()
60+
61+
62+

examples/object_oriented/cloud_balancing/domain/__init__.py

Whitespace-only changes.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
2+
from greyjack.persistence.CotwinBuilderBase import CotwinBuilderBase
3+
from greyjack.variables.GJInteger import GJInteger
4+
from examples.object_oriented.cloud_balancing.cotwin.CotScheduleCB import CotScheduleCB
5+
from examples.object_oriented.cloud_balancing.cotwin.CotProcess import CotProcess
6+
from examples.object_oriented.cloud_balancing.cotwin.CotComputer import CotComputer
7+
from examples.object_oriented.cloud_balancing.score.PlainScoreCalculatorCB import PlainScoreCalculatorCB
8+
from examples.object_oriented.cloud_balancing.score.IncrementalScoreCalculatorCB import IncrementalScoreCalculatorCB
9+
import numpy as np
10+
from numba import jit
11+
12+
class CotwinBuilder(CotwinBuilderBase):
13+
14+
def __init__(self, use_incremental_score_calculator, use_greed_init):
15+
16+
self.use_incremental_score_calculator = use_incremental_score_calculator
17+
self.use_greed_init = use_greed_init
18+
19+
pass
20+
21+
def build_cotwin(self, domain_model, is_already_initialized):
22+
23+
cotwin_model = CotScheduleCB()
24+
25+
cotwin_model.add_planning_entities_list(self._build_planning_processes(domain_model), "processes")
26+
cotwin_model.add_problem_facts_list(self._build_problem_fact_computers(domain_model), "computers")
27+
28+
if self.use_incremental_score_calculator:
29+
score_calculator = IncrementalScoreCalculatorCB()
30+
31+
#to avoid joining, fast get common info only
32+
score_calculator.utility_objects["processes_info"] = self._build_processes_common_info(domain_model)
33+
score_calculator.utility_objects["computers_info"] = self._build_computers_common_info(domain_model)
34+
score_calculator.utility_objects["computers_costs"] = self._build_computers_costs(domain_model)
35+
else:
36+
score_calculator = PlainScoreCalculatorCB()
37+
38+
cotwin_model.set_score_calculator( score_calculator )
39+
40+
return cotwin_model
41+
42+
def _build_planning_processes(self, domain_model):
43+
44+
cot_processes = []
45+
n_computers = len(domain_model.computers)
46+
47+
if self.use_greed_init:
48+
initial_computer_ids = self._build_greed_initial_computer_ids(domain_model)
49+
else:
50+
initial_computer_ids = n_computers * [None]
51+
52+
53+
for i, process in enumerate(domain_model.processes):
54+
cot_process = CotProcess(
55+
process.process_id,
56+
process.cpu_power_req,
57+
process.memory_size_req,
58+
process.network_bandwidth_req,
59+
GJInteger(0, n_computers-1, False, initial_computer_ids[i])
60+
)
61+
cot_processes.append(cot_process)
62+
63+
return cot_processes
64+
65+
def _build_greed_initial_computer_ids(self, domain_model):
66+
67+
processes_info = self._build_processes_common_info(domain_model)
68+
computers_info = self._build_computers_common_info(domain_model)
69+
n_processes = len(processes_info)
70+
m_computers = len(computers_info)
71+
72+
initial_computer_ids = self._build_initial_ids(n_processes, m_computers, processes_info, computers_info)
73+
initial_computer_ids = [int(initial_computer_ids[i]) if initial_computer_ids[i] >= 0 else None for i in range(len(initial_computer_ids))]
74+
75+
76+
return initial_computer_ids
77+
78+
@staticmethod
79+
@jit(nopython=True, cache=True)
80+
def _build_initial_ids(n_processes, m_computers, processes_info, computers_info):
81+
initial_computer_ids = np.zeros(n_processes, np.int64) - 1
82+
current_consumed_resources = np.zeros(3, np.int64)
83+
assigned_processes_index = [np.zeros(n_processes, np.int64) - 1 for i in range(m_computers)]
84+
assigned_processes_counts = np.zeros(m_computers, np.int64)
85+
for process_id in range(n_processes):
86+
87+
acceptable_computer_id = None
88+
for computer_id in range(m_computers):
89+
current_consumed_resources = np.zeros(3, np.int64)
90+
for i in range(assigned_processes_counts[computer_id]):
91+
current_consumed_resources += processes_info[assigned_processes_index[computer_id][i]]
92+
93+
current_consumed_resources += processes_info[process_id]
94+
resource_deltas = current_consumed_resources - computers_info[computer_id]
95+
resource_deltas = np.where(resource_deltas > 0, resource_deltas, 0)
96+
resources_unacceptance = np.sum(resource_deltas)
97+
if resources_unacceptance == 0:
98+
acceptable_computer_id = computer_id
99+
assigned_processes_index[computer_id][assigned_processes_counts[computer_id]] = process_id
100+
assigned_processes_counts[computer_id] += 1
101+
break
102+
103+
if acceptable_computer_id is not None:
104+
initial_computer_ids[process_id] = acceptable_computer_id
105+
106+
return initial_computer_ids
107+
108+
109+
def _build_problem_fact_computers(self, domain_model):
110+
111+
cot_computers = [CotComputer.build_from_domain_computer(computer) for computer in domain_model.computers]
112+
113+
return cot_computers
114+
115+
def _build_processes_common_info(self, domain_model):
116+
117+
n_processes = len(domain_model.processes)
118+
m_info_fields = 3
119+
processes_common_info = np.zeros((n_processes, m_info_fields), dtype=np.int64)
120+
for i in range(n_processes):
121+
processes_common_info[i][0] = domain_model.processes[i].cpu_power_req
122+
processes_common_info[i][1] = domain_model.processes[i].memory_size_req
123+
processes_common_info[i][2] = domain_model.processes[i].network_bandwidth_req
124+
125+
return processes_common_info
126+
127+
128+
def _build_computers_common_info(self, domain_model):
129+
130+
n_computers = len(domain_model.computers)
131+
m_info_fields = 3
132+
computers_common_info = np.zeros((n_computers, m_info_fields), dtype=np.int64)
133+
for i in range(n_computers):
134+
computers_common_info[i][0] = domain_model.computers[i].cpu_power
135+
computers_common_info[i][1] = domain_model.computers[i].memory_size
136+
computers_common_info[i][2] = domain_model.computers[i].network_bandwidth
137+
138+
return computers_common_info
139+
140+
def _build_computers_costs(self, domain_model):
141+
142+
# to avoid unnecessary slicing while constraints computation
143+
n_computers = len(domain_model.computers)
144+
computers_costs = np.zeros((n_computers), dtype=np.int64)
145+
for i in range(n_computers):
146+
computers_costs[i] = domain_model.computers[i].cost
147+
148+
return computers_costs
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
import json
3+
from greyjack.persistence.DomainBuilderBase import DomainBuilderBase
4+
from examples.object_oriented.cloud_balancing.domain.Process import Process
5+
from examples.object_oriented.cloud_balancing.domain.Computer import Computer
6+
from examples.object_oriented.cloud_balancing.domain.ScheduleCB import ScheduleCB
7+
8+
class DomainBuilder(DomainBuilderBase):
9+
10+
def __init__(self, file_path):
11+
12+
super().__init__()
13+
self.file_path = file_path
14+
15+
pass
16+
17+
def build_domain_from_scratch(self):
18+
19+
with open(self.file_path, "r") as json_file:
20+
readed_json = json.load(json_file)
21+
22+
computers = []
23+
for cumputer_dict in readed_json["computerList"]:
24+
current_computer = Computer(
25+
cumputer_dict["id"],
26+
cumputer_dict["cpuPower"],
27+
cumputer_dict["memory"],
28+
cumputer_dict["networkBandwidth"],
29+
cumputer_dict["cost"],
30+
)
31+
computers.append(current_computer)
32+
33+
34+
processes = []
35+
for process_dict in readed_json["processList"]:
36+
current_process = Process(
37+
process_dict["id"],
38+
process_dict["requiredCpuPower"],
39+
process_dict["requiredMemory"],
40+
process_dict["requiredNetworkBandwidth"],
41+
process_dict["computer"],
42+
)
43+
processes.append(current_process)
44+
45+
domain_model = ScheduleCB(computers, processes)
46+
47+
return domain_model
48+
49+
def build_from_solution(self, solution, initial_domain=None):
50+
51+
n_processes = len(solution.variable_values_dict.values())
52+
process_assigned_computer_id_map = [-1 for i in range(n_processes)]
53+
for assign_name in solution.variable_values_dict.keys():
54+
computer_id = solution.variable_values_dict[assign_name]
55+
process_id = int(assign_name.split("-->")[0].split(" ")[-1])
56+
process_assigned_computer_id_map[process_id] = computer_id
57+
58+
if initial_domain is None:
59+
domain_model = self.build_domain_from_scratch()
60+
else:
61+
domain_model = initial_domain
62+
63+
for i in range(n_processes):
64+
domain_model.processes[i].computer_id = process_assigned_computer_id_map[i]
65+
66+
return domain_model
67+
68+
def build_from_domain(self, domain):
69+
return super().build_from_domain(domain)

examples/object_oriented/cloud_balancing/persistence/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)