Compare commits

...

5 Commits

6 changed files with 300 additions and 0 deletions

21
task6/entities.py Normal file
View File

@@ -0,0 +1,21 @@
from dataclasses import dataclass
from typing import Literal
@dataclass
class Request:
request_time: int
plane: Plane
@dataclass
class ProcessedRequest(Request):
start_process_time: int
process_time: int
type_: Literal["landing", "launching"]
class Plane:
__id_increment = 0
def __init__(self) -> None:
self.id = self.__id_increment
Plane.__id_increment += 1

100
task6/main.py Normal file
View File

@@ -0,0 +1,100 @@
from stats import Stats, finalize_waiting_stats, show_stats
from entities import Plane, ProcessedRequest, Request
from queues import EnforcingQueue, PermissiveQueue, Queue
from numpy import random
from typing import Final, Iterable, Optional
from numpy.typing import NDArray
def warn_about_outcoming_queue_overload(queue: Queue) -> None:
print(f"Outcoming queue is overloaded: {len(queue)} planes/{queue.size} planes")
def reject_plane(plane: Plane) -> None:
stats.rejected_in_requests += 1
print(f"Rejected incoming plane №{plane.id}")
def launch_plane(plane: Plane, stats: Stats) -> None:
stats.launches_count += 1
print(f"Launched plane №{plane.id}")
def land_plane(plane: Plane, stats: Stats) -> None:
stats.landings_count += 1
print(f"Plane №{plane.id} landed")
def generate_timeline(incoming_planes_per_hour: float, outcoming_planes_per_hour: float, interval_minutes: int) -> Iterable[tuple[int, int]]:
def _generate(planes_per_hour: float) -> NDArray:
return random.poisson(planes_per_hour / 60, interval_minutes)
incoming_planes_per_minute = _generate(incoming_planes_per_hour)
outcoming_planes_per_minute = _generate(outcoming_planes_per_hour)
return zip(incoming_planes_per_minute, outcoming_planes_per_minute)
def process_new_request(in_queue: Queue[Request], out_queue: Queue[Request], current_time: int, process_duration: int) -> ProcessedRequest:
plane: Optional[Plane]
if in_queue:
request = in_queue.pop()
plane = request.plane
stats.in_waiting_time.append(current_time - request.request_time)
print(f"{current_time}: Processing incoming plane №{plane.id}")
process_type = "landing"
else:
request = out_queue.pop()
plane = request.plane
stats.out_waiting_time.append(current_time - request.request_time)
print(f"{current_time}: Processing outcoming plane №{plane.id}")
process_type = "launching"
return ProcessedRequest(request.request_time, request.plane, current_time, current_time + process_duration, process_type)
takeoff_duration: Final[int] = int(input("Takeoff duration: ")) # minutes
max_queue: Final[int] = int(input("Max queue: "))
interval: Final[int] = int(input("Interval: ")) # minutes
incoming_planes, outcoming_planes = map(float, input("Planes: ").split()) # per hour
in_queue: Queue[Request] = EnforcingQueue[Request](max_queue)
out_queue: Queue[Request] = PermissiveQueue[Request](max_queue, warn_about_outcoming_queue_overload)
current_request: Optional[ProcessedRequest] = None
stats = Stats()
timeline = generate_timeline(5,2, interval)
i = 0
for i, (in_planes_count, out_planes_count) in enumerate(timeline):
stats.total_plane_requests += in_planes_count + out_planes_count
stats.in_requests += in_planes_count
stats.out_requests += out_planes_count
for _ in range(in_planes_count):
new_plane = Plane()
try:
in_queue.add(Request(i, new_plane))
stats.accepted_in_requests += 1
except IndexError:
reject_plane(new_plane)
stats.rejected_in_requests += 1
for _ in range(out_planes_count):
new_plane = Plane()
out_queue.add(Request(i, new_plane))
stats.accepted_out_requests += 1
if not current_request:
if len(in_queue) or len(out_queue):
current_request = process_new_request(in_queue, out_queue, i, takeoff_duration)
continue
stats.sleep_minutes += 1
if current_request and current_request.process_time == i:
if current_request.type_ == "launching":
launch_plane(current_request.plane, stats)
else:
land_plane(current_request.plane, stats)
current_request = None
stats.in_queued = len(in_queue)
stats.out_queued = len(out_queue)
finalize_waiting_stats(stats, in_queue, out_queue, i)
show_stats(stats)

50
task6/queues.py Normal file
View File

@@ -0,0 +1,50 @@
from abc import ABC, abstractmethod
from collections import deque
from typing import Callable, Optional, Self, override
class Queue[T](ABC):
def __init__(self, size: int) -> None:
self.size = size
self.queue: deque[T] = deque()
def __len__(self) -> int:
return len(self.queue)
def __bool__(self) -> bool:
return bool(self.queue)
@abstractmethod
def add(self, item: T) -> None: pass
@abstractmethod
def pop(self) -> T: pass
class PermissiveQueue[T](Queue):
def __init__(self, size: int, overload_function: Optional[Callable[[Self], None]] = None) -> None:
super().__init__(size)
self._on_overload = overload_function
@override
def add(self, item: T) -> None:
self.queue.append(item)
if self._on_overload and len(self.queue) > self.size:
self._on_overload(self)
@override
def pop(self) -> T:
return self.queue.popleft()
class EnforcingQueue[T](Queue):
def __init__(self, size: int) -> None:
super().__init__(size)
@override
def add(self, item: T) -> None:
if len(self.queue) >= self.size:
raise IndexError
self.queue.append(item)
@override
def pop(self) -> T:
return self.queue.popleft()

53
task6/stats.py Normal file
View File

@@ -0,0 +1,53 @@
from dataclasses import dataclass, field
from numpy import average
from entities import Request
from queues import Queue
@dataclass
class Stats:
total_plane_requests = 0
in_requests = 0
out_requests = 0
accepted_in_requests = 0
accepted_out_requests = 0
rejected_in_requests = 0
rejected_out_requests = 0
landings_count = 0
launches_count = 0
in_queued = 0
out_queued = 0
sleep_minutes = 0
in_waiting_time: list[float] = field(default_factory=list)
out_waiting_time: list[float] = field(default_factory=list)
def show_stats(stats: Stats) -> None:
string = f"""============
Total requests: {stats.total_plane_requests}
In requests: {stats.in_requests}
Out requests: {stats.out_requests}
Accepted in requests: {stats.accepted_in_requests}
Accepted out requests: {stats.accepted_out_requests}
Rejected in/out: {stats.rejected_in_requests}/{stats.rejected_out_requests}
Landings: {stats.landings_count}
Launches: {stats.launches_count}
Left in queues (in/out): {stats.in_queued}/{stats.out_queued}
Sleep: {stats.sleep_minutes}
Average waiting time (in/out): {average(stats.in_waiting_time)}/{average(stats.out_waiting_time)}
"""
print(string)
def finalize_waiting_stats(stats: Stats, in_queue: Queue[Request], out_queue: Queue[Request], current_time: int) -> None:
for item in in_queue.queue:
stats.in_waiting_time.append(current_time - item.request_time)
for item in out_queue.queue:
stats.out_waiting_time.append(current_time - item.request_time)

40
task7/main.py Normal file
View File

@@ -0,0 +1,40 @@
from itertools import combinations, repeat
import random
from typing import Any, Final, Iterable
from collections import Counter
from icecream import ic
sets_count: Final[int] = random.randint(2, 1000)
elements_count: Final[Iterable[int]] = (random.randint(3, 10000) for _ in repeat(None, sets_count))
ic(sets_count)
sets: list[set[int]] = [
set(
random.sample(range(-2_000_000_000, 2_000_000_000 + 1), count)
)
for count in elements_count
]
elements_to_sets: dict[int, list[int]] = {}
pair_counts: Counter[tuple[int, int]] = Counter()
for i, set_ in enumerate(sets):
for element in set_:
elements_to_sets.setdefault(element, list()).append(i)
ic(len(elements_to_sets))
for sets_ in filter(lambda x: len(x) > 1, elements_to_sets.values()):
pair_counts.update(combinations(sets_, 2))
sets_with_most_intersections: list[tuple[Any, int]] = pair_counts.most_common(1)
if sets_with_most_intersections:
max_intersection: int = sets_with_most_intersections[0][1]
else:
max_intersection = 0
print(max_intersection)

36
task7/naive_approach.py Normal file
View File

@@ -0,0 +1,36 @@
from itertools import repeat
import random
from typing import Final, Iterable
from icecream import ic
sets_count: Final[int] = random.randint(2, 1000)
elements_count: Final[Iterable[int]] = (random.randint(3, 10000) for _ in repeat(None, sets_count))
ic(sets_count)
sets: list[set[int]] = [
set(
random.sample(range(-2_000_000_000, 2_000_000_000 + 1), count)
)
for count in elements_count
]
sets.sort(key=lambda x: len(x), reverse=True)
ic(list(map(len, sets)))
max_intersection = 0
for i in range(len(sets) - 1):
if max_intersection >= len(sets[i]):
ic(f"break on {i}")
break
for j in range(i + 1, len(sets)):
if max_intersection > len(sets[j]):
ic(f"break on {i};{j}")
break
if (intersection := len(sets[i].intersection(sets[j]))) > max_intersection:
max_intersection = intersection
ic(max_intersection)
print(max_intersection)