Printer Diagnosis Model =============================== In this notebook we translate into Probabilistic Logic Programming the Figaro example from Section 5.3 of [A. Pfeffer, Practical Probabilistic Programming](https://www.manning.com/books/practical-probabilistic-programming), pages 145-155.

Author: Damiano Azzolini

Suppose you work in a technical support center and you want to predict what is the cause of a malfunction given certain evidences. To give a quickly answer you could create a probabilistic program and feed the evidence to it to obtain an accurate answer, given the probability of each state that a component can be into. In this example we analyze how probabilistic programming can help us to understand, for instance, why a printer doesn't work. This is how the full network for the computer system diagnosis looks like:
:- use_rendering(graphviz).
X = dot("digraph G { PaperFlow->PaperJamIndicatorOn; PaperFlow->PrinterState; TonerLevel->TonerLowIndicatorOn; TonerLevel->PrinterState; PrinterPowerButtonOn->PrinterState; UserCommandCorrect->NumberPrintedPages; NetworkState->NumberPrintedPages; NetworkState->PrintsQuality; SoftwareState->NumberPrintedPages; SoftwareState->PrintsQuality; PrinterState->NumberPrintedPages; PrinterState->GoodPrintQuality; NumberPrintedPages->PrintResultSummary; PrintsQuality->PrintResultSummary; GoodPrintQuality->PrintResultSummary }").
Code Description ---------------- Some events can happen randomly. First of all we can think that the printer could prints perfectly, not quite right or doesn't print at all. Then we can start thinking about what is the cause of the problem, how is the printing process and which elements of the systems might influence the printing process: is the printer power button on? How many pages does the printer print? Does the printer prints quickly? In this example we consider facts like: =softwareState/1=, which could be =correct=, =glitchy= or =crashed=; =networkState/1=, which could be =up=, =intermittent= or =down=; =userCommandCorrect/1=, which could be =true= or =false=.
:- use_module(library(pita)). :- pita. :- begin_lpad. softwareState(correct):0.8; softwareState(glitchy):0.15; softwareState(crashed):0.05. networkState(up):0.7; networkState(intermittent):0.2; networkState(down):0.1. userCommandCorrect:0.65.
=userCommandCorrect/0=, =networkState/1= and =softwareState/1= might influence the number of printed pages and the print speed. We can express this with:
numPrintedPages(zero):- printerState(out). numPrintedPages(zero):- softwareState(crashed). numPrintedPages(zero):- networkState(down). numPrintedPages(zero):0.3; numPrintedPages(some):0.6; numPrintedPages(all):0.1:- \+(userCommandCorrect), \+ printerState(out),\+ softwareState(crashed), \+ networkState(down). numPrintedPages(zero):0.01; numPrintedPages(some):0.01; numPrintedPages(all):0.98:- userCommandCorrect, \+ printerState(out),\+ softwareState(crashed), \+ networkState(down). printsQuickly:0.5 :- networkState(intermittent),softwareState(correct). printsQuickly:0.5 :- networkState(intermittent),softwareState(glitchy). printsQuickly:0.5 :- networkState(up),softwareState(glitchy). printsQuickly:0.9 :- networkState(up), softwareState(correct).
If the printerState(out) or the softwareState(crashed) or the networkState(down) no pages will be printed. If the users uses the wrong command then the we can think the printer will print with more probability only some pages than all the pages, or no pages at all. Instead if the users uses the correct command we can imagine that the printer will print, almost surely, all the pages. Now we can take in consideration other facts like: =printerPowerButtonOn/0= which could be =true= or =false=; =tonerLevel/1= which could be =high=, =low= or =out= and =paperFlow= which could be =smooth=, =uneven= or =jammed=.
printerPowerButtonOn:0.95. tonerLevel(high):0.7; tonerLevel(low):0.2; tonerLevel(out):0.1. paperFlow(smooth):0.6; paperFlow(uneven):0.2; paperFlow(jammed):0.2.
The introduction of this new variables allow us to express the probability for more facts like =printResultSummary/1=, =tonerLowIndicator/1=, =paperJamIndicator/1=, =printerState/1= and =goodPrintQuality/1=.
printResultSummary(none):- numPrintedPages(zero). printResultSummary(poor):- numPrintedPages(some). printResultSummary(poor):- \+(numPrintedPages(zero)),\+ goodPrintQuality. printResultSummary(poor):- \+(numPrintedPages(zero)),\+ printsQuickly. printResultSummary(excellent):- \+(numPrintedPages(some)),\+(numPrintedPages(zero)),printsQuickly,goodPrintQuality. tonerLowIndicatorOn:0.2 :- printerPowerButtonOn, tonerLevel(high). tonerLowIndicatorOn:0.6 :- printerPowerButtonOn, tonerLevel(low). tonerLowIndicatorOn:0.99 :- printerPowerButtonOn, tonerLevel(out). paperJamIndicatorOn:0.1 :- printerPowerButtonOn, paperFlow(smooth). paperJamIndicatorOn:0.3 :- printerPowerButtonOn, paperFlow(uneven). paperJamIndicatorOn:0.99 :- printerPowerButtonOn, paperFlow(jammed). printerState(good):- printerPowerButtonOn, tonerLevel(high), paperFlow(smooth). printerState(out):- printerPowerButtonOn, tonerLevel(out). printerState(poor):- printerPowerButtonOn, \+(tonerLevel(high)), \+(tonerLevel(out)), \+ paperFlow(smooth). printerState(out):- \+(printerPowerButtonOn). goodPrintQuality:0.95 :- printerState(good). goodPrintQuality:0.3 :- printerState(poor).
printResultSummary(excellent) means that the printer printed all the pages, quickly and with a good print quality. Instead if it didn't print all the pages quickly and with a good quality the result is =poor=, or =none= if no pages were printed. =tonerLowIndicatorOn/0= and =paperJamIndicatorOn/0= depends respectively on =tonerLevel/1= and the =paperFlow/1= and on the state of the printer power button (if it's off, the toner low indicator and the paper jam indicator must be off because the printer is off). =paperFlow/1= and =tonerLevel/1=, together with =printerPowerButtonOn/0=, influence =printerState/1= that could be =good=, =poor= or =out=. Finally =printerState/1= determines the print quality. To observe more than a fact we can include some evidences like:
evidence_printerState_out_printResultSummary_none:-printerState(out),printResultSummary(none). evidence_not_printsQuickly_networkState_up:- \+(printsQuickly),networkState(up). :- end_lpad.
Results ------- First of all we can query the probability that the printer button is on, without any evidence.
prob(printerPowerButtonOn,Prob).
As expected the result is 0.95 because we define this probability into the program. Now we can insert the evidence, for instance, printResultSummary(poor).
prob(printerPowerButtonOn,printResultSummary(poor),Prob).
We can see that the probability now is 1, meaning that if the printer result is =poor= (or =excellent=) the printer must be on, as we can imagine. Instead if no pages were printed, we obtain a lower probability.
prob(printerPowerButtonOn,printResultSummary(none),Prob).
Now let's compute the probability that the printer power button is on given that the printerState(out)
prob(printerPowerButtonOn,printerState(out),Prob).
and the probability that the printer power button is on given that printerState(out) and printResultSummary(none). To include multiple evidences into the query previously we have defined a simple predicate, called =evidence_printerState_out_printResultSummary_none=.
prob(printerPowerButtonOn,evidence_printerState_out_printResultSummary_none,Prob).
We can see that the probability is exactly the same; learning that printResult(none) doesn't change the probability that the printer power button is on if you already know that that the printerState(out). This mean that =printResultSummary/1= is conditionally independent from =printerPowerButtonOn= given =printerState/1=. Now we can focus on the =printerState/1= queries. Let's first compute the probability that printerState(good).
prob(printerState(good),Prob).
and the probability printerState(good) given that =tonerLowIndicatorOn=
prob(printerState(good),tonerLowIndicatorOn,Prob).
We can see that the probability decrease, as expected, if the toner low indicator is on. We can do further probability evaluation. Let's see how the probability that softwareState(correct) changes given different observation. First of all probability that softwareState(correct)
prob(softwareState(correct),Prob).
then we observe the fact networkState(up)
prob(softwareState(correct),networkState(up),Prob).
As we can see the probability is still the same and also in this case there is conditionally independence. Now we observe that the printer doesn't prints quickly
prob(softwareState(correct),\+(printsQuickly),Prob).
and networkState(up)
prob(softwareState(correct),evidence_not_printsQuickly_networkState_up,Prob).
Learning networkState(up) reduces the probability that the software is correct. We can also see that =softwareState/1= and =networkState/1= are independent but they aren't conditionally independent given =printsQuickly=.