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

gov.sandia.cognition.framework.io.CSVDefaultCognitiveModelLiteHandler Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                CSVDefaultCognitiveModelLiteHandler.java
 * Authors:             Justin Basilico and Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Framework Lite
 *
 * Copyright March 2, 2006, Sandia Corporation.  Under the terms of Contract
 * DE-AC04-94AL85000, there is a non-exclusive license for use of this work by
 * or on behalf of the U.S. Government. Export of this program may require a
 * license from the United States Government. See CopyrightHistory.txt for
 * complete details.
 *
 *
 */

package gov.sandia.cognition.framework.io;

import gov.sandia.cognition.framework.CognitiveModule;
import gov.sandia.cognition.framework.CognitiveModuleFactory;
import gov.sandia.cognition.framework.DefaultSemanticLabel;
import gov.sandia.cognition.framework.DefaultSemanticNetwork;
import gov.sandia.cognition.framework.SemanticLabel;
import gov.sandia.cognition.framework.SemanticNetwork;
import gov.sandia.cognition.framework.lite.ArrayBasedPerceptionModuleFactory;
import gov.sandia.cognition.framework.lite.CognitiveModelLiteFactory;
import gov.sandia.cognition.framework.lite.MutableSemanticMemoryLiteFactory;
import gov.sandia.cognition.framework.lite.SharedSemanticMemoryLiteFactory;
import gov.sandia.cognition.framework.lite.SimplePatternRecognizer;
import gov.sandia.cognition.io.CSVParseException;
import gov.sandia.cognition.io.CSVUtility;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;

/**
 * The CSVDefaultCognitiveModelLiteHandler class implements a format handler for
 * CSV files that specify a default setup for a CognitiveModelLite. It is
 * implemented by calling static methods to parse a file or stream and then an
 * object is instantiated to read from the stream to parse it into the proper
 * model factory.
 * 
 * It also supports writing to the CSV file format.
 * 
 * @author Justin Basilico
 * @author Kevin R. Dixon
 * @since 1.0
 */
public class CSVDefaultCognitiveModelLiteHandler 
    extends java.lang.Object
{
    /** The name of the format that the file parses. */
    public static final String FORMAT_NAME = "CSVDefaultCognitiveModelLite";

    /** The current version that is parsed. */
    public static final double FORMAT_VERSION = 1.0;

    /** The network being read in. */
    private DefaultSemanticNetwork network = null;

    /** The mapping of String label names to the actual labels. */
    private HashMap labels = null;

    /**
     * Creates a new instance of CommaSeparatedValueHandler.
     */
    protected CSVDefaultCognitiveModelLiteHandler()
    {
        super();

        setNetwork(new DefaultSemanticNetwork());
        setLabels(new HashMap());
    }

    /**
     * The main parsing function. It reads through the CSV values in the stream
     * and handles them.
     * 
     * @param br
     *            The reader to read the CSV values from.
     * @return True if the parsing was successful.
     * @throws CSVParseException
     *             If there is an error in the CSV formatting.
     * @throws IOException
     *             If there is an IO error.
     */
    protected boolean parse(
        BufferedReader br) 
        throws CSVParseException, IOException
    {
        // First parse the header. The only thing we really need from it is
        // the version number.
        final double version = parseHeader(br);

        if (version <= 0.0)
        {
            // Not a valid version number.
            throw new CSVParseException("Unknown version number: " + version);
        }

        // Now that we've read the header, read the actual data in this loop
        // until there is no more data.
        String[] entries = null;
        while ((entries = CSVUtility.nextNonEmptyLine(br)) != null)
        {
            if (entries.length <= 0)
            {
                // No data on this line.
                continue;
            }

            // Figure out what to do based on the first entry now that we know
            // there is at least one.
            final String first = entries[0].trim();
            final int numEntries = entries.length;

            if (first.length() <= 0)
            {
                // This is really just a blank line.
                continue;
            } else if (first.equalsIgnoreCase("node"))
            {
                // It is a node directive.

                if (numEntries < 2)
                {
                    // Error: Not enough parameters.
                    throw new CSVParseException("Node specified with no name.");
                }

                // Add the node.
                final String name = entries[1];
                addNode(name);
            } else if (first.equalsIgnoreCase("link"))
            {
                if (numEntries < 4)
                {
                    // Error: Not enough parameters.
                    throw new CSVParseException(
                        "Link specified without enough arguments: 4 expected.");
                }

                // Parse the arguments.
                final String from = entries[1];
                final String to = entries[2];
                final String linkString = entries[3];
                double link = 0.0;

                try
                {
                    link = Double.parseDouble(linkString);
                } catch (final NumberFormatException nfe)
                {
                    throw new CSVParseException(nfe);
                }

                // Add a link.
                addLink(from, to, link);
            } else
            {
                // Treat it as a parameter.
                throw new CSVParseException("Unknown directive " + first);
            }
        }

        return true;
    }

    /**
     * Parses the header and returns the version number. It throws an exception
     * if there is any issue with the header so the returned version number is
     * always valid.
     * 
     * @param br
     *            The reader to read the CSV values from.
     * @return True if the parsing was successful.
     * @throws CSVParseException
     *             If there is an error in the CSV formatting.
     * @throws IOException
     *             If there is an IO error.
     */
    protected double parseHeader(
        BufferedReader br) 
        throws CSVParseException, IOException
    {
        // Read the first non-empty line.
        String[] entries = CSVUtility.nextNonEmptyLine(br);
        if (entries == null || entries.length <= 0)
        {
            throw new CSVParseException("No CSV data given.");
        }

        // Make sure that this is the proper format.
        if (entries.length < 1 || !entries[0].equalsIgnoreCase(FORMAT_NAME))
        {
            throw new CSVParseException("Format " + FORMAT_NAME
                    + " not specified.");
        }

        // Next read the version line.
        entries = CSVUtility.nextNonEmptyLine(br);
        if (entries == null || entries.length <= 0)
        {
            throw new CSVParseException("No CSV data given.");
        }

        if (entries.length < 2 || !entries[0].equalsIgnoreCase("Version"))
        {
            throw new CSVParseException("Version not specified.");
        }

        // Ensure this is the proper version.
        final String versionString = entries[1];
        double version = -1.0;

        try
        {
            version = Double.parseDouble(versionString);
        } catch (final NumberFormatException e)
        {
            version = -1.0;
        }

        // See if we can handle this version.
        if (version != FORMAT_VERSION)
        {
            throw new CSVParseException("Not a valid version number: "
                    + versionString);
        }

        // The version is valid.
        return version;
    }

    /**
     * Called when the "node" directive is seen. It adds a node to the network
     * 
     * @param name
     *            The name of the node to add.
     * @throws CSVParseException
     *             If there is an error in adding the node, such as it already
     *             existing.
     */
    protected void addNode(
        String name)
        throws CSVParseException
    {
        // Get the label for the node.
        DefaultSemanticLabel label = getLabel(name);

        if (label != null)
        {
            // Error: One already exists.
            throw new CSVParseException("Label " + name + " already exists.");
        }

        // Create a label for the node.
        label = new DefaultSemanticLabel(name);

        // Add the label to the mapping.
        labels.put(name, label);

        // Add the label to the network.
        network.addNode(label);
    }

    /**
     * Called when the "link" directive is seen. It adds a link to the network
     * 
     * @param fromName
     *            The node the link is from.
     * @param toName
     *            The node the link is to.
     * @param weight
     *            The weight for the link.
     * @throws CSVParseException
     *             If there is an error in adding the link, such as one of the
     *             nodes not existing.
     */
    protected void addLink(
        String fromName,
        String toName,
        double weight)
        throws CSVParseException
    {
        // Get the labels for the nodes.
        final DefaultSemanticLabel fromLabel = getLabel(fromName);
        final DefaultSemanticLabel toLabel = getLabel(toName);

        if (fromLabel == null)
        {
            // Error: No from node.
            throw new CSVParseException("Node " + fromName + " does not exist.");
        }

        if (toLabel == null)
        {
            // Error: No to node.
            throw new CSVParseException("Node " + toName + " does not exist.");
        }

        // Add the association to the network.
        network.setAssociation(fromLabel, toLabel, weight);
    }

    /**
     * Gets the sharable module factory that has been read in.
     * 
     * @return The module factory that has been read in.
     */
    protected CognitiveModuleFactory getSharedModuleFactory()
    {
        return new SharedSemanticMemoryLiteFactory(new SimplePatternRecognizer(
                network));
    }

    /**
     * Gets the sharable module factory that has been read in.
     * 
     * @return The module factory that has been read in.
     */
    protected CognitiveModuleFactory getMutableModuleFactory()
    {
        return new MutableSemanticMemoryLiteFactory(
                new SimplePatternRecognizer(network));
    }

    /**
     * Takes a name and returns its DefaultSemanticLabel or null if there is
     * none.
     * 
     * @param name
     *            The name of the label to get.
     * @return The DefaultSemanticLabel associated with that name, if one
     *         exists, otherwise null.
     */
    protected DefaultSemanticLabel getLabel(
        String name)
    {
        return labels.get(name);
    }

    /**
     * Gets the underlying network.
     * 
     * @return The underlying semantic network.
     */
    protected DefaultSemanticNetwork getNetwork()
    {
        return network;
    }

    /**
     * Set the network being parsed.
     * 
     * @param network
     *            The new network being parsed.
     */
    protected void setNetwork(
        DefaultSemanticNetwork network)
    {
        this.network = network;
    }

    /**
     * Sets the label mapping.
     * 
     * @param labels
     *            The new label mapping.
     */
    protected void setLabels(
        HashMap labels)
    {
        this.labels = labels;
    }

    /**
     * Reads a default CognitiveModuleFactory from the given CSV file and
     * returns it.
     * 
     * @param fileName
     *            The file to read from.
     * @param mutable
     *            True to create a mutable module.
     * @return The default CognitiveModuleFactory read from the file.
     * @throws CSVParseException
     *             If the CSV file is not properly formatted.
     * @throws IOException
     *             If there is an IO error, such as the file not existing.
     */
    public static CognitiveModuleFactory parseCSVToModuleFactory(
        String fileName, 
        boolean mutable)
        throws CSVParseException, IOException
    {
        // Create the stream and parse it.
        return parseCSVToModuleFactory(
            new BufferedReader(new FileReader(fileName)), mutable);
    }

    /**
     * Reads a default CognitiveModuleFactory from the given buffered reader and
     * then returns it.
     * 
     * @param br
     *            The reader to read from.
     * @param mutable
     *            True to create a mutable module.
     * @return The default CognitiveModuleFactory read from the reader.
     * @throws CSVParseException
     *             If the CSV file is not properly formatted.
     * @throws IOException
     *             If there is an IO error, such as the file not existing.
     */
    public static CognitiveModuleFactory parseCSVToModuleFactory(
        BufferedReader br, 
        boolean mutable) 
        throws CSVParseException,
        IOException
    {
        // Create the handler.
        final CSVDefaultCognitiveModelLiteHandler handler = 
            new CSVDefaultCognitiveModelLiteHandler();

        // Parse the network.
        handler.parse(br);

        if (mutable)
        {
            // Return the mutable factory.
            return handler.getMutableModuleFactory();
        } else
        {
            // Return the shared factory.
            return handler.getSharedModuleFactory();
        }
    }

    /**
     * Reads a default CognitiveModuleFactory from the given file and puts it in
     * a default CognitiveModelFactory.
     * 
     * @param fileName
     *            The file to read from.
     * @param mutable
     *            True to create a mutable module.
     * @return The default CognitiveModuleFactory read from the reader.
     * @throws CSVParseException
     *             If the CSV file is not properly formatted.
     * @throws IOException
     *             If there is an IO error, such as the file not existing.
     */
    public static CognitiveModelLiteFactory parseCSVToModelFactory(
        String fileName, 
        boolean mutable)
        throws CSVParseException, IOException
    {
        // Create the stream and parse it.
        return parseCSVToModelFactory(new BufferedReader(new FileReader(
                fileName)), mutable);
    }

    /**
     * Reads a default CognitiveModuleFactory from the given buffered reader and
     * puts it in a default CognitiveModelFactory.
     * 
     * @param br
     *            The reader to read from.
     * @param mutable
     *            True to create a mutable model factory.
     * @return The default CognitiveModuleFactory read from the reader.
     * @throws CSVParseException
     *             If the CSV file is not properly formatted.
     * @throws IOException
     *             If there is an IO error, such as the file not existing.
     */
    public static CognitiveModelLiteFactory parseCSVToModelFactory(
        BufferedReader br, 
        boolean mutable) 
        throws CSVParseException, IOException
    {
        // Create a CognitiveModelFactory from the module factory.
        return createModelFactory(parseCSVToModuleFactory(br, mutable));
    }

    /**
     * Creates a default CognitiveModelLiteFactory for the given module factory
     * and returns it. It primarily just adds a perception module to the model.
     * 
     * @param moduleFactory
     *            The module factory to wrap in a model factory.
     * @return A CognitiveModelLiteFactory using the given module factory.
     */
    private static CognitiveModelLiteFactory createModelFactory(
        CognitiveModuleFactory moduleFactory)
    {
        // Create the model factory.
        final CognitiveModelLiteFactory modelFactory = 
            new CognitiveModelLiteFactory();

        // Add a default perception factory.
        modelFactory.addModuleFactory(new ArrayBasedPerceptionModuleFactory());

        // Add the given module factory.
        modelFactory.addModuleFactory(moduleFactory);

        // Return the model factory.
        return modelFactory;
    }

    /**
     * Writes a SemanticNetwork to the given file using the CSV format.
     * 
     * @param fileName
     *            The name of the file to write the network.
     * @param network
     *            The network to write.
     * @throws FileNotFoundException
     *             If the file cannot be written to.
     */
    public static void write(
        String fileName,
        SemanticNetwork network)
        throws FileNotFoundException
    {
        write(new File(fileName), network);
    }

    /**
     * Writes a SemanticNetwork to the given file using the CSV format.
     * 
     * @param file
     *            The file to write the network.
     * @param network
     *            The network to write.
     * @throws FileNotFoundException
     *             If the file cannot be written to.
     */
    public static void write(
        File file, 
        SemanticNetwork network)
        throws FileNotFoundException
    {
        final PrintWriter pw = new PrintWriter(file);
        write(pw, network);
        pw.close();
    }

    /**
     * Writes a SemanticNetwork to the given stream using the CSV format.
     * 
     * @param pw
     *            The place to write the network.
     * @param network
     *            The network to write.
     */
    public static void write(
        PrintWriter pw, 
        SemanticNetwork network)
    {
        // Write the header.
        pw.println(FORMAT_NAME);
        pw.println("Version," + FORMAT_VERSION);
        pw.println();

        // Write the nodes.
        for (final SemanticLabel node : network.getNodes())
        {
            pw.println("node," + node.getName());
        }

        // Put a space between the nodes and the links.
        pw.println();

        // Write the links.
        for (final SemanticLabel from : network.getNodes())
        {
            for (final SemanticLabel to : network.getOutLinks(from))
            {
                final double value = network.getAssociation(from, to);
                pw.println("link," + from.getName() + "," + to.getName() + ","
                        + value);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy