Package wyautl_old.util

Source Code of wyautl_old.util.Generator

// Copyright (c) 2011, David J. Pearce (djp@ecs.vuw.ac.nz)
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//    * Redistributions of source code must retain the above copyright
//      notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//    * Neither the name of the <organization> nor the
//      names of its contributors may be used to endorse or promote products
//      derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL DAVID J. PEARCE BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package wyautl_old.util;

import java.io.*;
import java.util.*;

import wyfs.io.BinaryOutputStream;
import wyil.lang.*;
import wyautl_old.io.*;
import wyautl_old.lang.*;

/**
* The generator class is used generate automata, primarily for testing
* purposes.
*
* @author David J. Pearce
*
*/
public class Generator {

  public interface Data {
    /**
     * Generate all possible forms of supplementary data for the given
     * state.
     *
     * @param state
     * @return
     */
    public List<Object> generate(Automaton.State state);
  }

  public static final class Kind {
    /**
     * Determine whether this kind is deterministic or not.
     */
    public boolean DETERMINISTIC;

    /**
     * Determine minimum number of children this kind can have.
     */
    public int MIN_CHILDREN;

    /**
     * Determine maximum number of children this kind can have.
     */
    public int MAX_CHILDREN;

    /**
     * A method for generating approprate supplementary data.
     */
    public Data DATA;

    public Kind(boolean deterministic, int min, int max, Data data) {
      this.DETERMINISTIC = deterministic;
      this.MIN_CHILDREN = min;
      this.MAX_CHILDREN = max;
      this.DATA = data;
    }
  }

  public static class Config {
    /**
     * Provide details of kinds used.
     */
    public Kind[] KINDS;

    /**
     * Allow recursive links or not.
     */
    public boolean RECURSIVE;

    /**
     * Determine size of automata to generate.
     */
    public int SIZE;
  }

  private final static class Template {
    public final int[] kinds;
    public final int[] children;
    public final BitSet transitions;

    public Template(int size) {
      this.kinds = new int[size];
      this.children = new int[size];
      transitions = new BitSet(size*size);
    }

    public final void add(int from, int to) {
      transitions.set((from*kinds.length)+to,true);
    }

    public final void remove(int from, int to) {
      transitions.set((from*kinds.length)+to,false);
    }

    public final boolean isTransition(int from, int to) {
      return transitions.get((from*kinds.length)+to);
    }
  }

  /**
   * Turn a template into an actual automaton.
   *
   * @param template
   * @param writer
   */
  private static void generate(Template template,
      GenericWriter<Automaton> writer, Config config) throws IOException {

    Kind[] KINDS = config.KINDS;
    int[] kinds = template.kinds;
    int[] nchildren = template.children;
    Automaton.State[] states = new Automaton.State[kinds.length];

    for(int i=0;i!=kinds.length;++i) {
      int kind = kinds[i];
      int[] children = new int[nchildren[i]];
      int index = 0;
      for(int j=0;j!=kinds.length;++j) {
        if(template.isTransition(i,j)) {
          children[index++] = j;
        }
      }
      states[i] = new Automaton.State(kind,KINDS[kind].DETERMINISTIC,children);
    }
    Automaton automaton = new Automaton(states);
    generate(0,automaton,writer,config);
  }

  private static void generate(int index, Automaton automaton,
      GenericWriter<Automaton> writer, Config config) throws IOException {
    if(index >= automaton.size()) {
      writer.write(automaton);
      writer.flush();
      count++;
      if(verbose) {
        System.err.print("\rWrote " + count + " automata.");
      }
    } else {
      Automaton.State state = automaton.states[index];
      int[] state_children = state.children;
      for(int[] nchildren : Automata.permutations(state_children)) {
        state.children = nchildren;
        generateData(index,automaton,writer,config);
      }
    }
  }


  private static void generateData(int index, Automaton automaton,
      GenericWriter<Automaton> writer, Config config) throws IOException {
    Automaton.State state = automaton.states[index];
    Kind kind = config.KINDS[state.kind];
    if (kind.DATA != null) {
      // this kind requires supplementary data
      List<Object> datas = kind.DATA.generate(state);
      for (Object data : datas) {
        state.data = data;
        generate(index + 1, automaton, writer, config);
      }
    } else {
      generate(index + 1, automaton, writer, config);
    }
  }

  private static boolean verbose = false;
  private static int count = 0;

  private static void debug(Template base) {
    int[] kinds = base.kinds;
    for(int i=0;i!=kinds.length;++i) {
      int kind = kinds[i];
      System.out.print("(" + kind +")");
    }
    for(int i=0;i!=kinds.length;++i) {
      for(int j=0;j!=kinds.length;++j) {
        if(base.isTransition(i,j)) {
          System.out.print(i + "->" +j + " ");
        }
      }
    }
    System.out.println();
  }

  private static void generate(int from, int to, Template base,
      GenericWriter<Automaton> writer, Config config) throws IOException {
    int[] nchildren = base.children;
    int[] kinds = base.kinds;
    Kind fromKind = config.KINDS[kinds[from]];

    if(to >= config.SIZE) {
      if(nchildren[from] < fromKind.MIN_CHILDREN){
        // this indicates an invalid automaton, since this state doesn't
        // have enough children.
        return;
      }

      if(from > 0) {
        // non-root state, so ensure has parent
        boolean hasParent = false;
        for(int i=0;i!=from;++i) {
          if(base.isTransition(i,from)) {
            hasParent = true;
            break;
          }
        }

        if(!hasParent) { return; }
      }

      from = from + 1;
      to = from;

      if(to >= config.SIZE) {
        // ok, generate the automaton.
        generate(base,writer,config);
        return;
      }
    }

    // first, generate no edge (if allowed)
    generate(from,to+1,base,writer,config);
    Kind toKind = config.KINDS[kinds[to]];

    // second, generate forward edge (if allowed)
    if (from != to && nchildren[from] < fromKind.MAX_CHILDREN) {
      nchildren[from]++;
      base.add(from,to);
      generate(from,to+1,base,writer,config);

      // third, generate bidirectional edge (if allowed)
      if (config.RECURSIVE && nchildren[to] < toKind.MAX_CHILDREN) {
        nchildren[to]++;
        base.add(to, from);
        generate(from, to+1, base, writer, config);
        base.remove(to, from);
        nchildren[to]--;
      }
      base.remove(from,to);
      nchildren[from]--;
    }

    // fourth, generate reverse edge (if allowed)
    if (config.RECURSIVE && nchildren[to] < toKind.MAX_CHILDREN) {
      nchildren[to]++;
      base.add(to, from);
      generate(from, to+1, base, writer, config);
      base.remove(to, from);
      nchildren[to]--;
    }
  }

  private static void generate(int index, Template base,
      GenericWriter<Automaton> writer, Config config) throws IOException {
    if(index == config.SIZE) {
      // now start generating transitions
      generate(0,0,base,writer,config);
    } else {
      Kind[] kinds = config.KINDS;
      for(int k=0;k!=kinds.length;++k) {
        Kind kind = kinds[k];
        if(kind != null) {
          base.kinds[index] = k;
          generate(index+1,base,writer,config);
        }
      }
    }
  }

  /**
   * The generate method generates all possible automata matching of a given
   * size. Observe that this may be an extremely expensive operation, and
   * significant care must be exercised in setting the configuration
   * parameters!
   *
   * @param size
   *            --- generated automata will have exactly this size.
   * @param recursive
   *            --- generated automata permit recursive links.
   * @param writer
   *            --- generate automata are written to this writer.
   */
  public static void generate(GenericWriter<Automaton> writer, Config config) throws IOException {
    Template base = new Template(config.SIZE);
    generate(0,base,writer,config);
  }

  private static final Config config = new Config() {{
    KINDS = new Kind[]{
      new Kind(false,0,2,null),
      new Kind(true,1,1,null)
    };
    RECURSIVE = true;
    SIZE = 3;
  }};

  public static void main(String[] args) {
    boolean binary = false;
    GenericWriter<Automaton> writer;
    OutputStream out = System.out;
    int minSize = 1;
    int maxSize = config.SIZE;

    try {
      int index = 0;
      while(index < args.length) {
        if(args[index].equals("-b")) {
          binary=true;
        } else if(args[index].equals("-o")) {
          String filename = args[++index];
          out = new FileOutputStream(filename);
        } else if(args[index].equals("-s") || args[index].equals("-size")) {
          String arg = args[++index];
          if(arg.indexOf(':') >= 0) {
            String[] ss = arg.split(":");
            minSize = Integer.parseInt(ss[0]);
            maxSize = Integer.parseInt(ss[1]);
          } else {
            maxSize = Integer.parseInt(arg);
          }
        } else if(args[index].equals("-v") || args[index].equals("-verbose")) {
          verbose = true;
        } else if(args[index].equals("-m") || args[index].equals("-model")) {
          config.RECURSIVE = false;
          for(Kind k : config.KINDS) {
            if(!k.DETERMINISTIC) {
              k.DETERMINISTIC = true;
              k.MIN_CHILDREN = 0;
              k.MAX_CHILDREN = 1;
            }
          }
        }
        index++;
      }

      if(binary) {
        BinaryOutputStream bos = new BinaryOutputStream(out);
        writer = new BinaryAutomataWriter(bos);
      } else {
        writer = new TextAutomataWriter(out);
      }
      for(int i=minSize;i<=maxSize;++i) {
        config.SIZE = i;
        generate(writer,config);
      }
      if(!verbose) {
        System.err.print("\rWrote " + count + " automata.");
      }
      writer.close();
    } catch(IOException ex) {
      System.out.println("Exception: " + ex);
    }
  }
}
TOP

Related Classes of wyautl_old.util.Generator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.