python in php umschreiben

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Antworten
sanktusm
User
Beiträge: 2
Registriert: Freitag 3. April 2020, 12:42

Hallo,
ich habe hier ein tolles Script, das ich gerne mit php umsetzen will. Leider funktionieren einige Ansätze nicht. Kann mir jemand helfen? eventuell gebe ich den Job auch in Auftrag:

Code: Alles auswählen

# -*- coding: utf-8 -*-
"""
Created on Wed Apr  1 09:52:19 2020
Hier wird sicher nicht die global beste Lösung gefunden, aber eine die 
wahrschienlich auch ganz OK ist. Die optimale Lösung aus dem Skript "cutting_stock.py" 
mittels mip modul 
aus https://python-mip.readthedocs.io/en/latest/examples.html 
ist sicher besser (mit nur einer Vorratslänge), aber nicht selber geschwind zu implementieren.
Hier wird Platte für Platte geprüft wie man sie zerlegen kann, um möglichst wenig Verschnitt 
in der platte zu haben. Es werden alle zur Verfügung stehenden Vorrats-Platten
im Auge behalten. Es wird also jeweils pro Platte das Optimum gesucht, insgesamt ergibt sich aber
ein gutes Ergebnis. Die Beste Zerlegung pro Platte wird dabei durch Probieren aller Varianten erreicht.
Bei großen Zahlen kann das hohe Refchenzeiten erfordern -> sollte abgefangen werden. 
Das durchprobieren aller möglicher Zerlegungen geschieht durch Rekusive Programmierung 
"""
import numpy as np
import sys


gw_L  = np.array([1.6, 1.2, 2.5, 2.7]) #vom Kunden gewuenschte Laengen, Beispielzahlen
gw_NL = np.array([6,4,7,11],dtype=int)      #vom Kunden gewuenschte Anzahl der Laengen, Beispielzahlen
st_L  = np.array([3, 4, 5, 6])       #Vorrat an vorhandenen Laengen in theoretisch unbegrentzter Anzahl, Beispielzahlen

n_rekursiv = len(gw_L)-1    
rest=10
kombination=np.zeros(n_rekursiv+1)
k_glob=np.copy(kombination)
r_glob=rest

orig_stdout = sys.stdout
f = open('out.txt', 'w')
sys.stdout = f

#erst prüfen ob alle vom Kunden gewuenschten Laengen kleiner sind als die maximal verfügbare 
#Laenge im Vorrat, sonst Fehlermeldung und Abbruch des Programms:
if max(gw_L)>max(st_L):
    print("Es kann keine Platte der Breite:",max(gw_L), "bestellt werden")
    quit()


def eine_gewuenschte_Laenge_dazufuegen_und_pruefen(index,delta,L,gw_NL,gw_L,n_rekursiv): #definition der rekursiven Funktion 
#    print("hallo")
    global rest          #aktueller rest bei aktueller Zerlegung der Vorratsplatte
    global kombination   #aktuelle Zerlegung der Vorratsplatte
    global r_glob        #derzeit bester/kleinster rest bei bester Zerlgung
    global k_glob        #derzeit beste Zerlegung  
    i=0                            #laufindex von 0 bis zur vom Kunden gewünschten Anzahl an platten gw_NL[index] 
    while i <= gw_NL[index] :
        kombination[index] = i
        # print(" ")
        # print("schleife startet")
        # print("index: ",index)
        # print("  i: ",i)
        # print("kombi: ", kombination, " k_glob: ",k_glob)
        if(index<n_rekursiv ):                   #Aufruf der rekursiven Funktion bis die "tiefste Ebene"(=Länge des Arrays gw_L/gw_NL) erreicht ist
#            print("eintauchen in tiefere index-Ebene")
            eine_gewuenschte_Laenge_dazufuegen_und_pruefen(index+1,delta,L,gw_NL,gw_L,n_rekursiv) #rufe rekursive Funktion auf
        else:                                    #wenn tiefste Ebene erreicht ist  (= die Anzahlen aller gewünschten Längen festgelegt ist) kann der verschnitt für diese Kombination berechnet werden 
            rest=10                              #Wähle irgendeine große Start Zahl 
            for s in delta:                      #Schleife über alle verschnitte, d.h für jede Verfüghbare Vorratsplattenlänge
                if s>=0 and rest>s:              # nur Verschnitte die positiv sind spielen mit negative Werte werden abgefangen 
                    rest = s                     #nimm den rest der Platte die den kleinsten Verschnitt hat     
#            print("rest: ",rest," r_glob: ",r_glob)
            if(rest<r_glob ):                   #wenn die aktuelle Kombination einen kleinen Verschnitt liefert als der bisherige Bestwert, nehme diese Kombination als neue Bestkonfiguration    
                # print("setze rest"," index: ", index, " i: ",i)
                # print("delta: ", delta)
                # print("rest, r_glob: ",rest,r_glob)
                # print("verbrauchte Länge " ,L)
                # print("Erste Platte so aufgeteilt:", kombination[0],"*",gw_L[0]," ", kombination[1],"*",gw_L[1]," ", kombination[2],"*",gw_L[2])
                k_glob = np.copy(kombination)
                r_glob = rest
#        print("k_glob: ",k_glob," r_glob: ", r_glob)
        L = L+gw_L[index]                                #versuche noch eine gewünschte Platte der Länge gw_L[index] "anzuhängen"->bisherige gesamtlänge
#        print(" L: ", L," index: ", index, " i: ",i)
        delta = delta - gw_L[index]                       #versuche noch eine gewünschte Platte der Länge gw_L[index] "anzuhängen"->bisherige verschnitt delta reduziert sich weiter
#        print(" delta: ",delta," rest ",rest)
        i = i + 1                                       #schleifenindex hochzählen
#    print("rückkehr zur höheren index-Ebene")
#    print()

#Nun wird Laenge für Laenge aus dem Vorrat geschaut was am 
#besten passen würde in eine 3m Laenge, 4m LAenge, 5m LAenge oder 6m Laenge
gw_NL_tmp = gw_NL

while(sum(gw_NL_tmp)>0):                                                  #schleife über alle benötigten Vorrats-Platten
    print('Noch benötigte Stücke: ',gw_NL_tmp, "der Längen: ",gw_L)
#    ist_fertig = False
    L = 0.0  #bisherige Länge der aneinander gehängten wunschplatten für diese Vorratsplatte
    delta = st_L    #bisheriger Verschnitt an dieser Vorratsplatte->array
    eine_gewuenschte_Laenge_dazufuegen_und_pruefen(0,delta,L,gw_NL_tmp,gw_L,n_rekursiv)#probiere alle Möglichkeiten aus und finde die beste Zerlegung der nächstzen Vorratsplatte
    print("gewählte Platte:",sum(k_glob*gw_L)+r_glob )                               #Nehme diese Vorratsplatte
    print("rest: ",r_glob," Zerlegung der Vorratsplatte: ", k_glob )                 #zerschniede sie auf diese Weise  
    print()
    gw_NL_tmp = gw_NL_tmp - k_glob                                                   #k_glob Teile konnten aus dieser Vorratsplatte ausgeschnitten werden, die noch offenen Platten reduzieren sich um diene Anteil
    rest=10                                                          #Setze beliebigen hohen Startwert
    kombination=np.zeros(n_rekursiv+1)                               #Neusetzen der Variabeln: null Teile jeder Länge für lokale Kombination
    k_glob=np.copy(kombination)                                      #Neusetzen der besten Kombination mit dem geringsten Verschnitt    
    r_glob=rest
    
    
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sanktusm: Du hast da kein tolles Skript – das sieht furchtbar aus. 😎
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
sanktusm
User
Beiträge: 2
Registriert: Freitag 3. April 2020, 12:42

So bin ich weitergekommen, nur dass das Script endlos durchläuft. Hat jemand einen Tipp. Das Script ist vielleicht nicht so toll, aber es funktioniert auf python

Code: Alles auswählen

<?php


$gw_L  = array(1.6, 1.2, 2.5, 2.7); #vom Kunden gewuenschte Laengen, Beispielzahlen
$gw_NL = array(6,4,7,11);      #vom Kunden gewuenschte Anzahl der Laengen, Beispielzahlen
$st_L  = array(3, 4, 5, 6);       #Vorrat an vorhandenen Laengen in theoretisch unbegrentzter Anzahl, Beispielzahlen

$n_rekursiv = count($gw_L)-1;
$rest = 10;
$kombination = sprintf($n_rekursiv+1);
$k_glob = $kombination;
$r_glob=$rest;



#erst prüfen ob alle vom Kunden gewuenschten Laengen kleiner sind als die maximal verfügbare
#Laenge im Vorrat, sonst Fehlermeldung und Abbruch des Programms:
if( max($gw_L)>max($st_L)):
    print("Es kann keine Platte der Breite:".max(gw_L)."bestellt werden");
endif;


function eine_gewuenschte_Laenge_dazufuegen_und_pruefen($index,$delta,$L,$gw_NL,$gw_L,$n_rekursiv) { #definition der rekursiven Funktion
#    print("hallo")
    global $rest;          #aktueller rest bei aktueller Zerlegung der Vorratsplatte
    global $kombination;   #aktuelle Zerlegung der Vorratsplatte
    global $r_glob;        #derzeit bester/kleinster rest bei bester Zerlgung
    global $k_glob;
    global $gw_NL_tmp;
           #derzeit beste Zerlegung
    $i=0;                            #laufindex von 0 bis zur vom Kunden gewünschten Anzahl an platten gw_NL[index]
    while( $i <= $gw_NL[$index]) :
        $kombination[$index] = $i;
        # print(" ")
        # print("schleife startet")
        # print("index: ",index)
        # print("  i: ",i)
        # print("kombi: ", kombination, " k_glob: ",k_glob)
        if($index < $n_rekursiv ):                   #Aufruf der rekursiven Funktion bis die "tiefste Ebene"(=Länge des Arrays gw_L/gw_NL) erreicht ist
#            print("eintauchen in tiefere index-Ebene")
            eine_gewuenschte_Laenge_dazufuegen_und_pruefen($index+1,$delta,$L,$gw_NL,$gw_L,$n_rekursiv); #rufe rekursive Funktion auf
        else:                                    #wenn tiefste Ebene erreicht ist  (= die Anzahlen aller gewünschten Längen festgelegt ist) kann der verschnitt für diese Kombination berechnet werden
            $rest=10;                              #Wähle irgendeine große Start Zahl
            for($s=0; $s<$delta; $s++)                      #Schleife über alle verschnitte, d.h für jede Verfüghbare Vorratsplattenlänge
                if($s>=0 AND $rest>$s)              # nur Verschnitte die positiv sind spielen mit negative Werte werden abgefangen
                    $rest = $s;                     #nimm den rest der Platte die den kleinsten Verschnitt hat
#            print("rest: ",rest," r_glob: ",r_glob)
            if($rest<$r_glob ):                   #wenn die aktuelle Kombination einen kleinen Verschnitt liefert als der bisherige Bestwert, nehme diese Kombination als neue Bestkonfiguration
                # print("setze rest"," index: ", index, " i: ",i)
                # print("delta: ", delta)
                # print("rest, r_glob: ",rest,r_glob)
                # print("verbrauchte Länge " ,L)
                # print("Erste Platte so aufgeteilt:", kombination[0],"*",gw_L[0]," ", kombination[1],"*",gw_L[1]," ", kombination[2],"*",gw_L[2])
                $k_glob = clone $kombination;
                $r_glob = $rest;

             endif;
#        print("k_glob: ",k_glob," r_glob: ", r_glob)
        $L = $L+$gw_L[$index];                                #versuche noch eine gewünschte Platte der Länge gw_L[index] "anzuhängen"->bisherige gesamtlänge
#        print(" L: ", L," index: ", index, " i: ",i)
        $delta = $delta - $gw_L[$index];                       #versuche noch eine gewünschte Platte der Länge gw_L[index] "anzuhängen"->bisherige verschnitt delta reduziert sich weiter
#        print(" delta: ",delta," rest ",rest)
        $i = $i + 1;

      endif;

   endwhile;                              #schleifenindex hochzählen
#    print("rückkehr zur höheren index-Ebene")
#    print()

#Nun wird Laenge für Laenge aus dem Vorrat geschaut was am
#besten passen würde in eine 3m Laenge, 4m LAenge, 5m LAenge oder 6m Laenge
return $gw_NL;

}
$gw_NL_tmp = $gw_NL;

while(array_sum($gw_NL_tmp)>0):                                                  #schleife über alle benötigten Vorrats-Platten
    print('Noch benötigte Stücke: '.$gw_NL_tmp. "der Längen: ".$gw_L);
#    ist_fertig = False
    $L = 0.0;  #bisherige Länge der aneinander gehängten wunschplatten für diese Vorratsplatte
    $delta = $st_L;    #bisheriger Verschnitt an dieser Vorratsplatte->array
    $gw_NL_tmp = eine_gewuenschte_Laenge_dazufuegen_und_pruefen(0,$delta,$L,$gw_NL_tmp,$gw_L,$n_rekursiv);
    #probiere alle Möglichkeiten aus und finde die beste Zerlegung der nächstzen Vorratsplatte
    print("gewählte Platte:".array_sum($k_glob*$gw_L)+$r_glob );                               #Nehme diese Vorratsplatte
    print("rest: ".$r_glob." Zerlegung der Vorratsplatte: ". $k_glob );                 #zerschniede sie auf diese Weise

    $gw_NL_tmp = $gw_NL_tmp - $k_glob;                                                   #k_glob Teile konnten aus dieser Vorratsplatte ausgeschnitten werden, die noch offenen Platten reduzieren sich um diene Anteil
    $rest=10;                                                          #Setze beliebigen hohen Startwert
    $kombination=sprintf($n_rekursiv+1);                               #Neusetzen der Variabeln: null Teile jeder Länge für lokale Kombination
    $k_glob= clone $kombination;                                      #Neusetzen der besten Kombination mit dem geringsten Verschnitt
    $r_glob=$rest;

    break;
endwhile;
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich verstehe nicht, was du hier damit willst. Wir können dir Tipps zu Python geben. Nicht zu PHP 🤷🏼‍♂️
Benutzeravatar
__blackjack__
User
Beiträge: 12984
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich wollte gerade schreiben das man `numpy.array` nicht einfach so mit PHPs `array` gleichsetzen kann, aber jetzt bin ich mir fast sicher das macht im Python-Code überhaupt gar keinen Sinn das dort Numpy-Arrays verwendet werden. Das ist wirklich ganz ganz gruselig geschrieben.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
nezzcarth
User
Beiträge: 1631
Registriert: Samstag 16. April 2011, 12:47

sanktusm hat geschrieben: Freitag 3. April 2020, 13:00 Hallo,
ich habe hier ein tolles Script, das ich gerne mit php umsetzen will. Leider funktionieren einige Ansätze nicht.
Wenn du das wirklich selbst portieren möchtest, wäre aus meiner Sicht ein sinnvoller erste Schritt, das Python-Skript zu überarbeiten. Wenn man diese Vorlage, wie du es versucht hast, 1:1 überträgt, kommt da eher nur noch schlechterer Code raus, wenn es überhaupt funktioniert. Damit machst du es dir schwerer, als es sein müsste.
nezzcarth
User
Beiträge: 1631
Registriert: Samstag 16. April 2011, 12:47

Ich hatte mal versucht, den Code etwas aufzuräumen. Allerdings ist das hier (neben den ganzen anderen Problemen) ein weiteres (originelles) Beispiel dafür, wozu die Verwendung von 'global' führen kann. Funktionen sollten eigentlich einen Rückgabewert haben, der mit 'return' zurückgegeben wird. Stattdessen wird 'global' hier verwendet, um den Zustand zwischen Funktionsaufrufen zu erhalten. Dadurch muss man etwas mehr Arbeit investieren, um das überhaupt erst einmal zu "entwirren". Da man hier relativ tief in den Scoping-Feinheiten der Programmiersprache drin steckt, wird eine direkte Übertragung noch schwieriger. Dass dein Versuch in PHP nicht terminiert, deutet in diese Richtung. Eine schöne Python-Version würde zudem eh ohne Rekursion auskommen und die Kombinationen vmtl. mit etwas aus dem itertools-Modul erzeugen. Dann wird es aber wieder schwieriger das 1:1 zu portieren.
Antworten