Represent Accounting Equation Using SWI-Prolog

XBRL is interesting but I’m not sure what does correct usage mean here. I can imagine consistent usage with the consistency being defined between different types of reports: balance sheet, profit, and cash flow. Besides this, there are tons of other types of reports, like gov taxes, employment expenses etc. Of course, all of them have to be consistent with those 3 main reports and each other. Correctness, on the other hand, would mean XBRL’s true representation of entity’s business transactions, which is likely a non-automatable task. In Estonia, we file annuals electronically, and filing an XBRL file is one of the options. I have not used it but I have used the form-based entry. It has extensive validation between the reports but I don’t know how it’s been implemented.

I have built two accounting systems in Prolog. One of them I use every day for doing daily accounting for my Estonian company. Prolog is perfect for this. The system itself is very simple and includes both the API interface (frontend is a trivial SPA) and “logic” in 300 lines of code. It uses a simple journaled database to record grouped credit/debit lines. The way how entries are recorded guaratees that the accounting equation is always satisfied. Account balances and cash flows are calculated with the most basic aggregation. Prolog is fast enough, no tabling is neccessary. It’s been audited and found be a good system. XBRL is a very complicated file format and adding support for generating reports in it takes way more effort than just using the simple form-based entry of the gov registry and filling it with the aggregated values from my own system.

I was wondering whether mode directed incremental tabling could be made so intelligent, that your 300 lines of codes reduce to 100 lines of codes. For example I suggested the following trigger under the hood, as a result of incremental tabling algorithm:

assertz_journal(F) :-
   assertz(F),
   retractall_table(account_end(_,_)),
   retractall_table(book_ok(_)).

But another trigger would be also possible, if we could reach into the tabled data. Since there is no simple standard API, I guess it would involve using the trie or whatever datastructure, I can nevertheless demonstrate the idea.

Assume instead of tabling, we have compute the tabling result by some other means and store it in dynamic facts. Then changes to the journal can be updated by the following trigger:

assertz_journal(booking(B,T,F,V)) :-
   assertz(booking(B,T,F,V)),
   retract(account_end(F,H)),
   J is H-V,
   assertz(account_end(F,J)),
   retract(account_end(T,K)),
   L is K+V,
   assertz(account_end(T,L)).

If a system could do this automatically for mode directed tabled predicates, this would be quite fun. The advantage of a network of table predicates is that they can express sharing. And incremental tabling would propage changes in that results are not unnecessarely calculated many times.

See also (random internet pick):
https://www.cs.cmu.edu/~jgc/publication/Incremental_Aggregation_ISMIS_2006.pdf

In my view, the focus should not be the XBRL syntax; rather, the focus should be on the fact that because the information is “digitized” and machine-readable, then automation of accounting, reporting, auditing, and analysis tasks are possible. You may be interested in these two documents:

General Ledger Trial Balance to External Financial Report

Accounting in the Fourth Industrial Revolution

So, a couple of questions about your Prolog accounting system. Would it be possible to modify the accounting system to (a) add an XBRL concept to the accounting system as a property of each account in the chart of accounts, (b) add a transaction grouping code (which is an XBRL concept) to each journal entry, and © try and output the XBRL instance from the journal entries and an XBRL taxonomy. Basically, this XBRL instance.

For the back of your mind, OMG (Object Management Group) is creating what they call the Standard Business Report Model (SBRM) which makes the question of syntax rather moot. Use whatever syntax you might want, or use the syntax that a regulator REQUIRES you to use.

I know someone who might be very interested in your Prolog accounting system, particularly if it could leverage logic articulated within an XBRL taxonomy to manage and monitor transaction entry and output a financial report.

I used to teach accounting information systems. I have a very basic accounting system that I created in Microsoft Access. The interface is adequate, but because I am not a very good programmer I did not take the time to get the “innards” of the system working. You seem to have the “innards” and with a few modifications I suspect you can get your system to do what I have been trying to do. If you are interested, I would love to put your pieces and my pieces together. Here is a prototype transaction entry form that I created.

If you are interested, I can give you a lot more information on this topic.

I’m not sure if the response was meant for me. Out of these 300 lines, most are for handling API requests. The code is here: https://github.com/rla/expenses/blob/93bde49da7f4ebab9384d7e9917437b030b65f08/api.pl

There could be some opportunities for caching but I never saw any perf issues, even over multiple years and thousands of entries per year. Endpoints just take tens of milliseconds to execute. I think it’s mostly thanks to SWI’s automatic indexing which makes docstore (the underlying database) very fast. It’s written long time ago in “dict processing” style before tabling was available and tabling would be difficult to employ with this style I think.

Yeah, I cannot do anything with the prolog code; I would need to rely on someone else to actually build what I am talking about. I am a certified public accountant, not a programmer.

Also, here is something else that can help you and others think about this. Imagine taking a financial report, breaking it apart logically so that it is 100% machine readable. THAT is what XBRL does. Imagine that you wanted to leverage the fact that now computers can probe the report using automated processes (i.e. there was NO WAY to do this before financial statements where created using XBRL. So, say you take the XBRL, feed it to some sort of reasoner (i.e. prolog is a reasoner) and then you reasoned about the facts in the financial report. THAT is incredibly useful in two ways. First, if you use logical reasoning to MAKE SURE the report was put together in the first place. That checks the logical structure, mechanics of the report, mathematics, some other things, etc. That is what Auditing XBRL-based Financial Reports discusses. Then, you might even want to get into auditing the information in the report and accounting system. THAT is what companies like MindBridge and AI assisted Audits are all about.

Check this out. Grant Reporting Efficiency and Agreements Transparency Act. That will require 320,000 not-for-profit organizations to report against U.S. Federal Government grants using machine-readable form as opposed to what amounts to “e-paper”. This sort of thing is happening all across the world. This is a multi-billion dollar opportunity globally.

No joke.

It’s never too late to learn programming :slight_smile:

Anyway, the app could be modified to accept extra data on the account records which name the account and specify the type of account (asset, etc.). Types are currently hardcoded. If the XBRL concept is represented using a string, then that could be easily added as a text field.

Each entry contains a list of lines, each with credit and debit side (account references), the amount in cents, and the date. Base currency of EUR is hardcoded but the original amount in the original currency can also be entered. One entry has multiple lines because it’s very convenient to group certain entries together, for example, receiving a foreign currency invoice, doing conversion, paying the invoice, recording reverse vat charge, and copy/paste this as a whole for every month for recurring expenses. This speeds up data entry and solving inconsistencies later.

So an example entry data is (for the invoice case):

entry{
  '$id':'8dd8e9e5-be68-41c7-addb-9878a07c342a',
  title:"Linode invoice 11854109"
  items:[
    item{
      amount:1000,
      credit:'076a3de0-d5cb-454c-aa9b-fad22e0086ae',
      currency:usd,
      date:1541030400,
      debit:'4332dd24-b20d-4f6e-a148-64d7db04e119',
      eur_amount:878,
      title:"Invoice amount"
    },
    item{
      amount:1000,
      credit:'355bac91-8098-4caa-a703-42a4a13868ed',
      currency:usd,
      date:1541116800,
      debit:'076a3de0-d5cb-454c-aa9b-fad22e0086ae',
      eur_amount:878,
      title:"Invoice paid"
    },
    item{
      amount:15,
      credit:'355bac91-8098-4caa-a703-42a4a13868ed',
      currency:eur,
      date:1541116800,
      debit:'574f6fda-cd6e-449d-aaa2-c86d04ce7254',
      eur_amount:15,
      title:"USD/EUR conversion result including transfer fee"
    },
    item{
      amount:176,
      credit:'7ab3a21c-150d-412a-abb7-aa5b59aacd5e',
      currency:eur,
      date:1541116400,
      debit:'4332dd24-b20d-4f6e-a148-64d7db04e119',
      eur_amount:176,
      title:"VAT referse charge"
    }
  ]
}.

and this is how it’s represented in the user interface https://ibb.co/Wgtp3s9

Any report could be calculated from this data at any point of time (not just the latest) including reporting intervals. The system could be easily modified to have entry of “transaction grouping code” for each item although from purely human-readable analytic view, I can imagine an alternative solution by just using separate accounts of same type, like income “Sales from EU”, “Sales from US”, etc. to make them display separated under aggregate reports, for example, when it’s required to report sales income from different regions.

The data itself is accessible through the database query system. For example, this entry was obtained using query ds_col_get(entry, '8dd8e9e5-be68-41c7-addb-9878a07c342a', E). It uses https://www.swi-prolog.org/pack/list?p=docstore

That is a very nice interface. So imagine your accounting system, but you do NOT hard code the accounts in the system. You specify the accounts using XBRL. Basically, the information in XBRL serves somewhat like the chart of accounts plus the metadata of a report writer.

The transaction grouping codes are not in the chart of accounts. They represent the ROLL FORWARDS of each real (balance sheet) account.

I guess you have also some cut over functions, for end of year, or every quarter of year. End of year you need to close the income and expenses accounts, and correct the balance. I am affraid I don’t know the english names for these bigger use cases which are not related with data entry.

Can you start a new book from an old book in your system? In Switzerland thats the step where you get in contact with governement and big reporting time, because then taxes are determined etc… Also there are standards for different business types, called GAAP FER.

But usually what is recommended for taxes, without the negative connotation of shadow booking, is a secondary book or report. This gives the external tax view which does not need to correspond with the internal business view. So usually you have a couple of external and internal views.

Not only. You can invalidate a table explicitly. If your incremental tabled program depends on some external database you can invalidate the table(s) that directly depend on the database. If you can somehow get a trigger that the database changed, it all works automatically.

Incremental shared tabling works in SWI. It is not yet extensively tested though, so I would not rely on it for production usage. One reason is that for most of the tabling XSB provided a rich set of tests, but this is novel ground, so we have to roll our own tests. If anyone has an interesting application for shared incremental tabling, please step forward and see how we can cooperate. This actually also applies for shared tabling alone as this never became really stable in XSB and thus (again) there are is no good test suite.

Since tabling variants incremental and/or shared in SWI-Prolog are new, it seems they are also not known to the public. So it might take some time to find test cases, or lets say real world uses.

The problem with invalidating tables, this doesn’t work for mode directed tabling so well. Mode directed tabling does form aggregates:

" In this execution model one or more arguments are not added to the table. Instead, we remember a single aggregated value for these arguments."
https://www.swi-prolog.org/pldoc/man?section=tabling-mode-directed

When you invalidate a variant key, the whole aggregate for this variant key needs to be recalculated. But there are circumstances, where an aggregate could be updated more directly.

Sure. So far the only real-world test for incremental tabling is pharos. The SWI port is not yet integrated. It was unexpectedly simple to port and ran without issues right away after adding the necessary XSB library and built-in emulation. Since than some work was done on improving pharos and SWI-Prolog’s incremental tabling. It now also outperforms XSB on most of the pharos tests.

The analysis is not yet complete. XSB tabling is surely faster than SWI. It seems SWI’s tabling is starting to get fairly reliable though and SWI seems to outperform XSB on dealing with many dynamic predicates that have a lot of indexing requirements. The good news is that it does this without any indexing declarations while the XSB version is driven by indexing declarations.

2 Likes

Charles, thanks. Only the types (asset, liability, etc.) are hard-coded, not the accounts. Accounts can be added and updated using the user interface.

I had no idea that XBRL can encode or contain chart of accounts. But indeed it seems to be a one of the main concepts of XBRL and the extensibility of XBRL comes from ability to add custom accounts. I think that if I could associate each account with XBRL concept, then indeed I could automatically produce statements in XBRL format!

There is no closing or opening. You just don’t use multi-year aggregates and just add opening entries manually at the beginning of each year based on your last year annual report :slight_smile: This is a tradeoff of simplicity versus convenience.

Estonia has two accounting standards, RTJ and IFRS. IFRS is like the actual standard, also used elsewhere, RTJ is more like a set of guidelines concerning mostly special cases like biological assets. Everything else is just based on barebones double-entry accounting. There is no standard chart of accounts, some companies manage with using just those 5 accounts presented in the accounting formula and an Excel worksheet.

Estonia has no corporate income tax, or income tax benefits. This just makes lots of different income reports unnecessary. This is a pretty unique system in the world but it makes lots of reporting much easier, especially for small companies. From me, they don’t even ask for a cash flow report anymore.

This is a stark contrast from Soviet times (ended in Estonia about 1991) where accounting rules were much more strict and unified to support the planned economy. There were even strict rules how many accountants each organization, factory or plant had to have. If soviets had been able to produce more computers (which they failed due to planned, not demand-based economy) they would have likely been the first to do large-scale standards-based automation of financial reporting.

It seems like integration with docstore would be nearly trivial by declaring docstore:eav/3 as incrementral(true). The question is whether this is useful, since every modification of the database would trigger it.

That is also the case for dynamic predicates. Dependent tabling goals are not re-evaluated though. They are merely flagged as needing reevaluation. If you call one of the invalid tabled predicates it will re-evaluate the table. It does so starting from the dependent tables closest to the dynamic predicate(s). If a table re-evaluates to the same set of answers it re-validates dependent tables (if they only depend on this table). I.e., the re-evaluation is lazy. The system recomputes entire tables though (where it is surely sometimes possible to merely propagate a new fact). This is all pretty much the same as in XSB.

Thanks. That is an important and interesting fact to know! I can see it give huge boost to applications that mostly read data and write infrequently.

Note that the two examples that this group helped me to create are being provided with the examples/proof of concepts for the Standard Business Reporting Model (SBRM). Again, thank you very much to all of you in this group.

For more information on Standard Business Report Model (SBRM). (SBRM is still a work in progress but you can see where this is going. This is about a logical conceptualization of a business report (including financial reports), not about the XBRL syntax or any other specific syntax. If ZERO regulators used XBRL, the logical model of a business report would still be incredibly useful. Think semantic spreadsheet.