Cidr4 merge algorithm #5

Merged
PavelPatsey merged 91 commits from CIDR4_merge_algorithm into main 2025-01-27 22:05:39 +03:00
Showing only changes of commit 722bd5a751 - Show all commits
+51 -43
View File
@@ -1,6 +1,6 @@
from copy import deepcopy
Fedor-Lyanguzov commented 2025-01-07 17:54:03 +03:00 (Migrated from github.com)
Review

Здесь за один проход объединяются все возможные объединения, таким образом мы можем промахнуться мимо цели в M элементов списка.

Здесь за один проход объединяются все возможные объединения, таким образом мы можем промахнуться мимо цели в `M` элементов списка.
Fedor-Lyanguzov commented 2025-01-07 17:55:32 +03:00 (Migrated from github.com)
Review

Здесь не хватает возвращения количества адресов, "попавших под раздачу": не принадлежащих начальному списку, но попавших в результат из-за объединения. Это количество позволит найти оптимальное решение.

Здесь не хватает возвращения количества адресов, "попавших под раздачу": не принадлежащих начальному списку, но попавших в результат из-за объединения. Это количество позволит найти оптимальное решение.
Fedor-Lyanguzov commented 2025-01-07 17:57:45 +03:00 (Migrated from github.com)
Review

Я думаю, использование внешней библиотеки (и вообще любой библиотеки) размывает смысл алгоритма: хотя из следующих строк понятно, что будет сделано; однако не очевидно, как это будет сделано, и будет ли оптимальный ответ, и будет ли оптимальное решение (что не обязательно).

Я думаю, использование внешней библиотеки (и вообще любой библиотеки) размывает смысл алгоритма: хотя из следующих строк понятно, что будет сделано; однако не очевидно, как это будет сделано, и будет ли оптимальный ответ, и будет ли оптимальное решение (что не обязательно).
Fedor-Lyanguzov commented 2025-01-12 17:46:01 +03:00 (Migrated from github.com)
Review

Мне кажется, что функция merge_nodes содержит не все свои обязанности, некоторые из них похоже вложись в функцию reduce_nodes. Стоит их переместить.

Мне кажется, что функция `merge_nodes` содержит не все свои обязанности, некоторые из них похоже вложись в функцию `reduce_nodes`. Стоит их переместить.
Fedor-Lyanguzov commented 2025-01-12 19:00:28 +03:00 (Migrated from github.com)
Review

Алгоритм слишком много делает каждый шаг, из-за этого работает медленно. Как мне кажется, для оптимизации стоит разработать алгоритм начиная с рекурсии, возможно их будет штук 5 связанных, зато это позволит определить характеристики отдельных кусков и принять решение по оптимизации.

Алгоритм слишком много делает каждый шаг, из-за этого работает медленно. Как мне кажется, для оптимизации стоит разработать алгоритм начиная с рекурсии, возможно их будет штук 5 связанных, зато это позволит определить характеристики отдельных кусков и принять решение по оптимизации.
Fedor-Lyanguzov commented 2025-01-12 19:01:34 +03:00 (Migrated from github.com)
Review

Пора перенести тесты в отдельный файл?

Пора перенести тесты в отдельный файл?
from ipaddress import IPv4Address
from typing import List, Tuple
from typing import List, Tuple, Set
from itertools import groupby
from collections import defaultdict
import cProfile
@@ -42,6 +42,19 @@ def get_mask(binary: str) -> str:
return binary[: i + 1]
def remove_ips_with_subnets(binaries: Set[str]) -> Set[str]:
"""Убрать ip, у которых есть подсети"""
sorted_binaries = sorted(binaries)
i = 0
while i < len(sorted_binaries) - 1:
mask = get_mask(sorted_binaries[i])
if sorted_binaries[i + 1].startswith(mask):
del sorted_binaries[i]
else:
i += 1
return set(sorted_binaries)
def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ips = set(deepcopy(binaries))
reduction_limit_reached = False
@@ -50,23 +63,14 @@ def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
ip_with_max_vlsm = max(ips, key=lambda x: x.rfind("1"))
max_vlsm = ip_with_max_vlsm.rfind("1")
reduced_ips = set()
merged_ips = set()
other_ips = set()
for ip in ips:
if ip.rfind("1") == max_vlsm:
reduced_ips.add(reduce_binary(ip))
else:
merged_ips.add(ip)
filtered_set = set()
for r_ip in reduced_ips:
mask = get_mask(r_ip)
for ip in merged_ips:
if ip.startswith(mask):
filtered_set.add(r_ip)
reduced_ips -= filtered_set
merged_ips.update(reduced_ips)
other_ips.add(ip)
merged_ips = remove_ips_with_subnets(reduced_ips | other_ips)
if len(merged_ips) > req_len:
ips = merged_ips
else:
@@ -76,45 +80,29 @@ def rough_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
def smooth_merge_binaries(binaries: List[str], req_len: int) -> List[str]:
non_reducible_ips = set()
ips = set()
for ip in binaries:
if "1" not in reduce_binary(ip):
non_reducible_ips.add(ip)
else:
ips.add(ip)
while len(ips) > 0 and len(ips) + len(non_reducible_ips) > req_len:
# print(f"{req_len=} {len(ips) + len(non_reducible_ips)=}")
ips = set(deepcopy(binaries))
while len(ips) > req_len:
group_dict = defaultdict(list)
for ip in ips:
group_dict[ip.rfind("1")].append(ip)
max_len = max(group_dict)
lst = group_dict[max_len]
for x, y in zip(lst, lst[1:]):
i = x.rfind("1")
if y.startswith(x[:i]):
sorted_group = sorted(group_dict[max_len])
for x, y in zip(sorted_group, sorted_group[1:]):
mask = get_mask(x)
if y.startswith(mask):
ips.remove(x)
ips.remove(y)
ips.add(reduce_binary(x))
break
else:
x = lst[0]
x = sorted_group[0]
ips.remove(x)
ips.add(reduce_binary(x))
_ips = ips | non_reducible_ips
non_reducible_ips = set()
ips = set()
for ip in _ips:
if "1" not in reduce_binary(ip):
non_reducible_ips.add(ip)
else:
ips.add(ip)
ips = remove_ips_with_subnets(ips)
ips.update(non_reducible_ips)
return sorted(ips)
@@ -133,12 +121,12 @@ def main():
for ip in rough_merged_bin_ips:
print(ip)
# print("#" * 128)
#
# smooth_merged_bin_ips = smooth_merge_binaries(rough_merged_bin_ips, required_len)
# print(f"{len(smooth_merged_bin_ips)=}")
# for ip in smooth_merged_bin_ips:
# print(ip)
print("\n" + "#" * 128 + "\n")
smooth_merged_bin_ips = smooth_merge_binaries(rough_merged_bin_ips, required_len)
print(f"{len(smooth_merged_bin_ips)=}")
for ip in smooth_merged_bin_ips:
print(ip)
# smooth_merged_bin_ips = smooth_merge_binaries(bin_ips, required_len)
# print(f"{len(smooth_merged_bin_ips)=}")
@@ -170,5 +158,25 @@ if __name__ == "__main__":
assert get_mask("00000000000000000000000000000000") == ""
assert get_mask("00000000000010000000000000000000") == "0000000000001"
assert remove_ips_with_subnets(
{
"0001000",
"0001100",
"0001110",
"0001111",
"0101000",
}
) == {
"0001111",
"0101000",
}
assert remove_ips_with_subnets({"0001000"}) == {"0001000"}
assert remove_ips_with_subnets({"1111000", "0101000"}) == {
"1111000",
"0101000",
}
assert remove_ips_with_subnets(set()) == set()
main()
# cProfile.run("main()")