/*
* JFLAP - Formal Languages and Automata Package
*
*
* Susan H. Rodger
* Computer Science Department
* Duke University
* August 27, 2009
* Copyright (c) 2002-2009
* All rights reserved.
* JFLAP is open source software. Please see the LICENSE for terms.
*
*/
package pumping;
import java.io.Serializable;
import java.util.*;
/**
* A PumpingLemma
contains the information needed
* to guide the user through a pumping lemma proof.
*
* @author Jinghui Lim & Chris Morgan
*
*/
public abstract class PumpingLemma implements Serializable
{
/**
* Tag for when the computer goes first.
*/
public static final String COMPUTER = "Computer";
/**
* Tag for when the user goes first.
*/
public static final String HUMAN = "Human";
/**
* String representing "{a, b}*".
*/
protected static String AB_STAR = "{a, b}*";
/**
* String representing "not equals", "≠".
*/
protected static String NOT_EQUAL = "≠";
/**
* HTML code for "element of", "∈".
*/
protected static String ELEMENT_OF = "∈";
/**
* HTML code for "greater than or equal to", "≥".
*/
protected static String GREATER_OR_EQ = "≥";
/**
* HTML code for "grater than", ">".
*/
protected static String GREATER_THAN = ">";
/**
* HTML code for "less than", "<".
*/
protected static String LESS_THAN = "<";
/**
* HTML code for "less than or equal to", "≤".
*/
protected static String LESS_OR_EQ = "≤";
/**
* States whether there is a valid partition for the language in question.
*/
protected boolean partitionIsValid;
/**
* A description of why this language does or does not have a valid partition.
*/
protected String explanation;
/**
* States who the first player is, the human or the computer.
*/
protected String firstPlayer;
/**
* The m value used by this pumping lemma.
*/
protected int m;
/**
* The w value used by this pumping lemma.
*/
protected String w;
/**
* The w value used by this pumping lemma.
*/
protected int i;
/**
* All the possible cases. Cases should not be removed from this list.
*/
protected ArrayList myAllCases;
/**
* Cases that the user has already done. Cases should not be removed from
* myAllCases
to add to this, they should just be added.
*/
protected ArrayList myDoneCases;
/**
* Stores all the decompositions and i values the user has already attempted
* in separate int[] entries.
*/
protected ArrayList myAttempts;
/**
* A suggested range for m.
*/
protected int[] myRange;
/**
* The current decomposition of this lemma.
*/
protected int[] myDecomposition;
/**
* Constructs a new PumpingLemma
.
*
*/
public PumpingLemma()
{
myDoneCases = new ArrayList();
myAllCases = new ArrayList();
myAttempts = new ArrayList();
setRange();
setDescription();
reset();
addCases();
}
/**
* Returns a string repeated i times, si.
*
* @param s the string to repeat
* @param i the number of times to repeat it
* @return the string si
*/
protected static String pumpString(String s, int i)
{
StringBuffer sb = new StringBuffer();
for(int n = i; n > 0; n--)
sb.append(s);
return sb.toString();
}
/**
* Returns who is the first player, the human or the computer.
*
* @return the first player
*/
public String getFirstPlayer()
{
return firstPlayer;
}
/**
* Returns the current m value.
*
* @return the current m value
*/
public int getM()
{
return m;
}
/**
* Returns the current w value.
*
* @return the current w value
*/
public String getW()
{
return w;
}
/**
* Returns the current decomposition as an int[].
*
* @return the current decomposition
*/
public int[] getDecomposition()
{
return myDecomposition;
}
/**
* Returns the decomposition as a string with explicit labeling of which variables
* in the decomposition are assigned to what substrings.
*/
public abstract String getDecompositionAsString();
/**
* Returns the number of times to pump the string, i.
*
* @return the current i value
*/
public int getI()
{
return i;
}
/**
* Returns the list of attempts already made.
*
* @return the current list of attempts
*/
public ArrayList getAttempts()
{
return myAttempts;
}
/**
* Returns whether a valid partition can be applied to this function, meaning there is a
* valid repeatable decomposition.
*
* @return the partition's validity
*/
public boolean getPartitionValidity()
{
return partitionIsValid;
}
/**
* Returns the explanation of this language. The explanation has html tags, so the explanation should
* only be shown in an html text editor.
*
* @return the explanation
*/
public String getExplanation()
{
return explanation;
}
/**
* Returns a string title of the pumping lemma.
*
* @return the title of the lemma
*/
public abstract String getTitle();
/**
* Returns a title with HTML tags that will allow for a better
* representation of the language of the lemma.
*
* @return a title with HTML tags
*/
public abstract String getHTMLTitle();
/**
* Returns the recommended range form.
*
* @return the recommended range form
*/
public int[] getRange()
{
return myRange;
}
/**
* Sets a recommended range for m.
*
*/
protected abstract void setRange();
/**
* Sets who the first player is.
*/
public void setFirstPlayer(String s)
{
firstPlayer = s;
}
/**
* Sets the isInClassification
and explanation
values.
*/
protected abstract void setDescription();
/**
* Sets m to the number given.
*
* @param n the number m will be set to
*/
public void setM(int n)
{
reset();
m = n;
chooseW();
}
/**
* /**
* Sets w to the number given.
*
* @param s the string w will be set to
*/
public void setW(String s){
w = s;
}
/**
* Sets i and sets the decomposition given.
*
* @param decomposition the decomposition to set for this lemma
* @param num the number to set i to
* @return true
if this deocmposition is legal, false
otherwise
*/
public abstract boolean setDecomposition(int[] decomposition, int num);
/**
* Sets the decomposition, with the length of each part of the
* decomposition in the corresponding space of the input array,
* then chooses an acceptable i.
*
* @see #setDecomposition(int[], int)
* @param decomposition the array that contains the length of each part of the decomposition
* @return true
if this decomposition is legal, false
otherwise
*/
public abstract boolean setDecomposition(int[] decomposition);
/**
* Sets the i this instance of the pumping lemma uses.
*
* @param num the value i will be set to
*/
public void setI(int num)
{
i = num;
}
/**
* Adds the given attempt to the list of attempts.
*
* @param attempt the attempt to be added.
*/
public void addAttempt(String attempt)
{
myAttempts.add(attempt);
}
/**
* Clears all existing attempts from the list of attempts.
*/
public void clearAttempts()
{
myAttempts.clear();
}
/**
* Clears all information the user has entered and other fields, including
* m, w, and its decomposition.
*
*/
public abstract void reset();
/**
* The computer chooses a sutiable value for m. Called when the computer goes first
*/
public void chooseM()
{
m = LemmaMath.fetchRandInt(myRange[0], myRange[1]);
}
/**
* The computer chooses a suitable string w. Called when the user goes first.
*/
protected abstract void chooseW();
/**
* The computer chooses an acceptable decomposition for the string when given an
* acceptable 'w' value. 'w' is known to be in the lemma before this method is
* called. Regular lemmas will have two values (x-y, y-z) dividers, while context-free
* lemmas will have four. Called when the computer goes first.
*/
public abstract void chooseDecomposition();
/**
* The computer chooses and returns a suitable number of times to pump the string, i.
* Called when the user goes first.
*/
public abstract void chooseI();
/**
* Returns the pumped string according the the decomposition and choice of
* i.
*
* @return the pumped string
*/
public abstract String createPumpedString();
/**
* Returns the total number of cases.
*
* @return the total number of cases
*/
public int numCasesTotal()
{
return myAllCases.size();
}
/**
* Does all the remaining undone cases.
*/
public void doAll()
{
for(int i = 0; i < myAllCases.size(); i++)
{
if(!myDoneCases.contains(myAllCases.get(i)))
myDoneCases.add(myAllCases.get(i));
}
}
/**
* Clears all cases that the user has done. The user set decompositions
* of those cases are also cleared.
*/
public void clearDoneCases()
{
myDoneCases.clear();
for(int i = 0; i < myAllCases.size(); i++)
((Case)myAllCases.get(i)).reset();
}
/**
* Removes a particular case from the "done" pile.
*
* @param n the index of the case to be removed
*/
public void clearCase(int n)
{
((Case)myDoneCases.remove(n)).reset();
}
/**
* Returns the case at index
that was added with
* {@link #addCase(int[], int)}.
*
* @param index the index of the decomposition to be retrieved
* @return the case at index
*/
public Case getCase(int index)
{
return (Case)myDoneCases.get(index);
}
/**
* Adds the decomposition to the list that the user has done. It should only be
* called after {@link #setDecomposition(int[])} to ensure the fields are set
* up properly. If the case is not a legal decomposition, the it returns
* -1
. If the case has already been done, it returns the index of
* the case without changing the case. If it hasn't been done, it moves the case
* to the "done" list and returns its position in the done list.
*
* @see Case#isCase(String, String)
* @see #replaceCase(int[], int, int)
* @param decomposition the decomposition we wish to add
* @param num the value of i
* @return -1
if it is an illegal decomposition, the index of the
* decomposition if it has already been done, or a number bigger than or equal
* to the total number of cases, which can be found by calling
* {@link #numCasesTotal()}.
*/
public abstract int addCase(int[] decomposition, int num);
/**
* Replaces the decomposition in the list of that the user has done. It should only be
* called after {@link #setDecomposition(int[])} to ensure the fields are set
* up properly. If the user has not done the case, it returns false
.
*
* @see Case#isCase(String, String)
* @see #addCase(int[], int)
* @param decomposition the decomposition we wish to add
* @param num the value of i
* @param index the place of the decomposition we wish to have replaced
* @return true
if the decomposition and case match,
* false otherwise
*/
public abstract boolean replaceCase(int[] decomposition, int num, int index);
/**
* Returns an ArrayList
of String
s that describe
* each case.
*
* @return descriptions of each case
*/
public ArrayList getDoneDescriptions()
{
ArrayList ret = new ArrayList();
for(int i = 0; i < myDoneCases.size(); i++)
ret.add(myDoneCases.get(i).toString());
return ret;
}
/**
* Initializes all the possible cases for this pumping lemma.
*
*/
protected abstract void addCases();
/**
* Checks to see whether every case can be generated with the current w
* value. It also clears the list of done cases, so this should be called only
* when the list is empty or when one wishes to clear the list.
*
* @return whether every case can be generated
*/
/*public boolean checkAllCasesPossible()
{
//Uncomment this method if using cases when the computer goes first.
int[] currentDecomposition = myDecomposition;
clearDoneCases();
for (int i=0; iCase
s
*/
public ArrayList getDoneCases()
{
return myDoneCases;
}
/**
* Tests if the given string is in the language represented by this
* PumpingLemma
.
*
* @return true
if the pumped string is in the language,
* false
otherwise
*/
public abstract boolean isInLang(String s);
}