import java.util.*; // T J Finney, 2001 // Not to be sold without my permission. class Audience { // instance variables // place private String name; // latitude (radians N) private double latitude; // longitude (radians E) private double longitude; // population private double population; // population growth rate private double growth; // population limit private double limit; // all audiences private Audience[] aud; // library of MSS // MSS are ranked in order of popularity private Vector lib = new Vector(); // discarded MSS private Vector bin = new Vector(); // constructors public Audience (String a, String b, String c, double d, double e, double f, Audience [] g) { name = a; latitude = degtorad(b); longitude = degtorad(c); population = d; growth = e; limit = f; aud = g; } // static methods // main: test class public static void main (String [] args) { Audience[] group = new Audience[4]; group[0] = new Audience ("Constantinople", "41 N", "29 E", 10, 0.05, 10000, group); group[1] = new Audience ("Antioch", "36 N", "36 E", 10, 0.05, 10000, group); group[2] = new Audience ("Caesarea", "32 N", "35 E", 10, 0.05, 10000, group); group[3] = new Audience ("Alexandria", "31 N", "30 E", 10, 0.05, 10000, group); MS.initStates(); System.out.println("Audience()"); Audience home = group[2]; MS ms1 = MS.makeArchetype(); System.out.println("addMS()"); home.addMS(ms1); System.out.println("copyMS()"); home.copyMS(0.8); System.out.println("getMS()"); for (int i = 0; i < home.getLibSize(); i++) { home.getMS(i).print(); } System.out.println("correctMSS()"); home.correctMSS(1.0); System.out.println("discardMSS()"); home.discardMSS(1.0); home.addMS(ms1); home.copyMS(0.9); home.copyMS(0.9); home.copyMS(0.9); home.copyMS(0.9); System.out.println("getExem()"); home.getExem().print(); System.out.println("getExem()"); group[0].getExem(); System.out.println("getMS()"); group[0].getMS(0); System.out.println("getPop()"); System.out.println(home.getPop()); System.out.println("howFarIs()"); for (int i = 0; i < group.length; i++) { System.out.println(home.howFarIs(group[i])); } System.out.println("importMS() ten times"); for (int i = 0; i < 10; i++) { home.importMS(); } // do cycles for (int i = 35; i <= 300; i++) { System.out.println("Year " + i); home.cycle(0.02, 0.01, 0.9, 0.02, 0.05); home.print(); System.out.println(); } // output sample MS ms; Vector mss = home.getBin(); for (int i = 0; i < 10; i++) { int index = Stats.getRandInt(mss.size()); ms = (MS) mss.remove(index); ms.print(); } } // service methods // add MS public void addMS (MS addition) { // select rank int rank = Stats.getRandInt(lib.size() + 1); lib.add(rank, addition); } // copy MS // acc = prob. of making an accurate copy (per unit) public void copyMS (double acc) { if (lib.size() > 0) { // select exemplar MS exemplar = getExem(); // copy MS MS ms = Scribe.copy(exemplar, acc); // add to library addMS(ms); // print System.out.println("Copy MS" + ms.getID() + " from MS" + exemplar.getID()); } } // correct MSS // p1 = annual prob. of MS correction public void correctMSS (double p1) { int num = lib.size(); for (int i = 0; i < num; i++) { if (Stats.trial(p1) && (num > 1)) { // get specified MS MS ms = getMS(i); MS exemplar = getExem(); // ensure MS and exemplar differ while (ms.getID() == exemplar.getID()) { exemplar = getExem(); } // correct MS Scribe.correct(ms, exemplar); // print System.out.println("Correct MS" + ms.getID() + " against MS" + exemplar.getID()); } } } // cycle through annual activities // p1 = annual probability of MS correction // p2 = prob. of correcting a difference // p3 = annual probability of MS discard // p4 = prob. of correctly copying a unit // r1 = ratio of MSS to audience members // r2 = ratio of imported to local MSS public void cycle (double p1, double p2, double p3, double r1, double r2) { // update audience size population += Stats.logistic(population, growth, limit); // correct MSS correctMSS(p1); // discard MSS discardMSS(p2); // calculate demand for new MSS int demand = (int) (population * r1 - lib.size()); // force import if no MSS if ((demand == 2) && (lib.size() == 0)) { importMS(); if (lib.size() == 1) { demand--; } } // supply MSS for (int i = 0; i < demand; i++) { // decide whether to import MS if (Stats.trial(r2)) { // import MS importMS(); } else { // copy MS locally copyMS(p3); } } } // discard MSS // d is annual probability of MS discard public void discardMSS (double d) { MS ms; for (int i = 0; i < lib.size(); i++) { if (Stats.trial(d)) { ms = (MS) lib.remove(i); // compensate index i--; // add discarded MS to bin bin.add(ms); System.out.println("Discard MS" + ms.getID()); } } } // get bin public Vector getBin () { return bin; } // get bin size public int getBinSize () { return bin.size(); } // get exemplar from lib according to rank // (uses Zipf's law) public MS getExem () { MS ms; try { int index = Stats.zipf(lib.size()); ms = (MS) lib.get(index); } catch (ArrayIndexOutOfBoundsException problem) { System.out.println("No MSS in library"); ms = null; } return ms; } // get library public Vector getLib () { return lib; } // get library size public int getLibSize () { return lib.size(); } // get specified MS from lib public MS getMS (int index) { MS ms; try { ms = (MS) lib.get(index); } catch (ArrayIndexOutOfBoundsException problem) { System.out.println("No MSS in library"); ms = null; } return ms; } // get name of audience public String getName () { return name; } // get population of audience public int getPop () { return (int) population; } // calculate great circle distance in km // (law of cosines formula) public int howFarIs (Audience that) { double theta = Math.sin(this.latitude) * Math.sin(that.latitude) + Math.cos(this.latitude) * Math.cos(that.latitude) * Math.cos(this.longitude - that.longitude); return (int) (6367 * Math.acos(theta)); } // import MS public void importMS () { // list distances double[] dist = new double[aud.length]; for (int i = 0; i < aud.length; i++) { dist[i] = (double) howFarIs(aud[i]); } // select place using power law int index = Stats.select(dist, -1.0); // select MS and transfer int num = aud[index].getLibSize(); if (num > 0) { // select MS (not by rank) int ind = Stats.getRandInt(num); // transfer MS ms = (MS) aud[index].getLib().remove(ind); lib.add(ms); System.out.println("Import MS" + ms.getID() + " from " + aud[index].getName()); } } // print public void print () { System.out.println("Audience: " + (int) population + "\t" + "Holdings: " + lib.size()); } // support methods // convert degrees to radians // input format: ddd mm ss N, S, E, or W private double degtorad (String angle) { StringTokenizer tokens = new StringTokenizer (angle); String next = new String(); int index = 0; int [] DMS = new int[3]; while (tokens.hasMoreTokens()) { next = tokens.nextToken(); if (Character.isDigit(next.charAt(0))) { DMS[index] = Integer.decode(next).intValue();; index++; } } double decimalDegrees = DMS[0] + DMS[1]/60 + DMS[2]/3600; if (next.equalsIgnoreCase("S") || next.equalsIgnoreCase("W")) { decimalDegrees = -decimalDegrees; } return Math.PI * decimalDegrees/180; } }