Skip to content

Ενδεικτική λύση εργαστηριακής άσκησης 1 2023-2024

Εκφώνηση

Λύση

Τα ακόλουθα αρχεία: utils.py, erotima1.py και erotima2.py όπως και το αρχείο points.txt πρέπει να βρίσκονται στον ίδιο φάκελο.

utils.py
def distance(x1, y1, x2, y2):
    return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5


def area(x1, y1, x2, y2, x3, y3):
    a = distance(x1, y1, x2, y2)
    b = distance(x2, y2, x3, y3)
    c = distance(x3, y3, x1, y1)
    s = (a + b + c) / 2
    if s * (s - a) * (s - b) * (s - c) <= 0:
        raise ValueError(
            f"Invalid triangle with sides {a}, {b}, {c} and semiperimeter {s}, points {x1, y1}, {x2, y2}, {x3, y3}"
        )
    return (s * (s - a) * (s - b) * (s - c)) ** 0.5


def mean(values):
    return sum(values) / len(values)


def median(values):
    values.sort()
    n = len(values)
    if n % 2 == 0:
        return (values[n // 2 - 1] + values[n // 2]) / 2
    else:
        return values[n // 2]


def stdev(values):
    m = mean(values)
    return (sum((x - m) ** 2 for x in values) / len(values)) ** 0.5
erotima1.py
import itertools
import os
import random
import statistics as stats

from utils import area, mean, median, stdev


def generate_points(n, seed=None):
    if seed:
        random.seed(seed)
    points = []
    for _ in range(n):
        x = random.randint(-100, 100)
        y = random.randint(-100, 100)
        points.append((x, y))
    return points


def save_points(points, filename):
    with open(os.path.join(os.path.dirname(__file__), filename), "w") as f:
        for x, y in points:
            f.write(f"{x} {y}\n")


# Λύση Α: με χρήση εμφωλευμένων for
# def get_areas(points):
#     areas = []
#     for i in range(len(points)):
#         for j in range(i + 1, len(points)):
#             for k in range(j + 1, len(points)):
#                 p1 = points[i]
#                 p2 = points[j]
#                 p3 = points[k]
#                 try:
#                     areas.append(area(*p1, *p2, *p3))
#                 except ValueError:
#                     pass
#     return areas


# Λύση Β: με χρήση του itertools
def get_areas(points):
    areas = []
    for i, j, k in itertools.combinations(range(len(points)), 3):
        p1 = points[i]
        p2 = points[j]
        p3 = points[k]
        try:
            areas.append(area(*p1, *p2, *p3))
        except ValueError:
            pass
    return areas


if __name__ == "__main__":
    points = generate_points(100, seed=12345)
    # save_points(points, "points.txt")
    areas = get_areas(points)
    print(f"Valid triangles: {len(areas)}")
    print(f"Mean   = {mean(areas):.2f}")
    print(f"Median = {median(areas):.2f}")
    print(f"Stdev  = {stdev(areas):.2f}")

    print("Using statistics module")
    print(f"Mean   = {stats.mean(areas):.2f}")
    print(f"Median = {stats.median(areas):.2f}")
    print(f"Stdev  = {stats.stdev(areas):.2f}")
$ python erotima1.py
Valid triangles: 161673
Mean   = 3206.82
Median = 2392.50
Stdev  = 2843.24
Using statistics module
Mean   = 3206.82
Median = 2392.50
Stdev  = 2843.25
erotima2.py
import os
import unittest

from erotima1 import get_areas
from utils import mean, median, stdev


def load_points(filename):
    points = []
    with open(os.path.join(os.path.dirname(__file__), filename), "r") as f:
        for line in f:
            x, y = line.strip().split()
            points.append((int(x), int(y)))
    return points


class TestPoints(unittest.TestCase):
    def test_100_points_from_file(self):
        points = load_points("points.txt")
        areas = get_areas(points)
        self.assertEqual(len(areas), 161673)
        self.assertAlmostEqual(mean(areas), 3206.82, places=2)
        self.assertAlmostEqual(median(areas), 2392.50, places=2)
        self.assertAlmostEqual(stdev(areas), 2843.24, places=2)


if __name__ == "__main__":
    unittest.main()
$ python erotima2.py
.
----------------------------------------------------------------------
Ran 1 test in 0.419s

OK