Strona główna Polish Python Coders Group
   Strona główna   Pomoc Zaloguj się Rejestracja  
Witamy, Gość. Zaloguj się lub zarejestruj.
Czy dotarł do Ciebie email aktywacyjny?

Zaloguj się podając nazwę użytkownika, hasło i długość sesji

Aktualności: ##python.pl na FreeNode - ogarniamy zlot na Mazurach lub Podlasiu :>?
Szukaj Szukaj
Strony: [1] 2   Do dołu
Drukuj
Wątek: Potrzebuję pomocy. Zmienna przyjmuje złą wartość  (Przeczytany 375 razy)
« : 21:48 11/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Witam wszystkich gdyż jestem nowy na tym forum.

Od niedawna uczę się Pythona i mam problem z kodem.
Program jest fragmentem kodu optymalizującego rozkrój płyt i działa raczej dobrze jeśli chodzi o wybór formatek, liczenie ich powierzchni i odpadu lecz zmienna "pas2" która powinna wypisywać właściwe formatki za każdym razem wypisuje ostatnie cztery elementy listy. Pewnie to jakiś głupi błąd ale niestety nie wiem jaki.

Kod
formatki = [(930, 290), (930, 290), (930, 290), (720, 290), (690, 290), (690, 290), (2690, 290), (690, 290), (864, 280), (864, 280), (864, 280), (864, 280), (-4, -4), (-4, -4), (-4, -4), (864, 280)]
ilosc = 0
odpad = 5796000
szerokosc = 2070
szeroko = 0
dlugosc = 2800
pas = [None]*5
zaz = 4
def optymalizuj(lista, lista2):
   global zaz
   global odpad
   global szerokosc
   global pas
   global dlugosc
   global szeroko
   szer = 0
   suma = 0
   pas2 = 0
   b = 0
#sprawdza ile elementów listy zawiera wartości
   for a in range(len(lista)):
       if lista[a] != None:
           b += 1
#Przegląda listę według wartości z poprzedniej listy
   for i in range(b):
       j = lista[i]
       x = lista2[j][1] + zaz
       y = lista2[j][0] + zaz
# oblicza długość według wartości z listy
       suma = suma + y
#oblicza powierzchnie według listy
       pas2 = pas2 + (y * x)
#wyszukuje najszerszą formatkę
       if (lista2[j][1] + zaz) > szer:
           szer = x
#sprawdza czy wybrane formatki mieszczą się w płycie, oblicza odpad i zastępuje zmienne globalne wartościami jeśli odpad jest mniejszy od poprzedniego
   if suma <= dlugosc and szer <= szerokosc:
       powi = szer * dlugosc
       odpad1 = powi - pas2
       if odpad1 < odpad:
           odpad = odpad1
           szeroko = szer
           pas = lista
           return lista
#jeśli odpas jest mniejszy zwraca listę
       else:
           return False
   else:
       return False
 
 
def rozkroj(lista):
   kierunek = 0
   pas2 = [None]*10
   tab2 = [None]*10
   tab = [None]*10
   for x in range(len(tab)):
       tab[x]=[None]*2
 
# dobiera kolejne elementy listy i sprawdza czy się nie powtarzają
   for i1 in range(len(lista)):
       tab[0] = lista[i1]
       tab2[0] = i1
       for i2 in range(len(lista)):
           if i2 not in tab2:
               tab2[1] = i2
               tab[1] = lista[i2]
               suma = optymalizuj(tab2, lista)
# jeżeli funkcja zwróci inną wartość niż False podmienia tą wartością listę z najbardziej optymalnym rozkrojem
               if suma != False:
                   pas2 = suma
               suma = optymalizuj(tab2, lista)
               if suma != False:
                   pas2 = suma
 
           else:
               continue
 
           for i3 in range(len(lista)):
               if i3 not in tab2:
                   tab2[2] = i3
                   tab[2] = lista[i3]
                   suma = optymalizuj(tab2, lista)
                   if suma != False:
                       pas2 = suma
 
                   suma = optymalizuj(tab2, lista)
                   if suma != False:
                       pas2 = suma
 
               else:
                   continue
 
               for i4 in range(len(lista)):
                   if i4 not in tab2:
                       tab2[3] = i4
                       tab[3] = lista[i4]
                       suma = optymalizuj(tab2, lista)
                       if suma != False:
                           pas2 = suma
 
                       suma = optymalizuj(tab2, lista)
                       if suma != False:
                           pas2 = suma
 
   print(pas2)
 
rozkroj(formatki)
input("\n\nAby kzakończyć program naciśnij klawisz Enter.")
 

3 dni z tym walczę i nie umiem wyszukać błędu mimo iż właściwie od początku go przepisałem.
Z góry dziękuję za pomoc.
Pozdrawiam
Zapisane
« Odpowiedz #1 : 02:27 12/07/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 261


Myślę że komentarze w kodzie co masz zamiar robić w danych pętlach, znacząco przyspieszy pomoc którą chcesz uzyskać. Ponieważ kod jest nieoptymalny i nieczytelny, przez co podejrzewam że większość osób olewa problem, bo zagłębienie się w to, wymaga poświęcenia dłuższej chwili czasu Uśmiech.

Wrzuć proszę zakomentowane co masz zamiar robić w poszczególnych segmentach kodu, wtedy na pewno łatwiej będzie wskazać gdzie masz błąd logiczny - który uniemożliwia ci rozwiązanie tego w sposób jakiego wymagasz Uśmiech
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #2 : 10:22 12/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Dziękuję za rade, już dodałem komentrze, mam nadzieje że pomogę one w zrozumieniu mojego kodu i następnym razem będę  o nich pamiętał.
Zapisane
« Odpowiedz #3 : 22:13 12/07/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 261


Cóż, przyznam szczerze że niewiele pomogły te komentarze, to jest taki kod spaghetti, że cięzko coś wydedukować. Może zacznijmy od tego co chcesz uzyskać, spróbuj to opisać krok po kroku to wtedy pomogę ci coś stworzyć sensownego, co będzie dało się odczytać według zamysłu 'clear code'. Ponieważ operacje tego typu:
Kod
    #~ b = 0 #To można rozwiązać inaczej. 
#sprawdza ile elementów listy zawiera wartości
   #~ for a in range(len(lista)):
       #~ if lista[a] != None:
           #~ b += 1
#~ Mianowicie tak:
   b = len(lista) - lista.count(None)
 
(...) #Kolejny przykład:
   tab = [[None, None] for i in range(10)] #Zastępuje poniższe trzy linie
   #~ tab = [None]*10
   #~ for x in range(len(tab)):
       #~ tab[x]=[None]*2
są sztucznym wydłużaniem kodu które zmniejsza czytelność, w dodatku zmienne kompletnie nic nie mówią co mają symbolizować Uśmiech.

Może ktoś inny miałby siłę to analizować - może ci pomoże. Ale zakładam że większość tutaj potwierdziłaby że łatwiej to napisać od początku niż próbować zrozumieć kod tak napisany i tak opisany :p.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #4 : 23:04 12/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Wybacz, ja się dopiero uczę i nie znam jeszcze wielu sztuczek a raczej niewiele znam i robię według tego co wyczytam w różnych kursach a tam jest wszystko napisane tak aby było łatwo zrozumieć ale dzięki za rady, każda jest dla mnie bardzo cenna.

Kod ma działać tak:
-mam listę elementów z długościami i szerokościami (x, y)
-sprawdza wszystkie możliwe kombinacje elementów z listy dobierając po 4.
-każdą taką kombinacje sprawdza czy suma długości elementów X nie jest większa niż długość płyty. Jeśli jest większa kombinacja jest odrzucana
-jeśli element mieszczą się w płycie to szukam największy Y bo z płyty można odcinać tylko pasy od krawędzi do krawędzi
- sprawdzam czy Y nie jest szerszy niż płyta
- jeśli te wszystkie warunki są spełnione to obliczam pole powierzchni pasa który muszę odciąć czyli Y * długość płyty
- następnie liczę pole powierzchni tych 4 elementów
- obliczam różnicę między powierzchnią pasa a powierzchnią 4 elementów czyli odpad
- jeżeli  odpad jest mniejszy niż poprzedni:
+zastępuję go wyliczoną wartością odpad
+zapamiętuję tą największą szerokość pasa płyty
+zapamiętuję listę tych 4 elementów.

- na koniec programu chcę wypisać tę kombinację 4 elementów przy których wartość odpad była najmniejsza

Ale się rozpisałem ale mam nadzieję że dobrze wyjaśniłem jak ten program ma działać.
Dziękuję za chęć pomocy
Zapisane
« Odpowiedz #5 : 02:36 13/07/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 261


Dobra, to zobaczmy najpierw czy dobrze cię rozumiem.

1. Mamy formatki - zakładam że są to jakieś arkusze na których możesz coś zadrukować i chcesz nanieść na płytę.

2. Płyty są jednego rozmiaru i traktujesz je jako kwadrat.

(Ewentualnie na odwrót, jest jedna formatka, a płyty są różnych wielkości - tylko mnie mylą nazwy)

3. Sprawdzasz jaka kombinacja formatek będzie najlepsza aby odkroić z niego jak najmniej aby odpad był jak najmniejszy.

Jeśli coś źle zrozumiałem, myślę że lepiej będzie podać żywy przykład w formie bliższej powyższej, nazywając odpowiednio rzeczy, inaczej skróty myślowe mogą dalej zatuszowywać co chcesz osiągnąć Uśmiech. A jak uda nam się dojść do porozumienia, napiszę to komentując kolejno co robię w każdej linii aby kod był zrozumiały ;p.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #6 : 07:52 13/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Nie do końca chyba dobrze wytłumaczył ale spróbuję inaczej.

1. Płyta to taka kartka papieru A4 (tylko dużo większa) a formatki to prostokąty które chcę z niej wyciąć czy też na niej narysować.

2. Miedzy tymi prostokątami jest 4mm dostępu (zaś)

3. Zasada jest taka że rysować po tej kartce można tylko od brzegu lub lini wcześniej narysowane do brzegu lub lini wcześniej narysowanej

4. Po kartkach można rysować w obie strony

5. Kartki mają jeden rozmiar wyjściowy ale on się co jakiś czas zmienia

6. Należy wyszukać najbardziej optymalne ułożenie prostokatów na kartce

7. Prostokatów może być nawet 200 w niektórych przypadkach  i w różnych rozmiarach

Mam nadzieję że teraz bedzie bardziej zrozumiałe
Zapisane
« Odpowiedz #7 : 23:30 13/07/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 261


Tak, teraz jest bardziej zrozumiałe, problem jest inny Uśmiech. Niestety program osiąga taką złożoność obliczeniową że nigdy ci się nie wykona, jeśli ma sprawdzać kombinacje od 2 do 200 elementów które jest najbardziej optymalne.

Musisz przyjąć jakieś kryteria według których będziesz wybierać elementy, inaczej napisanie tego programu, może nie być możliwe do wykonania (nawet w przeciągu tygodni) dla dużego zestawu danych. To trochę jak z algorytmami optymalnego wydawania reszty gdy nie masz wszystkich nominałów dostepnych.

Przykład:
Automat ma wydać resztę 64 zł, a dostępne nominały to 50, 20 i 1 zł.
Algorytm zachłanny: Wyda 50 zł, później będzie wydawał po złotówce = 15 jednostek monetarnych.
Algorytm optymalny: Wyda trzykrotnie 20 zł, później będzie wydawał po złotówce = 7 jednostek monetarnych.

Z tym że ten drugi ma zadane kryterium zminimalizować ilość jednostek monetarnych do wydania, a pierwszy podejście najprostsze, które sprawdza się gdy mamy wszystkie nominały.
Ale przechodząc do konkluzji, bez wyznaczenia kryterium, dla kombinacji 50 elementów ze zbioru 200 elementów gdzie w dodatku nie ma znaczenia kolejność, jest to blisko (200! / (200-50)!). Co daje nam finalnie: 150*151*...*199*200.
Zakładając że jedną kombinację 50 elementów sprawdzi ci w 0,0001 sekundy. Przemnóżmy to następująco:
Kod
>>> 0.0001*150
0.015000000000000001
>>> _*151
2.265
>>> _*152
344.28000000000003
>>> _*153
52674.840000000004
>>> _*154
8111925.36
>>> #Tutaj już mamy 8111925.36 sekundy co daje nam:
...
>>> _/60
135198.756
>>> #135198.756 minut
...
>>> _/60
2253.3125999999997
>>> #Co daje nam 2253 godzin
...
>>> _/24
93.88802499999998
>>> #Co daje nam prawie 94 dni. A doszliśmy tylko do 154, gdzie tam do dwustu...
...
 

@Edit:
Zrobiłem błąd - 150 nie powinno być wliczone, od 151 powinienem zacząć ciąg, ale to niewiele zmienia jak widać.

W każdym razie, trzeba obrać kryterium, na przykład przesortować listę stosując jakiś klucz do sortowania, jak na przykład pole powierzchni tego kwadratu, albo któraś z długości. I na tej podstawie bym dobierał kolejne elementy do umieszczania na płycie.

Chyba że masz jakiś inny sprytny sposób na to wymyślony, bo niestety sprawdzanie wszystkich kombinacji typu brute-force, to żaden sposób Uśmiech.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #8 : 01:23 14/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Tych elementów w jednym pasie nie musi być więcej niż 10 co mam nadzieję trochę uprości program.

Elementy większe niż połowa długości kartki powinny być dobierane w pierwszej kolejności i więcej takich w jednym pasie może być omijna bo itak się nie zmieszczą.

W praktyce odbieram prostokąty o podobnych wymiarach w jedną lub drugą stronę i z nich składam taki pas tylko nie mam pojęcia jak to przenieść na kod programu.

Oczywiście im krócej tym lepiej ale nawet jeśli program będzie się wykonywał 10 minut to jest to akceptowalne.
Zapisane
« Odpowiedz #9 : 10:51 14/07/18 »
raydeal Offline
Professional Python User

Zobacz profil
***

Reputacja: 70
Wiadomości: 418


Koledzy, nie wynajdujcie koła na nowo. Ten problem jest rozwiązywany od setek, jeśli nie tysięcy lat na każdej budowie, każdym warsztacie stolarskim, przy produkcji odzieży, toreb, butów itd.

@skwarek36 poszukaj w internecie odpowiedniego algorytmu a może nawet znajdziesz gotowy kod. A jak nie to idź do porządnej biblioteki i szukaj książek z obszaru metody optymalizacji, optymalizacja produkcji.

@Guaz ma racje, że kod jest zupełnie niezrozumiały a opis problemu pozostawia sporo niewiadomych. Na pewno jeszcze nie wiadomo paru innych rzeczy o których @skwarek36 nie wspomniał, bo może nawet nie wie że są w tym przypadku ważne, a które mogą znacząco zaważyć na wydajności obliczeń i na wybranym algorytmie. My będziemy siedzieć godzinami i zastanawiać się nad algorytmem a kolega potem stwierdzi że zapomniał o jeszcze jednym szczególe... Uśmiech
Zapisane
« Odpowiedz #10 : 11:45 14/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Jak by się tak zastanowić to wiele problemów jest już dawno rozwiązanych a ludzie itak piszą takie same programy.

Ja chcę się trochę rozwinąć i nauczyć Pythona, dlatego chciałem napisać ten program. Właściwie to jest tylko fragment który mi nie działa. Całość jeszcze musi pobrać listę formatek z pliku oraz wyrysować wynik w postaci graficznej. A dalsze jego rozwijanie jeszcze nam w głowie no ale wszystko w swoim czasie.

Ja nie oczekuję że ktoś napisze ten program za mnie tylko że wskaże mi błędy lub pokaże lepszy sposob jak to rozwiązać. Już się dowiedziałem jak pozbyć się kilku lini kodu i że taki algorytm nie jest optymalny i o to mi w sumie chodziło bo moja wiedza się rozwinęła.

Kolega @Guaz już bardzo mi pomógł swoimi radami i bardzo mu za to dziękuję, widać że zna się na programowaniu i umie się tą wiedzą dzielić w sposób który każdy rozumie.  Mrugnięcie
Zapisane
« Odpowiedz #11 : 13:03 14/07/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 261


To może spróbuj od czegoś prostszego co pozwoli ci na dojście do wprawy i finalnie rozwiązania tego problemu swoim sposobem.

Załóżmy że masz macierz w której masz połączenia pomiędzy wierzchołkami, możesz ją przedstawić jako graf spójny (Czyli że od każdego wierzchołka, da się dojść do każdego innego.). Wypisz na ekran macierz w czytelnej postaci wykorzystując formatowanie napisów, następnie zapisz w tej formie do pliku json aby była gotowa do odczytu.
Cytuj
Zadanie pierwsze: Stwórz program który stworzy ci macierz reprezentującą jakiś losowy graf spójny i doda kilka nadmiarowych połączeń. Wyświetl macierz i ją zapisz.
Problem 1: Tworzenie grafu spójnego.
-Generowanie macierzy nie będącej referencją elementów, najlepiej poprzez list comprehension. [ [[x for x in costam] for y in costam] - ogólnie lista list.]
-Stworzenie odpowiednich losowych połączeń zachowując zasadę że z każdego wierzchołka da się dojść do innego jedną drogą. [ import random ]
-Zadbanie o odbicie lustrzane macierzy. [ operacje odwrotnie indeksowane ]
-Wykluczenie wierzchołków aby nie łączyły się same ze sobą. [ if ]

Problem 2: Dodawanie do grafu określoną ilość losowych połączeń.
-Dodawanie losowe, aby nie było to algorytmiczne że na przykład dla 7 wierzchołków zawsze doda po 1 wierzchołku do każdego. [ import random ]
-Zastosowanie pętli while, żeby ilość nadmiarowych wierzchołków była zawsze równa wprowadzonej ilości [ while costam ]
-Warunki uniemożliwiające dodanie połączenia wierzchołków w miejscach gdzie są już utworzone. [ if ]

Problem 3: Wypisanie i zapis
-Wykorzystaj formatownie stringów w formie f'{znaczniki}' (python3.6) lub '{znaczniki}'.format(argumenty). [ new format style python ]
-Zapisz do formatu json [opcjonalnie txt] dane aby je odczytać w drugim programie. [ import json ]

Drugi program będzie już szukał możliwych najkrótszych dróg pomiędzy wierzchołkami grafu reprezentowanymi przez macierz. Po ukończeniu pierwszego podeślę treść jeśli będziesz chciał Uśmiech

A trzecim zadaniem będzie optymalizacja tego Uśmiech.

Jeśli chcesz spróbować, służę pomocą, czy to na priv, czy też na forum. To powinno ci trochę zająć jak chcesz się uczyć na konkretnym przykładzie, pomimo że problem jest mało skomplikowany. Jak coś jest niezrozumiałe, albo się zatniesz, to możesz śmiało pisać, sam osobiście mam całą historię tego problemu (od tego jak zacząłem programować, do momentu obecnego mam siedem wersji rozwiązania tego problemu na różne sposoby. Więc nawet bez zastanowienia powinienem być w stanie odpisywać Chichot)

Ah, no i polecam troszkę dłuższe nazwy zmiennych - jak tworzysz macierz, nazwij zmienną macierz Język.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #12 : 19:07 14/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Spróbuję to napisać choć nie wszystko zrozumiałem ale już będę się kontaktował na priv żeby nie zaśmiecać forum.

Oficjalnie dziękuję @Guaz za pomoc  Uśmiech
Zapisane
« Odpowiedz #13 : 19:32 14/07/18 »
hurgadion Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Hej,
zgadzam się z przedmówcą... Jak chcesz napisać coś porządnego... To na początku ogarnij dobrze problem plecakowy... wykorzystując np. programowanie dynamiczne lub bardziej zaawansowane metody rozwiązywania tego zagadnienia optymalizacyjnego... następnie zajmij się problemem rozkroju jednowymiarowego... a jak już ogarniesz oba te tematy, to poczytaj np. to: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.565.5921&rep=rep1&type=pdf

Pozdrawiam...  Uśmiech
Zapisane
« Odpowiedz #14 : 01:00 15/07/18 »
skwarek36 Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 8


Dzięki @hurgadion że się odezwałeś.
Co prawda mocno się w te zagadnienia jeszcze nie wczytałem ale wydaje się że to jest to co powinienem wiedzieć przy pisaniu tego programu. Jutro się w to wczytam

Pozdrawiam  Uśmiech
Zapisane
Strony: [1] 2   Do góry
Drukuj
Skocz do:  

© 2007 - 2018 Polish Python Coders Group
Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines | Theme by PixelSlot