Represent Accounting Equation Using SWI-Prolog

I’m using: SWI-Prolog version, the online version.

I want the code to: I am trying to represent the accounting equation using SWISH, http://xbrlsite.azurewebsites.net/2019/Core/master-ae/

There are three terms: Assets, Liabilities, Equity

There is one structure: BalanceSheet

There is one assertion: Assets = Liabilities + Equity

I am just getting started, I am a certified public accountant, not a technical person.

Any help would be appreciated. I know this is pretty basic, but I am just getting started and am a big picture person. Trying to understand the big picture.

Just responding because I don’t want want you to think this is being ignored, it is just not the typical question we can give a specific answer too.

It seems from the way you ask the question that you do not know Prolog or even a single programming language, is this true?

Also it seems that you would like to create an application that can be used by many, but I have to warn you that many programmers don’t know Prolog so bear this in mind.

You might also find this of interest: Hoare logic

I have been programming for 30 years using VBA within Microsoft Access and with Visual Basic for Applications for about 20 years. Logic programming is significantly different than procedural programming. I have tried to figure out Prolog, DataLog, CLIPS, Answer Set Programming, OWL/RDF/SHACL, and a few other logic programming or declarative rules languages but I can only do the basics.

Prolog seems like it could meet the needs that I have. I probably spent three hours fiddling around with this yesterday and I came up with the following:

term(asset).
term(liability).
term(equity).
structure(balanceSheet).
entity(microsoft).

fact(term(asset), entity(microsoft), 5000).
fact(term(liabilities), entity(microsoft), 1000).
fact(term(equity), entity(microsoft), 4000).

% rule Assets = Liabilities + Equity %
does_balance_sheet_balance(entity(Entity)) := 
    fact(term(asset),entity(Entity),Value) = fact(term(liabilities),entity(Entity),Value) + fact(term(equity),entity(Entity),Value).

% ?- fact(term(Term),entity(Entity),Value). %
% ?- does_balance_sheet_balance %

Some things work, but I cannot get the rule to work correctly. So it does seem like Prolog can possibly achieve what it is that I am trying to achieve.

The reason I am trying to make this example work is because I want to use it as an example for an OMG (Object Management Group) standard I am helping to get created called Standard Business Reporting Model (SBRM). What SBRM does is separate the syntax of a business report from the semantics of the report. A financial report is a type (specialization) of a business report.

I think that Prolog and other logic languages are going to make a big come back over the next 10 years. This is also a really good opportunity to get programmers to better understand tools such as Prolog.

Anyway, any help would be greatly appreciated. And thanks for the pointer to Hoare Logic, I will check it out.

1 Like

As soon as I saw this I knew you made a basic mistake that most new Prolog programmers make, don’t feel bad as I did it also when learning.

Prolog does not have the numeric assignment operator =, but it does have is/2

So

fact(term(asset),entity(Entity),Value) = fact(term(liabilities),entity(Entity),Value) + fact(term(equity),entity(Entity),Value).

should be something like

Asset = fact(term(asset),entity(Asset_entity),Asset_value),
Liabilities = fact(term(liabilities),entity(Liabilities_entity),Liabilities_value),
Equity = fact(term(equity),entity(Equity_entity),Equity_value)

Asset_value is Liabilities_value + Equity_value.

and

does_balance_sheet_balance(entity(Entity)) := 
    fact(term(asset),entity(Entity),Value) = fact(term(liabilities),entity(Entity),Value) + fact(term(equity),entity(Entity),Value).

is probably

does_balance_sheet_balance(entity(Entity)) := 
   fact(term(asset),entity(Entity),Asset_value),
   fact(term(liabilities),entity(Entity),Liabilities_value),
   fact(term(equity),entity(Entity),Equity_value),
   Asset_value is Liabilities_value + Equity_value.

I say probably because I did not test it on a running system.

1 Like

I tried this:

Asset = fact(term(Asset),entity(Asset_entity),Asset_value),
Liabilities = fact(term(Liabilities),entity(Liabilities_entity),Liabilities_value),
Equity = fact(term(Equity),entity(Equity_entity),Equity_value)

Asset_value is Liabilities_value + Equity_value.

fact(term(Asset), entity(Microsoft), 5000).
fact(term(Liabilities), entity(Microsoft), 1000).
fact(term(Equity), entity(Microsoft), 4000).

does_balance_sheet_balance(entity(Entity)) := 
   fact(term(Asset),entity(Entity),Asset_value),
   fact(term(Liabilities),entity(Entity),Liabilities_value),
   fact(term(Equity),entity(Entity),Equity_value),
   Asset_value is Liabilities_value + Equity_value.

But that gets syntax errors.

It would be greatly appreciated if you might be able to help me get that foundation running. From there, I think that I would be good. Thanks again for the assistance.

Silly me, should have seen this. :smiley:

The syntax error

ERROR:    Full stop in clause-body?  Cannot redefine ,/2

is from := which should be :-

This code works

term(asset).
term(liability).
term(equity).
structure(balanceSheet).
entity(microsoft).

fact(term(asset), entity(microsoft), 5000).
fact(term(liabilities), entity(microsoft), 1000).
fact(term(equity), entity(microsoft), 4000).

% rule Assets = Liabilities + Equity %
does_balance_sheet_balance(Entity) :-
    fact(term(asset),entity(Entity),Asset),
    fact(term(liabilities),entity(Entity),Liabilities),
    fact(term(equity),entity(Entity),Equity),
    Asset is Liabilities + Equity.

Example run:

?- does_balance_sheet_balance(microsoft).
 true.

For the final code I would use something similar to

asset(microsoft,5_000).
liability(microsoft,1_000).
equity(microsoft,4_000).

does_balance_sheet_balance_01(Entity) :-
    asset(Entity,Asset),
    liability(Entity,Liabilities),
    equity(Entity,Equity),
    Asset is Liabilities + Equity.

but I do understand that you are learning and having the extra term names is quite helpful and what I also do.

Also note the Prolog can use _ in integers which makes it nicer when viewing large numbers.


Since Prolog is a logic language, if the predicate fails, the answer will be false.

asset(microsoft,5_000).
liability(microsoft,2_000).
equity(microsoft,4_000).

does_balance_sheet_balance(Entity) :-
    asset(Entity,Asset),
    liability(Entity,Liabilities),
    equity(Entity,Equity),
    Asset is Liabilities + Equity.
?- does_balance_sheet_balance(microsoft).
false.

If you want more meaningful error messages then using must_be/2 might be of use, e.g.

does_balance_sheet_balance(Entity) :-
    must_be(bound,Entity),
    asset(Entity,Asset),
    liability(Entity,Liabilities),
    equity(Entity,Equity),
    Asset is Liabilities + Equity.
?- does_balance_sheet_balance(Variable).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:   [14] throw(error(instantiation_error,_11210))
ERROR:   [10] does_balance_sheet_balance(_11234) at c:/users/eric/documents/projects/prolog/swi-discourse_016.pl:37
ERROR:    [9] <user>
ERROR: 
ERROR: Note: some frames are missing due to last-call optimization.
ERROR: Re-run your program in debug mode (:- debug.) to get more detail.

Yes, this works. I cannot tell you how much I appreciate you helping me to make this work!

Let me ask you a question. Is Prolog something that developers can work with? So, the average business professional would never be able to use that syntax. But, software engineers could build interfaces that helped business users. For example, LogicBlox is a really good example of this. https://developer.logicblox.com/playground/

Your thoughts would be greatly appreciated. And thank you once again for helping me to get that little example working.

That is subjective, but IMHO yes. Will they is the real question. As I noted, many programmers do not know Prolog. I learned it in the early 1980’s and went 20 years without ever working with another programmer who knew Prolog and I worked at several Fortune 50 companies.

But, software engineers could build interfaces that helped business users.

Questions asking how to interface Java, Python and .Net code to Prolog are common but not always straight forward. Also the interfaces are typically written by one user who then over time tends not keep the interface updated so caveat emptor.

Jan would be able to better answer this as he has more real world experience. Also if you have a budget you might let Jan know as he is always looking for sponsors for some projects.

LogicBlox is a really good example of this.

You might be interested in SWISH

You are welcome, but don’t forget to thank all of the others here who create the code like Jan and added to it over the years, I would not be able to help you if they did not do what they did.

1 Like

So here is what I was able to do with the little bit of guidance you provided (so thank you yet again and all the others that are making SWI-Prolog and SWISH real and useful tools).

http://xbrlsite.azurewebsites.net/2019/sbrm/prolog/Prolog_FASB_SFAC6.txt

You should be able to copy that file into SWISH and it should work fine.

I do have one additional question. I had to hack something and hard code something that should be a variable because I could not yet figure out how to represent it. I added this rule:

% rule EndingEquity = BeginningEquity + ComprehensiveIncome + InvestmentsByOwners - DistributionsToOwners %
does_equity_roll_forward(Entity, Period) :-
   fact(term(equity),entity(Entity),period(2016),BeginningEquity),
   fact(term(comprehensiveIncome),entity(Entity),period(Period),ComprehensiveIncome),
   fact(term(equity),entity(Entity),period(Period),EndingEquity),
   fact(term(distributionsToOwners),entity(Entity),period(Period),DistributionsToOwners),
   EndingEquity is BeginningEquity + ComprehensiveIncome - DistributionsToOwners.

Note that for the term(equity) i am using two different periods, 2016 (beginning) and 2017 (ending). I tried to pass in TWO variables BeginningPeriod, EndingPeriod; but that did not work. Any help would be greatly appreciated then I am done.

I really appreciate the time that you have already spent. The information you have provided is incredibly helpful. Hopefully others find these accounting examples helpful. Here is the first example, the accounting equation:

http://xbrlsite.azurewebsites.net/2019/sbrm/prolog/Prolog_AccountingEquation.txt

Hi Charles,

See this SWISH notebook, at the bottom you will see the answer for your question.

https://swish.swi-prolog.org/p/uNPkhWtD.swinb

Hope it helps. Feel free to change/add to the notebook as you play around with it, it is your property :slight_smile:

This is excellent!!! I really, really appreciate the assistance. :smiley:

Note: The name assertion is a predefined predicate used with unit testing. While your code is clear in understanding for me, it might catch some people off guard.

Out of my own interest are you aware of blockchain and if so how does it compare with what you are doing? e.g. the pros and cons of each.

I am very aware of “blockchain” but I prefer to refer to the functionality that something like a blockchain provides which is “immutable digital distributed ledger”. https://tinyurl.com/rktmemg

What I am doing is focused on representing financial reports digitally using the XBRL technical syntax which is the global standard. What I am trying to get accountants to recognize is that when you represent such financial statements using any syntax, you have to make sure that the information they are conveying by way of that syntax MUST be logical. Today, what accountants creating such reports tend to do is represent the facts, leave out the rules, and then make errors in the representation of the facts and being ignorant of the errors because they did not provide the rules. Basically, accountants tend to use XBRL incorrectly. Focusing on the logic fixes that problem.

Further, rules are underutilized (actually, not really used at all) in the process of creating XBRL-based financial reports. And finally, accountants don’t really understand how to audit XBRL-based financial reports; they tend to focus on the syntax and not on the information conveyed.

This is all getting sorted out. The Accounting Equation and SFAC 6 Elements of Financial Statements examples will help communicate some important ideas such as the difference between syntax and semantics.

1 Like

Thanks.

I would have never imaged that accounting was not doing these types of validations.

I see a valid example: http://xbrlsite.azurewebsites.net/2019/Core/master-ae/instance.xml

Can you provide several other examples, some that are simple and each have a unique error and some that have several errors? It looks simple enough that using SWI-Prolog SGML/XML parser I might be able tomorrow to put the entire reading and error reporting together in one simple program.

This sounds like an interesting problem. Possibly it is too early for my favorite message: do not represent your knowledge/rules as executable Prolog. Instead, create a representation as Prolog terms that expresses the rules in a format your domain experts will like. Next, write a Prolog program that make them work. This can either be by interpreting them, compiling them to executable Prolog or even compile them into something else (JavaScript, C, …).

The first step is typically easy. The others are a bit harder, but can be delayed until you hit scalability issues.

Note that such a format make your domain experts happy and make it much simpler to reason about your rules and find inconsistencies, produce explanations, etc.

2 Likes

I know there must be great wisdom in what that means, but could you give me more details on how to actually do it. :thinking:

The problem as given already has the representation set

<!-- Created by Charles Hoffman, CPA: 2019-11-02 -->
<xbrl xmlns="http://www.xbrl.org/2003/instance" xmlns:xbrll="http://www.xbrl.org/2003/linkbase" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:iso4217="http://www.xbrl.org/2003/iso4217" xmlns:xbrldi="http://xbrl.org/2006/xbrldi" xmlns:xbrldt="http://xbrl.org/2005/xbrldt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ae="http://www.xbrlsite.com/financialreporting/ae" xsi:schemaLocation="http://xbrl.org/2006/xbrldi http://www.xbrl.org/2006/xbrldi-2006.xsd">
<xbrll:schemaRef xlink:href="ae.xsd" xlink:type="simple" xlink:arcrole="http://www.xbrl.org/2003/linkbase"/>
<xbrll:linkbaseRef xlink:type="simple" xlink:arcrole="http://www.w3.org/1999/xlink/properties/linkbase" xlink:href="ae-formula.xml"/>
<context id="I-2020">
<entity>
<identifier scheme="http://standards.iso.org/iso/17442">GH259400TOMPUOLS65II</identifier>
</entity>
<period>
<instant>2020-12-31</instant>
</period>
</context>
<unit id="U-Monetary">
<measure>iso4217:USD</measure>
</unit>
<ae:Assets contextRef="I-2020" unitRef="U-Monetary" decimals="INF">5000</ae:Assets>
<ae:Liabilities contextRef="I-2020" unitRef="U-Monetary" decimals="INF">1000</ae:Liabilities>
<ae:Equity contextRef="I-2020" unitRef="U-Monetary" decimals="INF">4000</ae:Equity>
</xbrl>

and since this is not a homework problem but a real world problem that I take has the data in that format for many years, I don’t see how the representation can be changed. Did/am I missing something. :confused:

I’m sure Jan can provide some good DSL examples.

Meanwhile, Anne’s SingGen is a good DSL example:

On a much smaller scale, I blogged recently on using user-defined test dialects to make it simpler for domain experts to write tests:
https://logtalk.org/2019/11/05/user-defined-test-dialects.html

1 Like

@pmoura

So is Jan suggesting to create a DSL (Domain Specific Language) and create user defined operators, in this case redefine/extend =/2 to do the checking?

Yes. You cannot redefine =/2, but it only means unification when it appears as a goal in a clause. In any other context it is just a term.

So, from the example you just want to say

asset = liability + equity.

Now, this is a Prolog fact redefining =/2 and thus illegal. You can write e.g.

constraint(asset = liability + equity).

and write a Prolog predicate that computes the three values (either from the Prolog database or some external storage or …) and validates the constraint.

The important thing is that you model your knowledge as Prolog terms using the vocabulary of your domain without worrying about computation first. You can use all Prolog’s dirty tricks with operators and/or SWI-Prolog’s quasi quotations to make it look as natural as you can.

1 Like