Einbindung von einem GLPK-Solver

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Romell
Beiträge: 5
Registriert: Fr 10. Aug 2012, 11:58

Einbindung von einem GLPK-Solver

Beitrag von Romell »

Sehr geehrtes "Lazarus-Forum"-Team,

mein Name ist Romell, und ich muss aufgrund meines Praktikums mit Lazarus arbeiten.
Ich wusste nicht, wo ich diesen Beitrag reinschrieben sollte.
Es handelt sich um ein Programm, dass vorher in Delphi-Code geschrieben war, aber nun, um Kosten zu sparen, in Lazarus migriert werden soll.
Dies ist meine Aufgabe, und ich sitze mittlerweile seit 2 Wochen dran, und habe es leider noch nicht geschafft
Ich bin sehr sehr verzweifelt, und ihr seid meine letzte Hoffnung.
Ich habe bereits die Konvertierung vorgenommen, und ich weiß, dass das Programm auf Delphi einwandfrei funktioniert.
Bei dem Programm handelt es sich um ein lineares Optimierungsproblem, also wird in dem Programm ein LP-Solver eingebunden, und zwar glpk.
Bei der Kompilierung werden KEINE Fehlermeldungen angezeigt, aber das Programm stoppt irgendwann einfach.
Ich habe wenigstens herausgefunden, wo es stoppt.
Und zwar in der Unit Datei beim Definieren einer Funktion an der Stelle, an dem der Solver das Glgssystem lösen soll.
Dies ist in einem "try-except"-Block geschrieben, und im except-Block wäre ein writeln Argument, sodass ich wissen würde, wenn er diesen betreten sollte.
alls was nach diesem "try-except"-Block passiert, wird nicht mehr gemacht.
Nicht mal "writeln(test)".
Noch 2 wichtige Sachen, die ihr wissen solltet:
1.) Ich habe das Programm mal so umschrieben, dass das output file schon im try-Block geschrieben wird.
Es hat einwandfrei das Problem gelöst gehabt, aber das, was nach dem try-Block passiert ist, hat er leider nicht mehr durchgeführt.
2.) Ich habe auch mal versucht das "try" und "except" wegzulassen, da ich dachte, es passieren ja eh keine exceptions, weil die Meldungen nicht angezeigt wurden.
Aber DANN kam eine Fehlermeldung. Und zwar:
[Forms.PP] Exception Occured
Sender=EAccessviolation
[...]

Ich hoffe sehr, dass ihr mir helfen könnt, denn ich bin ziemlich ratlos, und habe keine Ideen mehr.
Leider kann ich euch das Programm nicht geben, da es ein privates Firmen-Dokument ist.

Vielen vielen Dank schonmal.
Beste Grüße,
Romell

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Einbindung von einem GLPK-Solver

Beitrag von Socke »

Willkommen im Forum!

Ohne Quelltext(-Auszüge) ist das ganze natürlich ein wenig wie die Suche nach der Nadel im Heuhaufen. Wenn du kannst, post hier die angesprochenen Ausschnitte (nicht gleich das ganze Programm, ein paar Zeilen sollten reichen); dann kann man sich den Code besser vorstellen.

Romell hat geschrieben:Dies ist in einem "try-except"-Block geschrieben, und im except-Block wäre ein writeln Argument, sodass ich wissen würde, wenn er diesen betreten sollte.
alls was nach diesem "try-except"-Block passiert, wird nicht mehr gemacht.
Nicht mal "writeln(test)".
Noch 2 wichtige Sachen, die ihr wissen solltet:
1.) Ich habe das Programm mal so umschrieben, dass das output file schon im try-Block geschrieben wird.
Es hat einwandfrei das Problem gelöst gehabt, aber das, was nach dem try-Block passiert ist, hat er leider nicht mehr durchgeführt.
Mit try-except-Blöcken kann man die Exceptions wunderbar ignorieren:

Code: Alles auswählen

try
  raise Exception.Create('Hallo, hier bin ich!');
except
  WriteLn('Jetzt ignoriere ich die Exception');
end;
Wenn das Writeln() ausgeführt wird, weißt du nur, dass eine Exception aufgetreten ist. Du weißt aber nicht welche und warum.

Code: Alles auswählen

try
  raise Exception.Create('Hallo, hier bin ich!');
except
  on e: Excpetion do
    WriteLn('Exception aufgetreten: ', e.ClassName, ' - ', e.Message);
end;
So kannst du feststellen, ob die Exception auch mit Try-Except-Block auftritt. Wenn Sie das nicht tut, liegt es vermutlich an dem, was du in dem Try-Except-Block machst.
Romell hat geschrieben:[Forms.PP] Exception Occured
Sender=EAccessviolation
[...]
Das hört sich so an, als ob das Programm unter Delphi nur in der Regel einwandfrei funktioniert hat. Eine Access-Violation (auf Deutsch Zugriffsverletzung) tritt immer dann auf, wenn das Programm auf einen Bereich im Arbeitsspeicher zugreifen will, der ihm vom Betriebssystem nicht zugeteilt wurde. Das kann zum Beispiel durch falsche Objekt-Variablen (Objekt existiert nicht) oder durch falsch berechneten direkten Speicherzugriff (über Zeiger) geschehen.

Diesen Fehler solltest du auf jeden Fall beheben. Wie gesagt: der muss nicht erst seit der Portierung auf Lazarus bestehen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Romell
Beiträge: 5
Registriert: Fr 10. Aug 2012, 11:58

Re: Einbindung von einem GLPK-Solver

Beitrag von Romell »

Vielen Dank Socke für deine Hilfe.
Ich werde am Montag meinen Chef fragen, welche Teile vom Code ich veröffentlichen darf.
Ich bedanke mich schonmal vielmals.

Romell
Beiträge: 5
Registriert: Fr 10. Aug 2012, 11:58

Re: Einbindung von einem GLPK-Solver

Beitrag von Romell »

Code: Alles auswählen

try
// tuhe irgendwas streng geheimes! ;)
 
 
// jetzt kommt der problematische Teil des Codes
 
 if solvertype = GLPK then
    begin
      OptimiserVersion := 'glpk_4_47.dll';
      lib := LoadLibrary(PChar(OptimiserVersion));
      if lib <> 0 then
      begin
        //flag:=nil;
        @GLPKCreateprob := GetProcAddress(lib, 'glp_create_prob');
        @GLPKReadLP := GetProcAddress(lib, 'glp_read_lp');
        @GLPKsetobjdir := GetProcAddress(lib, 'glp_set_obj_dir');
        @GLPKPrintSol := GetProcAddress(lib, 'glp_print_sol');
        @GLPKwritelp := GetProcAddress(lib, 'glp_write_lp');
        @GLPKDelProb := GetProcAddress(lib, 'glp_delete_prob');
        @GLPKsimplex := GetProcAddress(lib, 'glp_simplex');
        @GLPKgetobjval := GetProcAddress(lib, 'glp_get_obj_val');
        @GLPKchgobjco := GetProcAddress(lib, 'glp_set_obj_coef');
        @GLPKPara := GetProcAddress(lib, 'glp_init_smcp');
        @XEGLPKReadLP := GetProcAddress(lib, 'glp_read_lp');
       end
 
      else
      begin
        //Error[8]
        Writeln('GLPK could not be found! error: ' + IntToStr(stat));
        Ok := False;
        barray[8] := False;
        exit;
      end;
 
      sim := GLPKCreateprob(env);
      i := 0;
      for row := 0 to zaehlercol1 - 1 do
      begin   
        Inc(i);
 
        // write ('row:'+IntToStr(row) + ' problem nr: ' +IntTostr(i) + ' of ' + inttostr(zaehlercol1));  
        //-----------------------------------------------------------
        if i = 1 then
        begin
          if XE = True then
            stat := XEGLPKReadLP(sim, env, ansistring(dateiname + '.lp'))
          else
            stat := GLPKReadLP(sim, env, dateiname + '.lp');
          //  writeln(stat);
        end
        //---------------------------------------------------------------
        else
        begin
          flag := GLPKChgobjco(sim, i - 1, 0);
          flag := GLPKChgobjco(sim, i, 1);
        end;
        //-----------------------------------------------------
        x := row;
        y := zaehlercol1;
        //-- MOD 02.2012: use zaehlercol1 instead of zaehlercol, no change! --
        q := round((x / y) * 100);
        Write(Format(#13 + '%u percent complete.', [q]));
        //----------------------------------------------------------
        //write ('row:'+IntToStr(row) + ' problem nr: ' +IntTostr(i) + ' of ' + inttostr(zaehlercol1));   
        flag := GLPKsetobjdir(sim, 2);
        parm := @para;
        stat := GLPKpara(parm);
        //write(stat);
        para.msg_lev := 0;      //sets output of GLPK solver to Errors only.
        stat := GLPKsimplex(sim, Parm);   //maximize
        objval := GLPKGetobjval(sim);
        minmax[2, row + 1] := Floattostr(objval);
        //write ('; Max:', minmax[2,row+1]);
        flag := GLPKsetobjdir(sim, 1);
        stat:=GLPKsimplex(sim,Parm);   //minimize
        objval:=GLPKGetobjval(sim);
        minmax[1, row + 1] := FloatToStr(objval);
        //write ('; Min:', minmax[1,row+1]);
        //write(stat);
        if stat <> 0 then
        begin
          //Error[9]
          Writeln('Error in GLPK computation! error: ' + IntToStr(stat));
          Ok := False;
          barray[9] := False;
          exit;
        end;
 
      end;
 
 
 
 
      { stat:=GLPKReadLP(sim,env,dateiname+'.lp');
  flag:=GLPKsetobjdir(sim,1);
  parm:=nil;
  stat:=GLPKsimplex(sim,parm);
  writeln(Inttostr(stat));
  stat:=GLPKwritelp(sim,flag,'lpprob');
  dir:=1;
 
 stat:=GLPKPrintSol(sim,'output');
      env := GLPKdelProb(sim);  }
     end
 
 
 
 
    writeln(' ');
    writeln('test1');
 
 
 
  except
    on EMyError do
    begin
      OK := False;
      barray[19] := False;
      exit;
    end;
    else
      //Error[13]
      Writeln('error in the optimization procedure');
    OK := False;
    barray[13] := False;
    exit;
  end;
 
 
 
 
  writeln('test2');
Also: Er gibt mir test1 aus aber test2 nicht mehr.
wenn ich vor dem except Block eine output liste erstelle, dann kriege ich diese auch, aber nicht wenn ich es nach dem except block mache.
Vielen Dank schonmal für die Hilfe!

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Einbindung von einem GLPK-Solver

Beitrag von Socke »

Romell hat geschrieben:Also: Er gibt mir test1 aus aber test2 nicht mehr.
Nun, dass ist ein klassischer Fall von Bäumen und Wäldern :D

Du gehst am Ende des except-Blockes einfach mit exit; aus der Funktion heraus (auch an anderen Stellen). Daher wird test2 bei einem Fehler nicht ausgegeben.

Dass alle Exceptions, die nicht von der Klasse EMyError abstammen, mit einer einfachen Ausgabe "Hey, hier ist ein Fehler" bearbeitet werden, halte ich für problematisch. Damit nimmst du dir in der Entwicklung die Möglichkeit Programmierfehler (sollten nie in einem Programm auftreten, da hier grundlegende Fehler im Programmcode vorliegen; zum Beispiel EAccessViolation) von Laufzeitfehlern (dürfen oder sollen in einem Programm auftreten und werden dort entsprechend behandelt; zum Beispiel EConvertError, EDivByZero) zu unterscheiden und zu beheben.

Solange du keine Exception-Objekte verwendest, die nicht von der Klasse Exception abstammen (das ist möglich, aber sehr ungebräuchlich) wäre dieser Vorschlag bis auf die Ausgabe mit deinem Code identisch.

Code: Alles auswählen

uses LCLProc;
  try
  // ...
  except
    on EMyError do
    begin
      OK := False;
      barray[19] := False;
      exit;
    end;
    on e: Exception do // bei allen anderen Exceptions
    begin
      Writeln('error in the optimization procedure');
      writeln(e.Classname, ' - ', e.message);  // Klasse und Message des Fehlers ausgeben
      DumpExceptionBackTrace; // gibt den Stacktrace der aktuellen Exception aus (unit LCLProc)
      OK := False;
      barray[13] := False;
      exit; // hier aussteigen
    end;
  end;
 
  writeln('test2');
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Romell
Beiträge: 5
Registriert: Fr 10. Aug 2012, 11:58

Re: Einbindung von einem GLPK-Solver

Beitrag von Romell »

erstmal vielen Dank!

Leider funktioiert es immer noch nicht!

Er gibt weder test 2 aus, noch macht er nach der Funktion im hauptprogramm weiter.
Die Fehlermeldungen im except Block gibt er auch nicht wieder.
Das letzte, was er noch schreibt ist test1.
Danach gibt er nichts mehr aus, obwohl die Funktion und das Hauptprogramm weitergehen.
Ich hab das Gefühl, es liegt an der Einbindung von GLPK...

Aber danke trotzdem!
LG

Socke
Lazarusforum e. V.
Beiträge: 3178
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Einbindung von einem GLPK-Solver

Beitrag von Socke »

Romell hat geschrieben:Die Fehlermeldungen im except Block gibt er auch nicht wieder.
Das letzte, was er noch schreibt ist test1.
Das wäre wohl der Fall, dass eine Exception EMyError ausgelöst wird. Im except-Block steht für diesen Typ drinnen: Setze zwei Variablen auf False und gehe aus der Funktion heraus. Da ist klar, dass test2 nicht mehr ausgegeben wird.

Die Exception wird irgendwo in dem Programmcode ausgelöst, den du hier ausgespart hast. Daher musst du dort suchen. Wenn du ein wenig Hilfe bei der Suche brauchst, kannst du den except-Block dahingehen verändern, dass auch bei EMyError ein Stacktrace ausgegeben wird:

Code: Alles auswählen

except
    on e: Exception do // bei allen Exceptions
    begin
      Writeln('error in the optimization procedure');
      writeln(e.Classname, ' - ', e.message);  // Klasse und Message des Fehlers ausgeben
      DumpExceptionBackTrace; // gibt den Stacktrace der aktuellen Exception aus (unit LCLProc)
 
	  OK := False;
	  if e is EMyError then
	    barray[19] := False // bei EMyError setzen
	  else	    
        barray[13] := False; // bei allen anderen Exceptions
 
      exit; // hier aussteigen
    end; 
  end;
Romell hat geschrieben:Er gibt weder test 2 aus, noch macht er nach der Funktion im hauptprogramm weiter.
[...]
Danach gibt er nichts mehr aus, obwohl die Funktion und das Hauptprogramm weitergehen.
Kannst du das bitte noch einmal in anderen Worten wiederholen? Ich weiß jetzt nur:
  • test1 wird ausgegeben
  • test2 wird nicht ausgegeben
  • Nach test1 wird nichts mehr ausgegeben
  • Danach geht die Funktion und das Hauptprogramm weiter
  • "er macht [nicht] nach der Funktion im hauptprogramm weiter"
Insbesondere Punk 4 und 5 finde ich verwirrend.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Romell
Beiträge: 5
Registriert: Fr 10. Aug 2012, 11:58

Re: Einbindung von einem GLPK-Solver

Beitrag von Romell »

Vielen Dank für die Hilfe!
Das Problem lag an der Deklaration der GLPK Befehle!
Also gab es keine Chance, dass du mir helfen kannst, aber trotzdem vielen Dank!

Beste grüße,
Kaveh

Antworten