Laden...

P# - Prolog für C#

Erstellt von dr4g0n76 vor 18 Jahren Letzter Beitrag vor 14 Jahren 12.410 Views
dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren
P# - Prolog für C#

Wer schon immer mal Prolog in C# einbinden wollte, um mit KI und weiterem zu hantieren kann das hiermit kostenlos tun:

http://www.dcs.ed.ac.uk/home/jjc/psharp/psharp-1.1.3/Psharp-1.1.3.zip

Anleitung:

http://www.dcs.ed.ac.uk/home/jjc/psharp/psharp-1.1.3/manual.pdf

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

S
8.746 Beiträge seit 2005
vor 18 Jahren

Cool, schon ausprobiert? Ich hab zwar seit 10 Jahren nix mehr mit Prolog gemacht, aber es war so schön einfach, damit Logik-Rätsel-Aufgaben zu lösen (Wenn A lügt, dann hat B die Wahrheit gesagt. Wenn B gelogen hat, hat C die Wahrheit gesagt. ....... Sagt A die Wahrheit?).

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

klar @svenson,

es funktioniert, ist aber nicht ganz einfach zu benutzen...

vor allem geht es in beiden Richtungen

  1. "call C# from Prolog"
  2. "call Prolog from C#"

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

Noch eine neue Art Prolog von C# aufzurufen gibt es bei SICSTUS-Prolog. Nur wer nachguckt und dann feststellt, daß das A***-Teuer ist, der versucht es mal mit Visual Prolog, was wohl jetzt auch kostenlos (ältere Versionen) zu haben ist.

[/EDIT]Der Code für Visual Prolog 6 kann von http://www.visual-prolog.com/vip6/Community/prolog_in_net/default.htm heruntergeladen werden.[/EDIT]

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

49.485 Beiträge seit 2005
vor 18 Jahren

Hallo dr4g0n76,

bitte keine (potentiell) urheberrechlich geschützten Inhalte hochladen, auch und gerade, wenn diese im Internet frei verfügbar sind und es deshalb auch ein Verweis tut.

herbivore

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

Wichtig wäre dann auch wohl noch dieser Text:

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

auch trinc prolog kann von C# aus verwandt werden:

Microsoft Visual Basic Interface

It is possible to use the Trinc-Prolog DLL by programs developed with Microsoft Visual Basic. The basic file located at dll\vbasic\tp32.bas contains the Visual Basic declarations of the functions inside the DLL. In the subfolders of dll\vbasic there are examples developed with version 5 and 6 of Microsoft Visual Basic.
Do not forget to put the file tp32.dll and the files (system.txt, tcads.str, tcwin.str and pl.str) in a folder that is in the search path of Windows when running the application.
Function TPVersion () As Long
func Return the version number of the current interface of the DLL.
pre TRUE
post The version number was returned.

Function TPInit () As Long
func Initialize the Trinc-Prolog DLL. The instance handle of the DLL is used to initialize it.
pre TRUE
post If the DLL was correct initialized then was TP_TRUE returned, else a negative result code was returned.

Function TPInit2 (ByVal Instance As Long) As Long
func Initialize the Trinc-Prolog DLL with the supplied instance handle.
pre TRUE
post If the DLL was correct initialized then was TP_TRUE returned, else a negative result code was returned.

Function TPExit Lib () As Long
func Stop using the Trinc-Prolog DLL. Any prolog engine instances still present are deleted.
pre TRUE
post The DLL can no longer be used, all the allocated resources of the DLL were released.

Function TPExit2 (ByVal Instance As Long) As Long
func Stop using the Trinc-Prolog DLL. The same Instance handle as used for initialization, is used to release the allocated resources. Any prolog engine instances still present are deleted.
pre The same instance handle must have been used for initialization.
post The DLL can no longer be used, all the allocated resources of the DLL were released.

Function TPNewEngine () As Long
func Create a new prolog engine instance and initialize it.
pre The DLL must have been successfully initialized.
post The engine identifier of the new prolog engine instance was returned, if there was an error then a negative error code was returned (< 0).

Sub TPDeleteEngine (ByVal EngineId As Long)
func Delete the engine specified by the identifier "EngineId".
pre TRUE.
post The engine with the same identification number was deleted.

Function TPProve (ByVal EngineId As Long, ByVal Goal As String) As Long
func Have the specified goal proven by the engine identified by "EngineId".
pre The parameter "Goal" may not be NULL.
post If the goal was proven successfully and a solution was found was TP_SOLUTION returned, if the goal failed then was TP_FAIL returned, else one of the following error codes: "TPERROR_INCORRECT_GOAL", "TPERROR_UNKNOWN_ENGINE" or "TPERROR_PROVE" was returned.

Function TPContinue (ByVal EngineId As Long) As Long
func Continue proving the current goal of the engine until the next solution.
pre A solution must have been found by a previous call to the function Prove.
post If the goal was proven successfully and a solution was found was TP_SOLUTION returned, if the goal failed then was TP_NO returned, else one of the following error codes: "TPERROR_INCORRECT_GOAL", "TPERROR_UNKNOWN_ENGINE" or "TPERROR_PROVE" was returned.

Function TPNumVars (ByVal EngineId As Long) As Long
func Retrieve the number of variables in the last solution found by the specified engine.
pre A solution must have been found.
post The number of variables was returned, if the engine was not found then TPERROR_UNKNOWN_ENGINE was returned, else the number of variables was returned.

Function TPVarName(ByVal EngineId As Long, ByVal Index As Long) As String
func Get the name of the specified variable of the last solution generated by the engine identified by "EngineId".
pre A solution was found AND "Index" ≥ 0 AND "Index" < "NumVars".
post If the variable was found then the name of it was returned, else an empty string was returned. To store the name of the variable create a copy of the returned character string.

Function TPVarValue(ByVal EngineId As Long, ByVal Index As Long) As String
func Get the value of the specified variable of the last solution generated by the engine identified by "EngineId".
pre A solution was found AND "Index" ≥ 0 AND "Index" < "NumVars".
post If the variable was found then the value was returned, else an empty string was returned. To store the value of the variable create a copy of the returned character string.

Function TPVarType (ByVal EngineId As Long, ByVal Index As Long) As Long
func Get the type of the value of the specified variable of the last solution generated by the engine identified by "EngineId".
pre A solution was found AND "Index" ≥ 0 AND "Index" < "NumVars".
post If the variable was found then the type of the value was returned, else was TPTYPE_UNKNOWN returned. The following type constants are defined:
TPTYPE_UNKNOWN = No value or unknown type.
TPTYPE_EMPTYLIST = An empty list.
TPTYPE_LIST = A list with elements.
TPTYPE_EMPTY = An empty variable.
TPTYPE_INTEGER = An integer number value.
TPTYPE_FLOAT = A floating point value.
TPTYPE_STRUCTURE = A structure value.
TPTYPE_ATOM = An atom value.

Function TPPutSettings (ByVal AppName As String, ByVal AppVersion As String, ByVal AppHelpFile As String, ByVal AppCopyright As String, ByVal AppCompanyName As String) As Long
func Set the name, version, help file name, copyright message and company name of the application. These values are displayed if the user, for instance opens the About dialog from inside a TPWin application being interpreted by the Trinc-Prolog DLL.
pre Any of the parameters may be NIL.
post The supplied values were stored.
remark There is another version of this procedure that uses the pchar type instead of the string type for the parameters, this version of the function is called DLL_TPPutSettings.

[top] [up] [next]

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

und zu gutzer letzt, hier gibt es ein interface für swi-prolog (ich habe diese ein wenig angepasst):

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 18 Jahren

sind nur ausschnitte die rechtlich einwandfrei verwendbar sind, es sei denn ich hätte etwas überlesen.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

N
161 Beiträge seit 2006
vor 17 Jahren

Sorry, dass ich diesen alten Thread nochmal hochhole 8o

Original von dr4g0n76
Wer schon immer mal Prolog in C# einbinden wollte, um mit KI und weiterem zu hantieren kann das hiermit kostenlos tun:


>

Anleitung:


>

Das hier funktioniert bei mir wunderbar, bekomme meine Prolog Programme in C# zum laufen! DANKE für diesen tollen Einwurf! (auch wenn ich nicht ganz verstehe, wie es im Hintergrund eigentlich funktioniert... so wie ich das bisher sehe, wird Prolog in C# Code umgewandelt!???? Also kein "echter" Aufruf von C# nach Prolog?)

Original von dr4g0n76
und zu gutzer letzt, hier gibt es ein interface für swi-prolog (ich habe diese ein wenig angepasst):

Gibt es hierfür vielleicht auch eine Anleitung? Ich verstehe leider gar nicht, wie es funktioniert X( 🤔 Das ist schade, ich nutze nämlich SWI-Prolog gerne

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 17 Jahren

kannst du mir mal ein beispiel schicken mit einem einfachen Codeausschnitt?

Ich kriege ja momentan nicht mal das Beispiel das dabei ist zum laufen.

Wie muss ich das mit dem livesin_2 machen?

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

N
161 Beiträge seit 2006
vor 17 Jahren

Also das mit dem SWI-Prolog bekomme ich nicht zum Laufe, du sagtest, du hättest es angepasst, kannst du mir erklären wie es funzt?

Zum Psharp: (womit du den Thread eingeleitet hattest)

Das Manual ist etwas missverständlich. Du kannst nicht einfach Prolog von C# aufrufen, sondern musst Prolog zu C# kompilieren, daraus resultieren C# Klassen, die du für eine Prolog-Simulation(!) verwenden kannst.

Die im Beispiel aufgeführte "LivesIn_2" ist eine Klasse in C#, kompiliert aus Prolog und war ursprünglich eine Prolog-Regel. Wie gesagt, das Manual ist nicht so gut.


Hier mein Beispiel:

Das Prolog-Programm (was ich in C# verwenden möchte) ist hier mal das auf wikipedia (unter "Prolog") vorgestellte Rätzellösungsprogramm von Einstein`s Rätzel:


erstes(E,[E|_]).				% Kommt E als erstes (rechtes) Element vor?

mittleres(M,[_,_,M,_,_]).			% Kommt M als mittleres Element vor?

links(A,B,[A|[B|_]]).   			% Kommt A links neben B vor?
links(A,B,[_|R]):-links(A,B,R).			% Kommt A links neben B, in im Rest vor?

neben(A,B,L):-links(A,B,L);links(B,A,L).	% 

member(X, [X|_]).
member(X, [_|T]) :-
	member(X, T).

run:-
  X = [_,_,_,_,_],                                /* Es gibt (nebeneinander) 5 (noch unbekannte) Häuser */
  member([rot,brite,_,_,_],X),                    /* Der Brite lebt im roten Haus */
  member([_,schwede,_,_,hund],X),                 /* Der Schwede hält einen Hund */
  member([_,daene,tee,_,_],X),                    /* Der Däne trinkt gern Tee */
  links([gruen,_,_,_,_],[weiss,_,_,_,_],X),       /* Das grüne Haus steht links vom weißen Haus */
  member([gruen,_,kaffee,_,_],X),                 /* Der Besitzer des grünen Hauses trinkt Kaffee */
  member([_,_,_,pallmall,vogel],X),               /* Die Person, die Pall Mall raucht, hält einen Vogel */
  mittleres([_,_,milch,_,_],X),                   /* Der Mann, der im mittleren Haus wohnt, trinkt Milch */
  member([gelb,_,_,dunhill,_],X),                 /* Der Besitzer des gelben Hauses raucht Dunhill */
  erstes([_,norweger,_,_,_],X),                   /* Der Norweger wohnt im 1. Haus */
  neben([_,_,_,marlboro,_],[_,_,_,_,katze],X),    /* Der Marlboro-Raucher wohnt neben dem, der eine Katze hält */
  neben([_,_,_,_,pferd],[_,_,_,dunhill,_],X),     /* Der Mann, der ein Pferd hält, wohnt neben dem, der Dunhill raucht */
  member([_,_,bier,winfield,_],X),                /* Der Winfield-Raucher trinkt gern Bier */
  neben([_,norweger,_,_,_],[blau,_,_,_,_],X),     /* Der Norweger wohnt neben dem blauen Haus */
  member([_,deutsche,_,rothmans,_],X),            /* Der Deutsche raucht Rothmans */
  neben([_,_,_,marlboro,_],[_,_,wasser,_,_],X),   /* Der Marlboro-Raucher hat einen Nachbarn, der Wasser trinkt */
  member([_,N,_,_,fisch],X),                      /* Der mit der Nationalität N hat einen Fisch */
  write(X),nl,                                    /* Ausgabe aller Häuser */
  write('Der '),write(N),write(' hat einen Fisch als Haustier.'),nl.   /* Antwort auf die Frage */

...man beachte, das die Regel "run" das ist, was wir in C# ausführen wollen.

Nun nehmen wir die "PsharpGUI.exe", öffnen diese Prolog-Datei (mit dem obigen Inhalt(einfach in eine .txt kopieren und zu .pl umbenennen) und wählen im Menü "Editor" -> "Compile to C#".

Wenn der Prolog-Code fehlerfrei war, bekommen wir 7 C#-Klassen:


dollar_dummy Temp__0_3.cs
Erstes_2.cs
Links_3.cs
Mittleres_2.cs
Neben_3.cs
Run_0.cs
Member_2.cs

Wobei die Zahl die Anzahl der Parameter darstellt.

Folgend öffnen wir ein neues C#-Project (am besten Konsolen-Anwendung).

Unter "References" adden wir die mitgelieferte "Psharp.dll". Und gebe folgendes im Code vor:

using JJC.Psharp.Lang;
using JJC.Psharp.Predicates;
using JJC.Psharp.Lang.Resource;
using JJC.Psharp.Resources;

Und dann können wir die Regel "run" verwenden. "new LivesIn_2" ist in diesem Fall mit "new Run_0" gleichzusetzen, nur dass Run_0 keine Parameter verwendet (daher auch die 0). Wenn Parameter benötigt werden, müssen Variablen gesetzt und Konstanten vorgegeben werden, das ist im Manual-Beispiel zu sehen.


        void prolog_call()
        {
            PrologInterface pri = new PrologInterface();
            pri.AddAssembly(System.Reflection.Assembly.GetExecutingAssembly());
            
            pri.setPredicate(new Run_0(new ReturnCs( pri)));

            pri.Call();

            Console.ReadLine();
        }

Hoffe weitergeholfen zu haben.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 17 Jahren

Das hat geholfen, denn ich wusste bisher nur, wie ich kleine Terme usw. selber programmiere aber nicht wie ich quasi wi im Editor mit Consult() das Programm ausführen lasse. Da hätte ich mich genauer ausdrücken sollen.

Zum Manual:

...Prolog-Simulation!...

das sehe ich anders. Du hast durchaus Zugriff auf die Prolog-Engine und Dank Dir, weisst Du jetzt auch, wie Du das zur Laufzeit machen kannst.

Guck Dir mal den generierten Code an. Wie gesagt, mit einfachen Beispielen habe ich es schon hinbekommen. z.B. rot(rose).

Wenn ich das kompiliere geht es bestimmt noch einfacher. Ich werde dann die Lösung hier posten.

Wenn es wirklich so geht, wie ich meine.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

N
161 Beiträge seit 2006
vor 17 Jahren

Original von dr4g0n76
Ich werde dann die Lösung hier posten.

Ok gut, ich freu mich 🙂

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 17 Jahren

Habe mal soeben Dein Beispiel probiert. Wie bekomme ich eine Ausgabe?

Habe eine Form-Anwendung erstellt.


  void PrologCall()
        {
            PrologInterface pri = new PrologInterface(false);
            pri.AddAssembly(System.Reflection.Assembly.GetExecutingAssembly());

            pri.SetPredicate(new Run_0(new ReturnCs(pri)));

            pri.Call();

            MessageBox.Show(Console.ReadLine());
        }

Die MessageBox ist immer leer.

EDIT: Sorry, habs schon längst herausgefunden. jetzt kann ich auch die allgemeine verbesserte Klasse posten. Wird wahrscheinlich morgen noch passieren.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 17 Jahren

Also jetzt gehts mal los:

Ich hab dein Programm mal übersetzt (Compiliert). Dann erhalte ich wie Du schon gesagt hast, die 7 Klassen.

Erstmal Erklärung:
============
Vorweg: Nicht gleich sagen, was soll der Blödsinn denn, bitte einfach mal durchlesen und ggf. überspringen.

In run_0 werden die Terme und die Variablen angelegt.

run_0 wird im Hauptprogramm dann über


pri.SetPredicate(new Run_0(new ReturnCs(pri)));

Run_0 ist abgeleitet von Predicate.

aufgerufen.

Soweit so gut?

Soweit das was wir schon haben.

Wo wollen wir jetzt hin?

Wir wollen doch nicht mehr haben, das wir jedes mal kompilieren müssen.
Also gilt es uns jetzt ein Framework zu schaffen, dass das kann.

Dazu generieren wir uns jetzt ein (ich hoffe mal ich benenne das richtig)
ein 1-stelliges Prädikat:

rot(rose).

Das lassen wir uns jetzt übersetzen:


public class Rot_1 : Predicate {
    static internal readonly SymbolTerm s1 = SymbolTerm.MakeSymbol("rose");

    public Term arg1;

    public Rot_1(Term a1, Predicate cont) {
        arg1 = a1; 
        this.cont = cont;
    }

    public Rot_1(){}
    public override void setArgument(Term[] args, Predicate cont) {
        arg1 = args[0]; 
        this.cont = cont;
    }

    public override Predicate exec( Prolog engine ) {
        engine.setB0();
        Term a1;
        a1 = arg1.Dereference();

        if ( !s1.Unify(a1, engine.trail) ) return engine.fail();
        return cont;
    }

    public override int arity() { return 1; }

    public override string ToString() {
        return "rot(" + arg1 + ")";
    }
}

Jetzt brauchen wir doch etwas, dass das zur Laufzeit kann richtig?

Störend ist jetzt also, dass das Prädikat rose einfach als String hard-codiert ist.
Aber ich denke, uns hindert doch niemand daran dies zu ändern.

Was spricht also gegen folgende Abänderung:

in rot_1:

wir machen aus


    internal static readonly s1 = SymbolTerm.MakeSymbol("rot");


    public static SymbolTerm s1 = null;

und in Run_0 lauten die letzten 3 Zeilen folgendermaßen:


      Rot_1.s1 = SymbolTerm.MakeSymbol("rose");
        p1 = new Predicates.Write_1(a1, cont);
        return new Predicates.Rot_1(a1, p1);

Das machen wir um auszuprobieren, ob das Programm noch läuft,

und Voilá ich erhalte immer noch als Ausgabe "rose" für mein Prolog-Programm.

Ach ja, hier noch das Prolog-Programm:


rot(rose).
    run:-
          rot(X),
          write(X).

Aber wo wollen wir eigentlich hin?

Der Traum wäre doch ein Programm á la

new rot("rose");
new rot("tulpe");
new blau("veilchen");

usw.

schreiben zu können und dann das ganze irgendwie zu starten,
z.B. per


     PrologRunner prologRunner = new PrologRunner();
            prologRunner.Items.Add(new Rot("rose"));
            prologRunner.Items.Add(new Rot("ferrari"));
            prologRunner.Run();

wie man sieht ist das noch unvollständig, denn wir können jetzt zwar die Fakten definieren aber noch nicht ausführen, was in RUN passieren soll.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

J
1 Beiträge seit 2006
vor 17 Jahren
Psharp

Hallo dr4g0n76, no1gizmo

wie kann ich von C# Code heraus, Psharp compiler starten. Ich implementiere eine Web Service, die RDF Statements einliest, dann ändere ich die RDF Triples in Prolog syntax. Mit einige Regeln will ich diese Triples in Psharp eingeben und in C# übersetzt bekommen. Und danach hoffe, ich bißchen Inferencing / Reasoning machen zu können.

Ich habe die Manual zu Psharp gelesen. Ist aber nicht sehr klar für mich.

Ihr seid die einzige, die im ganzen Web was zu Psharp in irgendeine Forum geschrieben habt. So meine Frage, kannst du vielleicht mir erklären, wie es im Ganzen funktioniert.
Oder wenn du Beispiel Code hast, kannst du vielleicht posten oder mir schicken.

Wäre sehr dankbar.

Jagga

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 17 Jahren

Sorr Jaggat, habe Dein Post hier erst heute bemerkt...

Werde mal sehen, was ich für dich tun kann.

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.

dr4g0n76 Themenstarter:in
2.921 Beiträge seit 2005
vor 14 Jahren

Hier gibt's inzwischen ebenfalls eine Prolog Implementierung für .NET:
[URL=http://prolog.hodroj.net/[/url]Prolog.NET[/url]

Und genau das was hier in diesem Thread erreicht werden sollte, ist wohl inzwischen auch mit diesem Projekt möglich.


using System;
using Prolog.Assembly;
using Axiom.Runtime; // required only for AbstractTerm
namespace PrologAndMath
{
class Program
{
static void Main(string[] args)
{
MyMath math = new MyMath();
// Calculate the factorial
AbstractTerm a = new AbstractTerm();
math.factorial(3, a);
Console.WriteLine("Factorial of 3 is: " + a);
// calculate the fifth fibonacci (should be 8)
AbstractTerm fibValue = new AbstractTerm();
math.fib(5, fibValue); // this is like fib(5, X) in Prolog
Console.WriteLine("Fibonacci of 3 is: " + fibValue);
}
}
}

Seit der Erkenntnis, dass der Mensch eine Nachricht ist, erweist sich seine körperliche Existenzform als überflüssig.