[net.ai] Bug in Turbo Prolog

pv@lln-cs.UUCP (Patrick Vandamme) (09/04/86)

I am testing the `famous' Turbo Prolog Software and, after all the good things
that I heard about it, I was very surprised at having problems with the first
large program I tried. I give here this program. It finds all the relations 
between a person and his family. But for some people, it answers with a lot
of strange characters. I think there must be a dangling pointer somewhere. 
Note that this happens only with large programs !

Have someone the same result ?

(for the stange characters, try with "veronique").

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
     +-----------------------------------------------------+
     |      Programme de gestion d'une base de donnees     |
     |               de relations familiales.              |
     +-----------------------------------------------------+
            P. Vandamme - Unite Info - UCL - Aout 1986
*/

domains
	nom        = string
	noms       = nom*
	couple     = integer
	relation   = string
	distance   = real
	chemin     = relation*
	qqn        = qqn(nom,distance,chemin)
	famille    = qqn*
	
predicates
	/* base de donnees */
	couple(couple,nom,nom)
        homme(couple,nom)
        femme(couple,nom)
        		
	/* relations familiales */
	etre(couple,nom)
	en_couple(couple,nom)
	conjoint(nom,nom)
	parent_de(nom,nom)
	frere_de(nom,nom)
	soeur_de(nom,nom)
	frere_ou_soeur_de(nom,nom)
	R(nom,relation,nom,distance)
	
	/* programmes */
	pgm
	repeat
	imprimer_famille(nom,famille)
	imprimer_chemin(chemin)
	entourage(nom,famille)
	entourage1(nom,qqn)
	explorer_famille(famille,famille,famille)
	referer_entourage(qqn,famille,famille)
	integrer_entourage(famille,famille,famille,famille,famille)
	integrer_qqn(qqn,famille,famille,famille,famille)
	equal_qqn(qqn,qqn)
	inclure_qqn(qqn,famille,famille)
	extraire_qqn(nom,famille,famille,qqn,famille)
	qqn_minimum(qqn,qqn,qqn)
	append_famille(famille,famille,famille)
	append_chemin(chemin,chemin,chemin)
	
goal
	pgm.
		
clauses
	/* BASE DE DONNEES */
	
	couple(01,"tom","natacha").
	couple(02,"luc","lennie").
	couple(03,"robert","veronique").
	couple(04,"henri","renee").
	couple(05,"charles","xiao-lou").
	couple(06,"manu","brigitte").
	couple(07,"marc","geraldine").
	couple(08,"francis","anne-marie").
	couple(09,"pierre","marie-louise").
	
	homme(00,"henri").
	homme(00,"pierre").
	homme(00,"manu").
	homme(06,"charles").
	homme(03,"luc").
	homme(03,"tom").
	homme(04,"marc").	
	homme(08,"philippe").
	homme(09,"robert").
	homme(09,"francis").
	homme(09,"jacques").
	
	femme(00,"lennie").
	femme(00,"xiao-lou").
	femme(00,"geraldine").
	femme(00,"veronique").
	femme(00,"renee").
	femme(00,"anne-marie").
	femme(00,"marie-louise").
	femme(00,"brigitte").
	femme(02,"katrina").
	femme(06,"natacha").
	femme(08,"anne-christine").
	femme(08,"louise").
	femme(08,"marielle").
	femme(09,"monique").
 	
	/* RELATIONS FAMILIALES */
	
	etre(C,X)               :- homme(C,X).
	etre(C,X) 		:- femme(C,X).
	
	en_couple(C,X) 		:- couple(C,X,_).
	en_couple(C,X) 		:- couple(C,_,X).
	
	conjoint(X,Y) 		:- couple(_,X,Y).
	conjoint(X,Y) 		:- couple(_,Y,X).
	
	parent_de(X,Y) 		:- etre(C,X), C <> 0, en_couple(C,Y).
	
	frere_de(X,Y) 		:- etre(C,X), C <> 0, homme(C,Y), X <> Y.
	
	soeur_de(X,Y) 		:- etre(C,X), C <> 0, femme(C,Y), X <> Y.
	
	frere_ou_soeur_de(X,Y)  :- frere_de(X,Y).
	frere_ou_soeur_de(X,Y)  :- soeur_de(X,Y).	
	
	
	R(X,"mari de",Y,1)         :- couple(_,X,Y).
	R(X,"femme de",Y,1)        :- couple(_,Y,X).
	R(X,"frere de",Y,1)        :- frere_de(Y,X).
	R(X,"soeur de",Y,1)        :- soeur_de(Y,X).
	R(X,"mere de",Y,1)         :- couple(C,_,X), etre(C,Y).	
	R(X,"pere de",Y,1)         :- couple(C,X,_), etre(C,Y).
	R(X,"grand mere de",Y,2)   :- R(X,"mere de",Z,_), parent_de(Y,Z).
	R(X,"grand pere de",Y,2)   :- R(X,"pere de",Z,_), parent_de(Y,Z).
	R(X,"fils de",Y,1)         :- homme(C,X), C <> 0, en_couple(C,Y).
	R(X,"fille de",Y,1)        :- femme(C,X), C <> 0, en_couple(C,Y).
	R(X,"petit fils de",Y,2)   :- R(X,"fils de",Z,_), parent_de(Z,Y).
	R(X,"petite fille de",Y,2) :- R(X,"fille de",Z,_), parent_de(Z,Y).
	R(X,"beau fils de",Y,2)    :- couple(_,X,Z), parent_de(Z,Y).
	R(X,"belle fille de",Y,2)  :- couple(_,Z,X), parent_de(Z,Y).
	R(X,"beau frere de",Y,2)   :- frere_de(Z,X), conjoint(Z,Y).
	R(X,"beau frere de",Y,2)   :- couple(_,X,Z), soeur_de(Y,Z).
	R(X,"belle soeur de",Y,2)  :- soeur_de(Z,X), conjoint(Z,Y).
	R(X,"belle soeur de",Y,2)  :- couple(_,Z,X), frere_de(Y,Z).
	R(X,"oncle de",Y,2)        :- frere_de(Z,X), parent_de(Y,Z).
	R(X,"tante de",Y,2)        :- soeur_de(Z,X), parent_de(Y,Z).
	R(X,"neveu de",Y,2)        :- R(X,"fils de",Z,_), frere_ou_soeur_de(Y,Z).
	R(X,"niece de",Y,2)        :- R(X,"fille de",Z,_), frere_ou_soeur_de(Y,Z).
	R(X,"cousin de",Y,3)       :- R(X,"fils de",W,_), frere_ou_soeur_de(W,Z), parent_de(Y,Z).
	R(X,"cousine de",Y,3)      :- R(X,"fille de",W,_), frere_ou_soeur_de(W,Z), parent_de(Y,Z).

	/* PROGRAMMES */
		
	pgm :-
		makewindow(1,7,7," FAMILLE ",0,0,25,80),
		repeat,
		clearwindow,
		nl, write("  Nom d'une personne ? "),
		readln(Nom), nl,
		explorer_famille([qqn(Nom,0,[])],[],Famille),
		imprimer_famille(Nom,Famille),
		readchar(_),
		fail.
		
	repeat.
	repeat :- repeat.
		
	imprimer_famille(_,[]) :- !.
	imprimer_famille(N,[qqn(Nom,_,Chemin)|Famille]) :-
		write("  ",N," est "),
		imprimer_chemin(Chemin),
		write(Nom), nl,
		imprimer_famille(N,Famille).
		
	imprimer_chemin([]) :- !.
	imprimer_chemin([Rel|Chemin]) :-
		write(Rel," "),
		imprimer_chemin(Chemin).

	/* 
	   entourage(Nom,Famille)
	   ----------------------
	   Permet de trouver l'ensemble des personnes qui ont
	   une relation directe avec Nom.
	*/	
	entourage(Nom,Famille) :-
		findall(Qqn,entourage1(Nom,Qqn),Famille).
	
	entourage1(Nom,qqn(Y,Distance,[A])) :-
		R(Nom,A,Y,Distance).
		
	/*
	   explorer_famille(Famille,[],NewFamille)
	   ---------------------------------------
	   Permet d'explorer toute la famille, en recherchant
	   successivement les entourages de tous les Qqn dans
	   la famille.
	*/
	explorer_famille([],Famille,Famille) :- !.	
	explorer_famille([Qqn|L_Qqn],Famille,Result) :-
		equal_qqn(Qqn,qqn(Nom,_,_)),
		write("   ",Nom,"\n"),
		entourage(Nom,Entourage),
		referer_entourage(Qqn,Entourage,NewEntourage),
		integrer_entourage(NewEntourage,L_Qqn,Famille,NewL_Qqn,NewFamille),
		explorer_famille(NewL_Qqn,[Qqn|NewFamille],Result).
	
	/*
	   referer_entourage(Qqn,Entourage,NewEntourage)
	   ------------------------------------------------
	   Permet de mettre a jour les chemins et distances de
	   l'Entourage, en fonction de Qqn.
	*/
	referer_entourage(_,[],[]) :- !.
	referer_entourage(Qqn,[qqn(N,D,C)|Ent],[qqn(N,NewD,NewC)|NewEnt]) :-
		referer_entourage(Qqn,Ent,NewEnt),
		equal_qqn(Qqn,qqn(_,Dist,Chem)),
		NewD = Dist + D + 0.01,
		append_chemin(Chem,C,NewC).
	
	/*
	   integrer_entourage(Entourage,Work,Famille,NewWork,NewFamille)
	   -------------------------------------------------------------
	   Permet de distribuer Entourage dans les ensembles
	   appropries. (cfr. integrer_qqn).
	*/	
	integrer_entourage([],Work,Famille,Work,Famille) :- !.
	integrer_entourage([Qqn|Entourage],Work,Famille,NewWork,NewFamille) :-	
		integrer_qqn(Qqn,Work,Famille,W,F),
		integrer_entourage(Entourage,W,F,NewWork,NewFamille).
	
	/*
	   integrer_qqn(Qqn,Work,Famille,NewWork,NewFamille)
	   -------------------------------------------------
	   Permet de placer Qqn dans l'ensemble approprie.
	   S'il existe deja dans Famille, on le laisse la en
	   gardant la distance minimum. Sinon on l'inclu dans
	   Work.
	*/
	integrer_qqn(Qqn1,Work,Famille,Work,[QqnMin|NewFamille]) :-
		equal_qqn(Qqn1,qqn(Nom,_,_)),
		extraire_qqn(Nom,Famille,[],Qqn2,NewFamille),
		qqn_minimum(Qqn1,Qqn2,QqnMin), !.
	integrer_qqn(Qqn,Work,Famille,NewWork,Famille) :-
		inclure_qqn(Qqn,Work,NewWork).
		
	equal_qqn(Qqn,Qqn).
	
	/* 
	   inclure_qqn(Qqn,Famille,NewFamille)
	   -----------------------------------
	   Permet d'ajouter Qqn dans une famille de relations.
	   Si ce Qqn n'existe pas, il est simplement ajoute dans
	   la liste. S'il existe deja, on compare les deux 
	   distances et on garde la relation ayant la distance
	   minimale.
	*/
	inclure_qqn(Qqn1,Famille,[QqnMin|NewFamille]) :-
		equal_qqn(Qqn1,qqn(Nom,_,_)),
		extraire_qqn(Nom,Famille,[],Qqn2,NewFamille),
		qqn_minimum(Qqn1,Qqn2,QqnMin), !.
	inclure_qqn(Qqn,Famille,[Qqn|Famille]).
	
	/* 
	   extraire_qqn(Nom,Famille,[],Qqn,NewFamille)
	   -------------------------------------------
	   Permet d'enlever Qqn dont on connait le Nom. Si ce
	   Qqn n'existe pas, ce predicat fail. Sinon, il renvoie
	   ce Qqn et la nouvelle famille.
	*/
	extraire_qqn(_,[],_,_,_) :- !, fail.
	extraire_qqn(Nom,[Qqn|L_Qqn],Work,Qqn,NewFamille) :-
		equal_qqn(Qqn,qqn(Nom,_,_)),
		append_famille(L_Qqn,Work,NewFamille), !.
	extraire_qqn(Nom,[Qqn|L_Qqn],Work,S1,S2) :-
		extraire_qqn(Nom,L_Qqn,[Qqn|Work],S1,S2).

	/* 
	   append_famille(Famille1,Famille2,NewFamille)
	   --------------------------------------------
	   Permet de concatener deux familles.
	*/		
	append_famille([],Famille,Famille).
	append_famille([Qqn|F1],F2,[Qqn|F3]) :-
		append_famille(F1,F2,F3).

	/* 
	   append_chemin(Chemin1,Chemin2,NewChemin)
	   --------------------------------------------
	   Permet de concatener deux chemins.
	*/		
	append_chemin([],Chemin,Chemin).
	append_chemin([Qqn|F1],F2,[Qqn|F3]) :-
		append_chemin(F1,F2,F3).
	
	/* 
	   qqn_minimum(Qqn1,Qqn2,QqnMinimum)
	   ---------------------------------
	   Permet de trouver le Qqn minimum entre deux Qqn.
	*/
	qqn_minimum(Qqn1,Qqn2,Qqn1) :-
		equal_qqn(Qqn1,qqn(_,Dist1,_)),
		equal_qqn(Qqn2,qqn(_,Dist2,_)),
		Dist1 <= Dist2, !.
	qqn_minimum(_,Qqn,Qqn).

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 
Patrick Vandamme

Unite d'Informatique              UUCP : (prlb2)lln-cs!pv
Universite Catholique de Louvain  Phone: +32 10 43 24 15
Place Sainte-Barbe, 2             Telex: 59037 UCL B
B-1348 Louvain-La-Neuve           Eurokom: Patrick Vandamme UCL
Belgium                           Fax  : +32 10 41 56 47

clh@cbrma.UUCP (C.Harting) (09/09/86)

I purchased Turbo Prolog Friday night, and immediately tried to compile the
GeoBase program on my Tandy 1000 (384K).  I could not even create a .OBJ file
on my machine, so I compiled it on a 640K AT&T PC6300.  Caveat No. 1: large
programs need large amounts of memory.  I compiled Patrick's "programme de
gestion" to disk and it ran flawlessly (I think -- this is my first lesson in
French!).  BUT when compiled to memory, I got the same errors as Patrick.
Caveat No. 2: compile large programs to disk and run standalone.  And, Caveat
No. 3: leave out as many memory-resident programs as you can stand when
booting the machine to run Turbo Prolog.
'Nuff said?

===============================================================================
Chris Harting				"Many are cold, few are frozen."
AT&T Network Systems			Columbus, Ohio
The Path (?!?):				cbosgd!cbrma!clh

john@uwmacc.UUCP (John Jacobsen) (09/11/86)

> Xref: uwmacc net.ai:1941 net.lang.prolog:528
> Summary: How to get around it.


I got the "Programme de Gestion de Base de Donnees" to work fine... on an
AT with a meg of memory.  I think Patrick Vandamme just ran out of memory,
cause his code is immaculate.

John E. Jacobsen
University of Wisconsin -- Madison Academic Computing Center