How to create a factor that connects to more than 4 variables?

38 views
Skip to first unread message

Yuhuan Jiang

unread,
Oct 20, 2015, 4:07:28 PM10/20/15
to Factorie
Hi, 

I have a question about factors. How do I create a factor that can (1) connect to more than 4 variables, and (2) be used in the built-in loopy belief propagation? Details are as follows:

Let's say I have 5 variables:
val v1 = new BooleanVariable(true)
val v2 = new BooleanVariable(false)
val v3 = new BooleanVariable(true)
val v4 = new BooleanVariable(false)
val v5 = new BooleanVariable(false)

Now, I would like to have a factor that connects to all 5 variables. No documentation is provided on how to do this, so I spent some time reading the source code, and ended up with this:
val globalFactor = new Factor { outer ⇒
  def numVariables: Int = variables.length
  def variables: Seq[factorie.Var] = Array(v1, v2, v3, v4, v5)
  def currentScore: Double = assignmentScore(currentAssignment)
  def assignmentScore(a: Assignment): Double = { ... }
  def variable(index: Int): factorie.Var = variables(index)

  def currentAssignment: Assignment = new Assignment { inner ⇒
    def variables: Iterable[factorie.Var] = outer.variables
    def get(v: factorie.Var): Option[v.Value] = Some(v.value)
    def apply(v: factorie.Var): v.Value = v.value
    def contains(v: factorie.Var): Boolean = outer.variables contains v
  }
}

However, this did not work when I needed to perform the following inference:
val model = new ItemizedModel(globalFactor)
val summary = InferByBPLoopy.infer(List(v1, v2, v3, v4, v5), model)

I soon discovered that the reason is that the implementation of the loopy belief propagation in InferByBPLoopy only considers Factor1 through Factor4. My globalFactor is a general Factor, and will not match any case. To show this, I list Lines 41 through 62 in the code file cc.factorie.infer.BP.scala as follows: 
// Excerpt from cc.factorie.infer.BP.scala

41    factor match {
42      case factor:Factor1[DiscreteVar @unchecked] => { ... }
44      case factor:Factor2[DiscreteVar @unchecked,DiscreteVar @unchecked] => { ... }
49      case factor:Factor3[VectorVar @unchecked,
                            VectorVar @unchecked,VectorVar @unchecked] => { ... }
58      case factor: Factor4[DiscreteVar @unchecked, DiscreteVar @unchecked, 
                             DiscreteVar @unchecked, DiscreteVar @unchecked] => { ... }
63    }

Having realized this, I then tried to write a Factor1 that connects to a Vars object that contains the 5 variables. So I created:
val vs = Vars(Array(v1, v2, v3, v4, v5))
val globalFactor = new Factor1(vs) {
  def score(vs: Seq[BooleanValue]): Double = { ... }
}

However, this failed again when I perform the same inference as in my previous approach, and asked summary to return the marginal of the global factor: 
val model = new ItemizedModel(globalFactor)
val summary = InferByBPLoopy.infer(vs, model)
summary.marginal(globalFactor)


I got the following run-time exception:
Method threw 'java.util.NoSuchElementException' exception.
    detailMessage = key not found: Factor(Vars(BooleanVariable(true),BooleanVariable(false),BooleanVariable(true),BooleanVariable(false),BooleanVariable(false)))


Can anyone please help me with this? Again, my question is: how to create a factor that can (1) connect to more than 4 variables, and (2) be used in the built-in loopy belief propagation. 

Thanks!

Regards,
Yuhuan
Reply all
Reply to author
Forward
0 new messages