de.saar.coli.salsa.reiter.framenet.Frame.java Source code

Java tutorial

Introduction

Here is the source code for de.saar.coli.salsa.reiter.framenet.Frame.java

Source

/**
 * 
 * Copyright 2007-2009 by Nils Reiter.
 * 
 * This FrameNet API is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3.
 *
 * This FrameNet API is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this FrameNet API.  If not, see www.gnu.org/licenses/gpl.html.
 * 
 */
package de.saar.coli.salsa.reiter.framenet;

import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;

import java.io.Serializable;

import org.dom4j.*;
import org.dom4j.tree.*;

/**
 * Represents a single frame. 
 * 
 * Frame objects are not created directly, but instead in the FrameNet object
 * with the method {@link FrameNet#getFrame(String) getFrame(String)}. The frame object 
 * can provide any information that is present in the XML file (in version 1.3).
 * <br/>
 * The XML data name, ID, cDate and definition are directly available via the 
 * corresponding get-methods. {@link Frame#getFrameElements()} and 
 * {@link Frame#getLexicalUnits()} provide access to frame elements and lexical 
 * units. 
 * <br/>
 * There are several methods providing access to the frame hierarchy. 
 * 
 * @author Nils Reiter
 *
 */
public abstract class Frame implements Serializable, IHasCDate, IHasDefinition, IHasNameAndID, IHasTrees {

    /**
     * The name of the frame.
     */
    String name = null;

    /**
     * The ID of the frame, as noted in the framenet database files.
     */
    String id = null;

    /**
     * The cdate of the frame, as noted in the framenet database files.
     * Creation date?
     */
    String cDate = null;

    /**
     * The textual definition of the frame, as noted in the database file.
     */
    String definition = null;

    /**
     * The source attribute has been added by Salsa.
     * @since 0.2
     */
    String source = "";

    /**
     * The framenet object.
     */
    FrameNet framenet = null;

    /**
     * The storage for the frame elements.
     */
    Map<String, FrameElement> frameElements = null;

    /**
     * The cache for the frame relations, so that they have to be retrieved from the XML file only once.
     */
    Map<FrameNetRelation, Map<FrameNetRelationDirection, Collection<Frame>>> frameRelations = null;

    /**
     * The cache for distances to other frames;
     */
    Map<Frame, Integer> distances = null;

    /**
     * The storage for the lexical units.
     */
    Collection<LexicalUnit> lexicalUnits = null;

    private static final long serialVersionUID = 17L;

    Map<String, Integer> lexicalUnitsPerPOS = null;

    protected Frame() {
        frameElements = new HashMap<String, FrameElement>();
        distances = new HashMap<Frame, Integer>();
        frameRelations = new HashMap<FrameNetRelation, Map<FrameNetRelationDirection, Collection<Frame>>>();

    }

    public boolean linkFrameNet(FrameNet fn) {
        if (!(this.getName() != null && this.getCDate() != null && this.getId() != null
                && this.getDefinition() != null))
            return false;
        this.framenet = fn;
        framenet.allFrames.put(this.getName(), this);
        fn.log(Level.INFO, "Frame " + this.getName() + " has been registered.");
        return true;
    }

    /**
     * Returns the given frame element.
     * 
     * @param fename
     * @return The frame element with the given name.
     * @throws FrameElementNotFoundException If the frame does not contain the given frame element.
     */
    public FrameElement getFrameElement(String fename) throws FrameElementNotFoundException {
        if (!frameElements.containsKey(fename))
            throw new FrameElementNotFoundException(this, fename);
        return frameElements.get(fename);
    }

    /**
     * 
     * @deprecated Use inheritsFrom() instead.
     * @return A collection of frames.
     */
    public Collection<Frame> superFrames() {
        return inheritsFrom();
    }

    /**
     * @deprecated Use isInheritedBy() instead.
     * @return A collection of the frames that inherit this frame.
     */
    public Collection<Frame> subFrames() {
        return isInheritedBy();
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */
    public Collection<Frame> isInheritedBy() {
        return relatedFrames("Inheritance", FrameNetRelationDirection.DOWN);

    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> inheritsFrom() {
        return relatedFrames("Inheritance", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> subframeOf() {
        return relatedFrames("Subframe", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> hasSubframe() {
        return relatedFrames("Subframe", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> usedBy() {
        return relatedFrames("Using", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> uses() {
        return relatedFrames("Using", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> later() {
        return relatedFrames("Precedes", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> earlier() {
        return relatedFrames("Precedes", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> neutral() {
        return relatedFrames("Perspective_on", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> perspectivized() {
        return relatedFrames("Perspective_on", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> referring() {
        return relatedFrames("See_also", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> referred() {
        return relatedFrames("See_also", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> inchoative() {
        return relatedFrames("Inchoative_of", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> inchoativeStative() {
        return relatedFrames("Inchoative_of", FrameNetRelationDirection.DOWN);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> causative() {
        return relatedFrames("Causative_of", FrameNetRelationDirection.UP);
    }

    /**
     * Retrieves related frames.
     * See {@link Frame#relatedFrames(String, FrameNetRelationDirection)} for details.
     * @return A collection of frames.
     */

    public Collection<Frame> causativeStative() {
        return relatedFrames("Causative_of", FrameNetRelationDirection.DOWN);
    }

    /**
     * Collects the frame that are in the given relation in the given 
     * direction with this frame. There are specific methods for every relation and 
     * every direction, which are more convenient to use. 
     * 
     * In FrameNet, eight relations between frames are defined. All are accessible in 
     * this package, but the naming is somewhat difficult. The following table provides 
     * an overview on the different frame relations and how the elements of the relations 
     * are called. Every relation is directed, which means that there are different names
     * for the two ends of relations. 
     * <table border="1">
     * <tr>
     * <th>Relation</th>
     * <th>Name of super element</th>
     * <th>Method to access super</th>
     * <th>Name of sub element</th>
     * <th>Method to access sub</th>
     * </tr>
     * <tr>
     * <td>Inheritance</td>
     * <td>Parent</td><td> {@link Frame#inheritsFrom() inheritsFrom()} </td>
     * <td>Child</td><td> {@link Frame#isInheritedBy() isInheritedBy()} </td>
     * </tr>
     * <tr>
     * <td>Precedes</td>
     * <td>Earlier</td><td> {@link Frame#earlier() earlier()} </td>
     * <td>Later</td><td> {@link Frame#later() later()} </td>
     * </tr>
     * <tr>
     * <td>Subframe</td>
     * <td>Complex</td><td> {@link Frame#subframeOf() subframeOf()} </td>
     * <td>Component</td><td> {@link Frame#hasSubframe() hasSubframe()} </td>
     * </tr>
     * <tr>
     * <td>Using</td>
     * <td>Parent</td><td> {@link Frame#uses() uses()} </td>
     * <td>Child</td><td> {@link Frame#usedBy() usedBy()} </td>
     * </tr>
     * <tr>
     * <td>Perspective_on</td>
     * <td>Neutral</td><td> {@link Frame#neutral() neutral()}</td>
     * <td>Perspectivized</td><td> {@link Frame#perspectivized() perspectivized()}</td>
     * </tr>
     * <tr>
     * <td>See_also</td>
     * <td>Main Entry</td><td> {@link Frame#referred() referred()} </td>
     * <td>Referring Entry</td><td> {@link Frame#referring() referring()} </td>
     * </tr>
     * <tr>
     * <td>Inchoative_of</td>
     * <td>Inchoative</td><td> {@link Frame#inchoative() inchoative() } </td>
     * <td>State</td><td> {@link Frame#inchoativeStative() inchoativeStative() } </td>
     * </tr>
     * <tr>
     * <td>Causative_of</td>
     * <td>Causative</td><td> {@link Frame#causative() causative() } </td>
     * <td>State</td><td> {@link Frame#causativeStative() causativeStative() } </td>
     * </tr>
     * </table>
     * 
     * 
     * @param relation The relation. Has to be given exactly as it is in the framenet database.
     * @param frameNetRelationDirection The direction. This is mostly trial-and-error.
     * @return The frames that are directly related with this frame.
     * @see FrameNetRelation#getSub(Frame)
     * @see FrameNetRelation#getSuper(Frame)
     * 
     */
    public Collection<Frame> relatedFrames(String relation, FrameNetRelationDirection frameNetRelationDirection) {
        FrameNetRelation fnrel = framenet.getFrameNetRelation(relation);
        if (!frameRelations.containsKey(fnrel))
            frameRelations.put(fnrel, new HashMap<FrameNetRelationDirection, Collection<Frame>>());
        if (!frameRelations.get(fnrel).containsKey(frameNetRelationDirection))
            frameRelations.get(fnrel).put(frameNetRelationDirection,
                    fnrel.getOther(this, frameNetRelationDirection));
        return frameRelations.get(fnrel).get(frameNetRelationDirection);

        /*Collection<FrameRelation> rels;
        Collection<Frame> ret = new HashSet<Frame>();
        if (frameNetRelationDirection == FrameNetRelationDirection.DOWN) {
           if (! this.getRelationsAsSuper().containsKey(fnrel))
        return ret;
           rels = this.getRelationsAsSuper().get(fnrel);
        } else {
           if (! this.getRelationsAsSub().containsKey(fnrel))
        return ret;
           rels = this.getRelationsAsSub().get(fnrel);
        }
        for (FrameRelation frel : rels) {
           if (frameNetRelationDirection == FrameNetRelationDirection.UP) {
        ret.add(frel.getSubFrame());
           } else {
        ret.add(frel.getSuperFrame());
           }
        }
        return ret;*/
        /*
        if (frameRelations.containsKey(relation)) {
           if (frameRelations.get(relation).containsKey(direction)) {
        return frameRelations.get(relation).get(direction);
           }
        }
        if (framenet.debug)
           System.err.print("Frame.relatedFrames("+relation+", "+direction+"): " + this.getName() + " - ");
        Collection<Frame> ret = framenet.getRelatedFrames(name, relation, direction);
        if (framenet.debug)
           System.err.println(" Newly retrieved.");      
        if (! frameRelations.containsKey(relation)) {
           frameRelations.put(relation, new HashMap<Integer, Collection<Frame>>());
        }
        if (! frameRelations.get(relation).containsKey(direction)) {
           frameRelations.get(relation).put(direction, ret);
        }
        return ret;
        */
    }

    /**
     * Checks, whether this frame is at the top of the inheritance tree.
     * @return True, if no super frames can be found, false otherwise.
     */
    public boolean isRootFrame() {
        return inheritsFrom().isEmpty();
    }

    /**
     * Checks, whether this frame is at the bottom of the inheritance tree.
     * 
     * @return True, if the no frame inherits this one.
     */
    public boolean isLeafFrame() {
        return isInheritedBy().isEmpty();
    }

    /**
     * Returns a RealizedFrame object, in which every frame element has been realized
     * using the dummy token. The dummy string is also stored as target of the
     * frame itself.
     * @param dummy The dummy token. 
     * @return A realized frame.
     */
    public RealizedFrame realizeAll(IToken dummy) {
        RealizedFrame rf = this.realize(dummy);
        for (FrameElement fe : frameElements()) {
            fe.realize(rf, dummy);
        }
        return rf;
    }

    /**
     * Connects the frame with a target text and an Id and 
     * returns a realized frame.
     * 
     * @param target The target of the frame.
     * @param xmlid An XML id of the target of the frame.
     * @return A realized frame.
     */
    public RealizedFrame realize(IToken target, String xmlid) {
        return new RealizedFrame(this, target, xmlid);
    }

    /**
     * Connects the frame with a target text and returns a realized 
     * frame. 
     * 
     * @param target The target of the frame.
     * @return A realized frame.
     */
    public RealizedFrame realize(IToken target) {
        return realize(target, "");
    }

    /**
     * Returns a string representation of the frame.
     * @return  The name of the frame.
     */
    public String toString() {
        return name;
    }

    /**
     * Collects all frames that inherit from this frame, either direct or indirect.
     * @return All frames that inherit this frame. Includes transitivity.
     * @since 0.1
     */
    public Collection<Frame> allInheritingFrames() {
        Set<Frame> ret = new HashSet<Frame>();
        for (Frame f : isInheritedBy()) {
            ret.add(f);
            ret.addAll(f.allInheritingFrames());
        }
        return ret;
    }

    /**
     * Like <code>allInheritingFrames()</code>, but with respect to the frames from which this has inherited.
     * @return A collection of frames.
     * @since 0.1
     */
    public Collection<Frame> allInheritedFrames() {
        Set<Frame> ret = new HashSet<Frame>();
        for (Frame f : inheritsFrom()) {
            ret.add(f);
            ret.addAll(f.allInheritedFrames());
        }
        return ret;
    }

    /**
     * Compares two frames. If they have the same name, then they should be considered equal.
     * @param other The other frame.
     * @return True if the names of the frames are identical, false otherwise.
     */
    public boolean equals(Frame other) {
        return (other.getName() == this.getName());
    }

    /**
     * Calculates the distance between two frames. 
     * <p>With distance, we mean the number of steps one has to
     * go upwards in the inheritance hierarchy to reach the
     * other frame. 
     * Therefore, the distance is directed: <code>f1.distance(f2)</code> is 
     * only the same as <code>f2.distance(f1)</code> if <code>f1 == f2</code>.</p>
     * <p>If the frames are identical, 0 (zero) is returned. If the
     * other frame is not among the ancestors of this frame, 
     * {@link java.lang.Integer#MAX_VALUE Integer.MAX_VALUE} is returned.</p>
     * 
     * <p>The behaviour of this method can be expected to change 
     * in future versions. It is planned to implement real tree distance.</p>
     * 
     * @param other The other frame
     * @return The distance (=number of inheritance steps upwards)
     */
    public Integer distance(Frame other) {
        if (this.equals(other))
            return new Integer(0);
        if (distances.containsKey(other))
            return distances.get(other);

        framenet.log(Level.INFO, "Searching for distance between " + this.getName() + " and " + other.getName());

        int adist = 1;
        Set<Frame> work = new HashSet<Frame>();
        work.addAll(this.inheritsFrom());
        while (!work.isEmpty()) {
            Collection<Frame> nextWork = new HashSet<Frame>();
            for (Frame sf : work) {
                Integer ret = new Integer(adist);
                distances.put(other, ret);
                if (sf.equals(other)) {
                    return ret;
                }
                nextWork.addAll(sf.inheritsFrom());
            }
            adist++;
            work.clear();
            work.addAll(nextWork);
            nextWork.clear();
        }
        Integer ret = Integer.MAX_VALUE;
        distances.put(other, ret);
        return ret;
    }

    /**
     * Generates a tree of the inheritance hierarchy. Uses indentation to mark the
     * descendent-levels
     * 
     * @return A string contain a tree-like representation of the inheritance hierarchy.
     * @param prefix A String containing whitespaces. Is used to represent the depth from here on.
     * @param up True if the true should follow the hierarchy upwards, false otherwise
     */
    private String tree(String prefix, boolean up) {
        StringBuffer ret = new StringBuffer();
        ret.append(prefix + name + "\n");
        Collection<Frame> others;
        if (up)
            others = this.inheritsFrom();
        else
            others = this.isInheritedBy();
        for (Frame f : others) {
            ret.append(f.tree(prefix + " ", up));
        }
        return ret.toString();
    };

    /**
     * Generates an ASCII-art tree-like representaton of the inheritance hierarchy of the frame.
     * Looks upwards.
     * @return A string containing the tree. Contains several newlines.
     */
    public String treeUp() {
        return tree("", true);
    }

    /**
     * Generates an ASCII-art tree-like representation of the inheritance hierarchy of the frame, 
     * but looks down. Stores the frames that inherit from this frame.
     * @return The string containing the tree.
     */
    public String treeDown() {
        return tree("", false);
    }

    public String getCDate() {
        return cDate;
    }

    public String getDefinition() {
        return definition;
    }

    /**
     * Returns a collection of the frame element objects.
     * @return All frame elements in this frame.
     */
    public Collection<FrameElement> frameElements() {
        return getFrameElements().values();
    }

    /**
     * Returns the map of frame element names to frame element objects.
     * Use {@link Frame#frameElements() frameElements()} to get a simple 
     * list of the frame element objects (or use <code>getFrameElements().value()</code>, which
     * is the same ... )
     * @return The frameElements as a map.
     */
    public Map<String, FrameElement> getFrameElements() {
        return frameElements;
    }

    /**
     * Returns the lexical units of this frame as collection of LexicalUnit objects.
     * @return The lexicalUnits.
     */
    public Collection<LexicalUnit> getLexicalUnits() {
        return lexicalUnits;
    }

    /**
     * Returns the lexical unit with the given name or null if it does not exist in 
     * this frame.
     * @param luName The name of the lexical unit as given in the XML files.
     * @return The lexical unit
     * @since 0.2
     */
    public LexicalUnit getLexicalUnit(String luName) {
        for (LexicalUnit lu : getLexicalUnits()) {
            if (lu.getName().equalsIgnoreCase(luName))
                return lu;
        }
        return null;
    }

    public String getName() {
        return name;
    }

    public String getId() {
        return id;
    }

    /**
     * Returns the number of lexical units for the parts of speech. 
     * 
     * @return A map containing the part of speech and the number of lexical units
     * @deprecated Use {@link #getNumberOfLexicalUnitsPerPOS()} instead
     */
    public Map<String, Integer> getLexicalUnitsPerPOS() {
        return getNumberOfLexicalUnitsPerPOS();
    }

    /**
     * Returns the number of lexical units for the parts of speech. 
     * 
     * @return A map containing the part of speech and the number of lexical units
     */
    public Map<String, Integer> getNumberOfLexicalUnitsPerPOS() {
        return lexicalUnitsPerPOS;
    }

    /**
     * This method returns true if the frame is isolated.
     * "Isolated" means, that it has no frames that either
     * inherit from it or are inherited by it. 
     * @return true or false.
     */
    public boolean isIsolated() {
        return (this.inheritsFrom().isEmpty() && this.isInheritedBy().isEmpty());

    }

    protected FrameNet getFramenet() {
        return framenet;
    }

    public String getSource() {
        return source;
    }

    protected void setName(String name) {
        this.name = name;
    }

    protected void setId(String id) {
        this.id = id;
    }

    protected void setCDate(String date) {
        cDate = date;
    }

    protected void setDefinition(String definition) {
        this.definition = definition;
    }

    protected void setSource(String source) {
        this.source = source;
    }

    public Element exportToSalsaTiger() {
        Namespace ns = new Namespace("fd", "http://www.clt-st.de/framenet/frame-database");

        Element elem = new DefaultElement("frame", ns);

        elem.add(new FlyweightAttribute("name", this.getName(), ns));

        for (FrameElement fe : this.frameElements()) {
            Element fee = new DefaultElement("element", ns);
            fee.add(new FlyweightAttribute("name", fe.getName(), ns));
            fee.add(new FlyweightAttribute("optional", String.valueOf(!fe.isCore()), ns));

            elem.add(fee);
        }

        return elem;

    }
}