home *** CD-ROM | disk | FTP | other *** search
/ Collection of Education / collectionofeducationcarat1997.iso / COMPUSCI / BAYES.ZIP / BAYES.AUG next >
Text File  |  1991-03-11  |  13KB  |  502 lines

  1. program BayesNet(NodeFile,LinkFile,Output);
  2. {
  3.    This code is a basic implementation of Judea Pearl's belief
  4.    propagation algorithm for tree-structured Bayesian belief
  5.    networks.  The procedures and functions can be divided into
  6.    three basic groups:
  7.    
  8.    Math Support:
  9.       Normalize
  10.       MakeIdentityVector
  11.       TermProduct
  12.       TermQuotient
  13.       MatMult
  14.    Core:
  15.       ReviseBelief
  16.       UpdateNode
  17.       SubmitEvidence
  18.    General Support:
  19.       ReadString
  20.       FindNode
  21.       DumpNetwork
  22.          DumpNode
  23.       ReadNet
  24.          ReadNodes
  25.          ReadLinks
  26.       
  27.    The Core routines are described in the August AI Expert article.
  28.    The main program is set up to run the example from the May AI
  29.    Expert article.  It reads the net from two data files which are
  30.    described in ReadNodes and ReadLinks.  Be sure to figure out how
  31.    to RESET these files so that they get picked up correctly by those
  32.    procedures.   
  33. }
  34.  
  35. const
  36.    MaxString      = 15;
  37.    MaxValues      =  5;
  38.          
  39. type
  40.    StringRange = 1..MaxString;
  41.    ValueRange  = 1..MaxValues;
  42.    StringType  = packed array[StringRange] of char;
  43.    NetVector   = record
  44.                     Data:  array [ValueRange] of real;
  45.                     NVals: ValueRange
  46.                  end;
  47.    CPType      = record
  48.                     Data:        array[ValueRange,ValueRange] of real;
  49.                     NRows,NCols: ValueRange
  50.                  end;
  51.    NetNodePtr  = ^NetNode;
  52.    NetNode     = record
  53.                     Name:                       StringType;
  54.                     NumValues:                  ValueRange;
  55.                     Values:                     array[ValueRange] of 
  56. StringType;
  57.                     Belief,Pi,IncomingPi,
  58.                     ExternalLambda,
  59.                     Lambda,OutgoingLambda:      NetVector;
  60.                     Parent,NextNode,
  61.                     NextSibling,FirstChild:     NetNodePtr;
  62.                     CPMatrix,TransCPMatrix:     CPType
  63.                  end;
  64.                         
  65. var      NodeFile,LinkFile:            Text;
  66.          NetRoot,NodeList:             NetNodePtr;
  67.          EvidenceVector:               NetVector;
  68.  
  69. { ******************** Math Support ******************** }
  70.         
  71. procedure Normalize(var Vector: NetVector);
  72. { Scales incoming Vector so that it sums to unity }
  73. var i:   ValueRange;
  74.     Sum: real;
  75.  
  76. begin
  77. Sum := 0;
  78. with Vector do
  79.    begin
  80.    for i := 1 to NVals do
  81.       Sum := Sum + Data[i];
  82.    for i := 1 to NVals do
  83.       Data[i] := Data[i] / Sum
  84.    end
  85. end;
  86.          
  87. procedure MakeIdentityVector(var Vector: NetVector;Length: ValueRange);
  88. { Makes incoming Vector into an identity vector of specified length}
  89. var i: ValueRange;
  90.  
  91. begin
  92. with Vector do
  93.    begin   
  94.    NVals := Length;
  95.    for i := 1 to Length do
  96.       Data[i] := 1.0   
  97.    end   
  98. end;
  99.  
  100. procedure TermProduct(var V1,V2,Result: NetVector);
  101. { Returns term product of V1 and V2 in Result }                      
  102. var i:  ValueRange;
  103.  
  104. begin
  105. if v1.NVals <> v2.Nvals then
  106.    writeln('*** Dimension error in TermProduct ***');
  107. with Result do
  108.    begin
  109.    Nvals := V1.Nvals;
  110.    for i := 1 to NVals do
  111.       Data[i] := V1.Data[i] * V2.Data[i]
  112.    end
  113.  
  114. end;
  115.  
  116. procedure TermQuotient(var V1,V2,Result: NetVector);
  117. { Returns term quotient of V1 and V2 in Result }                               
  118.              
  119. var i:  ValueRange;
  120.  
  121. begin
  122. if v1.NVals <> v2.Nvals then
  123.    writeln('*** Dimension error in TermQuotient ***');
  124. with Result do
  125.    begin
  126.    Nvals := V1.Nvals;
  127.    for i := 1 to NVals do
  128.       Data[i] := V1.Data[i] / V2.Data[i]
  129.    end
  130. end;
  131.  
  132. procedure MatMult(var InMat:  CPType;var InVec:  NetVector;var OutVec: 
  133. NetVector);
  134. { Simplified matrix multiplication matrix routine.  Multiplies InMat * InVec
  135.   to produce OutVec.  Interprets InVec to be a NVals X 1 matrix. }
  136. var Row,Col: ValueRange;
  137.  
  138. begin
  139. if InMat.NCols <> InVec.NVals then
  140.    writeln('*** Dimension error in MatMult ***');
  141. with InMat do
  142.    begin
  143.    OutVec.NVals := NRows;
  144.    for Row := 1 to NRows do
  145.       begin
  146.       OutVec.Data[Row] := 0.0;
  147.       for Col := 1 to NCols do
  148.          OutVec.Data[Row] := OutVec.Data[Row] + Data[Row,Col] * InVec.Data[Col]
  149.        end
  150.    end
  151. end;
  152.  
  153. { ******************** Core ******************** }
  154.  
  155. procedure ReviseBelief(Node: NetNodePtr);
  156. var Child:  NetNodePtr;
  157. begin
  158. with Node^ do
  159.    begin
  160.    { Part (a) of Figure 4 }
  161.    if Parent <> nil then
  162.       MatMult(TransCPMatrix,IncomingPi,Pi);
  163.    { Part (b) of Figure 4 }
  164.    Lambda := ExternalLambda;
  165.    Child := FirstChild;
  166.    while Child <> nil do
  167.       begin
  168.       TermProduct(Child^.OutgoingLambda,Lambda,Lambda);
  169.       Child := Child^.NextSibling
  170.       end;
  171.    { Shaded part of Figure 4 }
  172.    TermProduct(Lambda,Pi,Belief);   
  173.    Normalize(Belief)
  174.    end
  175. end;
  176.  
  177. procedure UpdateNode(Node,Sender: NetNodePtr);
  178. var Child:  NetNodePtr;
  179. begin
  180. with Node^ do
  181.    begin
  182.    ReviseBelief(Node);
  183.    { Update OutgoingLambda & send update message to parent
  184.      (part (c) of Figure 4) }
  185.    if (Parent <> Sender) and (Parent <> nil) then
  186.       begin
  187.       MatMult(CPMatrix,Lambda,OutgoingLambda);
  188.       UpdateNode(Parent,Node)
  189.       end;
  190.    { Update IncomingPi and send update message to children
  191.      (part (d) of Figure 4) }
  192.    Child := FirstChild;
  193.    while Child <> nil do
  194.       begin
  195.       if Child <> Sender then
  196.          begin
  197.          TermQuotient(Belief,Child^.OutgoingLambda,Child^.IncomingPi);
  198.          UpdateNode(Child,Node)
  199.          end;
  200.       Child := Child^.NextSibling
  201.       end
  202.    end
  203. end;
  204.  
  205. procedure SubmitEvidence(Node: NetNodePtr;var Evidence: NetVector);
  206. var i: ValueRange;
  207. begin
  208. with node^ do
  209.    begin
  210.    writeln('Submitting evidence to ',Node^.Name,', evidence is:');
  211.    for i := 1 to Evidence.NVals do
  212.       writeln('[',Values[i],'] = ',Evidence.Data[i]);
  213.    TermProduct(Evidence,ExternalLambda,ExternalLambda);
  214.    UpdateNode(Node,nil)
  215.    end
  216. end;
  217.  
  218. { ******************** General Support ******************** }
  219.  
  220. function ReadString(var InFile: Text;var InString: StringType): boolean;
  221. { Reads InFile, returning next string in InString.  Returns FALSE upon
  222.   encountering end of file, otherwise returns TRUE. }
  223. var i,j:  StringRange;
  224.  
  225. begin
  226. if eof(InFile) then
  227.    ReadString := false
  228. else
  229.    begin
  230.    i := 1;
  231.    while not eoln(InFile) do
  232.       begin
  233.       read(InFile,InString[i]);
  234.       i := i + 1
  235.       end;
  236.    readln(InFile);
  237.    for j := i to MaxString do
  238.       InString[j] := ' ';
  239.    ReadString := true   
  240.    end;   
  241. end;
  242.          
  243. function FindNode(NodeName: StringType):NetNodePtr;
  244. { Searches network for node having specified NodeName. }                  
  245. var CurrentNode:   NetNodePtr;
  246.  
  247. begin
  248. CurrentNode := NodeList;
  249. while (CurrentNode^.Name <> NodeName) and (CurrentNode <> nil) do
  250.    CurrentNode := CurrentNode^.NextNode;
  251. if CurrentNode = nil then
  252.    begin
  253.    writeln('*** Error in FindNode -- cannot find ',NodeName);
  254.    FindNode := nil
  255.    end
  256. else
  257.    FindNode := CurrentNode
  258. end;
  259.         
  260. procedure DumpNetwork(Node: NetNodePtr);
  261. { Recursive procedure to dump network, given pointer to root }
  262.  
  263. procedure DumpNode(Node: NetNodePtr);
  264. { Simple procedure to dump a single node }
  265. const Stars = '*************************************************';
  266.  
  267. var CurrentValue,NumRows,NumCols,Row,Col:  ValueRange;
  268.  
  269. begin
  270. writeln(Stars);
  271. with Node^ do
  272.    begin
  273.    writeln('Dumping ',Name);
  274.    for CurrentValue := 1 to NumValues do
  275.       writeln('Pi[',Values[CurrentValue],'] = ',Pi.Data[CurrentValue]);
  276.    for CurrentValue := 1 to NumValues do
  277.       writeln('Lambda[',Values[CurrentValue],'] = ',Lambda.Data[CurrentValue]);
  278.    for CurrentValue := 1 to NumValues do
  279.       writeln('Belief[',Values[CurrentValue],'] = ',Belief.Data[CurrentValue]);
  280.    if Parent <> nil then
  281.       begin
  282.       writeln;
  283.       writeln('CP Matrix:');
  284.       for Row := 1 to CPMatrix.NRows do
  285.          begin
  286.          for Col := 1 to CPMatrix.NCols do
  287.             write(CPMatrix.Data[Row,Col]);
  288.          writeln
  289.          end
  290.       end
  291.    end;
  292. writeln(Stars);
  293. writ