Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling an SDD into a PSDD #53

Closed
RenatoGeh opened this issue Jan 30, 2021 · 14 comments · Fixed by #56
Closed

Compiling an SDD into a PSDD #53

RenatoGeh opened this issue Jan 30, 2021 · 14 comments · Fixed by #56
Assignees
Labels
documentation Improvements or additions to documentation enhancement New feature or request

Comments

@RenatoGeh
Copy link
Contributor

Hi,

I don't know if I'm missing something from the docs or the code, but I couldn't seem to find any way to convert an SDD into a PSDD. What I want to do is load an SDD from a CNF/DNF like so

dnf = load_dnf(dnf_file)
sdd = compile(SddManager(Vtree(n, :random)), dnf)

and then learn through the LearnPSDD transformations. Except struct_learn only takes StructProbCircuits as argument and I couldn't find any function in Juice to convert an SddNode into StructProbCircuit. Is there no such function?

Thanks

@khosravipasha
Copy link
Contributor

I think you can try to do the following to get from LogicCircuit to ProbCircuit. (gotta douable check if it works with your code snippet)

pc = ProbCircuit(sdd);

An example in the code here: https://github.com/Juice-jl/ProbabilisticCircuits.jl/blob/0930ca0c6b9588908793f7dc942e5aa63e0d5739/test/plain_prob_nodes_tests.jl#L9-L14

But yeah, thanks for bringing this up, I think this would be a good addition to our docs and make it an easy API for it (if the one I suggested does not work).

@RenatoGeh
Copy link
Contributor Author

Hi Pasha. Thanks for the quick reply. Unfortunately your suggestion didn't work :( I get this error

ERROR: Cannot construct a probabilistic circuit from constant leafs: first smooth and remove unsatisfiable branches.
Stacktrace:
 [1] (::ProbabilisticCircuits.var"#f_con#84")(::SddFalseNode) at /home/renatogeh/.julia/packages/ProbabilisticCircuits/grgUo/src/structured_prob_nodes.jl:131
 [2] (::LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}})(::SddFalseNode) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:71
 [3] #foldup_aggregate_rec#21 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:238 [inlined]
 [4] (::LogicCircuits.Utils.var"#22#23"{StructProbCircuit,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}},LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}})(::SddFalseNode) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234
 [5] map!(::LogicCircuits.Utils.var"#22#23"{StructProbCircuit,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}},LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}}, ::Array{StructProbCircuit,1}, ::Array{SddLeafNode,1}) at ./abstractarray.jl:2155
 [6] foldup_aggregate_rec(::Sdd⋀Node, ::LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}}, ::LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}, ::Type{StructProbCircuit}; nload::typeof(nload), nsave::typeof(nsave)) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234
 [7] #22 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234 [inlined]
 [8] map!(::LogicCircuits.Utils.var"#22#23"{StructProbCircuit,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}},LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}}, ::Array{StructProbCircuit,1}, ::Array{Sdd⋀Node,1}) at ./abstractarray.jl:2155
 [9] #foldup_aggregate_rec#21 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234 [inlined]
 [10] #22 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234 [inlined]
 [11] map!(::LogicCircuits.Utils.var"#22#23"{StructProbCircuit,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}},LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}}, ::Array{StructProbCircuit,1}, ::Array{Sdd⋁Node,1}) at ./abstractarray.jl:2155
 [12] foldup_aggregate_rec(::Sdd⋀Node, ::LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}}, ::LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}, ::Type{StructProbCircuit}; nload::typeof(nload), nsave::typeof(nsave)) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234
 [13] #22 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234 [inlined]
 [14] map!(::LogicCircuits.Utils.var"#22#23"{StructProbCircuit,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}},LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}}, ::Array{StructProbCircuit,1}, ::Array{Sdd⋀Node,1}) at ./abstractarray.jl:2155
 [15] foldup_aggregate_rec(::Sdd⋁Node, ::LogicCircuits.var"#f_leaf#21"{StructProbCircuit,ProbabilisticCircuits.var"#f_con#84",ProbabilisticCircuits.var"#f_lit#85"{LogicCircuits.SddMgrInnerNode}}, ::LogicCircuits.var"#f_inner#22"{StructProbCircuit,ProbabilisticCircuits.var"#f_a#86",ProbabilisticCircuits.var"#f_o#87"}, ::Type{StructProbCircuit}; nload::typeof(nload), nsave::typeof(nsave)) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:234
 [16] foldup_aggregate(::Sdd⋁Node, ::Function, ::Function, ::Type{StructProbCircuit}; nload::Function, nsave::Function, reset::Bool) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:215
 [17] #foldup_aggregate#20 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:76 [inlined]
 [18] foldup_aggregate at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:70 [inlined]
 [19] compile at /home/renatogeh/.julia/packages/ProbabilisticCircuits/grgUo/src/structured_prob_nodes.jl:135 [inlined]
 [20] compile at /home/renatogeh/.julia/packages/ProbabilisticCircuits/grgUo/src/structured_prob_nodes.jl:118 [inlined]
 [21] compile at /home/renatogeh/.julia/packages/ProbabilisticCircuits/grgUo/src/structured_prob_nodes.jl:112 [inlined]
 [22] ProbCircuit(::Sdd⋁Node) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/abstract_logic_nodes.jl:130

When trying to smooth the SDD before with smooth(sdd), I get

ERROR: MethodError: no method matching conjoin(::Array{SddLiteralNode,1}; reuse=(-1,2))
Closest candidates are:
  conjoin(::SddFalseNode, ::SddFalseNode) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/sdd/apply.jl:11 got unsupported keyword argument "reuse"
  conjoin(::SddFalseNode, ::SddTrueNode) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/sdd/apply.jl:4 got unsupported keyword argument "reuse"
  conjoin(::SddFalseNode, ::Sdd) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/sdd/apply.jl:9 got unsupported keyword argument "reuse"
  ...
Stacktrace:
 [1] (::LogicCircuits.var"#f_a#124")(::Sdd⋀Node, ::LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:22
 [2] f_inner at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:48 [inlined]
 [3] #foldup_rec#18 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:197 [inlined]
 [4] callback at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:196 [inlined]
 [5] #120 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:25 [inlined]
 [6] _mapreduce(::LogicCircuits.var"#120#127"{LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}}, ::typeof(union), ::IndexLinear, ::Array{Sdd⋀Node,1}) at ./reduce.jl:408
 [7] _mapreduce_dim at ./reducedim.jl:318 [inlined]
 [8] #mapreduce#620 at ./reducedim.jl:310 [inlined]
 [9] mapreduce at ./reducedim.jl:310 [inlined]
 [10] (::LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}})(::Sdd⋁Node, ::LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:25
 [11] f_inner at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:48 [inlined]
 [12] #foldup_rec#18 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:197 [inlined]
 [13] callback at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:196 [inlined]
 [14] #119 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:18 [inlined]
 [15] map!(::LogicCircuits.var"#119#125"{LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}},BitSet}, ::Array{Node,1}, ::Array{Sdd⋁Node,1}) at ./abstractarray.jl:2155
 [16] (::LogicCircuits.var"#f_a#124")(::Sdd⋀Node, ::LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:17
 [17] f_inner at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:48 [inlined]
 [18] #foldup_rec#18 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:197 [inlined]
 [19] callback at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:196 [inlined]
 [20] #120 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:25 [inlined]
 [21] _mapreduce(::LogicCircuits.var"#120#127"{LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}}, ::typeof(union), ::IndexLinear, ::Array{Sdd⋀Node,1}) at ./reduce.jl:408
 [22] _mapreduce_dim at ./reducedim.jl:318 [inlined]
 [23] #mapreduce#620 at ./reducedim.jl:310 [inlined]
 [24] mapreduce at ./reducedim.jl:310 [inlined]
 [25] (::LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}})(::Sdd⋁Node, ::LogicCircuits.Utils.var"#callback#19"{Tuple{Node,BitSet},typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#18"{Tuple{Node,BitSet},LogicCircuits.var"#f_con#122",LogicCircuits.var"#f_lit#123"},LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}}}) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:25
 [26] (::LogicCircuits.var"#f_inner#19"{Tuple{Node,BitSet},LogicCircuits.var"#f_a#124",LogicCircuits.var"#f_o#126"{Dict{Int32,LogicCircuit}}})(::Sdd⋁Node, ::Function) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:48
 [27] #foldup_rec#18 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:197 [inlined]
 [28] #foldup#17 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/Utils/graphs.jl:179 [inlined]
 [29] #foldup#17 at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:49 [inlined]
 [30] foldup at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/queries.jl:47 [inlined]
 [31] smooth(::Sdd⋁Node) at /home/renatogeh/.julia/packages/LogicCircuits/Mesmi/src/transformations.jl:33

@khosravipasha
Copy link
Contributor

Uh yes, currently the smoothing does not work properly for structured decomposable circuits (for example psdds) Tractables/LogicCircuits.jl#43. In addition you might need to also do propagate_constants.

How do you make the SDDs, do you make them in Juice or do you have them as sdd format?

One quick hack until we fix these could be changing your .sdd files and add paramters (arbitrary) to them so they become .psdd files and then load them from file in Juice. Then, you can call paramter learning or even structure learning on top of that as needed.

Or if you are making the circuits in Juice, can directly do them in ProbCircuit. Some examples here: https://github.com/Juice-jl/JuiceExamples/blob/master/Juice-Example.ipynb

For example:

X1, X2, X3 = literals(ProbCircuit, 3)
pc = 0.3 * (X1[1] * 
             (0.2X2[1] + 0.8X3[2])) + 
     0.7 * (X1[2] *
             (0.4X2[2] + 0.6X3[1]))

Give you the following circuit:
image

@khosravipasha khosravipasha added documentation Improvements or additions to documentation enhancement New feature or request labels Jan 30, 2021
@RenatoGeh
Copy link
Contributor Author

I'm compiling them from a DNF file.

dnf = load_dnf(dnf_file)
sdd = compile(SddManager(Vtree(n, :random)), dnf)

@RenatoGeh
Copy link
Contributor Author

Hi,

So I hacked something up to convert SDDs to PSDDs, and it does seem to work on the CNFs I'm working on. Once I have the time I'll open a PR and do some other tests so we can have this in Juice.

Thanks

@khosravipasha
Copy link
Contributor

Awesome, thanks, this would be a good feature, to have.

@eliavw
Copy link

eliavw commented Feb 24, 2021

Hi, so it seems I'm more or less struggling with a very similar issue.

I'm starting from .sdd files, rather than from a dnf. But ultimately, the goal is also to convert the sdd into a psdd and learn the parameters on data.

Currently, this is my workflow (as per a suggestion made above):

c = load_logic_circuit("my_sdd.sdd")
c2 = smooth(c);
c3 = propagate_constants(c2);
pc = ProbCircuit(c3);

And that seems to work well enough.

However, this then fails as soon as I want to actually use this PSDD circuit, for instance to compute likelihoods of fully observed data like so;

EVI(pc, some_data)

This is where I get stuck on the following error:

AssertionError: BitCircuits only support AND gates with at least two children

Stacktrace:
 [1] (::LogicCircuits.var"#f_and#12")(::PlainMulNode, ::Array{NodeIds,1}) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:114
 [2] f_inner at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/queries.jl:73 [inlined]
 [3] #foldup_aggregate_rec#21 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:236 [inlined]
 [4] (::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}})(::PlainMulNode) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234
 [5] map!(::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}}, ::Array{NodeIds,1}, ::Array{PlainProbCircuit,1}) at ./abstractarray.jl:2155
 [6] #foldup_aggregate_rec#21 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234 [inlined]
 [7] (::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}})(::PlainMulNode) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234
 [8] map!(::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}}, ::Array{NodeIds,1}, ::Array{PlainProbCircuit,1}) at ./abstractarray.jl:2155
 [9] foldup_aggregate_rec(::PlainSumNode, ::LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}}, ::LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}, ::Type{NodeIds}; nload::typeof(nload), nsave::typeof(nsave)) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234
 [10] #foldup_aggregate#20 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:215 [inlined]
 [11] #foldup_aggregate#20 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/queries.jl:75 [inlined]
 [12] BitCircuit(::PlainSumNode, ::Int64; reset::Bool, on_decision::ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}}) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:161
 [13] #BitCircuit#7 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:74 [inlined]
 [14] ParamBitCircuit(::PlainSumNode, ::DataFrame; reset::Bool) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/param_bit_circuit.jl:21
 [15] ParamBitCircuit at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/param_bit_circuit.jl:10 [inlined]
 [16] log_likelihood_per_instance(::PlainSumNode, ::DataFrame; use_gpu::Bool) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/queries/likelihood.jl:26
 [17] log_likelihood_per_instance(::PlainSumNode, ::DataFrame) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/queries/likelihood.jl:23
 [18] top-level scope at In[12]:4
 [19] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091

Any pointers to what I am doing wrong?

Thanks.
-E

@khosravipasha
Copy link
Contributor

@eliavw yeah it seems there is some issue with smoothing. We are trying to simplify this workflow but have not pushed the changes yet.

In the meanwhile: If the SDD you have is already smooth then you don't have to call smoothing: Have you tried the following? Or maybe even without the propogate_constants.

c = load_logic_circuit("my_sdd.sdd")
c2 = propagate_constants(c);
pc = ProbCircuit(c2);

@khosravipasha
Copy link
Contributor

khosravipasha commented Feb 25, 2021

@RenatoGeh What solution did you end up using in the end? Basically trying to streamline the whole workflow in different situtaions so wanted to know what solved the problem for you. For now we have this two scenarios:

  1. DNF/CNF -> Compile to SDD -> Convert to PC
  2. Given SDD -> Convert to PC

The main issue seems to come from smoothing (Tractables/LogicCircuits.jl#43). The random.sdd is not smooth, for example.

@RenatoGeh
Copy link
Contributor Author

I wrote a quick hack to convert an SDD into a PSDD. Strangely, although it did work in my use cases (it outputs a smooth, decomposable, deterministic, vtree respecting PSDD consistent with the CNF/DNF), it sometimes doesn't work. Anyway, I kept this as a WIP PR (#56) until I find out what's wrong.

@eliavw
Copy link

eliavw commented Feb 25, 2021

@eliavw yeah it seems there is some issue with smoothing. We are trying to simplify this workflow but have not pushed the changes yet.

In the meanwhile: If the SDD you have is already smooth then you don't have to call smoothing: Have you tried the following? Or maybe even without the propogate_constants.

c = load_logic_circuit("my_sdd.sdd")
c2 = propagate_constants(c);
pc = ProbCircuit(c2);

@khosravipasha , thanks for the quick reply!

So, as for your suggestion, that does not work unfortunately. The SDDs I want to convert to PSDDs are compiled using the pysdd package, which just calls the SDD package.
These SDDs I obtain that way are not necessarily smooth it seems, nor is there any functionality to enforce it. Of course, I could be missing something trivial, I'm still a novice when it comes to circuits.

So, just to provide some info on where I'm at;

c = load_logic_circuit("my_sdd.sdd")
c2 = propagate_constants(c);
pc = ProbCircuit(c2);

yields this error

AssertionError: BitCircuits only support AND gates with at least two children

Stacktrace:
 [1] (::LogicCircuits.var"#f_and#12")(::PlainMulNode, ::Array{NodeIds,1}) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:114
 [2] f_inner at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/queries.jl:73 [inlined]
 [3] #foldup_aggregate_rec#21 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:236 [inlined]
 [4] (::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}})(::PlainMulNode) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234
 [5] map!(::LogicCircuits.Utils.var"#22#23"{NodeIds,typeof(nload),typeof(nsave),LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}},LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}}, ::Array{NodeIds,1}, ::Array{PlainProbCircuit,1}) at ./abstractarray.jl:2155
 [6] foldup_aggregate_rec(::PlainSumNode, ::LogicCircuits.var"#f_leaf#21"{NodeIds,LogicCircuits.var"#f_con#9",LogicCircuits.var"#f_lit#10"{Int64}}, ::LogicCircuits.var"#f_inner#22"{NodeIds,LogicCircuits.var"#f_and#12",LogicCircuits.var"#f_or#13"{ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}},Array{Array{Int32,1},1},Array{Int32,1},Array{Int32,1},Array{Array{Int32,1},1}}}, ::Type{NodeIds}; nload::typeof(nload), nsave::typeof(nsave)) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:234
 [7] #foldup_aggregate#20 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/Utils/graphs.jl:215 [inlined]
 [8] #foldup_aggregate#20 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/queries.jl:75 [inlined]
 [9] BitCircuit(::PlainSumNode, ::Int64; reset::Bool, on_decision::ProbabilisticCircuits.var"#on_decision#42"{Array{Float64,1}}) at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:161
 [10] #BitCircuit#7 at /home/zissou/.julia/packages/LogicCircuits/G8c43/src/bit_circuit.jl:74 [inlined]
 [11] ParamBitCircuit(::PlainSumNode, ::DataFrame; reset::Bool) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/param_bit_circuit.jl:21
 [12] ParamBitCircuit at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/param_bit_circuit.jl:10 [inlined]
 [13] log_likelihood_per_instance(::PlainSumNode, ::DataFrame; use_gpu::Bool) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/queries/likelihood.jl:26
 [14] log_likelihood_per_instance(::PlainSumNode, ::DataFrame) at /home/zissou/.julia/packages/ProbabilisticCircuits/1xCSr/src/queries/likelihood.jl:23
 [15] top-level scope at In[26]:1
 [16] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091

Which I'm guessing is due to the original SDD not being smooth, as you already mentioned. To be clear

is_smooth(c)

yields False, so I do know for a fact my SDD obtained from the SDD package is not smooth. So the question seems to boil down to finding a workflow to somehow enforce smooth SDDs; either on the side of the SDD package itself, or here. Or finding a creative hack that circumvents this issue altogether.

Anyways, thanks for the feedback already. I'm now gonna take a closer look at @RenatoGeh solution and see if it could apply to my case as well.

@eliavw
Copy link

eliavw commented Feb 25, 2021

Hi, so just to give you an update on what works and what doesn't.

Disregarding my SDD and just importing my BK as CNF and following @RenatoGeh's workflow seems to work well on my (toy) data for now. The PSDDs that come out behave as expected.

I also tried a bit more in converting my SDDs directly;

circuit = load_logic_circuit(filename)

# Initialize VTree with correct amount of vars
vtree = Vtree(num_variables(circuit), :balanced)
mgr = SddMgr(vtree)
    
# Add structure to the logic circuit (i.e. vtree)
struct_circuit = StructLogicCircuit(mgr, circuit)
struct_circuit = propagate_constants(struct_circuit; remove_unary=true)

# Convert to probabilistic circuit
prob_circuit = StructProbCircuit(mgr, struct_circuit)
psdd = convert(StructProbCircuit, prob_circuit)
psdd

which sure enough works all the way up to and including parameter estimation. But... if you then do an EVI-query the results are off (probabilities do not sum to one), so somewhere along the way the workflow above still introduces errors.

Going forward, I'll disregard my SDDs for the time being and directly read in BK from CNF files. Thanks for the feedback and quick replies here.

@khosravipasha
Copy link
Contributor

@eliavw Good, glad that the workaround works for now. This boils down to the smoothness issue, we will be fixing the smoothness issue, for us till now it has not been a big deal since we direclty learn psdds from data. Easy conversion of SDD/CNF/DNF into probabilistic circuits is definely something we like to support.

But... if you then do an EVI-query the results are off (probabilities do not sum to one), so somewhere along the way the workflow above still introduces errors

Yeah, in most cases we impclicity assume smoothness for our query implementations. I will try to make those assumptions more explicit in the documentation. Without assuming smoothnes the implementations become a bit more complicated.

@talf301
Copy link
Member

talf301 commented Mar 3, 2021

With Tractables/LogicCircuits.jl#69, structured smoothing should be supported (though for now you have to smooth the logic circuit). You can see the new tests in that PR for examples of how to use structured smoothing - the only requirement is that you propagate constants first.

Once you've done that you can convert a structured logic circuit to a probabilistic one with
prob_circ = compile(StructProbCircuit, log_circ)

Let me know if you find something that doesn't work or cases that break smoothing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants