Added contribution from Ian Clarke.

This commit is contained in:
talisman%anamorphic.com 2000-04-08 06:16:32 +00:00
parent 529deac28b
commit f42f6c0b2c
4 changed files with 669 additions and 0 deletions

101
grendel/filters/Applet.java Normal file
View File

@ -0,0 +1,101 @@
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the GFilt filter package, as integrated into
* the Grendel mail/news reader.
*
* The Initial Developer of the Original Code is Ian Clarke.
* Portions created by Ian Clarke are
* Copyright (C) 2000 Ian Clarke. All
* Rights Reserved.
*
* Contributor(s):
*/
package grendel.filters; // formerly GFilt
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
public class Applet extends java.applet.Applet
{
/**
* The constructor, creates the Applet
*/
public Applet()
{
}
/**
* Called by the browser or applet viewer to inform
* this applet that it has been loaded into the system. It is always
* called before the first time that the <code>start</code> method is
* called.
* <p>
* A subclass of <code>Applet</code> should override this method if
* it has initialization to perform. For example, an applet with
* threads would use the <code>init</code> method to create the
* threads and the <code>destroy</code> method to kill them.
* <p>
* The implementation of this method provided by the
* <code>Applet</code> class does nothing.
*/
public void init()
{
}
/**
* Called by the browser or applet viewer to inform
* this applet that it should start its execution. It is called after
* the <code>init</code> method and each time the applet is revisited
* in a Web page.
* <p>
* A subclass of <code>Applet</code> should override this method if
* it has any operation that it wants to perform each time the Web
* page containing it is visited. For example, an applet with
* animation might want to use the <code>start</code> method to
* resume animation, and the <code>stop</code> method to suspend the
* animation.
* <p>
* The implementation of this method provided by the
* <code>Applet</code> class does nothing.
*
*/
public void start()
{
}
/**
* Called by the browser or applet viewer to inform
* this applet that it should stop its execution. It is called when
* the Web page that contains this applet has been replaced by
* another page, and also just before the applet is to be destroyed.
* <p>
* A subclass of <code>Applet</code> should override this method if
* it has any operation that it wants to perform each time the Web
* page containing it is no longer visible. For example, an applet
* with animation might want to use the <code>start</code> method to
* resume animation, and the <code>stop</code> method to suspend the
* animation.
* <p>
* The implementation of this method provided by the
* <code>Applet</code> class does nothing.
*
*/
public void stop()
{
}
}

View File

@ -0,0 +1,194 @@
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the GFilt filter package, as integrated into
* the Grendel mail/news reader.
*
* The Initial Developer of the Original Code is Ian Clarke.
* Portions created by Ian Clarke are
* Copyright (C) 2000 Ian Clarke. All
* Rights Reserved.
*
* Contributor(s):
*/
package grendel.filters; // formerly GFilt
public class Breeder
{
public static void main(String[] args)
{
/**
* A list of strings that should "pass" the filter
**/
String[] pos = {"sdfviawnasdvb","asdciainasdf","erpianwdr"};
/**
* A list of strings that should "fail" the filter
**/
String[] neg = {"sdfviarnasdvb","asdciwanasdf","eriyanwdr"};
System.out.println("Best: "+evolve(pos, neg, 500));
}
public static Filter evolve(String[] pos, String[] neg, int popSz)
{
Breeder b = new Breeder(pos,neg,popSz);
float bestScore = 0, lastBestScore = -1;
int BSrun=0;
for (int x=0; (x<1000 && BSrun < 20); x++)
{
b.scoreAll();
bestScore = b.getBestScore();
if (bestScore == lastBestScore)
{
BSrun++;
}
else
{
BSrun = 0;
lastBestScore = bestScore;
}
System.out.println(""+x+":"+bestScore+":"+b.getBest());
b.updatePop();
}
return b.getBest();
}
protected String[] positives, negatives;
protected float[] scores;
protected int totalScore = 0;
protected Filter[] population;
protected java.util.Random r = new java.util.Random();
protected Mutator mut;
public Breeder(String[] p, String[] n, int popSz)
{
this(p, n, null);
population = new Filter[popSz];
for (int x=0; x<population.length; x++)
{
population[x] = new Filter();
int np = (Math.abs(r.nextInt()) % 10) + 2;
for (int y=0; y<np; y++)
{
mut.addPattern(population[x]);
}
}
}
public Breeder(String[] p, String[] n, Filter[] f)
{
positives = p;
negatives = n;
population = f;
StringBuffer sb = new StringBuffer();
for (int x=0; x<p.length; x++)
{
sb.append(p[x]);
}
mut = new Mutator(sb.toString());
}
public void updatePop()
{
Filter[] nextPop = new Filter[population.length];
nextPop[0] = getBest();
nextPop[1] = new Filter();
int np = (Math.abs(r.nextInt()) % 10) + 2;
for (int y=0; y<np; y++)
{
mut.addPattern(nextPop[1]);
}
for (int x=2; x<nextPop.length; x++)
{
nextPop[x] = selectRandFilt().duplicate();
for (int p=0; p<2;p++)
mut.mutate(nextPop[x]);
}
population = nextPop;
}
public float getBestScore()
{
float bestScore = scores[0];
for (int x=1; x<population.length; x++)
{
if (scores[x] > bestScore)
{
bestScore = scores[x];
}
}
return bestScore;
}
public Filter getBest()
{
Filter best = population[0];
float bestScore = scores[0];
for (int x=1; x<population.length; x++)
{
if (scores[x] > bestScore)
{
bestScore = scores[x];
best = population[x];
}
}
return best;
}
protected Filter selectRandFilt()
{
int p=0, x = Math.abs(r.nextInt()) % totalScore;
while(x>=0)
{
x -= scores[p];
p++;
}
return population[p-1];
}
public void scoreAll()
{
scores = new float[population.length];
float s;
totalScore = 0;
for (int x=0; x<population.length; x++)
{
s = score(population[x]);
scores[x] = s;
totalScore += s;
}
}
protected float score(Filter f)
{
int score = 0;
for (int x=0; x<positives.length; x++)
{
if (f.match(positives[x]))
score++;
}
for (int x=0; x<negatives.length; x++)
{
if (!(f.match(negatives[x])))
score++;
}
return score + ((float) score/((float) (f.getTLength()+30)));
}
}

238
grendel/filters/Filter.java Normal file
View File

@ -0,0 +1,238 @@
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the GFilt filter package, as integrated into
* the Grendel mail/news reader.
*
* The Initial Developer of the Original Code is Ian Clarke.
* Portions created by Ian Clarke are
* Copyright (C) 2000 Ian Clarke. All
* Rights Reserved.
*
* Contributor(s):
*/
package grendel.filters; // formerly GFilt
import java.util.*;
public class Filter {
/**
* Set to true to output debugging information
**/
public boolean debug = false;
Pattern patterns = null;
/**
* Get the number of patterns in the filter
* @return The number of patterns in the filter
**/
public int getLength() {
Pattern cur = patterns;
int r = 0;
while (cur != null) {
cur = cur.next;
r++;
}
return r;
}
public int getTLength() {
Pattern cur = patterns;
int r = 0;
while (cur != null)
{
r += cur.str.length() + 1;
cur = cur.next;
}
return r;
}
public void setString(String str, int p) {
Pattern pat = patterns;
for (int x = 0; x < p; x++) {
pat = pat.next;
}
pat.str = str;
}
public void setAnd(boolean and, int p) {
Pattern pat = patterns;
for (int x = 0; x < p; x++) {
pat = pat.next;
}
pat.and = and;
}
public void del(int p) {
if (p == 0) {
patterns = patterns.next;
} else {
Pattern cur = patterns;
for (int x = 0; x < (p - 1); x++) {
cur = cur.next;
}
cur.next = cur.next.next;
}
}
public String getString(int p) {
Pattern pat = patterns;
for (int x = 0; x < p; x++) {
pat = pat.next;
}
return pat.str;
}
public boolean getAnd(int p) {
Pattern pat = patterns;
for (int x = 0; x < p; x++) {
pat = pat.next;
}
return pat.and;
}
public void insert(String s, boolean and, int p) {
Pattern n = new Pattern(s, and);
Pattern cur = patterns;
if (p == 0) {
n.next = patterns;
patterns = n;
} else {
for (int x = 0; x < p - 1; x++) {
cur = cur.next;
}
n.next = cur.next;
cur.next = n;
}
}
public void push(String s, boolean and) {
if (patterns == null) {
patterns = new Pattern(s, and);
} else {
Pattern p = patterns;
while (p.next != null) {
p = p.next;
}
p.next = new Pattern(s, and);
}
}
public boolean match(String str) {
return match(str, 0, patterns);
}
public Filter duplicate()
{
Filter n = new Filter();
Pattern cur = patterns;
while(cur != null)
{
n.push(cur.str, cur.and);
cur = cur.next;
}
return n;
}
protected boolean match(String str, int pos, Pattern pat)
{
if (pat == null)
{
System.err.println("Attempted to match with empty pattern list");
return false;
}
int p = str.indexOf(pat.str, pos);
if (debug)
System.err.print("Matching "+pat.str + " from "+pos + " - ");
if (p == -1) {
if (debug)
System.err.print("Not found - ");
if (pat.next == null) {
if (debug)
System.err.println("Last pattern - failing");
return false;
}
if (pat.and) {
if (debug)
System.err.println("And relationship - failing");
return false;
} else {
if (debug)
System.err.println("Or relationship - recursing");
return match(str, pos, pat.next);
}
} else {
if (debug)
System.err.print("Found at "+p + " - ");
Pattern tPat = pat;
while (!(tPat.and)) {
if (tPat.next == null) {
if (debug)
System.err.println("Last one - success");
return true;
}
tPat = tPat.next;
}
if (tPat.next == null) {
if (debug)
System.err.println("All others are 'or' - success");
return true;
}
if (debug)
System.err.println("Skipping to end of or group");
if (match(str, p + pat.str.length(), tPat.next))
return true;
else {
if (debug)
System.err.println("Backtracking..");
return (match(str, pos, pat.next));
}
}
}
public String toString() {
StringBuffer s = new StringBuffer();
Pattern cur = patterns;
while (cur != null) {
String andV;
if (cur.and)
andV = " and then ";
else
andV = "or";
if (cur.next != null)
s.append("\""+cur.str + "\" "+andV + " ");
else
s.append("\""+cur.str + "\"");
cur = cur.next;
}
return s.toString();
}
}
class Pattern {
public boolean and;
public Pattern next = null;
public String str;
public Pattern(String s, boolean a) {
and = a;
str = s;
}
}

View File

@ -0,0 +1,136 @@
/* -*- Mode: java; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Mozilla Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the GFilt filter package, as integrated into
* the Grendel mail/news reader.
*
* The Initial Developer of the Original Code is Ian Clarke.
* Portions created by Ian Clarke are
* Copyright (C) 2000 Ian Clarke. All
* Rights Reserved.
*
* Contributor(s):
*/
package grendel.filters; // formerly GFilt
import java.util.*;
/**
* Allows a filter to be mutated in a variety of ways, using a
* string as a source for new material
**/
public class Mutator
{
String source;
Random r = new Random();
public static void main(String[] args)
{
Mutator s = new Mutator("abcdefghijklmnopqrstuvwxyz");
for (int x=0; x<10; x++)
System.out.println("\"vwxyz\" -> \""+s.modify("vwxyz")+"\"");
}
public Mutator(String s)
{
source = s;
}
public void mutate(Filter f)
{
int p = Math.abs(r.nextInt()) % 4;
int ps;
ps = (Math.abs(r.nextInt()) % f.getLength());
if ((p==0) && (f.getLength() > 1))
{ // Delete a pattern
f.del(ps);
}
else if (p==1)
{ // Modify a string in a pattern
String s = f.getString(ps);
f.setString(modify(s), ps);
}
else if (p==2)
{ // Invert the 'and' in a pattern
f.setAnd(!(f.getAnd(ps)), ps);
}
else if (p==3)
{ // Add a new pattern
addPattern(f);
}
}
public void addPattern(Filter f)
{
int ps;
if (f.getLength() > 0)
ps = (Math.abs(r.nextInt()) % f.getLength());
else
ps = 0;
int len = Math.abs(r.nextInt()) % 10;
int pos = Math.abs(r.nextInt()) % (source.length()-len);
f.insert(source.substring(pos, pos+len),
((r.nextInt() % 2) == 0), ps);
}
public Filter breed(Filter a, Filter b)
{
Filter shorter, longer, ret = new Filter();
if (a.getLength() < b.getLength())
{
shorter = a;
longer = b;
}
else
{
shorter = b;
longer = a;
}
int p = (Math.abs(r.nextInt()) % shorter.getLength());
for(int x=0; x<p; x++)
{
ret.push(shorter.getString(x), shorter.getAnd(x));
}
for(int x=p; x<longer.getLength(); x++)
{
ret.push(longer.getString(x), longer.getAnd(x));
}
return ret;
}
protected String modify(String s)
{
int len = s.length();
len += (Math.abs(r.nextInt()) % 6) - 3;
if (len < 1)
len = 1;
int pos = source.indexOf(s);
if (pos == -1)
{
pos = (Math.abs(r.nextInt())% (source.length()-len));
}
else
{
pos += (Math.abs(r.nextInt()) % 6) - 3;
}
if (pos < 1)
pos = 1;
if ((source.length() - pos) < len)
{
len = source.length() - pos;
}
return source.substring(pos, pos+len);
}
}