Represent Accounting Equation Using SWI-Prolog

Regarding…

I’ve implemented accounting systems (not using Prolog) and can assure you that Prolog (or Datalog) would be a fine way of adding business rules to databases.

This is good information.

What are your thoughts on Answer Set Programming?

The conformance suite is public domain, free for anyone to use.

So I have a proposal that might help you meet your needs. This example, Common Elements of Financial Statements, is small but very comprehensive example. It is also well documented.

What I could do is create a new conformance suite for you that would help you achieve what is is that you want to achieve. In my view, it would be really great to be able to convert XBRL into SWI-Prolog. In fact, what would be REALLY useful would be to import XBRL into SWI-Prolog directly (not sure if I am explaining this precisely).

I have created this informally defined logical model of a business report, Open Source Framework for Implementing XBRL-based Digital Financial Reporting. Those would be the preferable terms to use.

Also, of use might be my “standard” explanation of a logical system terms.

The objective of all this is to be able to explain the logic of a business report (note that a financial report is a specialization of the more general business report).

Answer Set Programming (ASP) is the opposite end of the spectrum from Datalog. :wink:

A step back from ASP is constraint solving (there are a number of such solvers within SWI-Prolog). These are very powerful and can be quite efficient. But debugging constraint solvers can be difficult – the constraint solver says “no” but doesn’t give a hint as to why because there are an infinite number of ways that the constraints can’t be solved. (As an experiment, one of our PhD interns tried using a boolean satisfiability solver to infer Python datatypes; even trivial programs ended up with millions of constraints, which were impossible to debug.)

So, if you use constraints – and I think that they’re a great way of doing certain things – you need to think about how the constraint solver would explain failures. If the constraints can be thought of an extension to how Prolog computes a solution (e.g., using freeze/2 to delay goals until sufficiently instantiated), they are fairly easy to use; more sophisticated constraints can be a challenge.

Thanks.

Let me do the basic conformance items first to get my feet in the water and better understand the accounting terms then we can expand on it from there. I don’t want to bite off more than I can chew.

Also and I noted to another programmer many years ago when she could not understand that I did not learn about debits and credits in school is that I have a BS and not a BA. In other words the STEM stuff is more of my knowledge and this accounting problem will help to expand my knowledge. :grinning:

Peter, what is your view of OWL as contrast to Prolog/Datalog? One of the reasons OMG is interested in SBRM is so that they can get XBRL converted to RDF/OWL. Both XBRL processors and OWL/RDF have limitations in terms of their capabilities to process the logic of a financial report. With XBRL, you have to add some specific things and I know what those are. With OWL/RDF; you also have to use SHACL (Shapes Constraint Language) . I will know exactly how much you need to use SHACL within a couple of days most likely. What would be really good to understand is what Prolog/Datalog might be missing.

You might be interested in this; here is information that explains double-entry accounting in terms of mathematics. Double-entry accounting is basic freshman algebra.

Notations such as OWL (or “Semantic Web” or “RDF” or …) are more constrained than Datalog or Prolog. In return, computations over OWL ontologies can be more efficient because of the restrictions.

In the “old days”, there was a lot of work with systems such as KL-ONE, which turned out to have almost intractable problems with defining concepts such as “is-a” versus “has-attribute” (e.g., you might define a class of “red object” but what about objects that have an attribute “color=red”?). These problems endure, but are often swept under the rug by proponents of simple ontological representation systems.

It’s been many years since I’ve worked on this; and I don’t consider myself very competent in it. You might want read http://www.jfsowa.com/ or ask a question on http://gnowledge.org/pipermail/cg/ or Redirecting to Google Groups – people such as John Sowa or Harry Delugach (and many others whose names I don’t remember off-hand) know far more about this than I ever will.

Here is the some proof of concept code that reads the sample XBLR data and checks that the formula

Assets = Liabilities + Equity

is true.

I originally tried to read the data with the SGML parser but it expected end tags instead of tags that ended with /> which was causing more problems than it was worth. As this is the first time I have used either the SGML or XML parser with SWI-Prolog, probably something I need to learn, I could not find an option for allowing tags ending with />.

Note: Click triangle below to expand section.

Proof of concept code
xbrl(Xbrl,Assets,Liabilities,Equity) :-
    Xbrl = element(xbrl,_,Elements),
    elements(Elements,Assets,Liabilities,Equity), !.

elements([],0,0,0).
elements([element('ae:Assets',_,Value_list)|Elements],Assets,Liabilities,Equity) :-
    Value_list = [Value_atom],
    atom_number(Value_atom,Value),
    elements(Elements,Assets0,Liabilities,Equity),
    Assets is Assets0 + Value.
elements([element('ae:Liabilities',_,Value_list)|Elements],Assets,Liabilities,Equity) :-
    Value_list = [Value_atom],
    atom_number(Value_atom,Value),
    elements(Elements,Assets,Liabilities0,Equity),
    Liabilities is Liabilities0 + Value.
elements([element('ae:Equity',_,Value_list)|Elements],Assets,Liabilities,Equity) :-
    Value_list = [Value_atom],
    atom_number(Value_atom,Value),
    elements(Elements,Assets,Liabilities,Equity0),
    Equity is Equity0 + Value.
elements([_|T],Assets,Liabilities,Equity) :-
    elements(T,Assets,Liabilities,Equity).

does_balance_sheet_balance(Assets,Liabilities,Equity) :-
    Assets is Liabilities + Equity.

:- begin_tests(xblr).

test(01) :-
    Xblr_string =
        "<!--  Created by Charles Hoffman, CPA: 2019-11-02  -->\n\c
        <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\">\n\c
        <xbrll:schemaRef xlink:href=\"ae.xsd\" xlink:type=\"simple\" xlink:arcrole=\"http://www.xbrl.org/2003/linkbase\"/>\n\c
        <xbrll:linkbaseRef xlink:type=\"simple\" xlink:arcrole=\"http://www.w3.org/1999/xlink/properties/linkbase\" xlink:href=\"ae-formula.xml\"/>\n\c
        <context id=\"I-2020\">\n\c
        <entity>\n\c
        <identifier scheme=\"http://standards.iso.org/iso/17442\">GH259400TOMPUOLS65II</identifier>\n\c
        </entity>\n\c
        <period>\n\c
        <instant>2020-12-31</instant>\n\c
        </period>\n\c
        </context>\n\c
        <unit id=\"U-Monetary\">\n\c
        <measure>iso4217:USD</measure>\n\c
        </unit>\n\c
        <ae:Assets contextRef=\"I-2020\" unitRef=\"U-Monetary\" decimals=\"INF\">5000</ae:Assets>\n\c
        <ae:Liabilities contextRef=\"I-2020\" unitRef=\"U-Monetary\" decimals=\"INF\">1000</ae:Liabilities>\n\c
        <ae:Equity contextRef=\"I-2020\" unitRef=\"U-Monetary\" decimals=\"INF\">4000</ae:Equity>\n\c
        </xbrl>",
    open_string(Xblr_string,Stream),
    load_xml(Stream,[Xbrl],[]),
    xbrl(Xbrl,Assets,Liabilities,Equity),
    does_balance_sheet_balance(Assets,Liabilities,Equity).

:- end_tests(xblr).

Example run.

You will need to change to the appropriate directory on your system.

?- working_directory(_,'c:/users/eric/documents/Projects/Prolog/xbrl').
true.

?- consult("xbrl.pl").
true.

?- run_tests.
% PL-Unit: xblr . done
% test passed
true.

I took a detailed look at some of the files in XBRL-based Digital Financial Reporting Conformance Suite Tests and while I could identify the values, it was not simple Assets, Liabilities and Equity as I expected so I didn’t know what kind of rules to write for it or how to view it to make sense. I did see the dates you noted earlier for the range checks you needed. :grinning:

There are zillion of options. But, e.g., <img .../> is not legal SGML AFAIK. Most likely that means the format is XML. If I recall well, HTML5 mode also allows for this. Not sure though. Given the right options it can parse almost any SGML/XML/HTML document, sometimes with warnings. Note that using simple DCGs or other simple pattern matching is quite likely to go wrong at some point. There are a lot of legal different serializations for the same document in all these dialects.

1 Like

It works perfectly fine, without warnings:

$ swipl
Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.15-10-g6718ecfeb)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

?- load_xml('instance.xml', T, []).
T = [element(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', ... = ...|...], ['\n\n  ', element('xbrll:schemaRef', ['xlink:href'='ae.xsd', 'xlink:type'=simple, 'xlink:arcrole'='http://www.xbrl.org/2003/linkbase'], []), '\n\n  ', element('xbrll:linkbaseRef', ['xlink:type'=simple, ... = ...|...], []), '\n\n   ', element(context, [...], [...|...]), '\n\n   '|...])].

instance.xml is the XML file linked, found exactly here.

Here is some more details on the reading of instance.xml .

In reading the documentation for package SWI-Prolog SGML/XML parser it notes in section 10 Unsupported SGML features

SHORTTAG
The SGML SHORTTAG syntax is only partially implemented. Currently, <tag/content/ is a valid abbreviation for <tag>content</tag> , which can also be written as <tag>content</> . Empty start tags ( <> ), unclosed start tags ( <a<b</verb> ) and unclosed end tags ( <verb></a<b ) are not supported.

This is not a show stopper as I have shown with the proof of concept code and as Jan notes there are other ways that can be more beneficial to deal with this.

The reason I am not exploring them in more detail at present is that I would like to see the code related to the validity rules and then other business concepts that might be implemented before optimizing the code. As this code has not been written yet, that is the next logical step. The rule of thumb “Premature optimization is the root of all evil” applies at this time.

To make the issue with the end tags more apparent, when I was writing the code I made use of print_term/2 but removed them in the presented version.

The output is presented here for closer inspection.

Use of load_sgml/3 and print_term/2
?- load_sgml('instance.xml',Xbrl,[]),print_term(Xbrl,[]).
Warning: SGML2PL(sgml): instance.xml:19: Inserted omitted end-tag for "xbrll:linkbaseref"
Warning: SGML2PL(sgml): instance.xml:19: Inserted omitted end-tag for "xbrll:schemaref"
[ element(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'
          ],
          [ element('xbrll:schemaref',
                    [ 'xlink:href' = 'ae.xsd',
                      'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.xbrl.org/2003/linkbase'
                    ],
                    [ '>\n',
                      element('xbrll:linkbaseref',
                              [ 'xlink:type' = simple,
                                'xlink:arcrole' = 'http://www.w3.org/1999/xlink/properties/linkbase',
                                'xlink:href' = 'ae-formula.xml'
                              ],
                              [ '>\n',
                                element(context,
                                        [id='I-2020'],
                                        [ element(entity,
                                                  [],
                                                  [ element(identifier,
                                                            [ scheme = 'http://standards.iso.org/iso/17442'
                                                            ],
                                                            [ 'GH259400TOMPUOLS65II'
                                                            ])
                                                  ]),
                                          element(period,
                                                  [],
                                                  [ element(instant,
                                                            [],
                                                            [ '2020-12-31'
                                                            ])
                                                  ])
                                        ]),
                                element(unit,
                                        [id='U-Monetary'],
                                        [ element(measure,
                                                  [],
                                                  ['iso4217:USD'])
                                        ]),
                                element('ae:assets',
                                        [ contextref = 'I-2020',
                                          unitref = 'U-Monetary',
                                          decimals = 'INF'
                                        ],
                                        ['5000']),
                                element('ae:liabilities',
                                        [ contextref = 'I-2020',
                                          unitref = 'U-Monetary',
                                          decimals = 'INF'
                                        ],
                                        ['1000']),
                                element('ae:equity',
                                        [ contextref = 'I-2020',
                                          unitref = 'U-Monetary',
                                          decimals = 'INF'
                                        ],
                                        ['4000'])
                              ])
                    ])
          ])
]
Xbrl = [element(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', ... = ...|...], [element('xbrll:schemaref', ['xlink:href'='ae.xsd', 'xlink:type'=simple, 'xlink:arcrole'='http://www.xbrl.org/2003/linkbase'], ['>\n', element('xbrll:linkbaseref', ['xlink:type'=simple, ... = ...|...], ['>\n', element(..., ..., ...)|...])])])].
Use of load_xml/3 and print_term/2
?- load_xml('instance.xml',Xbrl,[]),print_term(Xbrl,[]).
[ element(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'
          ],
          [ '\n',
            element('xbrll:schemaRef',
                    [ 'xlink:href' = 'ae.xsd',
                      'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.xbrl.org/2003/linkbase'
                    ],
                    []),
            '\n',
            element('xbrll:linkbaseRef',
                    [ 'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.w3.org/1999/xlink/properties/linkbase',
                      'xlink:href' = 'ae-formula.xml'
                    ],
                    []),
            '\n',
            element(context,
                    [id='I-2020'],
                    [ '\n',
                      element(entity,
                              [],
                              [ '\n',
                                element(identifier,
                                        [ scheme = 'http://standards.iso.org/iso/17442'
                                        ],
                                        ['GH259400TOMPUOLS65II']),
                                '\n'
                              ]),
                      '\n',
                      element(period,
                              [],
                              ['\n',element(instant,[],['2020-12-31']),'\n']),
                      '\n'
                    ]),
            '\n',
            element(unit,
                    [id='U-Monetary'],
                    ['\n',element(measure,[],['iso4217:USD']),'\n']),
            '\n',
            element('ae:Assets',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['5000']),
            '\n',
            element('ae:Liabilities',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['1000']),
            '\n',
            element('ae:Equity',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['4000']),
            '\n'
          ])
]
Xbrl = [element(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', ... = ...|...], ['\n', element('xbrll:schemaRef', ['xlink:href'='ae.xsd', 'xlink:type'=simple, 'xlink:arcrole'='http://www.xbrl.org/2003/linkbase'], []), '\n', element('xbrll:linkbaseRef', ['xlink:type'=simple, ... = ...|...], []), '\n', element(context, [...], [...|...]), '\n'|...])].

As is evident with load_xml/3 as used the tag endings are resulting in \n, however these are not disrupting the hierarchy for parsing the data structure.

On the other hand load_sgml/3 as used the tag endings are resulting in \n, and these are disrupting the hierarchy for parsing the data structure.

Using load_html/3 as suggested by Jan seems to not suffer from the end tag issue.

Use of load_html/3 and print_term/2
?- load_html('instance.xml',Xbrl,[]),print_term(Xbrl,[]).
[ element(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'
          ],
          [ element('xbrll:schemaref',
                    [ 'xlink:href' = 'ae.xsd',
                      'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.xbrl.org/2003/linkbase'
                    ],
                    []),
            element('xbrll:linkbaseref',
                    [ 'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.w3.org/1999/xlink/properties/linkbase',
                      'xlink:href' = 'ae-formula.xml'
                    ],
                    []),
            element(context,
                    [id='I-2020'],
                    [ element(entity,
                              [],
                              [ element(identifier,
                                        [ scheme = 'http://standards.iso.org/iso/17442'
                                        ],
                                        ['GH259400TOMPUOLS65II'])
                              ]),
                      element(period,
                              [],
                              [element(instant,[],['2020-12-31'])])
                    ]),,
            element(unit,
                    [id='U-Monetary'],
                    [element(measure,[],['iso4217:USD'])]),
            element('ae:assets',
                    [contextref='I-2020',unitref='U-Monetary',decimals='INF'],
                    ['5000']),
            element('ae:liabilities',
                    [contextref='I-2020',unitref='U-Monetary',decimals='INF'],
                    ['1000']),
            element('ae:equity',
                    [contextref='I-2020',unitref='U-Monetary',decimals='INF'],
                    ['4000'])
          ])
]
Xbrl = [element(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', ... = ...|...], [element('xbrll:schemaref', ['xlink:href'='ae.xsd', 'xlink:type'=simple, 'xlink:arcrole'='http://www.xbrl.org/2003/linkbase'], []), element('xbrll:linkbaseref', ['xlink:type'=simple, 'xlink:arcrole'='http://www.w3.org/1999/xlink/properties/linkbase', 'xlink:href'='ae-formula.xml'], []), element(context, [id='I-2020'], [element(entity, [], [element(..., ..., ...)]), element(period, [], [...])]), element(unit, [id='U-Monetary'], [element(measure, [], [...])]), element('ae:assets', [... = ...|...], ['5000']), element('ae:liabilities', [...|...], [...]), element(..., ..., ...)])].

Again, I do not see any of this as a show stopper, just a learning exercise.

Although I understand this is not your current priority, I think it is wise to point at features of the SGML/HTML/XML parser.

As @Boris shows, the document is XML. <x/> is XML and not valid SGML. White space is by default all part of the document in XML, unless the xml:space attribute says otherwise. SWI-Prolog’s XML parser however can be told to process the document otherwise. See https://www.swi-prolog.org/pldoc/man?section=xml-whitespace

1 Like

Thanks Jan.

With load_xml/3 and using the option space(remove) the XML loads without the end tag issue.

Use of load_xml/3 and option space(remove) with print_term/2
?- load_xml('instance.xml',Xbrl,[space(remove)]),print_term(Xbrl,[]).
[ element(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'
          ],
          [ element('xbrll:schemaRef',
                    [ 'xlink:href' = 'ae.xsd',
                      'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.xbrl.org/2003/linkbase'
                    ],
                    []),
            element('xbrll:linkbaseRef',
                    [ 'xlink:type' = simple,
                      'xlink:arcrole' = 'http://www.w3.org/1999/xlink/properties/linkbase',
                      'xlink:href' = 'ae-formula.xml'
                    ],
                    []),
            element(context,
                    [id='I-2020'],
                    [ element(entity,
                              [],
                              [ element(identifier,
                                        [ scheme = 'http://standards.iso.org/iso/17442'
                                        ],
                                        ['GH259400TOMPUOLS65II'])
                              ]),
                      element(period,
                              [],
                              [element(instant,[],['2020-12-31'])])
                    ]),
            element(unit,
                    [id='U-Monetary'],
                    [element(measure,[],['iso4217:USD'])]),
            element('ae:Assets',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['5000']),
            element('ae:Liabilities',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['1000']),
            element('ae:Equity',
                    [contextRef='I-2020',unitRef='U-Monetary',decimals='INF'],
                    ['4000'])
          ])
]
Xbrl = [element(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', ... = ...|...], [element('xbrll:schemaRef', ['xlink:href'='ae.xsd', 'xlink:type'=simple, 'xlink:arcrole'='http://www.xbrl.org/2003/linkbase'], []), element('xbrll:linkbaseRef', ['xlink:type'=simple, 'xlink:arcrole'='http://www.w3.org/1999/xlink/properties/linkbase', 'xlink:href'='ae-formula.xml'], []), element(context, [id='I-2020'], [element(entity, [], [element(..., ..., ...)]), element(period, [], [...])]), element(unit, [id='U-Monetary'], [element(measure, [], [...])]), element('ae:Assets', [... = ...|...], ['5000']), element('ae:Liabilities', [...|...], [...]), element(..., ..., ...)])].

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.

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.