:- module(autobuild_causal_groups,
    [
    find_causal_groups/0
    ]).

/** <module> Causal Groups : Automatic model building

@author Carsten van Weelden <mailto:cweelden@science.uva.nl>

*/


%% find_causal_groups
% Finds sets of super clusters belonging to the same causal group. Super clusters in the same causal group are linked by naive proportionalities. Adds the causal groups to the database
find_causal_groups :-
    get_single_quantity_from_each_super_cluster(Quantities),
    generate_causal_quantity_groups(Quantities, Quantities, AllCausalQuantityGroups),
    list_to_set(AllCausalQuantityGroups, CausalQuantityGroups),
    forall(
	member(CausalQuantityGroup, CausalQuantityGroups),
	(
	    findall(SuperClusterID,
	        (
		    member(Quantity, CausalQuantityGroup),
		    get_super_cluster(Quantity, SuperClusterID)
		),
            CausalGroup),
	    add_causal_group(CausalGroup),
	    format("Found causal group: ~w~n", [CausalGroup])
	)
     ).
    
generate_causal_quantity_groups(_, [], []).
generate_causal_quantity_groups(AllQuantities, Quantities, [CausalGroup | CausalGroups]) :-
    member(Quantity, Quantities),
    grow_causal_quantity_group([Quantity], AllQuantities, UnsortedCausalGroup),
    sort(UnsortedCausalGroup, CausalGroup),
    subtract(Quantities, [Quantity], RestQuantities),
    generate_causal_quantity_groups(AllQuantities, RestQuantities, CausalGroups).

grow_causal_quantity_group(CausalGroup, [], CausalGroup).
grow_causal_quantity_group(SeedQuantities, [Quantity | Quantities], CausalGroup) :-
    \+ member(Quantity, SeedQuantities),
    forall( %Only need to check one seed?  
        member(SeedQuantity, SeedQuantities),
	( %Only need to check one-way proportionality?
            (
	        naive_dependency(prop_pos(SeedQuantity, Quantity)),
	        naive_dependency(prop_pos(Quantity, SeedQuantity))
	        ;
	        naive_dependency(prop_neg(SeedQuantity, Quantity)),
	        naive_dependency(prop_neg(Quantity, SeedQuantity))
            ),
            get_super_cluster(SeedQuantity, SuperCluster1),
            get_super_cluster(Quantity, SuperCluster2),
            \+ same_object_group(SuperCluster1, SuperCluster2)
	)
    ),
    grow_causal_quantity_group([Quantity | SeedQuantities], Quantities, CausalGroup).
grow_causal_quantity_group(SeedQuantities, [_ | Quantities], CausalGroup) :-
    grow_causal_quantity_group(SeedQuantities, Quantities, CausalGroup).

%% same_object_group(+SuperCluster1, +SuperCluster2)
% Two superclusters represent the same type of object group if they contain the same types of quantities belonging to the same type of entities.
same_object_group(SuperCluster1, SuperCluster2) :-
    get_all_super_cluster_quantities(SuperCluster1, Quantities1),
    get_all_super_cluster_quantities(SuperCluster2, Quantities2),
    get_quantity_types(Quantities1, QuantityTypes1),
    get_quantity_types(Quantities2, QuantityTypes2),
    list_to_set(QuantityTypes1, QuantitySet1),
    list_to_set(QuantityTypes2, QuantitySet2),
    subtract(QuantitySet1, QuantitySet2, []),
    get_quantity_entity_types(Quantities1, Entities1),
    get_quantity_entity_types(Quantities2, Entities2),
    list_to_set(Entities1, EntitiesSet1),
    list_to_set(Entities2, EntitiesSet2),
    subtract(EntitiesSet1, EntitiesSet2, []).

