### SlideShare for iOS

by Linkedin Corporation

FREE - On the App Store

Academic text on Bayesian Stress Testing

Academic text on Bayesian Stress Testing

- Total Views
- 851
- Views on SlideShare
- 851
- Embed Views

- Likes
- 0
- Downloads
- 6
- Comments
- 0

No embeds

Uploaded via SlideShare as Adobe PDF

© All Rights Reserved

- 1. MASTER OF BANKING AND FINANCE 2010-2011 COHERENT STRESS TESTINGA Bayesian Approach to Scenario Analysis and Stress Testing GRADUATION PROJECT ADVISORS AUTHORS Rudi Vander Vennet KEVIN HOEFMAN Michael Frommel MAXENS BERRENikolas Vander Vennet Wim Konings 1|P a ge
- 2. IntroductionFor the past several decades, financial crises have highlighted the need to assess the stability of thefinancial system.The current global financial crisis has demonstrated limitations in the purely statistical approaches whichhave heretofore been employed to assess the stability of financial institutions. During 2007 and 2008,several multiple-standard-deviation loss events, predicted to only occur once every several thousandyears occurred in the space of 24 months. Clearly, the models in use were no longer functioning.1In January 2009, during the depths of the financial crisis, the Basel Committee on Banking Supervisionpublished its view that the bank stress-testing which had heretofore taken place was insufficient for anumber of reasons. The views of the BIS were that the long period of historical stability preceding thecrisis reduced likelihood that stress test was detecting severe shocks and systemic weaknesses.Furthermore, estimations of “severe” were dramatically underrated and neither correlation of shocksnor rational feedback effects were being taken into account. The effects of recent financial innovationswere also being ignored.2Essentially, the financial market had grown considerably more complex and less transparent since theprevious round of financial crises at the end of the 20th century. The BIS’ concern is that stress-testinghad not kept up with the times.In 2009, the Committee of European Banking Supervisors (CEBS), an independent advisory group on EUbanking supervision implemented the first EU-wide stress tests. These stress tests were also executed inaccordance with frequentist methodology. 22 major EU cross-border banks were examined. Potential2009-2010 trading and credit losses could amount to almost € 400 Billion in the adverse scenario.Nevertheless, none of the banks in the test saw their Tier-1 ratios potentially fall below 6%. TheEuropean Council subsequently requested that further stress testing be done with broader objectivesand measuring the ability to absorb further shocks.Subsequently, in July 2010 a more inclusive battery of stress test examining 91 banks was undertaken byCEBS, in which, five banks failed. This second-round of stress tests was undertaken amid concerns thatthe September 2009 round was insufficiently strict in its examinations and that, while large systemicbanks on the European scale were examined, not enough of the banks systemic to individual member-nations were accounted for in the CEBS 2010 stress tests. Furthermore, because illiquidity was assumedto be the primary threat, assets in the bank’s trading book were targeted while held-to-maturity assetsheld in the banking book were not. The latter represented approximately 83% of bank assets. Anothershortfall of the 2010 stress tests was the assumption that there would be no sovereign defaults in theEU. A better approach would have been to also attempt to determine which scenario could have led to asovereign default in the EU.1 Rebonato, 20102 BIS, 2009 2|P a ge
- 3. The subsequent 2011 European banking stress test is currently being performed by the newly foundedEuropean Banking Authority. The 2011 exercise incorporates lessons learned as well as policy demandsfrom Economic and Financial Affairs Council (ECOFIN) and the Economic and Financial Committee (EFC).One can take the fact that the EU has gone through three rounds of stress testing as an indication ofdissatisfaction with the thoroughness of the stress tests in unearthing bank vulnerabilities throughoutthe EU. A different approach was needed.The European stress tests tried to answer the question of what would happen in the event of bothcurrent loss expectations as well as a worst-case scenario whereby losses exceeded current lossexpectations. However, the stress tests consider each potential source of loss as a separate aspect,without accounting for dynamics of the situation where if one shock happens, it can have a causal effecton the other shocks. Thus, they have left something to be desired, irrespective of the number of banksor percentage of GDP investigated.According to Rebonato, the key missing ingredient from stress testing procedures is a solid way ofcapturing the co-relationships between the various stress events. Rebonato suggests that subjectiveexpert assessments for the marginal probabilities of the various stress events and the conditionalprobabilities between them, and a Bayesian procedure for consistently tying these together, can lead toa better understanding of the dynamics of the stress scenario that is being considered. This allows us togenerate statistical information about stress losses that are more realistic than losses captured byconventional stress testing methodologies.The rest of this paper proceeds as follows. The following section discusses what progress has thus farbeen made in stress testing, as well as the way forward. Section three presents a hypothetical Bayesianstress scenario. A bank and selected and its situation described in detail. Then sources of vulnerabilitiesare analyzed and a stress scenario is presented along with its accompanying topology. Lastly, the finalsection provides concluding analysis.Where Are We With Stress Testing?Where do We Need to Go?While economists have made great bounds in terms of designing scenarios, more progress is needed. Inthe view of the Basel Committee on Banking Supervision, there are major shortcomings which need tobe addressed, related to concerns that the financial world had fallen into a sense of security due to thelength of time since the last crisis and that systemic risks, correlation of shocks, and the effect financial 3|P a ge
- 4. innovations were being overlooked in stress testing. 3 The current shortcomings in stress-testing can alsobe seen in the European Council’s reception of the 2009 and 2010 CEBS stress tests.The traditional approach to stress-testing applies loss estimates that are ultimately based on frequentisttechniques. In order to come up with an adverse scenario for a stress test, one first needs to have anunderstanding of what the “normal” scenario is. This idea of what is “normal” is derived fromfrequentist techniques like VaR. This approach has the drawback of being backward-looking. Anotherdrawback comes in the area of extremely rare events. In order for the frequentist approach to generatemeaningful results, one needs a relatively large amount of relevant data. Extremely rare events aredifficult to analyze with a frequentist approach, meaning that assigning stress losses to them is equallydifficult.4 What is needed is a forward-looking and conditional approach to losses, which can be appliedin situations with little relevant data and in dynamic situations.In the view of both Keynes and Taleb, the frequentist approach has the major drawback that it reliesthat the future is like the future in that it is like the past, predictable, calculable to within a certainbound, and therefore hedge-able. This reaches to the basic difference, in the Keynesian view, of risk anduncertainty. Under uncertainty, “No scientiﬁc basis on which to form any calculable probabilitywhatever. We simply don’t know.” 5 By contrast, the prevailing neoclassical economic view is that marketparticipants have complete knowledge of probability distributions over future events. In other words,we face only measureable risk.6A further major drawback of the frequentist approach, expressed by Rebonato, is the unavailability ofsufficient quantities of relevant data concerning extremely rare situations. Fundamentally, in order for afrequentist approach to be valid, data must be drawn from identical conditions. If however we aregathering data on a black swan event or black swan scenario, we may find ourselves needing to drawdata from a wide breadth of sources and/or across a long time-horizon. Unfortunately, if we engage ineither drawing data from the distant past or from dissimilar situations, we cannot accurately use it forfrequentist analysis.WHAT IS NEEDED IN STRESS TESTING?Given the shortcomings enumerated, some improvements are necessary.The most important aspect needed in stress testing in order to overcome black swan events is aforward-looking element. Subjective probability is a plausible way in which this can be achieved. Asubjective probability is essentially an opinion – hopefully a well-informed expert opinion – regardingthe probability distribution of an event occurring. While there is no mathematical proof behind the3 BIS, 20094 Rebonato, 20105 Keynes, 19376 Skidelsky, 2009 4|P a ge
- 5. answer, one can expect that in addition to historical probability distribution, a subjective probabilitymight be influenced by expectations, indicators as to what may occur in the future, and indicators as towhy this time might be different. The most significant upsides to this approach are the incorporation ofa wide range of indicative and qualitative data, as well as the non-reliance on vast and often difficult-to-obtain amounts of data. The latter factor would render this approach particularly valuable duringscenarios involving one or more extremely rare (statistical tail) events.7Unfortunately, subjective probability is still subjective and might in fact be vulnerable to a high degreeof bias. Nevertheless, bias can be overcome by via the use of the law of larger numbers. That is, severalexpert subjective judgments can be employed in order to construct the subjective probability. Thiswould particularly be the case in situations in which a diversity of opinions and views could beassembled. Within a financial institution this can be achieved by polling experts and risk managers ofdifferent departments, regional offices and business segments on the same probabilistic views.Another important issue which needs to be addressed in stress testing is correlation of shocks. In manystress tests, this has truly come to be a key missing ingredient. The simple fact that a financial institutionsurvives an economic shock may might not be perfectly indicative of bank-survivability when theeconomic shock in question might also set off (or might otherwise be associated with) a chain reactionof economic shocks.In order to approach this within the context of stress-testing, conditional probabilities can be utilized. Incontrast, stress testing methodology so far relies chiefly on marginal probabilities. The questionanswered by this method is “Assuming that a specific economic shock (or set of shocks) takes place,what is the likelihood of bank failure?” A Bayesian approach to stress testing would instead ask thequestion “Assuming that a specific economic shock (or set of shocks) takes place, what is the likelihoodthat this will trigger other shocks as well? What would then be their effect on a financial institution ateach given stage? And finally, is bank failure likely to occur at any of these stages?”THE BAYESIAN NETA Bayesian net is a way of modeling the relationships between the various stress events that are beingconsidered in a single stress scenario.For instance, given a default of a Euro zone country, the risk free rate (German government bond) islikely to spike upward and equity markets will crash given that investors are likely to have a risk-aversereaction. One possible Bayesian net for this scenario looks like this:7 Rebonato, 2010 5|P a ge
- 6. E1: Euro zone Country DefaultE2: Yield curve shift E3: Equity market crashThe risk manager creates a Bayesian net according to his idea of how reality works. He assigns marginalprobabilities to the events in the net, and conditional probabilities to the causal relationships. Differentrisk managers could come up with different Bayesian nets and/or probabilities for the same stress test.Since all Bayesian nets are simplifications, there isn’t one “true” Bayesian net. The Bayesian netultimately expresses a statement of conditional independence reflecting the causal assumption that weintend to propose. While correlations and conditional probabilities don’t necessarily give informationabout causality, we can use expert subjective judgment to determine a causal structure.Consider the diagram above. Setting aside the fact that any of these three events can take place withprobability P(Ei) and that each of these three events has its own direct and independent effect on afinancial institution, the Bayesian net also indicates that, once we know that event E1 has occurred,there is a higher probability that the events E2 and E3 will occur.Ultimately, we can use the Bayesian net in order to determine the probability of joint occurrence of anycombination of the three economic shocks. As we can see from the Bayesian net, these probabilities arenot independent. Given such a structure, the probabilistic relationship between the occurrence of shockE1 and the joint occurrence of E1 and E2 is given by the relationship: P( E1 E2 ) PE2 | E1 P( E1 )In this scenario, there are six conditional probabilities. PE2 | E1 PE3 | E1 PE1 | E2 PE2 | E3 PE3 | E2 PE1 | E3 6|P a ge
- 7. One additional useful fact about the Bayesian net is that large and complex Bayesian nets are able toprovide us a powerful deductive tool in cases when we only have some of requisite information. 7|P a ge
- 8. DECONSTRUCTING A BAYESIAN NETWe can use the relationship between conditional and joint probabilities to deconstruct the jointoccurrence of any combination of events into a functional form. Consider the following Bayesian net:The probability of these events happening at the same time is: P(A ∩ B ∩ C ∩ D)Since for any two events E1 and E2: P( E1 E2 ) PE2 | E1 <=> P(E1 ∩ E2) = P(E2 | E1) . P(E1) P( E1 )It follows that: P(A ∩ B ∩ C ∩ D) = P(A | B ∩ C ∩ D) . P(B ∩ C ∩ D)The joint probability on the right hand side of the equation can further be deconstructed by using thesame rule. If we follow this through to its logical conclusion, we get:P(A ∩ B ∩ C ∩ D) = P(A | B ∩ C ∩ D) . P(B | C ∩ D) . P(C | D) . P(D)This principle of breaking down the full joint probability into a combination of conditional and marginalprobabilities is the first step towards solving the Bayesian net.A more practical way of deconstructing the Bayesian net is by ordering the events from bottom to topbefore deconstructing the model into a functional form. If we start from a reverse ordering, we canshow that: 8|P a ge
- 9. P(D ∩ C ∩ B ∩ A) = P(D | C ∩ B ∩ A) . P(C | B ∩ A) . P(B | A) . P(A)Of course, the end result should be the same. The rationale for this reverse ordering will become clear inthe next chapter.CONDITIONAL INDEPENDENCEThe Bayesian net orders the events in a parent-child relationship. In our diagram:Node A is a parent node of node D and node C. Node D and node C are children of node A. Node B is alsoa parent of node C, but not of node D.We can see that node A is the only node that affects node D. As a consequence, the probability of Dfollowing from A, B and C is equal to the probability of D following from just A. This can written as: P(D | C ∩ B ∩ A) = P(D | A)Node C is affected by node A and node B, but not by node D. By the same reasoning, the probability of Cfollowing from A, B and D is the same as the probability of C following from A and B: P(C | D ∩ B ∩ A) = P(C | B ∩ A)In general, a probability where a node is dependent on its parents and other nodes that are not itsparents can be reduced to the probability where that node depends only its parents. It is said that nodesC and D are conditionally independent: the nodes aren’t independent from one another (since they arestill connected through their parent A), but once the states of their parent A is known, node C containsno extra information that would help us determine whether event D has occurred, or vice versa. 9|P a ge
- 10. We can put the rules of conditional independence to use, and further reduce the functional form of theBayesian structure from the point where we left off in the earlier chapter:P(D ∩ C ∩ B ∩ A) = P(D | C ∩ B ∩ A) . P(C | B ∩ A) . P(B | A) . P(A) with P(D | C ∩ B ∩ A) = P(D | A)Which leads to:P(D ∩ C ∩ B ∩ A) = P(D | A) . P(C | B ∩ A) . P(B | A) . P(A)INDEPENDENCEWhen two nodes are fully independent, it means that they don’t contain information about each other’soccurrence. In the diagram we are considering:Nodes A and B are considered to be fully independent of one another. As a result, the conditionalprobability of one happening if the other has happened is equal to the probability of one happeningregardless of whether the other has happened: P(A | B) = P(A) P(B | A) = P(B)Note that it is not correct to state that P(D|C) = P(D). Node D and node C may be conditionallyindependent, but they are not independent since they are connected through their parent A(independence and conditional independence are different concepts with different rules). 10 | P a g e
- 11. Applying this principle, we can reduce the functional form of this model to its final form:P(D ∩ C ∩ B ∩ A) = P(D | A) . P(C | B ∩ A) . P(B | A) . P(A) with P(B | A) = P(B)Which leads to:P(D ∩ C ∩ B ∩ A) = P(D | A) . P(C | B ∩ A) . P(B) . P(A)The final functional form consists of marginal probabilities of the parent nodes and conditionalprobabilities of the occurrence of the parent nodes causing the occurrence of their children. Thisfunctional form will be used by the program (see section below) to create the table of joint probabilitiesfor all combinations of events.The ProgramTECHNOLOGYThe program is created in Excel and written in Visual Basic for Applications (VBA).DRAWING A BAYESIAN NET IN EXCELFirst of all, the risk manager needs to decide what the events are that he or she wishes to consider.These events are drawn in the structure of a Bayesian net. If we take the diagram: 11 | P a g e
- 12. In this scenario, a risk manager considers four possible events A, B, C and D. Event A could be an equitycrash, event B a housing market crash, and so on.The Bayesian net is entered into Excel in a two-dimensional matrix form. A matrix representation of thediagram above looks as follows: A B C D A 1 0 0 0 B 0 1 0 0 C 1 1 1 0 D 1 0 0 1The diagonal in the matrix is filled with ones. The upper right triangle is filled with zeros. These valuesaren’t used by the program. The connection structure of the Bayesian net can be read from the lowerleft triangle, where the ones indicate which nodes are connected to which: the titles of the columnsindicate where the connections start, whereas the titles of the rows indicate where each node isconnected to. The relevant ones are marked in bold.A VBA program is able to read values from cells in Excel. This allows the program to understand what theBayesian net looks like.ENTERING THE PROBABILITIESEach of the events has a probability of occurring within the time frame that the risk manager chooses toconsider. This marginal probability is the probability that the event occurs during the chosen time frame(regardless of how it is triggered). In addition, the Bayesian net shows that if event A occurs, there is aprobability that A will trigger events D and C. Similarly, event B can trigger event C.The risk manager needs to make an assessment for the following pieces of information: - P(A): the marginal probability that event A occurs - P(B): the marginal probability that event B occurs - P(C): the marginal probability that event C occurs - P(D): the marginal probability that event D occurs - P(D|A): the conditional probability that event A, when it occurs, triggers event D - P(C|A): the conditional probability that event A, when it occurs, triggers event C - P(C|B): the conditional probability that event B, when it occurs, triggers event C - P(C|A∩B): the conditional probability that events A and B, when they occur together, trigger event C 12 | P a g e
- 13. In general, the risk manager needs to specify a marginal probability for each of the events, and aconditional probability for each parent-child connection inside the Bayesian net. Note that while related,the conditional probability of C being triggered by events A and B occurring together does not followdirectly from the conditional probability of A triggering C and the conditional probability of B triggeringC. For example, the occurrence of A and B happening at the same time could lead to a dramaticallyhigher probability of C occurring than if A or B would occur separately. The risk manager takes this intoconsideration by supplying both the single-conditional probabilities and the double-conditionalprobability.Since these are probabilities, the risk manager will supply values between 0 and 1 for each.DOUBLE-CONDITIONED PROBABILITIESA double-conditioned probability arises from the situation where two parent nodes share one childnode. In the example we are considering there is one double-conditioned probability: where A and B arethe parent nodes and C is the child node.Rebonato assumes that there won’t be any networks where nodes can have more than two parents.This means that double-conditioned probabilities are the most complex conditioned probabilities we canencounter.Unfortunately, the book is incomplete as far as double-conditioned probabilities go (see A Word ofCaution About The Book, below). In order to allow the program to solve double-conditionedprobabilities, the risk manager needs to supply one more conditional probability: the one where oneparent leads to the other parent. In our example, this would be P(A|B). When the parent nodes areindependent this is easy: P(A|B) should then be given the same value as P(A), according to the Bayesianrules of independence. If the nodes are not independent but instead conditionally independent, thingsget more complex. See A Word Of Caution About The Book, below for a derivation.CHECK IF ALL VALUES ARE ENTEREDBased on the matrix representation above, the program knows the names of the nodes and theconnections between them. The program uses this information to deduce what the requiredprobabilities are, and checks the rest of the Excel sheet for their values. The program will prompt therisk manager if any values are missing. 13 | P a g e
- 14. SANITY CHECKSIt is possible that the risk manager provides values that by themselves look correct, but when combinedimply an impossible situation. For example, consider the following triplet of values: - P(A) = 0,16 - P(B) = 0,03 - P(B|A) = 0,25Each of these probabilities look fine by themselves (they are numbers between 0 and 1). However,combined they imply the following impossible situation: - Out of 100 situations, there will statistically be 16 situations where A occurs. - 25% of these situations lead to B also being true. Meaning that out of 100 situations, there are 4 instances where B is true following from the fact that A is true. - However, the probability of B in itself is only 3%. There should only be 3 cases out of 100 in total where B is true! The number of instances of B occurring as a result of the occurrence of A is too high.These kinds of impossible situations can be checked for by applying Bayes’ theorem. In our example: P(A|B) = P(B|A) . P(A) / P(B) with P(B|A) = 0,25; P(A) = 0,16; P(B) = 0,03<=> P(A|B) = 1,3333 (!)The resulting conditional probability is higher than 1. This is an impossible value. This procedure allowsthe program to recognize that the values that the risk manager supplied are inconsistent. The programchecks all possible conditional probabilities that can be created from the values that the risk managersupplied, and verifies that in no situation there is a probability that is not between 0 and 1. This is theprocess of sanity checking.The sanity checking process will warn the risk manager which values are inconsistent, if any. The riskmanager can then enter new values. In our example, the risk manager could lower the probability that Ahappens, lower the conditional probability that B happens if A happens, or raise the probability that Bhappens. Or a combination of all three.THE JOINT PROBABILITY TABLEOnce all required values have been found and are consistent, the program deduces the functional formof the Bayesian net from the matrix representation, by deconstructing the joint probability and applyingthe rules of conditional independence and (full) independence. The program then calculates the fulljoint probability table by applying the rules of Bayesian logic on the values that the risk manager 14 | P a g e
- 15. entered. While this is a calculation-heavy process, the risk manager only needs to sit back and wait forthe results.GAINS AND LOSSESThe program allows the risk manager to associate losses (or if appropriate, gains) for each of the events.These losses are used to calculate extra information: since a probability is calculated for everycombination of events, it is possible to calculate the loss that is associated with that combination ofevents, and the probabilistic loss. This can be used to calculate various forms of capital (economic,regulatory, etc.THE PROGRAM CODEA full listing of the program code can be found in Appendix 7.A WORD OF CAUTION ABOUT THE BOOKWhile Rebonato‘s insights into stress testing and his views on how to take it to the next level arecommendable, the way he puts the material in practice in this book leaves a lot to be desired. We weresurprised to discover that the procedure which Rebonato describes as a general way to generate thejoint probability table doesn’t actually work when one tries to put it in practice. This is because of tworeasons: - In Chapter 11, the transition in 11.24 is mathematically incorrect as it does not follow from the Bayesian rules as Rebonato claims. However, the further development of the procedure is based on this transition. - Also in Chapter 11, Rebonato gives a partial explanation for how to break up doubly-jointed probabilities. Formula 11.32 contains a term P(C|D) that can’t be solved in a trivial way. However, Rebonato concludes the explanation at this point with the sentence “The good news is that, given the limited topological complexity (…), matters do not get any more complex”. Unfortunately, matters really do get more complex.We created a new procedure for handling doubly-conditioned probabilities, and used this instead of theone that Rebonato suggests in Chapter 11. The current procedure for evaluating a Bayesian net is basedon the principles that are explained in Chapter 8, not on the procedure that can be found in Chapter 11.In order to make it work, we had to find a mathematically consistent way to obtain the term P(C|D)from 11.32, and for resolving doubly-conditioned probabilities in general. 15 | P a g e
- 16. We emailed Dr. Rebonato about the term P(C|D). He was quick to help us, confirming the situation byreplying that his thoughts on the matter have evolved a lot since he wrote the book and sending us adraft of a new book that looks at the same problems in a somewhat different light. We decided to staywith the old book for the scope of this thesis since that was its topic. However, we used theconfirmation of Dr. Rebonato as a basis for coming up with a way of solving the term in question thatisn’t in the book (credit Dr. Nicolas Vander Vennet and Wim Konings of Deloitte). This derivation is: P(D ∩ C) = P(D ∩ C ∩ A) + P(D ∩ C ∩ Â) = P(D|C ∩ A) . P(C|A) . P(A) + P(D|C ∩ Â) . P(C|Â) . P(Â) = P(D|A) . P(C|A) . P(A) + P(D|Â) . P(C|Â) . P(Â) with P(D ∩ C) = P(D|C) / P(C)This way of solving the term P(C|D) and similar terms in general allows us to reduce Bayesian nets withdoubly-jointed probabilities.LINEAR PROGRAMMINGRebonato explains two ways of coherent stress testing. The methodology explained in Chapter 10 relieson linear programming. The methodology explained in Chapter 10 relies on Bayesian nets.Suppose that the risk manager would supply values for the conditional probabilities P(A|C) and P(C|A).These values are not independent of one another: they are linked through the marginal probabilities ofP(A) and P(C) by Bayes’ theorem. A risk manager might accidentally enter values for the conditionalprobabilities that are inconsistent with one another. Linear programming is a technique that checkswhether conditional probabilities are consistent and if not, it alters the values in such a way that theyare made to be consistent.Since our program uses the Bayesian net approach, a risk manager needs only to provide conditionalprobabilities in one direction: from top to bottom. While it is certainly true that there are checks to bedone on the values that the risk manager supplies (the sanity checks), the checks that are performed bylinear programming aren’t relevant to us: the conditional probabilities will never be inconsistent in theway that linear programming checks for. As such, the linear programming technique, while interesting initself, had no added value to our program.Also: in an email exchange we had with Dr. Rebonato, he stated that he no longer uses linearprogramming. 16 | P a g e
- 17. The ScenarioTARGET BANKThe target bank for the stress scenario is Österreichische Volksbanken-AG. The bank’s activities arediversified into five strategic segments. These are retail banking, real estate, corporate banking(corporate segment), and investment banking (financial markets segment) and asset management(investment book/other operations segment). Overall, Volksbank has 594 subsidiaries, most of which aswholly-owned. For the most part, the Volksbank subsidiaries are headquartered in Central and EasternEurope.Volksbank’s retail banking operation is active in Austria via VB Leasing Finanzierungsgesellschaft m.b.H.and in Bosnia, Croatia, Czech Republic, Germany, Hungary, Malta, Romania, Serbia, Slovakia, Slovenia,Russia, and Ukraine via Volksbank International (VBI) and via VB-Leasing International Holding GmbH.Furthermore, Volksbank has a large number of daughter companies spread throughout Central andEastern Europe and operations in the CEE region have been ongoing since 1991.STRATEGIC BUSIENSS SEGMENTS Volksbank AG Financial Investment Corporate Retail Real Estate Book/Other Markets Operations Segment Segment Segment Segment SegmentThe Retail segment of Volksbank’s business provides various banking and related financial products andservices, including deposit products, lease financing, project and real estate financing, treasury products,and advisory services to private individuals, and small and medium sized enterprises. Furthermore, theretail segment involves retail banking in both Austria and in the Central / Eastern European region.Retail operations are divided into two companies. VB Leasing Finanzierungsgesellschaft m.b.H. is 17 | P a g e
- 18. responsible for domestic operations in Austria, while Volksbank International owns ten daughtercompanies responsible for retail banking in Central and Eastern Europe. 2010 domestic operations werethe most successful in Volksbank’s history8. Volksbank’s International holdings meanwhile, experienceda small decline in total value of assets. As outlined in the segmental reporting for 2010 displayed in theappendix, this is the largest of Volksbank’s business segments in terms of net income and the second-largest in terms of total assets, comprising 72% and 35% respectively of overall Volksbank figures. Inaddition, this operational segment is characterized by a large concentration of Volksbank’s exposure toCentral and Eastern European markets.This is an area of high initial vulnerability. Because success in the retail banking segments depends ongeneration of new loans, successful rates of loan repayment, and deposits, this may be an initial point ofshock-entry, where negative and positive economic shocks might first enter the banking system andstart to affect Volksbank. Furthermore, a shock in this commercial segment might lead to further riskswithin the bank. It would therefore be reasonable to assign shocks to this segment of Volksbank arelatively high spot on the Bayesian net topology.The bank’s real estate segment focuses on commercial real estate financing as well as real estate leasingand real estate project development (each via different subsidiaries) in both Austria and the CEE region.Furthermore, real estate project development is done in collaboration with partners and co-investorsfrom both the international public sector and private sector entities other European countries.Performance in this segment improved during 2010 and risks were reduced significantly vis-à-vis 2009.This is another potential entry point through which economic shocks might enter the banking system.During the 2008 financial crisis, the collapses of asset values within the real estate sector in the US werethe first shock which touched-off the worldwide financial crisis. For Volksbank, this is another businesssegment in which expose to the CEE market is concentrated. Moreover, Volksbank’s exposure to theregion in this segment reaches beyond the EU’s borders as far as Russia, making this segment potentiallymore volatile than other Volksbank business segments. Thus, a high place in the Bayesian topologyshould be assigned to shocks emanating from this segment.Volksbank’s corporate segment provides banking services to firms and entrepreneurs. This includes adiverse range of services ranging from project finance to private equity, M&A, leveraged finance,corporate lending, and syndicated financing. Germany is the core market for the corporate segment.The 2010 Annual report indicates that corporate lending was muted because corporate spreads werehigh and that client firms were in fact not expanding their operations nor their physical capital. Exportfinancing meanwhile saw an increase in demand for transaction-linked loans. As for project finance onthe other hand, 2010 was a successful year.While it is likely that corporate banking may suffer some vulnerability, due to generalized downturns incorporate activity and profitability, any initial shocks suffered in this area are likely to be highly localized.In the event of a wider stress situation however, a generalized exposure of corporate counterparty8 Volksbank, 2010 18 | P a g e
- 19. clients to an economic shock would threaten the sustainability of this business segment withinVolksbank. Therefore, in a real-life situation, it would be likely that a generalized shock to this segmentwould emerge only as a secondary step within a crisis scenario.The financial markets segment offers exchange rate, derivatives, money market, and interest and priceproducts, as well as involves in securities and foreign exchange trading, and asset managementbusinesses.The investment book/other operations segment in concentrated on management of Volksbank Group’sassets. It is the group’s largest segment in terms of total assets, but has seen negative net income inboth 2009 and 2010.9While Volksbank group’s geographic focus is primarily on Central and Eastern Europe, the segmentreporting by regional markets reveal that 81% of income from financial investments is drawn from“other markets” in 2010, while 90% of income from financial investments was drawn from Austria in2009.10The potential vulnerabilities of these two segments lie in their international transmission roles.Essentially, this segment could turn into a transmission mechanism for contagion in the CEE region, as istrue for this segment’s counterparts in competitor banks in the CEE such as KBC and Credit Agricole. It istherefore plausible that regulatory authorities in the CEE region may act in order to either respond to orpreempt contagion transmission. Such action might take the form of capital controls affecting foreignexchange positions and transactions or special taxes and restrictions suddenly erected vis-à-vis positionsin specific asset classes.Another viable possibility would be that of sudden radical loss in asset values and portfolios. These couldcome as a result of bond defaults (either sovereign or corporate) or the crash of equities markets. This inturn could affect the bank’s overall financial health and even bring problems home to Austria, as assetswould have to be reduced in order to maintain liquidity and solvency. Such an event should be assignedan intermediate position within a Bayesian topographical structure.CENTRAL AND EASTERN EUROPEThe Central and Eastern European market is quite an interesting market for in which to analyze bankoperations due to its position on the frontier of the EU. This market is constituted by a dynamic mix ofEurozone countries, peripheral non-Eurozone EU countries and non EU countries. Operations in this areaplay a central role in Volksbank’s activities and Volksbank’s exposures. According to the 2010 AnnualReport, 71% of Volksbank’s net income flows from CEE region operations while 18.6% was drawn fromAustrian operations. Despite the fact that9 Volksbank, 201010 Ibid 19 | P a g e
- 20. Nevertheless, the Non-EU regions of Central and Eastern Europe suffer for much higher volatility thando the core EU countries. Ukraine suffered a 15.1% GDP decline in 2009 and returned to positive GDPgrowth figures the following year while Romania swung from a 7.3% GDP increase in 2008 to a 7.3%contraction the following year.11 It would appear that Volksbank takes seriously the risks of doingbusiness in the CEE region. According to its 2010 Annual Report, risk provisions for operations in Austriawere 36% of regional net income. Risk provisions for CEE operations meanwhile were 54% of regionalnet income.2009 was a year of negative GDP growth across the entire region of operation, ranging from a 15.1%GDP drop in the Ukraine to a 3% GDP drop in Serbia. In Croatia, direct investments and gross capitalinvestments have also declined year-after year. Direct investments have declined by a full 30% in 2009,as the flow of investment from the core EU dried up. 12In 2010, recovery was uneven across the region, with Croatia and Romania experiencing negative GDPgrowth, while Slovakia experienced a 4.1% GDP growth. Overall, exports are a main driver of GDPgrowth in the region, while government expenditures declines year-after year.In comparison, the German GDP saw a 1% increase during 2008 and a 4.7% decrease as Germanyreduced its spending in 2009. In 2010, German GDP growth recovered to 3.7%, the highest GDP growthfigure since reunification. 13The Eurozone GDP meanwhile, grew at 0.4% in 2008 and suffered a 4.1% GDP contraction in 2009. Thefollowing year brought 1.7% GDP growth. In 2010, the also Eurozone experienced a strong recovery ofindustrial production, with capital goods experiences double-digit growth rates.14According to Volksbank’s 2010 annual report, the stated business strategy for the CEE region includes aconservative risk strategy and a focus on microenterprise and SME’s.SOURCES OF VULNERABILITYGiven the structure and exposures of Volksbank, there are a number of potential sources of bank stress.There are both environmental potential sources of bank stress as well as firm-specific idiosyncraticpotential sources. Intransparency in the financial markets Poor understanding and management of risks and uncertainties Poor understanding and management of liquidity and characteristics of assets in portfolio11 Ibid12 Ibid13 Ibid14 Ibid 20 | P a g e
- 21. Underlying the 2008 financial crisis was increased intransparency in the global financial markets inrelation to the growth of financial innovation during the period immediately preceding the financialcrisis. This intransparency was the result of financial innovation outpacing the growth in accompanyingregulation aimed at ensuring best practices. In fact, regulation actually shrank during this period, as didfinancial regulatory enforcement capability.The resulting financial environment was one in which gaps and lags in general understanding of risk anduncertainty in the financial markets were widespread.Another feature of the 2008 financial crisis was immediate onset of chronic illiquidity which ensuedonce it became clear that the financial models upon which many of the positions and portfolios of manyof the major investment banks were built had – for all their complexity – failed to provide a completeunderstanding of risks and uncertainties in the financial markets.Since 2008, a consensus has emerged regarding generalized misunderstanding of risk and uncertainty inthe financial markets reflecting the Keynesian view that there are clear distinctions between uncertaintyand risk. The key difference is that we essentially know, understand and can quantify risk. It is a knownunknown. Uncertainty on the other hand, is best represented by the idea that we cannot predictperfectly the events of the future. 15 Taleb argues that while the bell curve has made us confident thatwe have tamed uncertainty, it in fact ignores large and actually cannot handle deviations. 16 Essentially,the mathematical models built based on understanding of the bell-curve become useless in this context.In short, many of the largest players in the financial markets became victim of their unknown unknowns. Lax lending standards and regulations Leverage during a bubble situation Insufficient standards for capital vis-à-vis the positions, portfolios, and activities of the financial and banking sectorsGenerally, the development of asset bubbles takes place in a context of massive amounts of leverageand lax lending standards. Furthermore, standards for capital and loss provisions are usually insufficientfor the riskiness of the operations of the parties.During the US asset bubble linked to the 2008 financial crisis, lax capital requirements stemmed from animperfect understanding of the risks, uncertainties, liquidity, and correlation of recently-developedfinancial derivatives being traded. Interconnectedness/correlation of segments and segmental shocksCorrelation of asset classes is a common characteristic of nearly all financial crises. This undermines thestability and security value of diversified portfolios during such times. In many cases, it is the growth offinancial innovation and the nature of ownership structure which actually leads to theinterconnectedness of the asset classes.15 Skidelsky, 200916 Taleb, 2007 21 | P a g e
- 22. Prior to the 2008 financial crisis for instance, (Real Estate Investment Trust) REITs were a common wayin which real estate exposure was included in portfolios. This is especially true of exposure to overseasreal estate. While real estate investment is typically characterized by its non-correlation with other assetclasses, REITs were known to have high correlation to equity. Currency crisis Collapse of one of the CEE region economies ContagionThe CEE region’s dependence on export-led growth could easily make it susceptible to economicdownturns in trading partners. Furthermore, given the CEE region’s highly volatile GDP growth anddependence on the core EU countries as a source of investment, the collapse of an individual economyin the CEE region could occur. Such an event would have far-reaching consequences.Due to both dependence on export-driven growth and the economic interconnectedness of this region,the possibilities for contagion are quite good. Furthermore, the most of the region’s financialinvestments come from the same source-Western Europe-. This means that the same asset managersmight quickly dump all of their assets in the region once they detected trouble in one country, furtherexacerbating contagion potential. During the 1998 Asian financial crisis, the collapse of export-growth-dependent economies came in theform of a localized currency crisis, which then provoked a regional contagion. The central mechanismwas one of losses in Thailand due to devaluation of the Thai Baht led to a region-wide sell-off of assetsby international investors. Furthermore, the Asian financial crisis arose in the aftermath of a region-wideliberalization of foreign portfolio investment regulations and financial capital mobility regulations in theearly 1990’s. It is a well-documented phenomenon that increases in capital mobility have historicallybeen followed by crisis.17Currency instability in one of the CEE countries would lead to losses in value of local-currency-denominated assets, leading to their sell-off, irrespective of the actual domestically-weightedperformance of said assets. Decline in the retail banking business in home market or in low-volatility foreign markets.Any sound bank, business, or portfolio needs solid diversification in order to minimize idiosyncratic risk.Given the size and importance of Volksbank’s retail segment as part of its overall business, it would besafe to assume that potentially more lucrative, higher-risk operations on the periphery of the CEE regionare being financed with deposits and income from retail operations in less volatile countries. Thedeposits and income from the retail segment also serve to maintain the banks liquidity as it invests inperipheral risky projects and maintain solvency in the event of losses stemming from riskier peripheralactivities. Thus, the bank’s riskier activities are counterbalanced by a large and regionally-diversified17 Reinhart and Rogoff, 2008 22 | P a g e
- 23. retail banking business. A decline in this business would lead to high exposure and higher sensitivity toperipheral volatility, exacerbating the effect of any adverse shocks.CAPITALVolksbank’s regulatory capital can be broken into three elements.18 Tier I: Core Capital consisting of capital reserves, retained earnings, subscribed capital, and hybrid capital less intangible assets. Tier II: Supplementary Capital consisting of non-current subordinated liabilities, unrealized trading profits, and risk provisions from lending operations. Amount is limited to 100% of Tier I capital. Tier III: Short-term (current) Subordinated Liabilities.19 Tier III capital may only be employed to cover market risks.20In 2010, Austrian capital requirements were slightly in excess of Basel II requirements. Capitalrequirements in Austria are compared against a risk-weighted assessment base, comprised of assets,activities, and positions. Volksbank’s 2010 regulatory risk-weighted assessment base was reported at 25,25.5 Billion EUR.While the minimum credit risk capital requirement was 8%, the Austrian government imposed furthercapital requirements for both market risk and operational risk. According to Volksbank’s Annual Report,2010 Tier I capital requirement stood at 2.230 Billion EUR, constituting a core capital requirement ratioof 8.76% of the risk-weighted assessment base. Nevertheless, Volksbank’s actual capital stood at 2.612Billion EUR, constituting a core capital ratio of 9.37%.Volksbank’s 2010 Total Eligible Capital figures showed a total capital buffer of 3.562 Billion EUR,constituting 14% of the bank’s risk-weighted assessment base.2118 Volksbank 201019 Ibid20 Ibid21 Ibid 23 | P a g e
- 24. THE STRESS SEQUENCEA1: A localized currency crisis occurs in the CEE region. Foreign-currency-denominated assets radicallydecrease in value. Total assets and annual result before taxes suffer a 10% haircut vis-à-vis 2010 figures. This represents losses caused by exposure to the localized currency crisis, which is assumed to locally penetrate all business segments.A2: A spike in industrial plant closures occurs in the core Eurozone counties. The macro-effect of theclosures in the Eurozone economy is a drop in output, demand, and employment. All of these factorscome to have an effect in node B2. The direct and immediate effect of the closures takes the form of: A 5% decrease in corporate segment annual result before taxes, as the flow of projects diminishes. Correspondingly, a 5% increase in real estate annual results stems from commercial space turnover in the real estate segment.B1: The shock, which was localized in node A1, spreads throughout the CEE region as asset managersrebalance their portfolios, and as there is a generalized sell-off of CEE financial assets. GDP growthbecomes negative through the region, Germany. While Germany meets the 2011 GDP growth forecast 24 | P a g e
- 25. outlined in Appendix 2, the rest of the region posts GDP growth figures in line with 2009 results. Nettrading income and income from financial investments decline as a result. Net trading income and income from financial investments for the CEE region recede to 2009 levels. These losses are ascribed to the financial markets and investment book segments as outlined in Appendix 3.B2: The secondary effect of the industrial plant closures in core Eurozone countries for the bankingsector overall and specifically for Volksbank, is decline in core-EU-based retail, real estate, and corporatebanking. A generalized 20% decline in net interest income, fee and commission income derived from Austrian operations. A 10% decline net interest income, fee and commission income, representing the German market.C: The combination of downturns in retail and corporate banking in the core Eurozone and the spreadof financial crises across Central and Eastern Europe transmit to Western European equity markets. Theresult is a drop in Western European equity markets. For Volksbank, the effects are multi-faceted.Trading and financial income take a haircut avoid going negative. Increases in cost of capital causeliabilities to increase while assets from both the trading book and held-to-maturity segments ofVolksbank. Liabilities increase as financing costs increase. Amount owed to credit institutions increases by 15%. Assets of the Trading Book, Financial Market, and Corporate segmental assets fall in value by 20% (this amounts to a 12% decline on total assets). Net income from financial investments becomes zero.D: Volksbank is forced to deleverage and unwind its positions at a loss in order to attempt to maintainsolvency as well as to rebuild its capital buffers and risk provisions. No specific assumptions are madevis-à-vis the makeup of the liquidated assets. Total assets fall by an additional 15%. The losses are proportionally distributed across the segments. Shareholder’s Equity declines by offsetting amount. 25 | P a g e
- 26. Node Loss/Gain Amount (000) To/FromA1 Total assets and annual result before taxes suffer a 10% haircut vis-à-vis 2010 -4,655,567 • Total Assets figures. • Annual result before taxesA2 • A 5% decrease in corporate segment annual result before taxes, as the flow of -1,360 • Corp. result before projects diminishes. taxes • Correspondingly, a 5% increase in real estate annual results stems from • RE result before taxes commercial space turnover in the real estate segment.B1 Net trading income and income from financial investments for the CEE region -15,125 • Net Trading Income recede to 2009 levels. These losses are ascribed to the financial markets and • Income from Fin. Inv. investment book segmentsB2 • A generalized 20% decline in fee and commission income derived from Austrian -23,735 • Fee and commission operations. income • A 10% decline in fee and commission income, representing the German market.C • Liabilities increase as financing costs increase. Amount owed to credit -6,329,424 • Amount owed to institutions increases by 15%. credit institutions • Assets of the Trading Book, Financial Market, and Corporate segmental assets • Assets fall in value by 20% (this amounts to a 12% decline on total assets). • Annual result before • Net income from financial investments becomes zero. taxesD Total assets fall by an additional 15%. The losses are proportionally distributed -5,652,794 Total Assets across the segments.THE BAYESIAN NET 26 | P a g e
- 27. ConclusionThe intention of this research is to suggest improvements to commonly-used stress-testingmethodologies in order to address what have been identified as methodological shortcomings,particularly in the European context, wherein the European Commission has already expresseddissatisfaction with both the 2009 and the 2010 stress tests.The key missing ingredient from stress testing procedures is a solid way of capturing the co-relationshipsbetween the various stress events. The co-relationship between the stress events should be assigned byexperts, and informed by as broad a range as possible of indicators or future occurrences, events, andvulnerabilities. By finding such a way, we would be able to generate statistical information about stresslosses that are more realistic than losses captured by conventional stress testing methodologies.The Bayesian net approach to stress testing proposed here is based on the work of Dr. Rebonato. Wedeveloped a teaching tool based on this material in the form of a Powerpoint presentation, withcontents that should take one workshop day to cover. In addition, we developed a program written inExcel and Visual Basic for Applications (VBA) that allows a risk manager to enter a Bayesian scenario witha structure of choice and accompanying subjective probabilities and potential losses. The programchecks the entered data for consistency, and then generates the full joint probability table and anaccompanying conditional losses table that allows the risk manager to assign capital positions to hisscenario. Finally, we developed a realistic case that demonstrates the usefulness of the approach topotential clients with the example of Volksbank. The scenario which we construct for Volksbank is amulti-stage stress scenario. Essentially, it is a meta-stress scenario. The subjective probabilities in thescenario are based on, as well as drawn from the sources of potential vulnerability included in thescenario analysis.In creating these contents, we had to revise some points from the practical procedure of resolving aBayesian net in the book that turned out to be problematic. We feel that our work is a useful addition tothe book.What we suggest in this paper is a viable, more complete and comprehensive way of stress testingwhich can be easily implemented by banks and regulators in order to cope with the causality andcorrelation among economic shocks. The step towards a more complete methodology for stress testing,which is both updating and includes forward-looking information is necessary going into the future. Ifwe have learned anything from the 1998 Asian financial crisis and the 2008 global financial crisis, it isthat economics shocks are often correlated and that a severe crisis comes in stages. 27 | P a g e
- 28. ReferencesBasel Committee on Banking Supervision, “Principles for Sound Stress Testing and Supervision”,Consultative Document, Basel, January, 2009Bloomber Businessweekhttp://investing.businessweek.com/research/stocks/private/snapshot.asp?privcapId=875308De Jonghe, Frank, “Financial Risk Management”, Lecture Series, Ghent University, 2010De Jonghe, Frank and Nikolas Vander Vennet, “Some New Approaches to Stress Testing and ScenariosAnalysis”, Deloitte, 2011Rebonato, Ricardo “Coherent Stress Testing: A Bayesian Approach to the Analysis of Financial Risk” 2010Reinhart and Rogoff, “This Time it’s Different: A Panoramic View of Eight Centuries of Financial Crises”NBER, 2008Skidelsky, Robert “Keynes, Return of the Master” Allen Lane, 2009Taleb, Nassim, “The Black Swan: The impact of the Highly Improbable” Allen Lane, 2007Volksbank, “2010 Annual Report”, Vienna, 2010 28 | P a g e
- 29. Appendix 1Regulatory Own Resources and Capital 29 | P a g e
- 30. Risk-Weighted Assessment Base and Minimum Capital RequirementTier 1 Issues 30 | P a g e
- 31. Tier 2 Issues 31 | P a g e
- 32. 32 | P a g e
- 33. Appendix 22010 Volksbank segmental breakdown taken form page 156 of Volksbank’s 2010 Annual Report 33 | P a g e
- 34. Appendix 32010 Volksbank regional breakdown, domestic vs. foreign markets, taken from page 157 of Volksbank’s2010 Annual Report 34 | P a g e
- 35. Appendix 42010 Income Statement, taken from page 98 of Volksbank’s Annual Report 35 | P a g e
- 36. Appendix 5Volksbank Statement of Financial Position (Balance Sheet), taken from page 99 of 2010 Annual Report 36 | P a g e
- 37. Appendix 6Economic Growth outlooks and construction activity outlook in the CEE region, taken from pages 34 and48 of the 2010 Volksbank Annual Report 37 | P a g e
- 38. Appendix 7Visual Basic for Applications code of the programOption Explicit Author: Kevin Hoefman, 22 June 2011, contact: kevin.hoefman@howest.be Notes: - I am using one-based array counting throughout this program. In a variable Values(4), I will use Values(1), Values(2), Values(3) and Values(4)Sub CheckTopology() Select Topology range and dimensions Dim Topology As Range Set Topology = Worksheets(1).Cells(1, 1).CurrentRegion Dim Message As String CheckTopology_Range Topology, Message MsgBox (Message)End SubFunction CheckTopology_Range(ByVal MyRange As Range, ByRef Message As String) As Boolean Dim RowCount, ColumnCount RowCount = MyRange.Rows.Count ColumnCount = MyRange.Columns.Count Check matrix symmetry, abort if not If RowCount <> ColumnCount Then Message = "Fail: Matrix is not symmetric" CheckTopology_Range = False Exit Function End If Check if cells are filled in properly, abort if not If Trim(MyRange.Cells(1, 1)) <> "" Then MsgBox ("Fail: Improperly formed topology - Top left cell should be empty") CheckTopology_Range = False Exit Function End If Dim Count For Count = 2 To RowCount If Trim(MyRange.Cells(1, Count)) <> Trim(MyRange.Cells(Count, 1)) Then Message = "Fail: Improperly formed topology - Column titles dont match row titles" CheckTopology_Range = False Exit Function End If Next Dim SubTopology As Range Set SubTopology = Range(MyRange.Cells(2, 2), MyRange.Cells(RowCount, ColumnCount)) Dim Cell For Each Cell In SubTopology If Trim(Cell) <> "0" And Trim(Cell) <> "1" Then Message = "Fail: Improperly formed topology - At least one inner field is neither 0 nor 1" CheckTopology_Range = False Exit Function End If Next If all was successful, report dimension of topology Message = "This is a " & (RowCount - 1) & " event topology" CheckTopology_Range = TrueEnd Function 38 | P a g e
- 39. Sub GenerateJointProbabilities() Select Topology range Dim Topology As Range Set Topology = Worksheets(1).Cells(1, 1).CurrentRegion Select SubTopology range Dim SubTopology As Range Set SubTopology = Range(Topology.Cells(3, 2), Topology.Cells(Topology.Rows.Count, Topology.Columns.Count - 1)) Select full sheet Dim FullRange As Range Set FullRange = Worksheets(1).UsedRange Check the Topology just to be sure TODO: checktopology hier insteken Dim Message As String If CheckTopology_Range(Topology, Message) = False Then MsgBox ("Malformed topology - use the CheckTopology button for more information") Exit Sub End If Extract the event names from the topology Dim EventNames() As String ExtractEventNames Topology, EventNames Create arrays to hold marginal probabilities, single conditioned probabilities and double conditioned probabilities ReDim MarginalProbArr(UBound(EventNames)) As MarginalProb ReDim SingleCondProbArr(1) As SingleCondProb will be redimmed ReDim DoubleCondProbArr(1) As DoubleCondProb will be redimmed Extract required marginal probabilities and report missing values if any, exit function if missing values If ExtractMarginalProbabilities(EventNames, MarginalProbArr, FullRange) = False Then Exit Sub Extract required single conditioned probabilities If ExtractSingleConditionedProbs(EventNames, SingleCondProbArr, SubTopology, FullRange, MarginalProbArr) = False Then Exit Su b Extract required double conditioned probabilities and their corresponding extra single conditioned probability If ExtractDoubleConditionedProbs(EventNames, DoubleCondProbArr, SubTopology, FullRange, MarginalProbArr, SingleCondProbArr) = FalseThen Exit Sub Do Sanity Checks If CheckSanity(MarginalProbArr, SingleCondProbArr, DoubleCondProbArr) = False Then Exit Sub Determine the functional form of the topology ReDim Functional_MarginalProbArr(1) As MarginalProb ReDim Functional_SingleCondProbArr(1) As SingleCondProb Dim SingleConditioned_Count, Marginal_Count, CountSingle, CountMarginal, CountDouble As Integer SingleConditioned_Count = 0 Extract the functional single conditioned probability nodes For CountSingle = 1 To UBound(SingleCondProbArr) If SingleCondProbArr(CountSingle).IsFunctional() = True Then SingleConditioned_Count = SingleConditioned_Count + 1 Next ReDim Functional_SingleCondProbArr(SingleConditioned_Count) SingleConditioned_Count = 1 For CountSingle = 1 To UBound(SingleCondProbArr) If SingleCondProbArr(CountSingle).IsFunctional() = True Then Set Functional_SingleCondProbArr(SingleConditioned_Count) = SingleCondProbArr(CountSingle) SingleConditioned_Count = SingleConditioned_Count + 1 End If Next Determine functional top nodes If UBound(EventNames) = 1 Then MsgBox ("Topology is of only 1 dimension, not much to be done here... exiting.") Exit Sub Else Dim CountEmptyRows, CountOnes, CountColumns As Integer 39 | P a g e
- 40. Dim IsEmptyRow As Boolean CountEmptyRows = 0 IsEmptyRow = True Do While IsEmptyRow = True And CountEmptyRows + 3 <= Topology.Rows.Count CountOnes = 0 For CountColumns = 1 To UBound(EventNames) + 1 If Topology.Cells(3 + CountEmptyRows, CountColumns) = 1 Then CountOnes = CountOnes + 1 If CountOnes > 1 Then IsEmptyRow = False Next If CountOnes = 1 Then CountEmptyRows = CountEmptyRows + 1 Loop Number of top nodes is 1 more than the number of empty rows ReDim Functional_MarginalProbArr(CountEmptyRows + 1) For CountMarginal = 1 To CountEmptyRows + 1 Set Functional_MarginalProbArr(CountMarginal) = MarginalProbArr(CountMarginal) Next End If Locate the target worksheet Dim ResultsSheet As Worksheet Set ResultsSheet = Worksheets(2) Clear the results sheet ResultsSheet.UsedRange.Clear Center the range, set titles to desired style, make each column autofit, set the number formats Dim BottomRow As Integer BottomRow = 1 + Power(2, UBound(EventNames)) Range(ResultsSheet.Cells(1, 1), ResultsSheet.Cells(BottomRow, UBound(EventNames))).HorizontalAlignment = xlCenter Range(ResultsSheet.Cells(1, 1), ResultsSheet.Cells(1, 3 + UBound(EventNames))).HorizontalAlignment = xlCenter Range(ResultsSheet.Cells(1, 1), ResultsSheet.Cells(1, 3 + UBound(EventNames))).Font.Bold = True Dim Cell As Range For Each Cell In Range(ResultsSheet.Cells(1, 1), ResultsSheet.Cells(1, 3 + UBound(EventNames))) Cell.EntireColumn.AutoFit Next Cell Range(ResultsSheet.Cells(2, 1 + UBound(EventNames)), ResultsSheet.Cells(BottomRow, 1 + UBound(EventNames))).NumberFormat ="0.00000000 " Range(ResultsSheet.Cells(2, 2 + UBound(EventNames)), ResultsSheet.Cells(BottomRow, 3 + UBound(EventNames))).NumberFormat ="###,###,###,###,##0.00 " Fill in Titles FillInTitles EventNames, ResultsSheet Write other table titles Dim TitleCount As Integer Dim Title As String Title = "P(" For TitleCount = 1 To UBound(EventNames) - 1 Title = Title & EventNames(TitleCount) & ", " Next Title = Title & EventNames(TitleCount) & ")" ResultsSheet.Cells(1, UBound(EventNames) + 1) = Title ResultsSheet.Cells(1, UBound(EventNames) + 2) = "Gain/Loss" ResultsSheet.Cells(1, UBound(EventNames) + 3) = "Conditional Gain/Loss" Write Zeros and Ones FillInZerosAndOnes EventNames, ResultsSheet Calculate and write the joint probabilities CalculateJointProbabilities EventNames, Functional_MarginalProbArr, Functional_SingleCondProbArr, DoubleCondProbArr, ResultsSheet Calculate gain/losses 40 | P a g e
- 41. CalculateGainLosses MarginalProbArr, ResultsSheet Write the capital Dim CapitalCell As Range Set CapitalCell = ResultsSheet.Cells(2 + BottomRow, UBound(EventNames) + 3) CapitalCell.Formula = "=Min(" & ResultsSheet.Cells(2, 3 + UBound(EventNames)).Address & ":" & ResultsSheet.Cells(BottomRow, 3 +UBound(EventNames)).Address & ") * -1" CapitalCell.NumberFormat = "###,###,###,###,##0.00 " CapitalCell.Font.Bold = True CapitalCell.Offset(0, -1) = "Capital:" CapitalCell.Offset(0, -1).Font.Bold = True CapitalCell.Offset(0, -1).HorizontalAlignment = xlRight Range(CapitalCell.Offset(0, -1), CapitalCell).BorderAround xlContinuous, xlThick, xlColorIndexAutomatic Set results sheet active ResultsSheet.ActivateEnd SubSub ExtractEventNames(ByVal MyRange As Range, ByRef EventNames() As String) Select Topology range and dimensions Dim RowCount, ColumnCount RowCount = MyRange.Rows.Count ColumnCount = MyRange.Columns.Count Check matrix symmetry, abort if not If RowCount <> ColumnCount Then MsgBox ("Fail: Matrix is not symmetric") Exit Sub End If ReDim EventNames(RowCount - 1) Dim Count For Count = 2 To RowCount EventNames(Count - 1) = MyRange.Cells(Count, 1) NextEnd SubFunction ExtractMarginalProbabilities(ByRef EventNames() As String, ByRef MarginalProbArr() As MarginalProb, ByRef FullRange As Range) AsBoolean Create the necessary amount of objects Dim Count As Integer For Count = 1 To UBound(EventNames) Set MarginalProbArr(Count) = New MarginalProb MarginalProbArr(Count).Create (EventNames(Count)) Next Find their values and exit with either true if all values are found or false if not ExtractMarginalProbabilities = ScanRangeForMarginalProbs(MarginalProbArr, FullRange)End FunctionFunction ScanRangeForMarginalProbs(ByRef MarginalProbArr() As MarginalProb, ByRef FullRange As Range) Dim MessageMissing As String Dim CountMarginals, CountFound, RowCount As Integer Dim Found As Boolean CountFound = 0 For CountMarginals = 1 To UBound(MarginalProbArr) Found = False RowCount = 1 Do While RowCount <= FullRange.Rows.Count And Found = False If Replace(FullRange.Cells(RowCount, 1), " ", "") = MarginalProbArr(CountMarginals).Name() Then MarginalProbArr(CountMarginals).CreateValues FullRange.Cells(RowCount, 2), FullRange.Cells(RowCount, 3) Found = True End If RowCount = RowCount + 1 41 | P a g e
- 42. Loop If Found = False Then MessageMissing = MessageMissing & vbCrLf & MarginalProbArr(CountMarginals).Name Else CountFound = CountFound + 1 End If Next If CountFound = UBound(MarginalProbArr) Then ScanRangeForMarginalProbs = True Else MsgBox ("Missing marginal probabilities:" & MessageMissing) ScanRangeForMarginalProbs = False End IfEnd FunctionFunction ExtractSingleConditionedProbs(ByRef EventNames() As String, ByRef SingleCondProbArr() As SingleCondProb, ByRef SubTopology AsRange, ByRef FullRange As Range, ByRef MarginalProbArr() As MarginalProb) As Boolean Determine necessary space in array Dim ConditionalCount As Integer ConditionalCount = 0 Dim CountRows, CountColumns As Integer For CountRows = 1 To SubTopology.Rows.Count For CountColumns = 1 To CountRows If SubTopology.Cells(CountRows, CountColumns) = 1 Then ConditionalCount = ConditionalCount + 1 Next Next Resize array ReDim SingleCondProbArr(ConditionalCount) Create the objects Dim Position As Integer Position = 1 For CountRows = 1 To SubTopology.Rows.Count For CountColumns = 1 To CountRows If SubTopology.Cells(CountRows, CountColumns) = 1 Then Set SingleCondProbArr(Position) = New SingleCondProb SingleCondProbArr(Position).Create EventNames(CountRows + 1), EventNames(CountColumns) Position = Position + 1 End If Next Next Find their values and exit with either true if all values are found or false if not ExtractSingleConditionedProbs = ScanRangeForSinglecondProbs(SingleCondProbArr, FullRange, MarginalProbArr)End FunctionFunction ScanRangeForSinglecondProbs(ByRef SingleCondProbArr() As SingleCondProb, ByRef FullRange As Range, ByRef MarginalProbArr() AsMarginalProb) Dim MessageMissing As String Dim CountSingleConds, CountMarginals, CountFound, RowCount, PositionChild, PositionParent As Integer Dim Found As Boolean CountFound = 0 For CountSingleConds = 1 To UBound(SingleCondProbArr) Found = False RowCount = 1 Do While RowCount <= FullRange.Rows.Count And Found = False If Replace(FullRange.Cells(RowCount, 1), " ", "") = SingleCondProbArr(CountSingleConds).Name() Then find the corresponding marginal probabilities For CountMarginals = 1 To UBound(MarginalProbArr) If MarginalProbArr(CountMarginals).Node = SingleCondProbArr(CountSingleConds).ChildNode Then PositionChild = CountMarginals If MarginalProbArr(CountMarginals).Node = SingleCondProbArr(CountSingleConds).ParentNode Then PositionParent =CountMarginals 42 | P a g e
- 43. Next SingleCondProbArr(CountSingleConds).CreateValues FullRange.Cells(RowCount, 2), MarginalProbArr(PositionChild),MarginalProbArr(PositionParent) Found = True End If RowCount = RowCount + 1 Loop If Found = False Then MessageMissing = MessageMissing & vbCrLf & SingleCondProbArr(CountSingleConds).Name Else CountFound = CountFound + 1 End If Next If CountFound = UBound(SingleCondProbArr) Then ScanRangeForSinglecondProbs = True Else MsgBox ("Missing single-conditional probabilities:" & MessageMissing) ScanRangeForSinglecondProbs = False End IfEnd FunctionFunction ExtractDoubleConditionedProbs(ByRef EventNames() As String, ByRef DoubleCondProbArr() As DoubleCondProb, ByRef SubTopologyAs Range, ByRef FullRange As Range, ByRef MarginalProbArr() As MarginalProb, ByRef SingleCondProbArr() As SingleCondProb) As Boolean Determine necessary space in array Dim DoubleConditionalCount As Integer DoubleConditionalCount = 0 Dim CountOnes As Integer Dim CountRows, CountColumns As Integer For CountRows = 1 To SubTopology.Rows.Count CountOnes = 0 For CountColumns = 1 To CountRows If SubTopology.Cells(CountRows, CountColumns) = 1 Then CountOnes = CountOnes + 1 Next If CountOnes = 2 Then DoubleConditionalCount = DoubleConditionalCount + 1 Next Resize array ReDim DoubleCondProbArr(DoubleConditionalCount) Create array for corresponding single conditionals ReDim DoubleCondBridgeArr(DoubleConditionalCount) As SingleCondProb Create the objects Dim Position As Integer Position = 1 Dim PositionOfOnes(2) As Integer For CountRows = 1 To SubTopology.Rows.Count CountOnes = 0 For CountColumns = 1 To CountRows If SubTopology.Cells(CountRows, CountColumns) = 1 Then CountOnes = CountOnes + 1 PositionOfOnes(CountOnes) = CountColumns End If Next If CountOnes = 2 Then double conditioned probability found Set DoubleCondProbArr(Position) = New DoubleCondProb DoubleCondProbArr(Position).Create EventNames(CountRows + 1), EventNames(PositionOfOnes(1)), EventNames(PositionOfOnes(2)) Set DoubleCondBridgeArr(Position) = New SingleCondProb DoubleCondBridgeArr(Position).Create EventNames(PositionOfOnes(1)), EventNames(PositionOfOnes(2)) Position = Position + 1 End If 43 | P a g e
- 44. Next Find their values and exit with either true if all values are found or false if not ExtractDoubleConditionedProbs = ScanRangeForDoublecondProbs(DoubleCondProbArr, DoubleCondBridgeArr, FullRange,SingleCondProbArr, MarginalProbArr)End FunctionFunction ScanRangeForDoublecondProbs(ByRef DoubleCondProbArr() As DoubleCondProb, ByRef DoubleCondBridgeArr() As SingleCondProb,ByRef FullRange As Range, ByRef SingleCondProbArr() As SingleCondProb, ByRef MarginalProbArr() As MarginalProb) As Boolean Dim MessageMissing As String Dim CountDoubleConds, CountMarginals, CountSingleConds, CountFound, RowCount, PositionChild, PositionParentLeft, PositionParentRight,PositionSingleLeft, PositionSingleRight As Integer Dim Found As Boolean CountFound = 0 First, find the bridge single conditional probabilities, abort if not found If ScanRangeForSinglecondProbs(DoubleCondBridgeArr, FullRange, MarginalProbArr) = False Then ScanRangeForDoublecondProbs = False Exit Function End If If found, find the double conditional probabilities For CountDoubleConds = 1 To UBound(DoubleCondProbArr) Found = False RowCount = 1 Do While RowCount <= FullRange.Rows.Count And Found = False If Replace(FullRange.Cells(RowCount, 1), " ", "") = DoubleCondProbArr(CountDoubleConds).Name() Then find the corresponding marginal probabilities For CountMarginals = 1 To UBound(MarginalProbArr) If MarginalProbArr(CountMarginals).Node = DoubleCondProbArr(CountDoubleConds).ChildNode Then PositionChild =CountMarginals If MarginalProbArr(CountMarginals).Node = DoubleCondProbArr(CountDoubleConds).ParentNodeLeft Then PositionParentLeft =CountMarginals If MarginalProbArr(CountMarginals).Node = DoubleCondProbArr(CountDoubleConds).ParentNodeRight Then PositionParentRight =CountMarginals Next find the corresponding single conditioned probabilities For CountSingleConds = 1 To UBound(SingleCondProbArr) If SingleCondProbArr(CountSingleConds).ChildNode = DoubleCondProbArr(CountDoubleConds).ChildNode AndSingleCondProbArr(CountSingleConds).ParentNode = DoubleCondProbArr(CountDoubleConds).ParentNodeLeft Then PositionSingleLeft =CountSingleConds If SingleCondProbArr(CountSingleConds).ChildNode = DoubleCondProbArr(CountDoubleConds).ChildNode AndSingleCondProbArr(CountSingleConds).ParentNode = DoubleCondProbArr(CountDoubleConds).ParentNodeRight Then PositionSingleRight =CountSingleConds Next DoubleCondProbArr(CountDoubleConds).CreateValues FullRange.Cells(RowCount, 2), MarginalProbArr(PositionChild),MarginalProbArr(PositionParentLeft), MarginalProbArr(PositionParentRight), _ SingleCondProbArr(PositionSingleLeft), SingleCondProbArr(PositionSingleRight),DoubleCondBridgeArr(CountDoubleConds) Found = True End If RowCount = RowCount + 1 Loop If Found = False Then MessageMissing = MessageMissing & vbCrLf & DoubleCondProbArr(CountDoubleConds).Name Else CountFound = CountFound + 1 End If Next If CountFound = UBound(DoubleCondProbArr) Then ScanRangeForDoublecondProbs = True Else MsgBox ("Missing double-conditional probabilities:" & MessageMissing) ScanRangeForDoublecondProbs = False 44 | P a g e
- 45. End IfEnd FunctionSub CalculateJointProbabilities(ByRef EventNames() As String, ByRef Functional_MarginalProbArr() As MarginalProb, ByRefFunctional_SingleCondProbArr() As SingleCondProb, ByRef DoubleCondProbArr() As DoubleCondProb, ByRef ResultsSheet As Worksheet) ReDim States(UBound(EventNames)) As Boolean Dim CountRows, CountColumns, CountMarginals, CountSingles, CountDoubles As Integer Dim Result As Double Do for every row For CountRows = 2 To ResultsSheet.UsedRange.Rows.Count Determine the states that correspond with this row For CountColumns = 1 To UBound(EventNames) If ResultsSheet.Cells(CountRows, CountColumns) = "1" Then States(CountColumns) = True Else States(CountColumns) = False End If Next Calculate the joint probability Result = 1 For CountMarginals = 1 To UBound(Functional_MarginalProbArr) Result = Result * Functional_MarginalProbArr(CountMarginals).GetValueByStates(EventNames, States) Next For CountSingles = 1 To UBound(Functional_SingleCondProbArr) Result = Result * Functional_SingleCondProbArr(CountSingles).GetValueByStates(EventNames, States) Next For CountDoubles = 1 To UBound(DoubleCondProbArr) Result = Result * DoubleCondProbArr(CountDoubles).GetValueByStates(EventNames, States) Next Write it to the sheet ResultsSheet.Cells(CountRows, UBound(EventNames) + 1) = Result NextEnd SubSub CalculateGainLosses(ByRef MarginalProbArr() As MarginalProb, ByRef ResultsSheet As Worksheet) Dim CountRows, CountColumns, CountMarginals As Integer Dim Result As Double Do for every row For CountRows = 2 To ResultsSheet.UsedRange.Rows.Count Calculate the total gain/loss for this row Result = 0 For CountColumns = 1 To UBound(MarginalProbArr) Result = Result + ResultsSheet.Cells(CountRows, CountColumns) * MarginalProbArr(CountColumns).GainLoss Next Write it to the sheet ResultsSheet.Cells(CountRows, UBound(MarginalProbArr) + 2) = Result Write the conditional result to the sheet ResultsSheet.Cells(CountRows, UBound(MarginalProbArr) + 3) = ResultsSheet.Cells(CountRows, UBound(MarginalProbArr) + 1) * Result NextEnd SubSub PrintSingleCondProb(ByRef MySingleCondProb As SingleCondProb, ByRef Nodes() As String) Dim Message As String Message = MySingleCondProb.Name Dim States(2) As Boolean States(1) = True States(2) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ": " &MySingleCondProb.GetValueByStates(Nodes, States) 45 | P a g e
- 46. States(1) = True States(2) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ": " &MySingleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ": " &MySingleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ": " &MySingleCondProb.GetValueByStates(Nodes, States) MsgBox (Message)End SubSub PrintDoubleCondProb(ByRef MyDoubleCondProb As DoubleCondProb, ByRef Nodes() As String) Dim Message As String Message = MyDoubleCondProb.Name Dim States(3) As Boolean States(1) = True States(2) = True States(3) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = True States(2) = True States(3) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = True States(2) = False States(3) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = True States(2) = False States(3) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = True States(3) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = True States(3) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = False States(3) = True Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) States(1) = False States(2) = False States(3) = False Message = Message & vbCrLf & Nodes(1) & "=" & States(1) & ", " & Nodes(2) & "=" & States(2) & ", " & Nodes(3) & "=" & States(3) & ": " &MyDoubleCondProb.GetValueByStates(Nodes, States) MsgBox (Message)End SubSub FillInTitles(ByRef EventNames() As String, ByRef ResultsSheet As Worksheet) Dim NamesCount For NamesCount = 1 To UBound(EventNames) 46 | P a g e
- 47. ResultsSheet.Cells(1, NamesCount) = EventNames(NamesCount) NextEnd SubSub FillInZerosAndOnes(ByRef EventNames() As String, ByRef ResultsSheet As Worksheet) Dim ColumnCount, IterationCount, WriteCount, RowCount As Integer For ColumnCount = UBound(EventNames) To 1 Step -1 RowCount = 2 For IterationCount = 1 To Power(2, ColumnCount - 1) For WriteCount = 1 To Power(2, UBound(EventNames) - ColumnCount) ResultsSheet.Cells(RowCount, ColumnCount) = "1" RowCount = RowCount + 1 Next For WriteCount = 1 To Power(2, UBound(EventNames) - ColumnCount) ResultsSheet.Cells(RowCount, ColumnCount) = "0" RowCount = RowCount + 1 Next Next NextEnd SubFunction Power(ByRef Number As Integer, ByRef Pow As Integer) If Pow = 0 Then Power = 1 Exit Function End If Dim PowCount As Integer Dim Result As Integer Result = 1 For PowCount = 1 To Pow Result = Result * Number Next Power = ResultEnd FunctionFunction CheckSanity(ByRef MarginalProbArr() As MarginalProb, ByRef SingleCondProbArr() As SingleCondProb, ByRef DoubleCondPr obArr() AsDoubleCondProb) As Boolean Dim Message As String Dim IsSane As Boolean IsSane = True Dim CountMarginal, CountSingle, CountDouble As Integer For CountMarginal = 1 To UBound(MarginalProbArr) If MarginalProbArr(CountMarginal).CheckSanity(Message) = False Then IsSane = False Next For CountSingle = 1 To UBound(SingleCondProbArr) If SingleCondProbArr(CountSingle).CheckSanity(Message) = False Then IsSane = False Next For CountDouble = 1 To UBound(DoubleCondProbArr) If DoubleCondProbArr(CountDouble).CheckSanity(Message) = False Then IsSane = False Next If IsSane = False Then MsgBox ("Performing sanity check..." & vbCrLf & vbCrLf & "Sanity check failed." & Message & vbCrLf & vbCrLf & "Aborting proce dure.") CheckSanity = False Else MsgBox ("Performing sanity check..." & vbCrLf & "Sanity check succeeded.") CheckSanity = True End IfEnd FunctionSub UnitTest_MarginalProb() Dim MargA As MarginalProb Set MargA = New MarginalProb 47 | P a g e
- 48. MargA.Create ("A") MargA.CreateValues (0.01) MsgBox (MargA.Name & ":" & vbCrLf & MargA.GetValue(True) & vbCrLf & MargA.GetValue(False)) Dim Nodes(3) As String Nodes(1) = "D" Nodes(2) = "C" Nodes(3) = "A" Dim States(3) As Boolean States(1) = True States(2) = True States(3) = True Dim ATrue, AFalse As Double ATrue = MargA.GetValueByStates(Nodes, States) States(3) = False AFalse = MargA.GetValueByStates(Nodes, States) MsgBox (MargA.Name & ":" & vbCrLf & ATrue & vbCrLf & AFalse) Nodes(3) = "E" ATrue = MargA.GetValueByStates(Nodes, States)End SubSub UnitTest_SingleCondProb() Dim MargA As MarginalProb Set MargA = New MarginalProb MargA.Create ("A") MargA.CreateValues (0.01) Dim MargD As MarginalProb Set MargD = New MarginalProb MargD.Create ("D") MargD.CreateValues (0.015) Dim P_D_A As SingleCondProb Set P_D_A = New SingleCondProb P_D_A.Create "D", "A" P_D_A.CreateValues 0.6, MargD, MargA MsgBox (P_D_A.Name & ":" & vbCrLf & P_D_A.GetValue(True, True) & vbCrLf & P_D_A.GetValue(True, False) & vbCrLf &P_D_A.GetValue(False, True) & vbCrLf & P_D_A.GetValue(False, False)) Dim Nodes(3) As String Nodes(1) = "C" Nodes(2) = "D" Nodes(3) = "A" Dim States(3) As Boolean States(1) = True Dim DATrueTrue, DATrueFalse, DAFalseTrue, DAFalseFalse As Double States(2) = True States(3) = True DATrueTrue = P_D_A.GetValueByStates(Nodes, States) States(2) = True States(3) = False DATrueFalse = P_D_A.GetValueByStates(Nodes, States) States(2) = False States(3) = True DAFalseTrue = P_D_A.GetValueByStates(Nodes, States) States(2) = False States(3) = False DAFalseFalse = P_D_A.GetValueByStates(Nodes, States) 48 | P a g e
- 49. MsgBox (P_D_A.Name & ":" & vbCrLf & DATrueTrue & vbCrLf & DATrueFalse & vbCrLf & DAFalseTrue & vbCrLf & DAFalseFalse) Nodes(2) = "E" Nodes(3) = "F" DAFalseFalse = MargA.GetValueByStates(Nodes, States)End SubSub UnitTest_DoubleCondProb() Dim MargD As MarginalProb Set MargD = New MarginalProb MargD.Create ("D") MargD.CreateValues (0.015) Dim MargC As MarginalProb Set MargC = New MarginalProb MargC.Create ("C") MargC.CreateValues (0.02) Dim MargE As MarginalProb Set MargE = New MarginalProb MargE.Create ("E") MargE.CreateValues (0.01) Dim P_E_D As SingleCondProb Set P_E_D = New SingleCondProb P_E_D.Create "E", "D" P_E_D.CreateValues 0.03, MargE, MargD Dim P_E_C As SingleCondProb Set P_E_C = New SingleCondProb P_E_C.Create "E", "C" P_E_C.CreateValues 0.2, MargE, MargC Dim P_D_C As SingleCondProb Set P_D_C = New SingleCondProb P_D_C.Create "D", "C" P_D_C.CreateValues 0.001885, MargD, MargC Dim P_E_DC As DoubleCondProb Set P_E_DC = New DoubleCondProb P_E_DC.Create "E", "D", "C" P_E_DC.CreateValues 0.4, MargE, MargD, MargC, P_E_D, P_E_C, P_D_C MsgBox (P_E_DC.Name & ":" & vbCrLf & P_E_DC.GetValue(True, True, True) & vbCrLf & P_E_DC.GetValue(True, True, False) & vbCrLf &P_E_DC.GetValue(True, False, True) & vbCrLf & P_E_DC.GetValue(True, False, False) & _ vbCrLf & P_E_DC.GetValue(False, True, True) & vbCrLf & P_E_DC.GetValue(False, True, False) & vbCrLf & P_E_DC.GetValue(False,False, True) & vbCrLf & P_E_DC.GetValue(False, False, False)) Dim Nodes(3) As String Nodes(1) = "E" Nodes(2) = "D" Nodes(3) = "C" Dim States(3) As Boolean Dim EDC(8) As Double States(1) = True States(2) = True States(3) = True EDC(1) = P_E_DC.GetValueByStates(Nodes, States) States(1) = True States(2) = True States(3) = False EDC(2) = P_E_DC.GetValueByStates(Nodes, States) States(1) = True 49 | P a g e
- 50. States(2) = False States(3) = True EDC(3) = P_E_DC.GetValueByStates(Nodes, States) States(1) = True States(2) = False States(3) = False EDC(4) = P_E_DC.GetValueByStates(Nodes, States) States(1) = False States(2) = True States(3) = True EDC(5) = P_E_DC.GetValueByStates(Nodes, States) States(1) = False States(2) = True States(3) = False EDC(6) = P_E_DC.GetValueByStates(Nodes, States) States(1) = False States(2) = False States(3) = True EDC(7) = P_E_DC.GetValueByStates(Nodes, States) States(1) = False States(2) = False States(3) = False EDC(8) = P_E_DC.GetValueByStates(Nodes, States) MsgBox (P_E_DC.Name & ":" & vbCrLf & EDC(1) & vbCrLf & EDC(2) & vbCrLf & EDC(3) & vbCrLf & EDC(4) & _ vbCrLf & EDC(5) & vbCrLf & EDC(6) & vbCrLf & EDC(7) & vbCrLf & EDC(8)) Nodes(1) = "B" Nodes(2) = "C" Nodes(3) = "A" EDC(8) = P_E_DC.GetValueByStates(Nodes, States)End SubSub Test_Independence() Dim MargA As MarginalProb Set MargA = New MarginalProb MargA.Create ("A") MargA.CreateValues (0.01) Dim MargB As MarginalProb Set MargB = New MarginalProb MargB.Create ("D") MargB.CreateValues (0.015) Dim P_A_B As SingleCondProb Set P_A_B = New SingleCondProb P_A_B.Create "A", "B" P_A_B.CreateValues MargA.GetValue(True), MargA, MargB MsgBox (P_A_B.Name & ":" & vbCrLf & P_A_B.GetValue(True, True) & vbCrLf & P_A_B.GetValue(True, False) & vbCrLf &P_A_B.GetValue(False, True) & vbCrLf & P_A_B.GetValue(False, False))End Sub 50 | P a g e
- 51. Option Explicit Author: Kevin Hoefman, 22 June 2011, contact: kevin.hoefman@howest.be Notes: - I am using one-based array counting throughout this program. In a variable Values(4), I will use Values(1), Values(2), Values(3) and Values(4) DatamembersPrivate m_Node As StringPrivate m_GainLoss As Double A positive number means a gain, a negative number means a lossPrivate m_Values(2) As Double PropertiesPublic Property Get Name() As String Name = "P(" & m_Node & ")"End PropertyPublic Property Get Node() As String Node = m_NodeEnd PropertyPublic Property Get GainLoss() As String GainLoss = m_GainLossEnd Property Subroutines & FunctionsPublic Sub Create(ByRef Node As String) m_Node = NodeEnd SubPublic Sub CreateValues(ByRef ValueTrue As Double, ByRef GainLoss As Double) m_Values(1) = ValueTrue m_Values(2) = 1 - ValueTrue m_GainLoss = GainLossEnd SubPublic Function GetValue(ByRef State As Boolean) As Double If State = True Then GetValue = m_Values(1) Else GetValue = m_Values(2) End IfEnd FunctionPublic Function GetValueByStates(ByRef Nodes() As String, ByRef States() As Boolean) As Double Dim Position As Integer Dim Found As Boolean Found = False For Position = 1 To UBound(Nodes) If Nodes(Position) = m_Node Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding node: node " & m_Node & " is not found in list of nodes") GetValueByStates = -1 Exit Function 51 | P a g e
- 52. End If GetValueByStates = GetValue(States(Position))End FunctionPublic Function CheckSanity(ByRef Message As String) As Boolean CheckSanity = True If m_Values(1) < 0 Or m_Values(1) >= 1 Then Message = Message & vbCrLf & "Invalid value for " & Name & ": " & m_Values(1) CheckSanity = False End IfEnd FunctionOption Explicit Author: Kevin Hoefman, 22 June 2011, contact: kevin.hoefman@howest.be Notes: - I am using one-based array counting throughout this program. In a variable Values(4), I will use Values(1), Values(2), Values(3) and Values(4) DatamembersPrivate m_ChildNode As StringPrivate m_ParentNode As StringPrivate m_Sanity1Value As DoublePrivate m_Sanity1Message As StringPrivate m_IsFunctional As BooleanPrivate m_Values(4) As Double m_Values(1) = TRUE/TRUE, m_Values(2) = TRUE/FALSE, m_Values(3) = FALSE/TRUE, m_Values(4) =FALSE/FALSE PropertiesPublic Property Get Name() As String Name = "P(" & m_ChildNode & "|" & m_ParentNode & ")"End PropertyPublic Property Get ChildNode() As String ChildNode = m_ChildNodeEnd PropertyPublic Property Get ParentNode() As String ParentNode = m_ParentNodeEnd Property Subroutines & FunctionsPublic Sub Create(ByRef ChildNode As String, ByRef ParentNode As String) m_ChildNode = ChildNode m_ParentNode = ParentNode m_IsFunctional = TrueEnd SubPublic Sub CreateValues(ByRef P_Child_Parent As Double, ByRef MarginalChild As MarginalProb, ByRef MarginalParent As Marginal Prob) m_Values(1) = P_Child_Parent Dim P_Parent_Child As Double P_Parent_Child = P_Child_Parent * MarginalParent.GetValue(True) / MarginalChild.GetValue(True) 52 | P a g e
- 53. m_Sanity1Value = P_Parent_Child m_Sanity1Message = "Invalid combination of " & Name & ", " & MarginalChild.Name & " and " & MarginalParent.Name & ": P(" &MarginalParent.Node & "|" & MarginalChild.Node & ") = " & P_Parent_Child m_Values(2) = (1 - P_Parent_Child) * MarginalChild.GetValue(True) / MarginalParent.GetValue(False) m_Values(3) = 1 - m_Values(1) m_Values(4) = 1 - m_Values(2)End SubPublic Function GetValue(ByRef ChildState As Boolean, ByRef ParentState As Boolean) As Double If ChildState = True And ParentState = True Then GetValue = m_Values(1) ElseIf ChildState = True And ParentState = False Then GetValue = m_Values(2) ElseIf ChildState = False And ParentState = True Then GetValue = m_Values(3) Else GetValue = m_Values(4) End IfEnd FunctionPublic Function GetValueByStates(ByRef Nodes() As String, ByRef States() As Boolean) As Double Dim PositionChild, PositionParent As Integer Dim Found As Boolean find the childnode Found = False For PositionChild = 1 To UBound(Nodes) If Nodes(PositionChild) = m_ChildNode Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding childnode: childnode " & m_ChildNode & " is not found in list of nodes") GetValueByStates = -1 Exit Function End If find the parentnode Found = False For PositionParent = 1 To UBound(Nodes) If Nodes(PositionParent) = m_ParentNode Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding parentnode: parentnode " & m_ParentNode & " is not found in list of nodes") GetValueByStates = -1 Exit Function End If retrieve the correct value GetValueByStates = GetValue(States(PositionChild), States(PositionParent))End FunctionPublic Sub SetFunctional(ByRef Value As Boolean) m_IsFunctional = ValueEnd SubPublic Function IsFunctional() As Boolean IsFunctional = m_IsFunctionalEnd FunctionPublic Function CheckSanity(ByRef Message As String) As Boolean 53 | P a g e
- 54. CheckSanity = True If m_Values(1) < 0 Or m_Values(1) >= 1 Then Message = Message & vbCrLf & "Invalid value for " & Name & ": " & m_Values(1) CheckSanity = False End If If m_Sanity1Value < 0 Or m_Sanity1Value >= 1 Then Message = Message & vbCrLf & m_Sanity1Message CheckSanity = False End IfEnd FunctionOption Explicit Author: Kevin Hoefman, 22 June 2011, contact: kevin.hoefman@howest.be Notes: - I am using one-based array counting throughout this program. In a variable Values(4), I will use Values(1), Values(2), Values(3) and Values(4) DatamembersPrivate m_ChildNode As String Nodes: m_ParentNodeLeft m_ParentNodeRight => P(m_ChildNode | m_Par entNodeLeft,m_ParentNodeRight)Private m_ParentNodeLeft As String m_ChildNodePrivate m_Sanity1Value, m_Sanity2Value As DoublePrivate m_Sanity1Message, m_Sanity2Message As StringPrivate m_ParentNodeRight As String Note about the ordering of the nodes: mathematically, parent left and parent right can be switched.Program wise the order is important, dont confuse them.Private m_Values(8) As Double Values(1) = TRUE/TRUE/TRUE, Values(2) = TRUE/TRUE/FALSE, Values(3) = TRUE/FALSE/TRUE, Values(4) =TRUE/FALSE/FALSE, Values(5) = FALSE/TRUE/TRUE, Values(6) = FALSE/TRUE/FALSE, Values(7) = FALSE/FALSE/TRUE, Values(8) =FALSE/FALSE/FALSE, in correspondence with the sequence: 1 1 1 1 1 0 1 0 1 1 0 0 0 1 1 0 1 0 0 0 1 0 0 0 PropertiesPublic Property Get Name() As String Name = "P(" & m_ChildNode & "|" & m_ParentNodeLeft & "," & m_ParentNodeRight & ")"End PropertyPublic Property Get ChildNode() As String ChildNode = m_ChildNodeEnd PropertyPublic Property Get ParentNodeLeft() As String ParentNodeLeft = m_ParentNodeLeftEnd PropertyPublic Property Get ParentNodeRight() As String ParentNodeRight = m_ParentNodeRightEnd Property 54 | P a g e
- 55. Subroutines & FunctionsPublic Sub Create(ByRef ChildNode As String, ByRef ParentNodeLeft As String, ByRef ParentNodeRight As String) m_ChildNode = ChildNode m_ParentNodeLeft = ParentNodeLeft m_ParentNodeRight = ParentNodeRightEnd SubPublic Sub CreateValues(ByRef P_Child_ParentLeft_ParentRight As Double, ByRef Marginal_Child As MarginalProb, ByRef Marginal_ParentLeftAs MarginalProb, _ ByRef Marginal_ParentRight As MarginalProb, ByRef SingleCond_Child_ParentLeft As SingleCondProb, _ ByRef SingleCond_Child_ParentRight As SingleCondProb, ByRef SingleCond_ParentLeft_ParentRight As SingleCondProb) m_Values(1) = P_Child_ParentLeft_ParentRight Dim TempReverse As Double calculate TRUE TRUE FALSE TempReverse = P_Child_ParentLeft_ParentRight * SingleCond_ParentLeft_ParentRight.GetValue(True, True) *Marginal_ParentRight.GetValue(True) / (SingleCond_Child_ParentLeft.GetValue(True, True) * Marginal_ParentLeft.GetValue(True)) m_Sanity1Value = TempReverse m_Sanity1Message = "Invalid combination of " & Name & ", " & SingleCond_ParentLeft_ParentRight.Name & ", " &Marginal_ParentRight.Name & ", " & _ SingleCond_Child_ParentLeft.Name & ", " & Marginal_ParentLeft.Name & ": P(" & Marginal_ParentRight.Node & "|" &Marginal_ParentLeft.Node & _ ", " & Marginal_Child.Node & ") = " & m_Sanity1Value m_Values(2) = (1 - TempReverse) * SingleCond_Child_ParentLeft.GetValue(True, True) * Marginal_ParentLeft.GetValue(True) /(SingleCond_ParentLeft_ParentRight.GetValue(True, False) * Marginal_ParentRight.GetValue(False)) calculate TRUE FALSE TRUE TempReverse = P_Child_ParentLeft_ParentRight * SingleCond_ParentLeft_ParentRight.GetValue(True, True) /SingleCond_Child_ParentRight.GetValue(True, True) m_Sanity2Value = TempReverse m_Sanity1Message = "Invalid combination of " & Name & ", " & SingleCond_ParentLeft_ParentRight.Name & ", " &SingleCond_Child_ParentRight.Name & ": P(" & Marginal_ParentLeft.Node & "|" & Marginal_Child.Node & ", " & Marginal_ParentRig ht.Node &") = " & m_Sanity2Value m_Values(3) = (1 - TempReverse) * SingleCond_Child_ParentRight.GetValue(True, True) /SingleCond_ParentLeft_ParentRight.GetValue(False, True) calculate TRUE FALSE FALSE TempReverse = m_Values(2) * SingleCond_ParentLeft_ParentRight.GetValue(True, False) / SingleCond_Child_ParentRight.GetValue(True,False) m_Values(4) = (1 - TempReverse) * SingleCond_Child_ParentRight.GetValue(True, False) /SingleCond_ParentLeft_ParentRight.GetValue(False, False) m_Values(5) = 1 - m_Values(1) m_Values(6) = 1 - m_Values(2) m_Values(7) = 1 - m_Values(3) m_Values(8) = 1 - m_Values(4) switch off functional for the single conditioned probabilities that are part of this double conditioned prob SingleCond_Child_ParentLeft.SetFunctional (False) SingleCond_Child_ParentRight.SetFunctional (False)End SubPublic Function GetValue(ByRef ChildState As Boolean, ByRef ParentLeftState As Boolean, ByRef ParentRightState As Boolean) As Double If ChildState = True And ParentLeftState = True And ParentRightState = True Then GetValue = m_Values(1) ElseIf ChildState = True And ParentLeftState = True And ParentRightState = False Then GetValue = m_Values(2) ElseIf ChildState = True And ParentLeftState = False And ParentRightState = True Then GetValue = m_Values(3) ElseIf ChildState = True And ParentLeftState = False And ParentRightState = False Then GetValue = m_Values(4) ElseIf ChildState = False And ParentLeftState = True And ParentRightState = True Then GetValue = m_Values(5) 55 | P a g e
- 56. ElseIf ChildState = False And ParentLeftState = True And ParentRightState = False Then GetValue = m_Values(6) ElseIf ChildState = False And ParentLeftState = False And ParentRightState = True Then GetValue = m_Values(7) Else GetValue = m_Values(8) End IfEnd FunctionPublic Function GetValueByStates(ByRef Nodes() As String, ByRef States() As Boolean) As Double Dim PositionChild, PositionParentLeft, PositionParentRight As Integer Dim Found As Boolean find the childnode Found = False For PositionChild = 1 To UBound(Nodes) If Nodes(PositionChild) = m_ChildNode Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding childnode: childnode " & m_ChildNode & " is not found in list of nodes") GetValueByStates = -1 Exit Function End If find the parentnode left Found = False For PositionParentLeft = 1 To UBound(Nodes) If Nodes(PositionParentLeft) = m_ParentNodeLeft Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding parentnode left: parentnode left " & m_ParentNodeLeft & " is not found in list of nodes") GetValueByStates = -1 Exit Function End If find the parentnode right Found = False For PositionParentRight = 1 To UBound(Nodes) If Nodes(PositionParentRight) = m_ParentNodeRight Then Found = True Exit For End If Next If Found = False Then MsgBox ("Error finding parentnode right: parentnode right " & m_ParentNodeRight & " is not found in list of nodes") GetValueByStates = -1 Exit Function End If retrieve the correct value GetValueByStates = GetValue(States(PositionChild), States(PositionParentLeft), States(PositionParentRight))End FunctionPublic Function CheckSanity(ByRef Message As String) As Boolean CheckSanity = True If m_Values(1) < 0 Or m_Values(1) >= 1 Then Message = Message & vbCrLf & "Invalid value for " & Name & ": " & m_Values(1) CheckSanity = False End If If m_Sanity1Value < 0 Or m_Sanity1Value >= 1 Then 56 | P a g e
- 57. Message = Message & vbCrLf & m_Sanity1Message CheckSanity = False End If If m_Sanity2Value < 0 Or m_Sanity2Value >= 1 Then Message = Message & vbCrLf & m_Sanity2Message CheckSanity = False End IfEnd Function 57 | P a g e

Full NameComment goes here.