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

com.kotlinnlp.neuralparser.parsers.lhrparser.helpers.CyclesFixer.kt Maven / Gradle / Ivy

/* Copyright 2018-present KotlinNLP Authors. All Rights Reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 * -----------------------------------------------------------------------------*/

package com.kotlinnlp.neuralparser.parsers.lhrparser.helpers

import com.kotlinnlp.dependencytree.DependencyTree
import com.kotlinnlp.lssencoder.decoder.ScoredArcs

/**
 * Naive strategy to fix possible cycles in a [dependencyTree].
 *
 * @param dependencyTree the dependency tree
 * @param scoredArcs the scored arcs between pair of tree elements
 */
internal class CyclesFixer(private val dependencyTree: DependencyTree, private val scoredArcs: ScoredArcs) {

  /**
   * The set of direct elements of the tree (elements that aren't involved in cycles).
   */
  private lateinit var directElements: Set

  /**
   * Fix the cycles of the dependency tree.
   */
  fun fixCycles() {

    val cycles: List = this.dependencyTree.getCycles()

    this.directElements = this.dependencyTree.elements.toSet() - cycles.toElementsSet()

    cycles.forEach { this.fixCycle(it) }
  }

  /**
   * @return the set of elements from a list of path
   */
  private fun List.toElementsSet(): Set {

    val elements = mutableSetOf()
    this.forEach { path -> elements += path.arcs.map { it.dependent } }
    return elements
  }

  /**
   * Remove a [cycle] from the dependency tree.
   *
   * @param cycle a cycle of the dependency tree
   */
  private fun fixCycle(cycle: DependencyTree.Path) {

    val dep: Int = this.removeLowestScoringArc(cycle.arcs)
    val (newGov: Int, score: Double) = this.findBestGovernor(dep)
    this.dependencyTree.setArc(dependent = dep, governor = newGov, score = score)
  }

  /**
   * Remove the lowest scoring arc and return the related dependent to be reattached.
   *
   * @param arcs a list of arcs
   *
   * @return the element to be reattached.
   */
  private fun removeLowestScoringArc(arcs: List): Int {

    val arc: DependencyTree.Arc = this.getLowestScoringArc(arcs)
    this.dependencyTree.removeArc(dependent = arc.dependent, governor = arc.governor)
    return arc.dependent
  }

  /**
   * @param arcs a list of arcs
   *
   * @return the lowest scoring arc according to the [scoredArcs].
   */
  private fun getLowestScoringArc(arcs: List): DependencyTree.Arc =
    arcs.minBy { arc -> this.scoredArcs.getScore(dependentId = arc.dependent, governorId = arc.governor) }!!

  /**
   * Find the best governor for the given element that doesn't introduce a cycle.
   *
   * @param element an element of the dependency tree
   *
   * @return the new governor id and the related score
   */
  private fun findBestGovernor(element: Int): Pair {

    val headsMap: Map = this.scoredArcs.getHeadsMap(element)

    val candidates: List = this.directElements.intersect(headsMap.keys).filter { candidateGov ->
      !this.dependencyTree.introduceCycle(dependent = element, governor = candidateGov)
    }

    return headsMap.filter { it.key in candidates }.maxBy { it.value }!!.toPair()
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy