Umstellen der Auswertungslogik
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
from utils.algo_context import AlgoContext
|
||||
from utils.algo_int import Int
|
||||
from utils.algo_array import Array
|
||||
from utils.algo_range import irange
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
from __future__ import annotations
|
||||
from random import randint
|
||||
from utils.algo_context import AlgoContext, _NullContext, NULL_CTX
|
||||
from utils.algo_int import Int
|
||||
from utils.project_dir import get_path
|
||||
|
||||
|
||||
class Array:
|
||||
"""
|
||||
Instrumentiertes Array.
|
||||
|
||||
Jede Zelle ist ein Int-Objekt, das Operationen an den gemeinsamen
|
||||
AlgoContext meldet.
|
||||
|
||||
Zugriff
|
||||
-------
|
||||
arr[i] gibt die Int-Zelle zurück (kein Zähler)
|
||||
arr[i] = v setzt den Wert der Zelle (1 write, +1 read falls v ein Int)
|
||||
len(arr) gibt plain int zurück
|
||||
arr.length() gibt Int zurück (für Algorithmen nützlich)
|
||||
arr.swap(i,j) tauscht zwei Elemente (2 reads + 2 writes)
|
||||
|
||||
Hinweis: arr[i] gibt eine Referenz auf die Zelle zurück.
|
||||
Lesende Verwendung (Vergleich, Arithmetik) zählt dort – nicht beim Zugriff selbst.
|
||||
|
||||
Fabrikmethoden
|
||||
--------------
|
||||
Array.random(n, min_val, max_val, ctx) zufällige Werte
|
||||
Array.sorted(n, ctx) aufsteigend sortiert 0..n-1
|
||||
Array.from_file(filename, ctx) Werte aus Textdatei (eine Zahl pro Zeile)
|
||||
|
||||
Beispiel
|
||||
--------
|
||||
ctx = AlgoContext()
|
||||
z = Array.random(10, 0, 99, ctx)
|
||||
if z[0] > z[1]: # 2 reads, 1 comparison
|
||||
z.swap(0, 1) # 2 reads, 2 writes
|
||||
"""
|
||||
|
||||
def __init__(self, data: list, ctx: AlgoContext | _NullContext):
|
||||
self._ctx = ctx
|
||||
self._cells = [Int(v, ctx) for v in data]
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Element-Zugriff
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __getitem__(self, index) -> Int:
|
||||
"""Gibt die Int-Zelle zurück. Kein Zähler – Zählung erfolgt bei Nutzung."""
|
||||
return self._cells[int(index)]
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""
|
||||
Setzt den Wert der Zelle.
|
||||
|
||||
Delegiert an Int.set() → 1 write (+1 read falls value ein Int ist).
|
||||
"""
|
||||
self._cells[int(index)].set(value)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Länge
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self._cells)
|
||||
|
||||
def length(self) -> Int:
|
||||
"""Gibt die Länge als Int zurück (für Algorithmen, die mit Int rechnen)."""
|
||||
return Int(len(self._cells), self._ctx)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Iteration
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self._cells)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Tausch
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def swap(self, i, j):
|
||||
"""
|
||||
Tauscht die Werte an Position i und j.
|
||||
|
||||
Zählt: 2 reads + 2 writes.
|
||||
"""
|
||||
ci = self._cells[int(i)]
|
||||
cj = self._cells[int(j)]
|
||||
self._ctx.reads += 2
|
||||
self._ctx.writes += 2
|
||||
ci._value, cj._value = cj._value, ci._value
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Darstellung
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __str__(self):
|
||||
return '[' + ', '.join(str(c) for c in self._cells) + ']'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Array({[c.value for c in self._cells]})"
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Fabrikmethoden
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@staticmethod
|
||||
def random(n: int, min_val: int, max_val: int, ctx: AlgoContext) -> Array:
|
||||
"""Erzeugt ein Array mit n zufälligen Werten aus [min_val, max_val]."""
|
||||
n = int(n)
|
||||
return Array([randint(min_val, max_val) for _ in range(n)], ctx)
|
||||
|
||||
@staticmethod
|
||||
def sorted(n: int, ctx: AlgoContext) -> Array:
|
||||
"""Erzeugt ein aufsteigend sortiertes Array 0, 1, …, n-1."""
|
||||
n = int(n)
|
||||
return Array(list(range(n)), ctx)
|
||||
|
||||
@staticmethod
|
||||
def from_file(filename: str, ctx: AlgoContext, limit: int | None = None) -> Array:
|
||||
"""
|
||||
Liest Ganzzahlen aus einer Textdatei (eine Zahl pro Zeile).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
filename : str
|
||||
Pfad relativ zum Projektverzeichnis oder absolut.
|
||||
ctx : AlgoContext
|
||||
limit : int | None
|
||||
Optionale Obergrenze für die Anzahl eingelesener Zeilen.
|
||||
"""
|
||||
path = get_path(filename)
|
||||
with open(path) as f:
|
||||
lines = f.readlines()
|
||||
if limit is not None:
|
||||
lines = lines[:limit]
|
||||
data = [int(line.strip()) for line in lines if line.strip()]
|
||||
return Array(data, ctx)
|
||||
@@ -0,0 +1,135 @@
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
class AlgoContext:
|
||||
"""
|
||||
Kontext für die Instrumentierung von Algorithmen.
|
||||
|
||||
Jeder Algorithmus erhält eine eigene Instanz – kein globaler Zustand.
|
||||
Die Zähler werden von Int- und Array-Operationen automatisch erhöht.
|
||||
|
||||
Zähler
|
||||
------
|
||||
reads Lesezugriffe (bei Vergleichen und Arithmetik je Operand)
|
||||
writes Schreibzugriffe (set, Zuweisung, augmented assignment)
|
||||
comparisons Vergleiche (<, <=, >, >=, ==, !=)
|
||||
additions Additionen (+, +=)
|
||||
subtractions Subtraktionen (-, -=)
|
||||
multiplications Multiplikationen (*, *=)
|
||||
divisions Divisionen (/, //, %, /=, //=)
|
||||
bitops Bitoperationen (&, |, ^, <<, >>)
|
||||
|
||||
Beispiel
|
||||
--------
|
||||
ctx = AlgoContext()
|
||||
z = Array.random(20, -100, 100, ctx)
|
||||
bubble_sort(z, ctx)
|
||||
print(ctx)
|
||||
ctx.save_stats(20)
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.reads = 0
|
||||
self.writes = 0
|
||||
self.comparisons = 0
|
||||
self.additions = 0
|
||||
self.subtractions = 0
|
||||
self.multiplications = 0
|
||||
self.divisions = 0
|
||||
self.bitops = 0
|
||||
self._stats: dict[int, dict] = {}
|
||||
|
||||
def reset(self):
|
||||
"""Setzt alle Zähler auf 0 zurück."""
|
||||
self.reads = 0
|
||||
self.writes = 0
|
||||
self.comparisons = 0
|
||||
self.additions = 0
|
||||
self.subtractions = 0
|
||||
self.multiplications = 0
|
||||
self.divisions = 0
|
||||
self.bitops = 0
|
||||
|
||||
def _snapshot(self) -> dict:
|
||||
return {
|
||||
"reads": self.reads,
|
||||
"writes": self.writes,
|
||||
"comparisons": self.comparisons,
|
||||
"additions": self.additions,
|
||||
"subtractions": self.subtractions,
|
||||
"multiplications": self.multiplications,
|
||||
"divisions": self.divisions,
|
||||
"bitops": self.bitops,
|
||||
}
|
||||
|
||||
def save_stats(self, n: int):
|
||||
"""Speichert einen Schnappschuss der aktuellen Zähler für Eingabegröße n."""
|
||||
self._stats[n] = self._snapshot()
|
||||
|
||||
def plot_stats(self, labels: list[str]):
|
||||
"""
|
||||
Zeichnet die gespeicherten Statistiken als Liniendiagramm.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
labels : list[str]
|
||||
Zähler-Namen, z.B. ["comparisons", "writes"]
|
||||
"""
|
||||
data = self._stats
|
||||
x = list(data.keys())
|
||||
|
||||
fig, axes = plt.subplots(len(labels), 1, figsize=(8, 4 * len(labels)), sharex=True)
|
||||
if len(labels) == 1:
|
||||
axes = [axes]
|
||||
|
||||
for ax, label in zip(axes, labels):
|
||||
y = [data[k][label] for k in x]
|
||||
ax.plot(x, y, label=label)
|
||||
ax.set_ylabel(label)
|
||||
ax.legend()
|
||||
|
||||
plt.xlabel("n")
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
def summary(self) -> str:
|
||||
"""Gibt alle Zähler als formatierten Text zurück."""
|
||||
return (
|
||||
f"Reads: {self.reads}\n"
|
||||
f"Writes: {self.writes}\n"
|
||||
f"Comparisons: {self.comparisons}\n"
|
||||
f"Additions: {self.additions}\n"
|
||||
f"Subtractions: {self.subtractions}\n"
|
||||
f"Multiplications: {self.multiplications}\n"
|
||||
f"Divisions: {self.divisions}\n"
|
||||
f"Bitwise ops: {self.bitops}"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.summary()
|
||||
|
||||
def __repr__(self):
|
||||
return (f"AlgoContext(reads={self.reads}, writes={self.writes}, "
|
||||
f"comparisons={self.comparisons})")
|
||||
|
||||
|
||||
class _NullContext:
|
||||
"""
|
||||
Kontext der alle Operationen stillschweigend ignoriert.
|
||||
|
||||
Wird intern von irange() verwendet, damit Schleifenindex-Arithmetik
|
||||
standardmäßig nicht mitgezählt wird.
|
||||
|
||||
__setattr__ ist absichtlich ein no-op: ``ctx.reads += 1`` bleibt wirkungslos.
|
||||
"""
|
||||
reads = writes = comparisons = 0
|
||||
additions = subtractions = multiplications = divisions = bitops = 0
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
pass # alle Schreibzugriffe ignorieren
|
||||
|
||||
def save_stats(self, n): pass
|
||||
def reset(self): pass
|
||||
|
||||
|
||||
NULL_CTX = _NullContext()
|
||||
@@ -0,0 +1,319 @@
|
||||
from __future__ import annotations
|
||||
from utils.algo_context import AlgoContext, _NullContext, NULL_CTX
|
||||
|
||||
|
||||
class Int:
|
||||
"""
|
||||
Instrumentierter Integer-Typ.
|
||||
|
||||
Alle Operationen werden im zugehörigen AlgoContext gezählt.
|
||||
Der Rohwert ist über das Attribut ``value`` direkt lesbar (kein Zähler),
|
||||
was für Visualisierungen benötigt wird.
|
||||
|
||||
Zählregeln
|
||||
----------
|
||||
Vergleich (a < b): 2 reads + 1 comparison
|
||||
Arithmetik (a + b): 2 reads + 1 arithmetische Operation → neues Int
|
||||
Augmented (a += b): 2 reads + 1 arithmetische Operation + 1 write
|
||||
set(v): 1 write (+1 read falls v ein Int ist)
|
||||
|
||||
Auto-Wrapping
|
||||
-------------
|
||||
Alle Operatoren akzeptieren auch plain-Python-Werte (int, float).
|
||||
Diese werden intern zu Int(v, NULL_CTX) gewrappt, ohne Zähler zu erhöhen.
|
||||
|
||||
Beispiel
|
||||
--------
|
||||
ctx = AlgoContext()
|
||||
a = Int(5, ctx)
|
||||
b = Int(3, ctx)
|
||||
if a > b: # 2 reads, 1 comparison
|
||||
a += b # 2 reads, 1 addition, 1 write
|
||||
print(a.value) # 8 (kein Zähler)
|
||||
"""
|
||||
|
||||
def __init__(self, value, ctx: AlgoContext | _NullContext = NULL_CTX):
|
||||
if isinstance(value, Int):
|
||||
self._value = value._value
|
||||
else:
|
||||
self._value = value
|
||||
self._ctx = ctx
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Rohwert-Zugriff (für Visualisierung, kein Zähler)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
"""Rohwert für Visualisierung – wird nicht gezählt."""
|
||||
return self._value
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Schreiben
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def set(self, new_value):
|
||||
"""
|
||||
Setzt den Wert.
|
||||
|
||||
Zählt: 1 write (+1 read falls new_value ein Int ist)
|
||||
"""
|
||||
self._ctx.writes += 1
|
||||
if isinstance(new_value, Int):
|
||||
self._ctx.reads += 1
|
||||
self._value = new_value._value
|
||||
else:
|
||||
self._value = new_value
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Interner Hilfshelfer
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _wrap(self, other) -> Int:
|
||||
"""Wraps plain Python-Wert zu Int mit NULL_CTX (kein Zähler)."""
|
||||
if isinstance(other, Int):
|
||||
return other
|
||||
return Int(other, NULL_CTX)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Vergleiche (2 reads + 1 comparison je Operation)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __eq__(self, other):
|
||||
if other is None:
|
||||
return False
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value == other._value
|
||||
|
||||
def __ne__(self, other):
|
||||
if other is None:
|
||||
return True
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value != other._value
|
||||
|
||||
def __lt__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value < other._value
|
||||
|
||||
def __le__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value <= other._value
|
||||
|
||||
def __gt__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value > other._value
|
||||
|
||||
def __ge__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.comparisons += 1
|
||||
return self._value >= other._value
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Arithmetik (2 reads + 1 op → neues Int mit gleichem ctx)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __add__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.additions += 1
|
||||
return Int(self._value + other._value, self._ctx)
|
||||
|
||||
def __radd__(self, other):
|
||||
return self._wrap(other).__add__(self)
|
||||
|
||||
def __sub__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.subtractions += 1
|
||||
return Int(self._value - other._value, self._ctx)
|
||||
|
||||
def __rsub__(self, other):
|
||||
return self._wrap(other).__sub__(self)
|
||||
|
||||
def __mul__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.multiplications += 1
|
||||
return Int(self._value * other._value, self._ctx)
|
||||
|
||||
def __rmul__(self, other):
|
||||
return self._wrap(other).__mul__(self)
|
||||
|
||||
def __truediv__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.divisions += 1
|
||||
return Int(self._value / other._value, self._ctx)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.divisions += 1
|
||||
return Int(self._value // other._value, self._ctx)
|
||||
|
||||
def __mod__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.divisions += 1
|
||||
return Int(self._value % other._value, self._ctx)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Augmented assignment (2 reads + 1 op + 1 write, in-place)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __iadd__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.additions += 1
|
||||
self._ctx.writes += 1
|
||||
self._value += other._value
|
||||
return self
|
||||
|
||||
def __isub__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.subtractions += 1
|
||||
self._ctx.writes += 1
|
||||
self._value -= other._value
|
||||
return self
|
||||
|
||||
def __imul__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.multiplications += 1
|
||||
self._ctx.writes += 1
|
||||
self._value *= other._value
|
||||
return self
|
||||
|
||||
def __itruediv__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.divisions += 1
|
||||
self._ctx.writes += 1
|
||||
self._value /= other._value
|
||||
return self
|
||||
|
||||
def __ifloordiv__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.divisions += 1
|
||||
self._ctx.writes += 1
|
||||
self._value //= other._value
|
||||
return self
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Bitoperationen (2 reads + 1 bitop + 1 write für in-place)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __and__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
return Int(self._value & other._value, self._ctx)
|
||||
|
||||
def __or__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
return Int(self._value | other._value, self._ctx)
|
||||
|
||||
def __xor__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
return Int(self._value ^ other._value, self._ctx)
|
||||
|
||||
def __lshift__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
return Int(self._value << other._value, self._ctx)
|
||||
|
||||
def __rshift__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
return Int(self._value >> other._value, self._ctx)
|
||||
|
||||
def __iand__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
self._ctx.writes += 1
|
||||
self._value &= other._value
|
||||
return self
|
||||
|
||||
def __ior__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
self._ctx.writes += 1
|
||||
self._value |= other._value
|
||||
return self
|
||||
|
||||
def __ixor__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
self._ctx.writes += 1
|
||||
self._value ^= other._value
|
||||
return self
|
||||
|
||||
def __ilshift__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
self._ctx.writes += 1
|
||||
self._value <<= other._value
|
||||
return self
|
||||
|
||||
def __irshift__(self, other):
|
||||
other = self._wrap(other)
|
||||
self._ctx.reads += 2
|
||||
self._ctx.bitops += 1
|
||||
self._ctx.writes += 1
|
||||
self._value >>= other._value
|
||||
return self
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Typkonvertierung und Darstellung
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def __int__(self):
|
||||
return int(self._value)
|
||||
|
||||
def __float__(self):
|
||||
return float(self._value)
|
||||
|
||||
def __index__(self):
|
||||
"""Ermöglicht Verwendung als Listen-Index (z.B. arr[i])."""
|
||||
return int(self._value)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self._value)
|
||||
|
||||
def __bool__(self):
|
||||
return bool(self._value)
|
||||
|
||||
def __neg__(self):
|
||||
return Int(-self._value, self._ctx)
|
||||
|
||||
def __abs__(self):
|
||||
return Int(abs(self._value), self._ctx)
|
||||
|
||||
def __str__(self):
|
||||
return str(self._value)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Int({self._value})"
|
||||
@@ -0,0 +1,51 @@
|
||||
from __future__ import annotations
|
||||
from utils.algo_context import AlgoContext, NULL_CTX
|
||||
from utils.algo_int import Int
|
||||
|
||||
|
||||
def irange(start_or_stop, stop=None, step: int = 1, ctx: AlgoContext = None):
|
||||
"""
|
||||
Drop-in Ersatz für range(), der Int-Objekte zurückgibt.
|
||||
|
||||
Wird wie Pythons range() aufgerufen:
|
||||
irange(stop)
|
||||
irange(start, stop)
|
||||
irange(start, stop, step)
|
||||
|
||||
Indexarithmetik und Zählung
|
||||
---------------------------
|
||||
Ohne ctx-Argument (Standard) erhalten die erzeugten Indices einen NULL_CTX –
|
||||
Arithmetik auf Loop-Indices (z.B. ``j - 1``) wird dann **nicht** gezählt.
|
||||
Das entspricht dem üblichen Lehrbuchwunsch: nur Operationen auf Array-Inhalten
|
||||
sollen in die Komplexitätsanalyse einfließen.
|
||||
|
||||
Mit ctx-Argument werden auch Indexoperationen gezählt:
|
||||
for j in irange(n, ctx=ctx): ...
|
||||
|
||||
Beispiel
|
||||
--------
|
||||
ctx = AlgoContext()
|
||||
z = Array.random(10, 0, 99, ctx)
|
||||
for i in irange(len(z) - 1): # i ist Int, Arithmetik nicht gezählt
|
||||
if z[i] > z[i + 1]: # Vergleich gezählt (z-Zellen haben ctx)
|
||||
z.swap(i, i + 1)
|
||||
"""
|
||||
_ctx = ctx if ctx is not None else NULL_CTX
|
||||
|
||||
if stop is None:
|
||||
start, stop_ = 0, int(start_or_stop)
|
||||
else:
|
||||
start, stop_ = int(start_or_stop), int(stop)
|
||||
step = int(step)
|
||||
|
||||
assert step != 0, "irange: step darf nicht 0 sein"
|
||||
|
||||
num = start
|
||||
if step > 0:
|
||||
while num < stop_:
|
||||
yield Int(num, _ctx)
|
||||
num += step
|
||||
else:
|
||||
while num > stop_:
|
||||
yield Int(num, _ctx)
|
||||
num += step
|
||||
@@ -1,5 +0,0 @@
|
||||
from utils.literal import Literal
|
||||
|
||||
MAX_VALUE = Literal(99999999999999999999)
|
||||
MIN_VALUE = Literal(-99999999999999999999)
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
|
||||
class Literal:
|
||||
def __init__(self, value):
|
||||
"""Initialisiert Literal."""
|
||||
if isinstance(value, Literal):
|
||||
self.value = value.value
|
||||
else:
|
||||
self.value = value
|
||||
self.read_count = 0
|
||||
self.compare_count = 0
|
||||
|
||||
def reset_counters(self):
|
||||
"""Setzt alle Zähler auf 0 zurück."""
|
||||
self.read_count = 0
|
||||
self.compare_count = 0
|
||||
|
||||
def get(self):
|
||||
"""Liest den Wert aus."""
|
||||
self.read_count += 1
|
||||
return self.value
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Vergleicht den Wert mit einem anderen Wert."""
|
||||
if other is None:
|
||||
return False
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value == other.value
|
||||
|
||||
def __ne__(self, other):
|
||||
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
if other is None:
|
||||
return True
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value != other.value
|
||||
|
||||
def __lt__(self, other):
|
||||
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value < other.value
|
||||
|
||||
def __le__(self, other):
|
||||
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value <= other.value
|
||||
|
||||
def __gt__(self, other):
|
||||
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value > other.value
|
||||
|
||||
def __ge__(self, other):
|
||||
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
|
||||
self.compare_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return self.value >= other.value
|
||||
|
||||
def __str__(self):
|
||||
"""Repräsentation des Werts."""
|
||||
return f"{self.value}"
|
||||
|
||||
def __repr__(self):
|
||||
"""Repräsentation des Werts für Debugging-Zwecke."""
|
||||
return f"Literal(value={self.value}, reads={self.read_count})"
|
||||
|
||||
def get_read_count(self):
|
||||
"""Gibt zurück, wie oft der Wert gelesen wurde."""
|
||||
return self.read_count
|
||||
|
||||
def __int__(self):
|
||||
"""Gibt den Wert als Integer zurück."""
|
||||
self.read_count += 1
|
||||
return int(self.value)
|
||||
|
||||
def succ(self):
|
||||
return Literal(self.value+1)
|
||||
|
||||
def pred(self):
|
||||
return Literal(self.value-1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
l1 = Literal(5)
|
||||
l2 = Literal(3)
|
||||
print(l1 == l2)
|
||||
print(l1 > l2)
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
from utils.literal import Literal
|
||||
from utils.memory_cell import MemoryCell
|
||||
from utils.memory_manager import MemoryManager
|
||||
from utils.project_dir import get_path
|
||||
from random import randint
|
||||
|
||||
class MemoryArray:
|
||||
|
||||
def __init__(self, parm):
|
||||
if isinstance(parm, Literal):
|
||||
self.init_with_size(parm)
|
||||
elif isinstance(parm, list):
|
||||
self.size = len(parm)
|
||||
self.cells = [MemoryCell(value) for value in parm]
|
||||
else:
|
||||
raise ValueError("Invalid parameter type")
|
||||
|
||||
def init_with_size(self, size):
|
||||
"""Initialisiert ein Speicherarray mit einer bestimmten Größe."""
|
||||
assert isinstance(size, Literal), "Size must be a Literal or MemoryCell"
|
||||
assert isinstance(size.value, int), "Size must be an int"
|
||||
assert size.value > 0, "Size must be positive"
|
||||
self.size = size.value
|
||||
self.cells = [MemoryCell() for _ in range(self.size)]
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""Gibt den Wert einer Speicherzelle zurück."""
|
||||
assert isinstance(index, Literal), "Index must be a Literal or MemoryCell"
|
||||
assert isinstance(index.value, int), "Index value must be an int"
|
||||
assert 0 <= index.value < self.size, "Index out of bounds"
|
||||
return self.cells[index.value]
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""Setzt den Wert einer Speicherzelle."""
|
||||
assert isinstance(index, Literal), "Index must be a Literal or MemoryCell"
|
||||
assert isinstance(index.value, int), "Index value must be an int"
|
||||
assert 0 <= index.value < self.size, "Index out of bounds"
|
||||
assert isinstance(value, Literal), "Value must be a Literal or MemoryCell"
|
||||
self.cells[index.value].set(value.value)
|
||||
|
||||
def __len__(self):
|
||||
"""Gibt die Größe des Speicherarrays zurück."""
|
||||
return self.size
|
||||
|
||||
def __str__(self):
|
||||
"""Gibt eine Liste der Speicherzellen zurück."""
|
||||
return str([cell.value for cell in self.cells])
|
||||
|
||||
def __iter__(self):
|
||||
"""Gibt einen Iterator über die Speicherzellen zurück."""
|
||||
return iter(self.cells)
|
||||
|
||||
def indices(self):
|
||||
"""Gibt eine Liste der Indizes der Speicherzellen zurück."""
|
||||
return [Literal(i) for i in range(self.size)]
|
||||
|
||||
def length(self):
|
||||
"""Gibt die Größe des Speicherarrays zurück."""
|
||||
return Literal(self.size)
|
||||
|
||||
def count_compares(self):
|
||||
return sum([cell.compare_count for cell in self.cells])
|
||||
|
||||
|
||||
def reset_counters(self):
|
||||
"""Setzt alle Zähler auf 0 zurück."""
|
||||
for cell in self.cells:
|
||||
cell.reset_counters()
|
||||
|
||||
@staticmethod
|
||||
def create_random_array(count, min_value, max_value):
|
||||
"""Erzeugt ein zufälliges Speicherarray."""
|
||||
size = Literal(count)
|
||||
a = MemoryArray(size)
|
||||
for i in a.indices():
|
||||
a[i] = Literal(randint(min_value, max_value))
|
||||
a.reset_counters()
|
||||
return a
|
||||
|
||||
@staticmethod
|
||||
def create_sorted_array(count):
|
||||
"""Erzeugt ein sortiertes Speicherarray."""
|
||||
a = MemoryArray(list(range(count)))
|
||||
a.reset_counters()
|
||||
return a
|
||||
|
||||
|
||||
@staticmethod
|
||||
def create_array_from_file(filename, limit=None):
|
||||
"""Erzeugt ein Speicherarray aus einer Datei."""
|
||||
filename = get_path(filename)
|
||||
with open(filename) as f:
|
||||
lines = f.readlines()
|
||||
if limit is not None:
|
||||
lines = lines[:limit]
|
||||
size = Literal(len(lines))
|
||||
a = MemoryArray(size)
|
||||
for i, line in enumerate(lines):
|
||||
a[Literal(i)] = Literal(int(line))
|
||||
a.reset_counters()
|
||||
return a
|
||||
|
||||
def __str__(self):
|
||||
result = "[ "
|
||||
for cell in self.cells:
|
||||
result += str(cell) + ", "
|
||||
result += "]"
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import random
|
||||
size = Literal(5)
|
||||
a = MemoryArray(size)
|
||||
for i in a.indices():
|
||||
a[i] = Literal(random.randint(1,100))
|
||||
print(a)
|
||||
s = MemoryCell(0)
|
||||
for cell in a.cells:
|
||||
s += cell
|
||||
print(s)
|
||||
print(f"Anzahl der Additionen: {MemoryManager.count_adds()}")
|
||||
|
||||
a = MemoryArray.create_array_from_file("data/seq0.txt")
|
||||
print(a)
|
||||
|
||||
@@ -1,194 +0,0 @@
|
||||
from utils.memory_manager import MemoryManager
|
||||
from utils.literal import Literal
|
||||
|
||||
class MemoryCell (Literal):
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Erstellt eine neue Instanz von MemoryCell."""
|
||||
instance = MemoryManager().acquire_cell()
|
||||
if instance is None:
|
||||
instance = super().__new__(cls)
|
||||
MemoryManager().register_cell(instance)
|
||||
return instance
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
MemoryManager().release_cell(self)
|
||||
|
||||
def __init__(self, value=None):
|
||||
"""Initialisiert eine Speicherzelle mit optionalem Startwert."""
|
||||
super().__init__(value)
|
||||
self.write_count = 0
|
||||
self.add_count = 0
|
||||
self.sub_count = 0
|
||||
self.mul_count = 0
|
||||
self.div_count = 0
|
||||
self.bitop_count = 0
|
||||
if value is not None:
|
||||
self.write_count +=1
|
||||
else:
|
||||
self.value = 0
|
||||
|
||||
def reset_counters(self):
|
||||
"""Setzt alle Zähler auf 0 zurück."""
|
||||
super().reset_counters()
|
||||
self.write_count = 0
|
||||
self.add_count = 0
|
||||
self.sub_count = 0
|
||||
self.mul_count = 0
|
||||
self.div_count = 0
|
||||
self.bitop_count = 0
|
||||
|
||||
def set(self, new_value):
|
||||
"""Schreibt einen neuen Wert in die Speicherzelle und erhöht den Schreibzähler."""
|
||||
self.write_count += 1
|
||||
if isinstance(new_value, Literal):
|
||||
self.value = new_value.value
|
||||
else:
|
||||
self.value = new_value
|
||||
|
||||
def add(self, other):
|
||||
"""Addiert den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
self.set((self + other).value)
|
||||
|
||||
def sub(self, other):
|
||||
"""Subtrahiert den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
self.set((self - other).value)
|
||||
|
||||
def mul(self, other):
|
||||
"""Multipliziert den Wert der Speicherzelle mit einem anderen Wert."""
|
||||
self.set((self * other).value)
|
||||
|
||||
def div(self, other):
|
||||
"""Dividiert den Wert der Speicherzelle durch einen anderen Wert."""
|
||||
self.set((self // other).value)
|
||||
|
||||
def modulo(self, other):
|
||||
"""Berechnet den Modulo des Wertes der Speicherzelle durch einen anderen Wert."""
|
||||
self.set((self % other).value)
|
||||
|
||||
def lshift(self, other):
|
||||
"""Verschiebt den Wert der Speicherzelle um eine bestimmte Anzahl von Bits nach links."""
|
||||
assert isinstance(other, Literal), "Can only lshift Literal or MemoryCell by MemoryCell"
|
||||
self.bitop_count += 1
|
||||
self.read_count += 1
|
||||
self.write_count += 1
|
||||
other.read_count += 1
|
||||
self.value <<= other.value
|
||||
|
||||
def rshift(self, other):
|
||||
"""Verschiebt den Wert der Speicherzelle um eine bestimmte Anzahl von Bits nach rechts."""
|
||||
assert isinstance(other, Literal), "Can only rshift Literal or MemoryCell by MemoryCell"
|
||||
self.bitop_count += 1
|
||||
self.read_count += 1
|
||||
self.write_count += 1
|
||||
other.read_count += 1
|
||||
self.value >>= other.value
|
||||
|
||||
def and_op(self, other):
|
||||
"""Führt ein Bitweise AND auf den Wert der Speicherzelle mit einem anderen Wert aus."""
|
||||
assert isinstance(other, Literal), "Can only and Literal or MemoryCell with MemoryCell"
|
||||
self.bitop_count += 1
|
||||
self.read_count += 1
|
||||
self.write_count += 1
|
||||
other.read_count += 1
|
||||
self.value &= other.value
|
||||
|
||||
def or_op(self, other):
|
||||
"""Führt ein Bitweise OR auf den Wert der Speicherzelle mit einem anderen Wert aus."""
|
||||
assert isinstance(other, Literal), "Can only or Literal or MemoryCell with MemoryCell"
|
||||
self.bitop_count += 1
|
||||
self.read_count += 1
|
||||
self.write_count += 1
|
||||
other.read_count += 1
|
||||
self.value |= other.value
|
||||
|
||||
def xor_op(self, other):
|
||||
"""Führt ein Bitweise XOR auf den Wert der Speicherzelle mit einem anderen Wert aus."""
|
||||
assert isinstance(other, Literal), "Can only xor Literal or MemoryCell with MemoryCell"
|
||||
self.bitop_count += 1
|
||||
self.read_count += 1
|
||||
self.write_count += 1
|
||||
other.read_count += 1
|
||||
self.value ^= other.value
|
||||
|
||||
def get_write_count(self):
|
||||
"""Gibt zurück, wie oft der Wert geschrieben wurde."""
|
||||
return self.write_count
|
||||
|
||||
def __repr__(self):
|
||||
"""Repräsentation der Speicherzelle für Debugging-Zwecke."""
|
||||
return f"MemoryCell(value={self.value}, reads={self.read_count}, writes={self.write_count})"
|
||||
|
||||
def __add__(self, other):
|
||||
assert isinstance(other, Literal), "Can only add Literal or MemoryCell to MemoryCell"
|
||||
self.add_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value + other.value)
|
||||
|
||||
def __sub__(self, other):
|
||||
assert isinstance(other, Literal), "Can only add Literal or MemoryCell to MemoryCell"
|
||||
self.sub_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value - other.value)
|
||||
|
||||
def __mul__(self, other):
|
||||
assert isinstance(other, Literal), "Can only mul Literal or MemoryCell with MemoryCell"
|
||||
self.mul_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value * other.value)
|
||||
|
||||
def __truediv__(self, other):
|
||||
assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell"
|
||||
self.div_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value / other.value)
|
||||
|
||||
def __floordiv__(self, other):
|
||||
assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell"
|
||||
self.div_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value // other.value)
|
||||
|
||||
def __mod__(self, other):
|
||||
assert isinstance(other, Literal), "Can only div Literal or MemoryCell by MemoryCell"
|
||||
self.div_count += 1
|
||||
self.read_count += 1
|
||||
other.read_count += 1
|
||||
return Literal(self.value % other.value)
|
||||
|
||||
def __iadd__(self, other):
|
||||
self.add(other)
|
||||
return self
|
||||
|
||||
def __isub__(self, other):
|
||||
self.sub(other)
|
||||
return self
|
||||
|
||||
def __imul__(self, other):
|
||||
self.mul(other)
|
||||
return self
|
||||
|
||||
def __itruediv__(self, other):
|
||||
self.set(self // other)
|
||||
return self
|
||||
|
||||
def __ifloordiv__(self, other):
|
||||
self.div(other)
|
||||
return self
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
a = MemoryCell(5)
|
||||
b = MemoryCell(3)
|
||||
a += b
|
||||
print(f"Ergebnis: {a}")
|
||||
print(f"a wurde {a.get_read_count()} mal gelesen und {a.get_write_count()} mal geschrieben.")
|
||||
print(f"b wurde {b.get_read_count()} mal gelesen und {b.get_write_count()} mal geschrieben.")
|
||||
@@ -1,148 +0,0 @@
|
||||
import matplotlib.pyplot as plt
|
||||
import queue
|
||||
|
||||
|
||||
class MemoryManager:
|
||||
|
||||
_instance = None
|
||||
stats = {}
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
"""Erstellt eine einzige Instanz von MemoryManager."""
|
||||
if cls._instance is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls._instance._initialize() # Eigene Init-Methode, damit __init__ nicht mehrfach läuft
|
||||
return cls._instance
|
||||
|
||||
def _initialize(self):
|
||||
"""Initialisiert die Speicherverwaltung (einmalig)."""
|
||||
self.cells = []
|
||||
self._pool = queue.Queue()
|
||||
self._finalizers = {}
|
||||
|
||||
|
||||
@staticmethod
|
||||
def count_cells():
|
||||
return len(MemoryManager().cells)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def count_reads():
|
||||
return sum([cell.read_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_writes():
|
||||
return sum([cell.write_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_compares():
|
||||
return sum([cell.compare_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_adds():
|
||||
return sum([cell.add_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_subs():
|
||||
return sum([cell.sub_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_muls():
|
||||
return sum([cell.mul_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_divs():
|
||||
return sum([cell.div_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def count_bitops():
|
||||
return sum([cell.bitop_count for cell in MemoryManager().cells])
|
||||
|
||||
@staticmethod
|
||||
def reset():
|
||||
manager = MemoryManager()
|
||||
for cell in manager.cells:
|
||||
cell.reset_counters()
|
||||
|
||||
@staticmethod
|
||||
def purge():
|
||||
MemoryManager._instance = None
|
||||
|
||||
@staticmethod
|
||||
def save_stats(count):
|
||||
data = { "cells": MemoryManager.count_cells(),
|
||||
"reads": MemoryManager.count_reads(),
|
||||
"writes": MemoryManager.count_writes(),
|
||||
"compares": MemoryManager.count_compares(),
|
||||
"adds": MemoryManager.count_adds(),
|
||||
"subs": MemoryManager.count_subs(),
|
||||
"muls": MemoryManager.count_muls(),
|
||||
"divs": MemoryManager.count_divs(),
|
||||
"bitops": MemoryManager.count_bitops() }
|
||||
MemoryManager.stats[count] = data
|
||||
|
||||
@staticmethod
|
||||
def plot_stats(labels):
|
||||
data = MemoryManager.stats
|
||||
x = list(data.keys())
|
||||
|
||||
fig, axes = plt.subplots(len(labels), 1, figsize=(8, 4 * len(labels)), sharex=True)
|
||||
|
||||
if len(labels) == 1:
|
||||
axes = [axes] # Falls nur ein Plot vorhanden ist, in eine Liste umwandeln
|
||||
|
||||
for ax, l in zip(axes, labels):
|
||||
y = [data[k][l] for k in x]
|
||||
ax.plot(x, y, label=l)
|
||||
ax.set_ylabel(l)
|
||||
ax.legend()
|
||||
|
||||
plt.xlabel("n")
|
||||
plt.show()
|
||||
|
||||
|
||||
def acquire_cell(self):
|
||||
try:
|
||||
return self._pool.get_nowait()
|
||||
except queue.Empty:
|
||||
return None
|
||||
|
||||
def register_cell(self, cell):
|
||||
self.cells.append(cell)
|
||||
|
||||
def release_cell(self, cell):
|
||||
self._pool.put(cell)
|
||||
|
||||
|
||||
class Testcell:
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
instance = MemoryManager().acquire_cell()
|
||||
if instance is None:
|
||||
instance = super().__new__(cls)
|
||||
MemoryManager().register_cell(instance)
|
||||
return instance
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
MemoryManager().release_cell(self)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
# Einfaches Anlegen einer Zelle
|
||||
a = Testcell()
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
# Anlegen einer Zelle und Beenden des Scopes
|
||||
with Testcell() as b:
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
# Reuse einer Zelle
|
||||
c = Testcell()
|
||||
print(MemoryManager.count_cells())
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
from utils.literal import Literal
|
||||
|
||||
# a generator that yields items instead of returning a list
|
||||
def mrange(parm1, parm2=None, parm3=None):
|
||||
if parm2 is None:
|
||||
start = 0
|
||||
stop = int(parm1)
|
||||
step = 1
|
||||
elif parm3 is None:
|
||||
start = int(parm1)
|
||||
stop = int(parm2)
|
||||
step = 1
|
||||
else:
|
||||
start = int(parm1)
|
||||
stop = int(parm2)
|
||||
step = int(parm3)
|
||||
num = start
|
||||
if step > 0:
|
||||
while num < stop:
|
||||
yield Literal(num)
|
||||
num += step
|
||||
else:
|
||||
while num > stop:
|
||||
yield Literal(num)
|
||||
num += step
|
||||
|
||||
if __name__ == "__main__":
|
||||
for l in mrange(10):
|
||||
print(l)
|
||||
@@ -0,0 +1,175 @@
|
||||
import unittest
|
||||
from utils.algo_context import AlgoContext
|
||||
from utils.algo_int import Int
|
||||
from utils.algo_array import Array
|
||||
|
||||
|
||||
class TestArray(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.ctx = AlgoContext()
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Erzeugung
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_from_list(self):
|
||||
z = Array([3, 1, 4, 1, 5], self.ctx)
|
||||
self.assertEqual(len(z), 5)
|
||||
self.assertEqual(z[0].value, 3)
|
||||
self.assertEqual(z[4].value, 5)
|
||||
|
||||
def test_random(self):
|
||||
z = Array.random(20, 0, 99, self.ctx)
|
||||
self.assertEqual(len(z), 20)
|
||||
for cell in z:
|
||||
self.assertGreaterEqual(cell.value, 0)
|
||||
self.assertLessEqual(cell.value, 99)
|
||||
|
||||
def test_sorted(self):
|
||||
z = Array.sorted(5, self.ctx)
|
||||
values = [z[i].value for i in range(5)]
|
||||
self.assertEqual(values, [0, 1, 2, 3, 4])
|
||||
|
||||
def test_from_file(self):
|
||||
z = Array.from_file("data/seq0.txt", self.ctx)
|
||||
self.assertGreater(len(z), 0)
|
||||
|
||||
def test_random_uses_no_write_counts(self):
|
||||
"""Fabrikmethoden sollen keine Schreibzugriffe verzeichnen."""
|
||||
z = Array.random(10, 0, 9, self.ctx)
|
||||
self.assertEqual(self.ctx.writes, 0)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Zugriff
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_getitem_returns_int_cell(self):
|
||||
z = Array([10, 20], self.ctx)
|
||||
cell = z[0]
|
||||
self.assertIsInstance(cell, Int)
|
||||
self.assertEqual(cell.value, 10)
|
||||
|
||||
def test_getitem_with_int_index(self):
|
||||
z = Array([10, 20, 30], self.ctx)
|
||||
i = Int(2, self.ctx)
|
||||
self.assertEqual(z[i].value, 30)
|
||||
|
||||
def test_getitem_no_read_count(self):
|
||||
"""Array-Zugriff allein soll keinen read-Zähler erhöhen."""
|
||||
z = Array([5, 6, 7], self.ctx)
|
||||
_ = z[0]
|
||||
self.assertEqual(self.ctx.reads, 0)
|
||||
|
||||
def test_setitem_plain_int(self):
|
||||
z = Array([1, 2, 3], self.ctx)
|
||||
z[0] = 99
|
||||
self.assertEqual(z[0].value, 99)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
self.assertEqual(self.ctx.reads, 0)
|
||||
|
||||
def test_setitem_int_object(self):
|
||||
z = Array([1, 2, 3], self.ctx)
|
||||
v = Int(42, self.ctx)
|
||||
z[1] = v
|
||||
self.assertEqual(z[1].value, 42)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
self.assertEqual(self.ctx.reads, 1)
|
||||
|
||||
def test_setitem_cell_to_cell(self):
|
||||
"""z[i] = z[j] kopiert den Wert (keine Alias-Referenz)."""
|
||||
z = Array([10, 20], self.ctx)
|
||||
z[0] = z[1]
|
||||
self.assertEqual(z[0].value, 20)
|
||||
# Wert ändern – z[1] darf sich nicht mitändern
|
||||
z[0] = 99
|
||||
self.assertEqual(z[1].value, 20)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Swap
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_swap_exchanges_values(self):
|
||||
z = Array([1, 2, 3, 4, 5], self.ctx)
|
||||
z.swap(0, 4)
|
||||
self.assertEqual(z[0].value, 5)
|
||||
self.assertEqual(z[4].value, 1)
|
||||
|
||||
def test_swap_counts_reads_and_writes(self):
|
||||
z = Array([1, 2], self.ctx)
|
||||
z.swap(0, 1)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
self.assertEqual(self.ctx.writes, 2)
|
||||
|
||||
def test_swap_with_int_indices(self):
|
||||
z = Array([10, 20, 30], self.ctx)
|
||||
i = Int(0, self.ctx)
|
||||
j = Int(2, self.ctx)
|
||||
z.swap(i, j)
|
||||
self.assertEqual(z[0].value, 30)
|
||||
self.assertEqual(z[2].value, 10)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Vergleich über Array-Zellen (zählt beim Int, nicht beim Array)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_cell_comparison_counts_in_ctx(self):
|
||||
z = Array([5, 3], self.ctx)
|
||||
result = z[0] > z[1]
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(self.ctx.comparisons, 1)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Iteration
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_iteration(self):
|
||||
z = Array([1, 2, 3], self.ctx)
|
||||
values = [c.value for c in z]
|
||||
self.assertEqual(values, [1, 2, 3])
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Länge
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_len(self):
|
||||
z = Array([1, 2, 3, 4], self.ctx)
|
||||
self.assertEqual(len(z), 4)
|
||||
|
||||
def test_length_returns_int(self):
|
||||
z = Array([1, 2, 3], self.ctx)
|
||||
n = z.length()
|
||||
self.assertIsInstance(n, Int)
|
||||
self.assertEqual(n.value, 3)
|
||||
|
||||
|
||||
class TestArrayIntegration(unittest.TestCase):
|
||||
"""Bubble Sort als Integrationstest für das gesamte Framework."""
|
||||
|
||||
def test_bubble_sort_produces_correct_result(self):
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
|
||||
'../vorlesung/L02_elementares_sortieren'))
|
||||
from bubble_sorting import bubble_sort
|
||||
ctx = AlgoContext()
|
||||
z = Array([5, 3, 1, 4, 2], ctx)
|
||||
bubble_sort(z, ctx)
|
||||
values = [z[i].value for i in range(len(z))]
|
||||
self.assertEqual(values, [1, 2, 3, 4, 5])
|
||||
|
||||
def test_bubble_sort_counts_comparisons(self):
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__),
|
||||
'../vorlesung/L02_elementares_sortieren'))
|
||||
from bubble_sorting import bubble_sort
|
||||
ctx = AlgoContext()
|
||||
z = Array([5, 4, 3, 2, 1], ctx) # worst case
|
||||
bubble_sort(z, ctx)
|
||||
# n=5: maximal n*(n-1)/2 = 10 Vergleiche
|
||||
self.assertGreater(ctx.comparisons, 0)
|
||||
self.assertLessEqual(ctx.comparisons, 10)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,193 @@
|
||||
import unittest
|
||||
from utils.algo_context import AlgoContext
|
||||
from utils.algo_int import Int
|
||||
|
||||
|
||||
class TestInt(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.ctx = AlgoContext()
|
||||
|
||||
def _int(self, v):
|
||||
return Int(v, self.ctx)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Vergleiche
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_comparison_counts_reads_and_compare(self):
|
||||
a, b = self._int(5), self._int(3)
|
||||
result = a > b
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(self.ctx.comparisons, 1)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
|
||||
def test_all_comparison_operators(self):
|
||||
a, b = self._int(4), self._int(4)
|
||||
self.assertTrue(a == b)
|
||||
self.assertFalse(a != b)
|
||||
self.assertTrue(a <= b)
|
||||
self.assertTrue(a >= b)
|
||||
self.assertFalse(a < b)
|
||||
self.assertFalse(a > b)
|
||||
self.assertEqual(self.ctx.comparisons, 6)
|
||||
self.assertEqual(self.ctx.reads, 12)
|
||||
|
||||
def test_comparison_with_plain_int(self):
|
||||
a = self._int(5)
|
||||
result = a > 3 # 3 wird auto-gewrappt, kein extra Zähler
|
||||
self.assertTrue(result)
|
||||
self.assertEqual(self.ctx.comparisons, 1)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
|
||||
def test_eq_with_none_returns_false(self):
|
||||
a = self._int(1)
|
||||
self.assertFalse(a == None) # noqa: E711
|
||||
self.assertEqual(self.ctx.comparisons, 0) # keine Zählung
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Arithmetik (binär)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_addition_returns_new_int(self):
|
||||
a, b = self._int(3), self._int(4)
|
||||
c = a + b
|
||||
self.assertIsInstance(c, Int)
|
||||
self.assertEqual(c.value, 7)
|
||||
self.assertEqual(self.ctx.additions, 1)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
self.assertEqual(self.ctx.writes, 0)
|
||||
|
||||
def test_subtraction(self):
|
||||
a, b = self._int(10), self._int(4)
|
||||
c = a - b
|
||||
self.assertEqual(c.value, 6)
|
||||
self.assertEqual(self.ctx.subtractions, 1)
|
||||
|
||||
def test_multiplication(self):
|
||||
a, b = self._int(3), self._int(4)
|
||||
c = a * b
|
||||
self.assertEqual(c.value, 12)
|
||||
self.assertEqual(self.ctx.multiplications, 1)
|
||||
|
||||
def test_floordiv(self):
|
||||
a, b = self._int(10), self._int(3)
|
||||
c = a // b
|
||||
self.assertEqual(c.value, 3)
|
||||
self.assertEqual(self.ctx.divisions, 1)
|
||||
|
||||
def test_mod(self):
|
||||
a, b = self._int(10), self._int(3)
|
||||
c = a % b
|
||||
self.assertEqual(c.value, 1)
|
||||
self.assertEqual(self.ctx.divisions, 1)
|
||||
|
||||
def test_arithmetic_with_plain_int(self):
|
||||
a = self._int(5)
|
||||
c = a + 3
|
||||
self.assertEqual(c.value, 8)
|
||||
self.assertEqual(self.ctx.additions, 1)
|
||||
|
||||
def test_result_shares_context(self):
|
||||
a = self._int(5)
|
||||
b = self._int(3)
|
||||
c = a + b # c hat denselben ctx
|
||||
_ = c > self._int(0) # Vergleich auf c zählt im selben ctx
|
||||
self.assertEqual(self.ctx.comparisons, 1)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Augmented assignment
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_iadd_counts_read_add_write(self):
|
||||
a, b = self._int(5), self._int(3)
|
||||
a += b
|
||||
self.assertEqual(a.value, 8)
|
||||
self.assertEqual(self.ctx.reads, 2)
|
||||
self.assertEqual(self.ctx.additions, 1)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
|
||||
def test_isub(self):
|
||||
a, b = self._int(10), self._int(4)
|
||||
a -= b
|
||||
self.assertEqual(a.value, 6)
|
||||
self.assertEqual(self.ctx.subtractions, 1)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
|
||||
def test_imul(self):
|
||||
a, b = self._int(3), self._int(4)
|
||||
a *= b
|
||||
self.assertEqual(a.value, 12)
|
||||
self.assertEqual(self.ctx.multiplications, 1)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
|
||||
def test_iadd_with_plain_int(self):
|
||||
a = self._int(5)
|
||||
a += 1
|
||||
self.assertEqual(a.value, 6)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# set()
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_set_plain_counts_one_write(self):
|
||||
a = self._int(0)
|
||||
a.set(42)
|
||||
self.assertEqual(a.value, 42)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
self.assertEqual(self.ctx.reads, 0)
|
||||
|
||||
def test_set_int_counts_write_and_read(self):
|
||||
a = self._int(0)
|
||||
b = self._int(7)
|
||||
a.set(b)
|
||||
self.assertEqual(a.value, 7)
|
||||
self.assertEqual(self.ctx.writes, 1)
|
||||
self.assertEqual(self.ctx.reads, 1)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Typkonvertierung
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_int_conversion(self):
|
||||
a = self._int(5)
|
||||
self.assertEqual(int(a), 5)
|
||||
|
||||
def test_index_usage(self):
|
||||
a = self._int(2)
|
||||
lst = [10, 20, 30]
|
||||
self.assertEqual(lst[a], 30) # __index__
|
||||
|
||||
def test_hash(self):
|
||||
a = self._int(5)
|
||||
self.assertEqual(hash(a), hash(5))
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# AlgoContext.reset()
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def test_context_reset(self):
|
||||
a, b = self._int(3), self._int(4)
|
||||
_ = a > b
|
||||
self.ctx.reset()
|
||||
self.assertEqual(self.ctx.comparisons, 0)
|
||||
self.assertEqual(self.ctx.reads, 0)
|
||||
|
||||
|
||||
class TestIntNullCtx(unittest.TestCase):
|
||||
"""Int ohne expliziten ctx (irange-Verwendung) – keine Zählung."""
|
||||
|
||||
def test_arithmetic_without_ctx_produces_no_counts(self):
|
||||
from utils.algo_context import NULL_CTX
|
||||
a = Int(5) # uses NULL_CTX by default
|
||||
b = Int(3)
|
||||
_ = a + b
|
||||
_ = a > b
|
||||
# NULL_CTX hat feste 0-Attribute – keine Ausnahme, keine Zählung
|
||||
self.assertEqual(NULL_CTX.additions, 0)
|
||||
self.assertEqual(NULL_CTX.comparisons, 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -1,47 +0,0 @@
|
||||
from unittest import TestCase
|
||||
from utils.literal import Literal
|
||||
from utils.memory_array import MemoryArray
|
||||
import random
|
||||
|
||||
class TestMemoryArray(TestCase):
|
||||
|
||||
def test_create_array(self):
|
||||
l = random.randint(5,10)
|
||||
size = Literal(l)
|
||||
a = MemoryArray(size)
|
||||
self.assertEqual(len(a), l)
|
||||
|
||||
def test_set_item(self):
|
||||
l = random.randint(5,10)
|
||||
size = Literal(l)
|
||||
a = MemoryArray(size)
|
||||
i = Literal(random.randint(0,l-1))
|
||||
v = Literal(random.randint(1,100))
|
||||
a[i] = v
|
||||
self.assertEqual(a[i].value, v.value)
|
||||
|
||||
def test_get_item(self):
|
||||
l = random.randint(5,10)
|
||||
values = [random.randint(1,100) for _ in range(l)]
|
||||
a = MemoryArray(values)
|
||||
for pos, i in enumerate(a.indices()):
|
||||
self.assertEqual(a[i].value, values[pos])
|
||||
|
||||
def test_reset_counters(self):
|
||||
l = random.randint(5,10)
|
||||
values = [random.randint(1,100) for _ in range(l)]
|
||||
a = MemoryArray(values)
|
||||
for i in a.indices():
|
||||
self.assertEqual(a[i].write_count, 1)
|
||||
a.reset_counters()
|
||||
for i in a.indices():
|
||||
self.assertEqual(a[i].write_count, 0)
|
||||
|
||||
def test_create_random_array(self):
|
||||
a = MemoryArray.create_random_array(10, 1, 100)
|
||||
self.assertEqual(len(a), 10)
|
||||
|
||||
def test_create_array_from_file(self):
|
||||
a = MemoryArray.create_array_from_file("data/seq0.txt")
|
||||
self.assertEqual(len(a), 14)
|
||||
|
||||
@@ -1,166 +0,0 @@
|
||||
from unittest import TestCase
|
||||
from utils.memory_cell import MemoryCell
|
||||
from utils.literal import Literal
|
||||
import random
|
||||
|
||||
|
||||
class TestMemoryCell(TestCase):
|
||||
|
||||
def test_create_cell(self):
|
||||
v = random.randint(1, 100)
|
||||
cell = MemoryCell(v)
|
||||
self.assertEqual(cell.value, v)
|
||||
self.assertEqual(cell.read_count, 0)
|
||||
self.assertEqual(cell.write_count, 1)
|
||||
self.assertEqual(cell.add_count, 0)
|
||||
self.assertEqual(cell.sub_count, 0)
|
||||
self.assertEqual(cell.mul_count, 0)
|
||||
self.assertEqual(cell.div_count, 0)
|
||||
self.assertEqual(cell.bitop_count, 0)
|
||||
|
||||
def test_cast_cell(self):
|
||||
v = random.randint(1, 100)
|
||||
cell = MemoryCell(v)
|
||||
self.assertEqual(int(cell), v)
|
||||
self.assertEqual(cell.read_count, 1)
|
||||
self.assertEqual(cell.write_count, 1)
|
||||
self.assertEqual(cell.add_count, 0)
|
||||
self.assertEqual(cell.sub_count, 0)
|
||||
self.assertEqual(cell.mul_count, 0)
|
||||
self.assertEqual(cell.div_count, 0)
|
||||
self.assertEqual(cell.bitop_count, 0)
|
||||
|
||||
def test_add(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
|
||||
# "in place" Addition zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
cell1 += cell2
|
||||
self.assertEqual(cell1.value, v1 + v2)
|
||||
self.assertEqual(cell1.add_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(cell1, MemoryCell))
|
||||
self.assertTrue(isinstance(cell2, MemoryCell))
|
||||
|
||||
# Freie Addition zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
result = cell1 + cell2
|
||||
|
||||
self.assertEqual(result.value, v1 + v2)
|
||||
self.assertEqual(cell1.add_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(result, Literal))
|
||||
|
||||
def test_sub(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
|
||||
# "in place" Subtraktion zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
cell1 -= cell2
|
||||
|
||||
self.assertEqual(cell1.value, v1 - v2)
|
||||
self.assertEqual(cell1.sub_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(cell1, MemoryCell))
|
||||
self.assertTrue(isinstance(cell2, MemoryCell))
|
||||
|
||||
# Freie Subtraktion zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
result = cell1 - cell2
|
||||
self.assertEqual(result.value, v1 - v2)
|
||||
self.assertEqual(cell1.sub_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(result, Literal))
|
||||
|
||||
def test_mul(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
|
||||
# "in place" Multiplikation zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
cell1 *= cell2
|
||||
|
||||
self.assertEqual(cell1.value, v1 * v2)
|
||||
self.assertEqual(cell1.mul_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(cell1, MemoryCell))
|
||||
self.assertTrue(isinstance(cell2, MemoryCell))
|
||||
|
||||
# Freie Multiplikation zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
result = cell1 * cell2
|
||||
self.assertEqual(result.value, v1 * v2)
|
||||
self.assertEqual(cell1.mul_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(result, Literal))
|
||||
|
||||
def test_div(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
|
||||
# "in place" Division zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
cell1 //= cell2
|
||||
|
||||
self.assertEqual(cell1.value, v1 // v2)
|
||||
self.assertEqual(cell1.div_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(cell1, MemoryCell))
|
||||
self.assertTrue(isinstance(cell2, MemoryCell))
|
||||
|
||||
# Freie Division zweier MemoryCells
|
||||
cell1 = MemoryCell(v1)
|
||||
cell2 = MemoryCell(v2)
|
||||
result = cell1 // cell2
|
||||
self.assertEqual(result.value, v1 // v2)
|
||||
self.assertEqual(cell1.div_count, 1)
|
||||
self.assertEqual(cell1.read_count, 1)
|
||||
self.assertEqual(cell2.read_count, 1)
|
||||
self.assertTrue(isinstance(result, Literal))
|
||||
|
||||
def test_reset_counters(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
cell = MemoryCell(v1)
|
||||
cell += Literal(v2)
|
||||
|
||||
self.assertEqual(cell.value, v1+v2)
|
||||
self.assertEqual(cell.read_count, 1)
|
||||
self.assertEqual(cell.add_count, 1)
|
||||
self.assertEqual(cell.write_count, 2)
|
||||
|
||||
cell.reset_counters()
|
||||
|
||||
self.assertEqual(cell.value, v1+v2)
|
||||
self.assertEqual(cell.read_count, 0)
|
||||
self.assertEqual(cell.add_count, 0)
|
||||
self.assertEqual(cell.write_count, 0)
|
||||
|
||||
|
||||
def test_set(self):
|
||||
v1 = random.randint(1, 100)
|
||||
v2 = random.randint(1, 100)
|
||||
|
||||
cell = MemoryCell(v1)
|
||||
cell.set(v2)
|
||||
|
||||
self.assertEqual(cell.value, v2)
|
||||
self.assertEqual(cell.read_count, 0)
|
||||
self.assertEqual(cell.write_count, 2)
|
||||
|
||||
Reference in New Issue
Block a user