All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.clulab.reach.darpa.NegationHandler.scala Maven / Gradle / Ivy

The newest version!
package org.clulab.reach.darpa

import org.clulab.odin._
import org.clulab.reach.mentions._
import org.clulab.struct.Interval


object NegationHandler {

  def detectNegations(mentions: Seq[Mention], state:State): Seq[Mention] = {
    // do something very smart to handle negated events
    // and then return the mentions

    // Iterate over the BioEventMentions
    mentions foreach {
        case event:BioEventMention =>

          val dependencies = event.sentenceObj.dependencies

          /////////////////////////////////////////////////
          // Check the outgoing edges from the trigger looking
          // for a neg label
          val outgoing = dependencies match {
            case Some(deps) => deps.outgoingEdges
            case None => Array.empty
          }

          for{
            tok <- event.tokenInterval
            out <- outgoing.lift(tok)
            (ix, label) <- out
            if label == "neg"
          }
            event.modifications += Negation(new BioTextBoundMention(
              Seq("Negation_trigger"),
              Interval(ix),
              sentence = event.sentence,
              document = event.document,
              keep = event.keep,
              foundBy = event.foundBy
            ))
          ///////////////////////////////////////////////////

          ///////////////////////////////////////////////////
          // Check for the presence of some negative verbs
          // in all the sentence except the tokens

          // First, extract the trigger's range from the mention
          val interval = event.trigger.tokenInterval

          //val pairs = for (lemma <- event.lemmas) yield (1, lemma)
          val pairs = event.tokenInterval zip event.lemmas.get

          val pairsL = pairs takeWhile (_._1 < interval.start)
          val pairsR = pairs dropWhile (_._1 <= interval.end)

          // Get the evidence for the existing negations to avoid duplicates
          val evidence:Set[Int] = event.modifications flatMap {
                  case mod:Negation => mod.evidence.tokenInterval
                  case _ => Nil
              }

          // Check for single-token negative verbs
          for{
            (ix, lemma) <- (pairsL ++ pairsR)
            if (Seq("fail", "not") contains lemma) && !(evidence contains ix)
          }{
              event.modifications += Negation(new BioTextBoundMention(
                Seq("Negation_trigger"),
                Interval(ix),
                sentence = event.sentence,
                document = event.document,
                keep = event.keep,
                foundBy = event.foundBy
              ))
            }

          def flattenTuples(left:(Int, String), right:(Int, String)) = {
            (
              (left._1, right._1),
              (left._2, right._2)
            )
          }

          val verbs = Seq(("play", "no"), ("play", "little"), ("is", "not"), ("be", "insufficient"))
          // Introduce bigrams for two-token verbs in both sides of the trigger
          for(side <- Seq(pairsL, pairsR)){
            val bigrams = (side zip side.slice(1, side.length)) map (x =>
              flattenTuples(x._1, x._2)
            )

            for{
              (interval, bigram) <- bigrams
              if (verbs contains bigram) && (evidence intersect (interval._1 to interval._2+1).toSet).isEmpty
            }
              {
                event.modifications += Negation(new BioTextBoundMention(
                Seq("Negation_trigger"),
                Interval(interval._1, interval._2 + 1),
                sentence = event.sentence,
                document = event.document,
                keep = event.keep,
                foundBy = event.foundBy
              ))}

          }
          ///////////////////////////////////////////////////
        case _ => ()
    }

    mentions
  }

  // Alter Negation modifications in-place
  def handleNegations(ms: Seq[BioMention]): Unit = {
    ms foreach { m =>
      val (negMods, other) = m.modifications.partition(_.isInstanceOf[Negation])
      val negationModifications = negMods.map(_.asInstanceOf[Negation])

      // count the negations
      negationModifications match {
        // 0 or 1 Neg modifications means no change...
        case noChange if noChange.size <= 1 => ()
        // if we have an even number of Negations, remove them all
        case pos if pos.size % 2 == 0 =>
          m.modifications = other
        // if we have an odd number, report only the first...
        case neg if neg.size % 2 != 0 =>
          val singleNeg =
            negationModifications
              .toSeq
              .sortBy(_.evidence.tokenInterval)
              .head
          m.modifications = other + singleNeg
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy