com.kotlinnlp.syntaxdecoder.transitionsystem.Transition.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of syntaxdecoder Show documentation
Show all versions of syntaxdecoder Show documentation
SyntaxDecoder is a generalized transition-based parsing framework designed to simplify the development of
statistical transition-based dependency parsers.
The newest version!
/* Copyright 2017-present The 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.syntaxdecoder.transitionsystem
import com.kotlinnlp.dependencytree.Deprel
import com.kotlinnlp.dependencytree.POSTag
import com.kotlinnlp.syntaxdecoder.syntax.DependencyRelation
import com.kotlinnlp.syntaxdecoder.syntax.SyntacticDependency
import com.kotlinnlp.syntaxdecoder.transitionsystem.state.State
/**
* The State Transition.
*
* @property refState the [State] on which this transition operates
* @property id the transition id
*/
abstract class Transition, StateType: State>(
val refState: StateType,
val id: Int
) {
/**
* The Transition type.
*
* @property direction
*/
enum class Type(val direction: Deprel.Position) {
SHIFT(direction = Deprel.Position.NULL),
RELOCATE(direction = Deprel.Position.NULL),
WAIT(direction = Deprel.Position.NULL),
UNSHIFT(direction = Deprel.Position.NULL),
NO_ARC(direction = Deprel.Position.NULL),
ARC_LEFT(direction = Deprel.Position.LEFT),
ARC_RIGHT(direction = Deprel.Position.RIGHT),
ROOT(direction = Deprel.Position.ROOT)
}
/**
* The Action is a transition abstraction that allows you to ignore which transition-system you are using.
*
* @property id a unique id that identifies this action within others generated at the same time
*/
abstract inner class Action internal constructor(val id: Int = -1) {
/**
* The [Transition] from which this [Action] originated.
*/
@Suppress("UNCHECKED_CAST")
val transition: SelfType = this@Transition as SelfType
/**
* True if the transition is allowed in the given parser state.
*/
val isAllowed: Boolean by lazy { this.transition.isAllowed }
/**
* The score of goodness of this action.
*/
var score: Double = 0.0
/**
* The error of the [score].
*/
var error: Double = 0.0
/**
* Apply this [Action] to the [refState] or a copy of it. Update the 'track' of the involved state.
*
* @param copyState whether perform this [Action] to the [refState] or a copy of it
*
* @return the state modified by this [Action]
*/
fun apply(copyState: Boolean = false): StateType {
require([email protected] == [email protected]()){
"Incompatible state track: " +
"Expected: ${[email protected]} Found: ${[email protected]()}"
}
val state: StateType = if (copyState)
this.transition.refState.copy()
else
this.transition.refState
[email protected](state)
this.perform(state) // call after the transition has been performed
state.track.incrementAndGet()
return state
}
/**
* Perform this [Action] modifying the DependencyTree of the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Action] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
protected abstract fun perform(state: StateType)
}
/**
* Shift Action.
*/
inner class Shift internal constructor(id: Int) : Action(id) {
/**
* Perform this [Action] modifying the DependencyTree of the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Action] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
override fun perform(state: StateType) = Unit
/**
* @return its string representation.
*/
override fun toString(): String = "shift"
}
/**
* Unshift Action.
*/
inner class Unshift internal constructor(id: Int) : Action(id) {
/**
* Perform this [Action] modifying the DependencyTree of the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Action] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
override fun perform(state: StateType) = Unit
/**
* @return its string representation.
*/
override fun toString(): String = "unshift"
}
/**
* Relocate Action (can be used to abstract the Swap transition).
*/
inner class Relocate internal constructor(id: Int) : Action(id) {
/**
* Perform this [Action] modifying the DependencyTree of the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Action] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
override fun perform(state: StateType) = Unit
/**
* @return its string representation.
*/
override fun toString(): String = "relocate"
}
/**
* NoArc Action.
*/
inner class NoArc internal constructor(id: Int) : Action(id) {
/**
* Perform this [Action] modifying the DependencyTree of the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Action] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
override fun perform(state: StateType) = Unit
/**
* @return its string representation.
*/
override fun toString(): String = "no-arc"
}
/**
* Arc Action.
*/
inner class Arc internal constructor(id: Int) : Action(id), DependencyRelation {
/**
* The dependent id (can be null in case the transition is not allowed).
*/
override var dependentId: Int? = null
private set
/**
* The governor id (can be null in case the transition is not allowed or the governor is the root).
*/
override var governorId: Int? = null
private set
/**
* The syntactic component of a dependency relation (can be null)
*/
override var deprel: Deprel? = null
/**
* The morphological component of a dependency relation (can be null)
*/
override var posTag: POSTag? = null
/**
* Initialize the action.
*/
init {
require(this@Transition is SyntacticDependency)
if (this.transition.isAllowed) {
this@Transition as SyntacticDependency
this.dependentId = [email protected]
this.governorId = [email protected]
}
}
/**
*
*/
override fun perform(state: StateType) {
require(this.dependentId != null) {
"Required a not-null dependent."
}
if (this.governorId != null) {
state.dependencyTree.setArc(
dependent = this.dependentId!!,
governor = this.governorId!!,
deprel = this.deprel,
posTag = this.posTag)
} else if (this.deprel != null) {
state.dependencyTree.setDeprel(
dependent = this.dependentId!!,
deprel = this.deprel!!)
if (this.posTag != null) {
state.dependencyTree.setPosTag(
dependent = this.dependentId!!,
posTag = this.posTag!!
)
}
}
}
/**
* @return its string representation.
*/
override fun toString(): String = if (this.posTag != null)
"${this.posTag!!}~${this.deprel!!}(${this.governorId} -> ${this.dependentId})"
else
"${this.deprel?:"arc"}(${this.governorId} -> ${this.dependentId})"
}
/**
* The 'track' of the [State] at the time this [Transition] is created.
*
* You can apply an action / transition to the [refState] or a copy of it only if its 'track' has not changed.
*/
val refStateTrack: Int = this.refState.track.get()
/**
* The Transition type, from which depends the building of the related [Action].
*/
abstract val type: Type
/**
* The priority of the transition in case of spurious-ambiguities.
*/
abstract val priority: Int
/**
* True if the transition is allowed in the given parser state.
*/
abstract val isAllowed: Boolean
/**
* @param id the id of the action
*
* @return a new [Action] tied to this transition.
*/
fun actionFactory(id: Int = -1, deprel: Deprel? = null, posTag: POSTag? = null): Action {
val action: Action = this.buildAction(id)
if (this is SyntacticDependency) {
action as DependencyRelation // An arc Transition must be associated to a DependencyRelation
action.deprel = deprel
action.posTag = posTag
}
return action
}
/**
* Perform this [Transition] on the given [state].
*
* It requires that the transition [isAllowed] on the given [state], however it is guaranteed that the [state] is
* compatible with this [Transition] as it can only be the [refState] or a copy of it.
*
* @param state a State
*/
protected abstract fun perform(state: StateType)
/**
* @param id the id of the action
*
* @return a new [Action] tied to this transition.
*/
private fun buildAction(id: Int = -1): Action = when (this.type) {
Type.ARC_LEFT, Type.ARC_RIGHT, Type.ROOT -> this.buildArc(id)
Type.NO_ARC -> this.buildNoArc(id)
Type.RELOCATE -> this.buildRelocate(id)
Type.SHIFT, Type.WAIT -> this.buildShift(id)
Type.UNSHIFT -> this.buildUnshift(id)
}
/**
* @param id the id of the action
*
* @return a new [Shift] tied to this transition.
*/
private fun buildShift(id: Int = -1) = this.Shift(id)
/**
* @param id the id of the action
*
* @return a new [Unshift] tied to this transition.
*/
private fun buildUnshift(id: Int = -1) = this.Unshift(id)
/**
* @param id the id of the action
*
* @return a new [Relocate] tied to this transition.
*/
private fun buildRelocate(id: Int = -1) = this.Relocate(id)
/**
* @param id the id of the action
*
* @return a new [Arc] tied to this transition.
*/
private fun buildNoArc(id: Int = -1) = this.NoArc(id)
/**
* @param id the id of the action
*
* @return a new [Arc] tied to this transition.
*/
private fun buildArc(id: Int = -1) = this.Arc(id)
}