# EYE Components for FGCM -- Gijs Muys

@prefix log: <http://www.w3.org/2000/10/swap/log#>.
@prefix fl: <http://eulersharp.sourceforge.net/2003/03swap/fl-rules#>.
@prefix e: <http://eulersharp.sourceforge.net/2003/03swap/log-rules#>.
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
@prefix fgcm: <http://eulersharp.sourceforge.net/2006/02swap/fgcm-plugin#>.
@prefix math: <http://www.w3.org/2000/10/swap/math#>.
@prefix dco: <http://www.debugit.eu/ontology/1.0/dco.owl#>.

{(?A ?B ?UnknownVar) fl:gpi (?C1 ?C2)} <=
{
    ?SCOPE e:call {
        ("if_then_else"
            {
                ("nb_getval" "fnet" "done") log:pro true.
            }
            true
            {
                (";"
                    {
                        () fgcm:expandClosureGmu true.
                        () fgcm:expandClosureGsigma true.
                        (?UnknownVar) fgcm:handleUnknownVariables true.
                        (?A 1) fgcm:iterate ?IterationsNeeded.
                        ("nb_setval" "IterationsNeeded" ?IterationsNeeded) log:pro true.
                    }
                    {
                        ("nb_setval" "fnet" "done") log:pro true.
                    }
                ) log:pro true
            }
        ) log:pro true.
        ("nb_getval" "IterationsNeeded" ?IterationsNeeded) log:pro true.
        ?A fgcm:gpi (?B ?MembershipLower ?MembershipUpper ?IterationsNeeded).
        ("if_then_else"
            {
                ?SCOPE e:closure {(?A ?B) fl:gpi (?FixedMembershipLower ?FixedMembershipUpper)}.
            }
            {
                ?C1 log:equalTo ?FixedMembershipLower.
                ?C2 log:equalTo ?FixedMembershipUpper.
            }
            {
                ?C1 log:equalTo ?MembershipLower.
                ?C2 log:equalTo ?MembershipUpper.
            }
        ) log:pro true.
    }
}.

{(?A ?B ?UnknownVar) fl:gpiWhitenized ?C} <=
{
    ?SCOPE e:call {
        ("if_then_else"
            {
                ("nb_getval" "fnet" "done") log:pro true.
            }
            true
            {
                (";"
                    {
                        () fgcm:expandClosureGmu true.
                        () fgcm:expandClosureGsigma true.
                        (?UnknownVar) fgcm:handleUnknownVariables true.
                        (?A 1) fgcm:iterate ?IterationsNeeded.
                        ("nb_setval" "IterationsNeeded" ?IterationsNeeded) log:pro true.
                    }
                    {
                        ("nb_setval" "fnet" "done") log:pro true.
                    }
                ) log:pro true
            }
        ) log:pro true.
        ("nb_getval" "IterationsNeeded" ?IterationsNeeded) log:pro true.
        ?A fgcm:gpi (?B ?MembershipLower ?MembershipUpper ?IterationsNeeded).
        ("if_then_else"
            {
                ?SCOPE e:closure {(?A ?B) fl:gpi (?FixedMembershipLower ?FixedMembershipUpper)}.
            }
            {
                (?FixedMembershipLower ?FixedMembershipUpper) fgcm:whitenize ?C.
            }
            {
                (?MembershipLower ?MembershipUpper) fgcm:whitenize ?C.
            }
        ) log:pro true.
    }
}.

#Expand deductive closure
#In the context of statements, a deductive closure is the set of all the statements that can be deduced from a given set of statements.

#Initialize given variable values
{() fgcm:expandClosureGmu true} <=
{
    ("forall"
        {
            (?X ?Y) fl:gmu (?Z ?Q).
        }
        {
            ("if_then_else"
                {
                    (?X) fgcm:fm true.
                }
                true
                {
                    ("assertz" {(?X) fgcm:fm true}) log:pro true.
                }
            ) log:pro true.
            ("assertz" {?X fgcm:gpi (?Y ?Z ?Q 0)}) log:pro true.
        }
    ) log:pro true.
}.

#Setup model
{() fgcm:expandClosureGsigma true} <=
{
    ("forall"
        {
            (?X ?Y) fl:gsigma (?V6 ?V7).
        }
        {
            ("if_then_else"
                {
                    (?X) fgcm:fs true.
                }
                true
                {
                    ("assertz" {(?X) fgcm:fs true}) log:pro true.
                }
            ) log:pro true.
            ("if_then_else"
                {
                    (?Y) fgcm:fs true.
                }
                true
                {
                    ("assertz" {(?Y) fgcm:fs true}) log:pro true.
                }
            ) log:pro true.
        }
    ) log:pro true.
}.

{(?UnknownVar) fgcm:handleUnknownVariables true} <= {
    ("if_then_else"
        {
            ("=" ?UnknownVar true) log:pro true.
        }
        {
            () fgcm:assignUnknownVariables true.
        }
        true
    ) log:pro true.
}.

#If variable value unknown, initialize value as [0,1]
{() fgcm:assignUnknownVariables true} <=
{

    (?Observable) fgcm:fm true.
    ("forall"
        {
            (?Node) fgcm:fs true.
        }
        {
            ("if_then_else"
                {
                    ?Observable fgcm:gpi (?Node ?MembershipLower ?MembershipUpper 0).
                }
                true
                {
                    ("assertz" {?Observable fgcm:gpi (?Node 0.0 1.0 0)}) log:pro true.
                }
            ) log:pro true.
        }
    ) log:pro true.
}.

#Calculates the sum of a list of tuples. eg [(1,1),(2,3)] = (3,4)
{(?List ?Acc) fgcm:tupleSum ?Acc} <=
{
    ?List log:equalTo ().
}.

{(?Hs (?A1 ?A2)) fgcm:tupleSum ?C} <=
{
    ?Hs e:firstRest ((?H1 ?H2) ?Tail).
    ("_H1+_A1" ?H1 ?A1) e:calculate ?NewA1.
    ("_H2+_A2" ?H2 ?A2) e:calculate ?NewA2.
    (?Tail (?NewA1 ?NewA2)) fgcm:tupleSum ?C.
}.

#Keeps on iterating until the difference between subsequent iterations is small enough. Maximum of 1000 iterations allowed
{(?A ?NbIterations) fgcm:iterate ?IterationsNeeded} <=
{
    ("if_then_else"
        {
            ("=<" ?NbIterations 1000) log:pro true.
        }
        {
            ("_NbIterations-1" ?NbIterations) e:calculate ?PrevNbIterations.
            (?A ?PrevNbIterations) fgcm:getNodes ?NodesPreviousValue.
            (";"
                {
                    (?PrevNbIterations ?NbIterations) fgcm:calculateNodes true.
                    #always fails once all nodes have been calculated
                }
                {
                    (?PrevNbIterations ?NbIterations) fgcm:refresh true.
                    (?A ?NbIterations) fgcm:getNodes ?NodesCurrentValue.
                    ("=" ?Epsilon 0.001) log:pro true.
                    ("if_then_else"
                        {
                            (?NodesPreviousValue ?NodesCurrentValue ?Epsilon) fgcm:differenceBelowEpsilon true.
                        }
                        {
                            ("=" ?IterationsNeeded ?NbIterations) log:pro true.
                        }
                        {
                            ("_NbIterations+1" ?NbIterations) e:calculate ?NewNbIterations.
                            (?A ?NewNbIterations) fgcm:iterate ?IterationsNeeded.
                        }
                    ) log:pro true.
                }
            ) log:pro true.
        }
        {
            ("throw" "Maximum number of iterations (1000) reached") log:pro true.
        }
    ) log:pro true.
}.

#Calculates nodes for one iteration. Once all nodes have been processed, method fails.
{(?PrevNbIterations ?NbIterations) fgcm:calculateNodes true} <=
{
    (?Observable) fgcm:fm true.
    (?Node) fgcm:fs true.
    ("findall"
        (?MinProduct ?MaxProduct)
        {
            (?IncomingNode ?Node) fl:gsigma (?EdgeLower ?EdgeUpper).
            ?Observable fgcm:gpi (?IncomingNode ?MembershipLower ?MembershipUpper ?PrevNbIterations).

            #Some networks use edge weights [0,1] instead of [-1,1], conversion necessary
            ("2*_EdgeLower-1" ?EdgeLower) e:calculate ?TempEdgeLower.
            ("2*_EdgeUpper-1" ?EdgeUpper) e:calculate ?TempEdgeUpper.

            #FCM UTI network required nodes to be in [-1,1] interval as well
            ("2*_MembershipLower-1" ?MembershipLower) e:calculate ?TempMembershipLower.
            ("2*_MembershipUpper-1" ?MembershipUpper) e:calculate ?TempMembershipUpper.

            ("_TempEdgeLower*_TempMembershipLower" ?TempEdgeLower ?TempMembershipLower) e:calculate ?ProductLL.
            ("_TempEdgeLower*_TempMembershipUpper" ?TempEdgeLower ?TempMembershipUpper) e:calculate ?ProductLU.
            ("_TempEdgeUpper*_TempMembershipLower" ?TempEdgeUpper ?TempMembershipLower) e:calculate ?ProductUL.
            ("_TempEdgeUpper*_TempMembershipUpper" ?TempEdgeUpper ?TempMembershipUpper) e:calculate ?ProductUU.

            ("min_list" (?ProductLL ?ProductLU ?ProductUL ?ProductUU) ?MinProduct) log:pro true.
            ("max_list" (?ProductLL ?ProductLU ?ProductUL ?ProductUU) ?MaxProduct) log:pro true.
        }
        ?L
    ) log:pro true.

    ("if_then_else"
        {
            ?L log:equalTo ().
        }
        true
        {
            (?L (0 0)) fgcm:tupleSum (?S1 ?S2).
            ("1/(1+exp(-_S1))" ?S1) e:calculate ?Z1.
            ("1/(1+exp(-_S2))" ?S2) e:calculate ?Z2.
            ("assertz" {?Observable fgcm:gpi (?Node ?Z1 ?Z2 ?NbIterations)}) log:pro true.
        }
    ) log:pro true.
    ("fail") log:pro true.
}.

#If node has been given a new value current iteration, nothing happens
#If node has not been given a new value current iteration, its value of previous iteration is taken and added to current iteration
{(?Prev ?Cur) fgcm:refresh true} <=
{
    ("forall"
        {
            (?Node) fgcm:fs true.
        }
        {
            ("if_then_else"
                {
                    ?Observable fgcm:gpi (?Node ?MembershipLower ?MembershipUpper ?Cur).
                }
                {
                    ("retractall" {?Observable fgcm:gpi (?Node ?V1 ?V2 ?Prev)}) log:pro true.
                }
                {
                    ("if_then_else"
                        {
                            ?Observable fgcm:gpi (?Node ?MembershipLower ?MembershipUpper ?Prev).
                        }
                        {
                            ("assertz" {?Observable fgcm:gpi (?Node ?MembershipLower ?MembershipUpper ?Cur)}) log:pro true.
                            ("retractall" {?Observable fgcm:gpi (?Node ?V1 ?V2 ?Prev)}) log:pro true.
                        }
                        {
                        }
                    ) log:pro true.
                }
            ) log:pro true.

        }
    ) log:pro true.
}.

#Retrieves all nodes of given iteration
{(?A ?NbIterations) fgcm:getNodes ?Nodes} <=
{
    ("findall"
        (?MembershipLower ?MembershipUpper)
        {
            ?A fgcm:gpi (?V1 ?MembershipLower ?MembershipUpper ?NbIterations).
        }
        ?Nodes #Sequence of nodes will be the same every iteration so no need to remember which node belongs to which lower & upper membership
    ) log:pro true.
}.

#Returns true if difference between two given lists is less than given epsilon
{(?H1s ?H2s ?Epsilon) fgcm:differenceBelowEpsilon true} <=
{
    ?H1s e:firstRest ((?H1LowerMembership ?H1UpperMembership) ()).
    ?H2s e:firstRest ((?H2LowerMembership ?H2UpperMembership) ()).
    (?H1LowerMembership ?H2LowerMembership) fgcm:absoluteSubtraction ?LowerSubtraction.
    (?H1UpperMembership ?H2UpperMembership) fgcm:absoluteSubtraction ?UpperSubtraction.
    ("=<" ?LowerSubtraction ?Epsilon) log:pro true.
    ("=<" ?UpperSubtraction ?Epsilon) log:pro true.
}.

{(?H1s ?H2s ?Epsilon) fgcm:differenceBelowEpsilon ?Result} <=
{
    ?H1s e:firstRest ((?H1LowerMembership ?H1UpperMembership) ?T1).
    ?H2s e:firstRest ((?H2LowerMembership ?H2UpperMembership) ?T2).
    (?T1) log:notEqualTo ().
    (?T2) log:notEqualTo ().
    (?H1LowerMembership ?H2LowerMembership) fgcm:absoluteSubtraction ?LowerSubtraction.
    (?H1UpperMembership ?H2UpperMembership) fgcm:absoluteSubtraction ?UpperSubtraction.
    ("if_then_else"
        {
            ("=<" ?LowerSubtraction ?Epsilon) log:pro true.
            ("=<" ?UpperSubtraction ?Epsilon) log:pro true.
        }
        {
            (?T1 ?T2 ?Epsilon) fgcm:differenceBelowEpsilon ?Result.
        }
        {
            ("=" ?Result false) log:pro true.
        }
    ) log:pro true.

}.

#abs(A-B)
{(?A ?B) fgcm:absoluteSubtraction ?C} <=
{
    ("abs(_A-_B)" ?A ?B) e:calculate ?C.
}.

{(?Left ?Right) fgcm:whitenize ?Result} <=
{
    ("_Left+(_Right-_Left)/2" ?Right ?Left) e:calculate ?Result.
}.
