class Cilj:
def __init__(self, d, r, p): # kaj imamo podano za vsak cilj: d = smer, r = cas sprostitve, p = zacetna pozicija
self.d = d
self.r = r
self.p = p
def pozicija(self, t, v): # pozicija cilja ob casu t, v = hitrost
return self.p + (t - self.r) * v * self.d
def __hash__(self):
return hash((self.d, self.r, self.p))
def __eq__(self, other): # preverimo enakost dveh ciljev
return (self.d, self.r, self.p) == (other.d, other.r, other.p)
def __repr__(self):
return f"Cilj({self.d}, {self.r}, {self.p})"
class Ureditev: # načini, kako razporedimo cilje
def __init__(self, seznam, kljuc): # seznam = vsi cilji, kljuc = funkcija, ki posortira
self.seznam = sorted(seznam, key=kljuc)
self.indeksi = {c: i for i, c in enumerate(self.seznam)}
def __len__(self): # stevilo ciljev
return len(self.seznam)
def __getitem__(self, index): # vrne element seznama z indeksom index
return self.seznam[index] # sigma^(-1)(index)
def indeks(self, cilj): # vrne indeks nekega cilja
return self.indeksi[cilj] # sigma(cilj)
class ObratnaUreditev: # obratni vrstni red razporeditve ciljev iz razreda Ureditev
def __init__(self, ureditev):
self.ureditev = ureditev
def __len__(self):
return len(self.ureditev)
def __getitem__(self, index):
if isinstance(index, slice):
index = slice(None if index.start is None else -index.start-1,
None if index.stop is None else -index.stop-1,
-1 if index.step is None else -index.step)
else:
index = -index-1
return self.ureditev.seznam[index]
def indeks(self, cilj):
return len(self) - self.ureditev.indeks(cilj) - 1
cilji = [Cilj(*p) for p in zip([1, 1, -1, -1, -1, 1, -1], [0, 5, 13, 15, 6, 8, 18], [2, 5, -3, 4, 1, -2, -7])]
v = 0.3
IPO = Ureditev(cilji, lambda c: c.pozicija(0, v))
TO = Ureditev(cilji, lambda c: (c.d, c.pozicija(0, v)))
IPOc = ObratnaUreditev(IPO)
TOc = ObratnaUreditev(TO)
IPOc[:0]
slice(None, None, -1)
[Cilj(-1, 15, 4), Cilj(1, 5, 5), Cilj(-1, 6, 1), Cilj(1, 0, 2), Cilj(-1, 13, -3), Cilj(-1, 18, -7), Cilj(1, 8, -2)]
[IPOc.indeks(c) for c in cilji]
[3, 1, 4, 0, 2, 6, 5]
cilji
[Cilj(1, 0, 2), Cilj(1, 5, 5), Cilj(-1, 13, -3), Cilj(-1, 15, 4), Cilj(-1, 6, 1), Cilj(1, 8, -2), Cilj(-1, 18, -7)]
IPOc[2]
Cilj(-1, 6, 1)
class SLMTTSP:
def __init__(self, cilji, v):
IPO = Ureditev(cilji, lambda c: c.pozicija(0, v))
TO = Ureditev(cilji, lambda c: (c.d, c.pozicija(0, v)))
IPOc = ObratnaUreditev(IPO)
TOc = ObratnaUreditev(TO)
self.v = v
self.cilji = cilji
self.ureditve = [IPO, IPOc, TO, TOc]
self.F = {} # tu so shranjena stanja (C, i) in najkrajši časi, ko do tega stanja lahko pridemo (elementi se dodajajo v metodi f)
def g(self, t, j, i): # najhitrejši čas obiska cilja i, če smo nazadnje obiskali cilj j ob času t
posi = i.pozicija(t, self.v)
posj = 0 if j is None else j.pozicija(t, self.v)
razlika = posi - posj
delta = 1 if razlika > 0 else -1 # hitrost gibanja agenta (pozitivna, če je razlika med zaporednima ciljema pozitivna)
tt = t + razlika / (delta - self.v * i.d) # najmanjši potreben čas obiska i, dodan k trenutnemu času t
if tt >= i.r:
return (tt, [(t, posj), (tt, posi)]) # s paroma znotraj [] si zapomnimo odseke trgovčeve poti (na katerih pozicijah je bil ob časih t in tt)
else:
return (i.r, [(t, posj), (t + abs(i.p - posj), i.p), (i.r, i.p)])
# v zadnjem primeru (srednji element seznama) agent čaka na poziciji i.p do časa i.r (v tem primeru je delta = 0)
def predhodno_stanje(self, C, i):
if i is None: # primer, ko ni predhodnega cilja
return None
return tuple(min(C[l], self.ureditve[l].indeks(i)) for l in range(4))
def phi(self, C): # vrne vsa že obiskana mesta v naboru C
return {j for l, m in enumerate(C) for j in self.ureditve[l][:m]} # vrne mesta, ki so bolj na začetku seznama l kot mesto m
def predhodnik(self, l, C, i): # j preteče indekse vseh ureditev
if i is None:
return None
CC = self.predhodno_stanje(C, i)
obiskana = self.phi(CC)
for j in reversed(self.ureditve[l][:CC[l]]):
if len(obiskana.difference(self.phi(self.predhodno_stanje(CC, j)))) == 1:
return j
return None
def f(self, C, i): # minimalni čas, da dosežemo stanje (C, i)
if (C, i) not in self.F:
kandidati = []
CC = self.predhodno_stanje(C, i)
for l in range(4):
j = self.predhodnik(l, C, i)
# če trenutni seznam ne da kandidata, ga preskočimo
if j is None:
continue
(t, _), _, _ = self.f(CC, j) # funkcija g potrebuje 3 argumente, prvi je čas, ki ga izračunamo s f
kandidati.append((self.g(t, j, i), l, j))
# vsak kandidat je določen s 3 argumenti:
# * rezultat funkcije g (najhitrejši čas obiska cilja i, če smo nazadnje obiskali cilj j ob času t),
# * indeks seznama, iz katerega je prišel naslednji obiskani cilj (l)
# * predhodnik (j)
# najmanjšega od kandidatov shranimo v F pod ključ (C, i) - pripadajoče stanje
# če ni kandidatov, gremo najprej proti cilju i
self.F[C, i] = min(kandidati) if kandidati else (self.g(0, None, i), None, None)
return self.F[C, i]
def resi(self):
n = len(self.cilji) # stevilo vseh ciljev
# izvedemo f na vseh možnih naborih C za vsak cilj i
for a in range(n):
for b in range(n):
for c in range(n):
for d in range(n):
for i in cilji:
self.f((a, b, c, d), i) # shrani v F minimalni čas, da dosežemo stanje (C, i)
return min(self.f((n, n, n, n), i) for i in cilji) # od zaključnega stanja "nazaj" poteka rekurzija
def rekonstruiraj_resitev(self):
resitev = sorted(self.F.items(), key = lambda c: c[1]) # uredi zapise v F po časih (kdaj smo kje)
return [C_i[1] for C_i, _ in resitev]
tsp = SLMTTSP(cilji, 0.3)
tsp.resi()
((25.769230769230766, [(21.384615384615383, -3.615384615384615), (25.769230769230766, 2.084615384615385)]), 2, Cilj(-1, 6, 1))
tsp.F[(7, 7, 7, 7), cilji[3]]
((25.769230769230766, [(21.384615384615383, -3.615384615384615), (25.769230769230766, 2.084615384615385)]), 2, Cilj(-1, 6, 1))
tsp = SLMTTSP(cilji, 0.3)
tsp.f((len(cilji), )*4, cilji[3])
(7, 7, 7, 7) Cilj(-1, 15, 4) (6, 0, 3, 3) Cilj(1, 5, 5) (5, 0, 3, 0) Cilj(-1, 6, 1) (4, 0, 2, 0) Cilj(1, 0, 2) (3, 0, 2, 0) Cilj(-1, 13, -3) (2, 0, 1, 0) Cilj(-1, 18, -7) (1, 0, 0, 0) Cilj(1, 8, -2) (2, 0, 1, 0) Cilj(-1, 18, -7) (3, 0, 2, 0) Cilj(-1, 13, -3) (5, 0, 3, 0) Cilj(-1, 6, 1) (6, 0, 3, 3) Cilj(-1, 6, 1) (4, 0, 2, 3) Cilj(1, 0, 2) (3, 0, 2, 1) Cilj(-1, 13, -3) (2, 0, 1, 1) Cilj(-1, 18, -7) (1, 0, 0, 1) Cilj(1, 8, -2) (0, 0, 0, 1) Cilj(1, 5, 5) (1, 0, 0, 1) Cilj(1, 5, 5) (1, 0, 0, 0) Cilj(1, 8, -2) (2, 0, 1, 1) Cilj(-1, 18, -7) (2, 0, 1, 1) Cilj(1, 5, 5) (2, 0, 1, 0) Cilj(-1, 18, -7) (2, 0, 1, 0) Cilj(-1, 18, -7) (3, 0, 2, 1) Cilj(-1, 13, -3) (3, 0, 2, 1) Cilj(1, 5, 5) (3, 0, 2, 0) Cilj(-1, 13, -3) (3, 0, 2, 0) Cilj(-1, 13, -3) (4, 0, 2, 3) Cilj(-1, 13, -3) (2, 0, 1, 3) Cilj(-1, 18, -7) (1, 0, 0, 3) Cilj(1, 8, -2) (0, 0, 0, 2) Cilj(1, 0, 2) (0, 0, 0, 1) Cilj(1, 5, 5) (1, 0, 0, 3) Cilj(1, 8, -2) (2, 0, 1, 3) Cilj(-1, 18, -7) (2, 0, 1, 3) Cilj(1, 8, -2) (0, 0, 1, 2) Cilj(-1, 18, -7) (0, 0, 0, 2) Cilj(1, 0, 2) (0, 0, 1, 2) Cilj(1, 0, 2) (0, 0, 1, 1) Cilj(-1, 18, -7) (0, 0, 0, 1) Cilj(1, 5, 5) (0, 0, 1, 1) Cilj(1, 5, 5) (0, 0, 1, 0) Cilj(-1, 18, -7) (4, 0, 2, 3) Cilj(1, 8, -2) (0, 0, 2, 2) Cilj(-1, 13, -3) (0, 0, 1, 2) Cilj(-1, 18, -7) (0, 0, 1, 2) Cilj(1, 0, 2) (0, 0, 2, 2) Cilj(1, 0, 2) (0, 0, 2, 1) Cilj(-1, 13, -3) (0, 0, 1, 1) Cilj(-1, 18, -7) (0, 0, 1, 1) Cilj(1, 5, 5) (0, 0, 2, 1) Cilj(1, 5, 5) (0, 0, 2, 0) Cilj(-1, 13, -3) (0, 0, 1, 0) Cilj(-1, 18, -7) (6, 0, 3, 3) Cilj(1, 8, -2) (0, 0, 3, 2) Cilj(-1, 6, 1) (0, 0, 2, 2) Cilj(-1, 13, -3) (0, 0, 2, 2) Cilj(1, 0, 2) (0, 0, 3, 2) Cilj(1, 0, 2) (0, 0, 3, 1) Cilj(-1, 6, 1) (0, 0, 2, 1) Cilj(-1, 13, -3) (0, 0, 2, 1) Cilj(1, 5, 5) (0, 0, 3, 1) Cilj(1, 5, 5) (0, 0, 3, 0) Cilj(-1, 6, 1) (0, 0, 2, 0) Cilj(-1, 13, -3)
((25.769230769230766, [(21.384615384615383, -3.615384615384615), (25.769230769230766, 2.084615384615385)]), 2, Cilj(-1, 6, 1))
[[cilji.index(i) for i in l] for l in tsp.ureditve]
[[5, 6, 2, 0, 4, 1, 3], [3, 1, 4, 0, 2, 6, 5], [6, 2, 4, 3, 5, 0, 1], [1, 0, 5, 3, 4, 2, 6]]
[tsp.ureditve[l][:m] for l, m in enumerate((6, 0, 3, 3))]
[[Cilj(1, 8, -2), Cilj(-1, 18, -7), Cilj(-1, 13, -3), Cilj(1, 0, 2), Cilj(-1, 6, 1), Cilj(1, 5, 5)], [], [Cilj(-1, 18, -7), Cilj(-1, 13, -3), Cilj(-1, 6, 1)], [Cilj(1, 5, 5), Cilj(1, 0, 2), Cilj(1, 8, -2)]]
C1 = tsp.predhodno_stanje((len(cilji), )*4, cilji[3])
C2 = tsp.predhodno_stanje(C1, cilji[1])
C1, C2, tsp.phi(C1), tsp.phi(C2)
((6, 0, 3, 3), (5, 0, 3, 0), {Cilj(-1, 13, -3), Cilj(-1, 18, -7), Cilj(-1, 6, 1), Cilj(1, 0, 2), Cilj(1, 5, 5), Cilj(1, 8, -2)}, {Cilj(-1, 13, -3), Cilj(-1, 18, -7), Cilj(-1, 6, 1), Cilj(1, 0, 2), Cilj(1, 8, -2)})
[tsp.f(C1, tsp.predhodnik(l, C1, cilji[3])) for l in range(4)]
(6, 0, 3, 3) Cilj(1, 5, 5) (5, 0, 3, 0) Cilj(-1, 6, 1) (4, 0, 2, 0) Cilj(1, 0, 2) (3, 0, 2, 0) Cilj(-1, 13, -3) (2, 0, 1, 0) Cilj(-1, 18, -7)
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-111-68e1c5939a07> in <module> ----> 1 [tsp.f(C1, tsp.predhodnik(l, C1, cilji[3])) for l in range(4)] <ipython-input-111-68e1c5939a07> in <listcomp>(.0) ----> 1 [tsp.f(C1, tsp.predhodnik(l, C1, cilji[3])) for l in range(4)] <ipython-input-99-dc81ee6d61bd> in f(self, C, i) 51 if j is None: 52 continue ---> 53 t, _, _ = self.f(CC, j) # funkcija g potrebuje 3 argumente, prvi je čas, ki ga izračunamo s f 54 kandidati.append((self.g(t, j, i), l, j)) 55 # vsak kandidat je določen s 3 argumenti: <ipython-input-99-dc81ee6d61bd> in f(self, C, i) 51 if j is None: 52 continue ---> 53 t, _, _ = self.f(CC, j) # funkcija g potrebuje 3 argumente, prvi je čas, ki ga izračunamo s f 54 kandidati.append((self.g(t, j, i), l, j)) 55 # vsak kandidat je določen s 3 argumenti: <ipython-input-99-dc81ee6d61bd> in f(self, C, i) 51 if j is None: 52 continue ---> 53 t, _, _ = self.f(CC, j) # funkcija g potrebuje 3 argumente, prvi je čas, ki ga izračunamo s f 54 kandidati.append((self.g(t, j, i), l, j)) 55 # vsak kandidat je določen s 3 argumenti: <ipython-input-99-dc81ee6d61bd> in f(self, C, i) 52 continue 53 t, _, _ = self.f(CC, j) # funkcija g potrebuje 3 argumente, prvi je čas, ki ga izračunamo s f ---> 54 kandidati.append((self.g(t, j, i), l, j)) 55 # vsak kandidat je določen s 3 argumenti: 56 # * rezultat funkcije g (najhitrejši čas obiska cilja i, če smo nazadnje obiskali cilj j ob času t), <ipython-input-99-dc81ee6d61bd> in g(self, t, j, i) 11 12 def g(self, t, j, i): # najhitrejši čas obiska cilja i, če smo nazadnje obiskali cilj j ob času t ---> 13 posi = i.pozicija(t, self.v) 14 posj = 0 if j is None else j.pozicija(t, self.v) 15 razlika = posi - posj <ipython-input-1-a9ce58033d0b> in pozicija(self, t, v) 6 7 def pozicija(self, t, v): # pozicija cilja ob casu t, v = hitrost ----> 8 return self.p + (t - self.r) * v * self.d 9 10 def __hash__(self): TypeError: unsupported operand type(s) for -: 'tuple' and 'int'
tsp.cilji[1]
Cilj(1, 5, 5)