eoss.problem.EOSSProblem.java Source code

Java tutorial

Introduction

Here is the source code for eoss.problem.EOSSProblem.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package eoss.problem;

import architecture.Explanation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import jess.Fact;
import jess.JessException;
import jess.RU;
import jess.Rete;
import jess.Value;
import jess.ValueVector;
import org.apache.commons.lang3.StringUtils;
import org.moeaframework.core.Solution;
import org.moeaframework.problem.AbstractProblem;
import architecture.util.FuzzyValue;
import architecture.util.Interval;
import eoss.jess.JessInitializer;
import eoss.jess.QueryBuilder;

/**
 * An assigning problem to optimize the allocation of n instruments to m orbits.
 * Also can choose the number of satellites per orbital plane. Objectives are
 * cost and scientific benefit
 *
 * @author nozomihitomi
 */
public class EOSSProblem extends AbstractProblem {

    private final int[] altnertivesForNumberOfSatellites;

    private Rete r;

    private QueryBuilder qb;

    private final boolean explanation;

    private final boolean withSynergy;

    /**
     *
     * @param altnertivesForNumberOfSatellites
     * @param instruments
     * @param orbits
     * @param buses
     * @param explanation determines whether or not to attach the explanations
     * @param withSynergy determines whether or not to evaluate the solutions
     * with synergy rules.
     */
    public EOSSProblem(int[] altnertivesForNumberOfSatellites, ArrayList<Instrument> instruments,
            ArrayList<Orbit> orbits, ArrayList<Bus> buses, boolean explanation, boolean withSynergy) {
        //2 decisions for Choosing and Assigning Patterns
        super(2, 2);
        this.altnertivesForNumberOfSatellites = altnertivesForNumberOfSatellites;
        this.r = new Rete();
        this.qb = new QueryBuilder(r);
        this.explanation = explanation;
        this.withSynergy = withSynergy;
    }

    public void renewJess() {
        this.r = new Rete();
        this.qb = new QueryBuilder(r);
        JessInitializer ji = new JessInitializer();
        ji.initializeJess(r, qb);
    }

    /**
     * Gets the instruments for this problem
     *
     * @return
     */
    public ArrayList<Instrument> getInstruments() {
        return EOSSDatabase.getInstruments();
    }

    /**
     * Gets the orbits for this problem
     *
     * @return
     */
    public ArrayList<Orbit> getOrbits() {
        return EOSSDatabase.getOrbits();
    }

    @Override
    public void evaluate(Solution sltn) {
        EOSSArchitecture arch = (EOSSArchitecture) sltn;

        try {
            long startTime = System.currentTimeMillis();
            r.reset();
            assertMissions(arch);
            double science = evaluatePerformance(arch); //compute science score
            arch.setObjective(0, -science); //negative because MOEAFramework assumes minimization problems

            r.reset();
            assertMissions(arch);
            //            evaluateCostEONRules(r, arch, qb); //compute cost
            double cost = evaluateCost(arch);
            arch.setObjective(1, cost / 33495.939796); //normalize cost to maximum value
            r.clearStorage();

            System.out.println("Arch " + arch.toString() + ": Science = " + arch.getObjective(0) + "; Cost = "
                    + arch.getObjective(1) + " :: " + arch.payloadToString());
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public Solution newSolution() {
        return new EOSSArchitecture(altnertivesForNumberOfSatellites, EOSSDatabase.getInstruments().size(),
                EOSSDatabase.getOrbits().size(), 2);
    }

    private void aggregate_performance_score_facts(EOSSArchitecture arch) {
        ArrayList subobj_scores = new ArrayList();
        ArrayList obj_scores = new ArrayList();
        ArrayList panel_scores = new ArrayList();
        double science = 0.0;
        FuzzyValue fuzzy_science = null;
        Explanation explanations = new Explanation();
        TreeMap<String, Double> tm = new TreeMap<String, Double>();
        try {
            ArrayList<Fact> vals = qb.makeQuery("AGGREGATION::VALUE");
            Fact val = vals.get(0);
            science = val.getSlotValue("satisfaction").floatValue(r.getGlobalContext());
            if (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES")) {
                fuzzy_science = (FuzzyValue) val.getSlotValue("fuzzy-value").javaObjectValue(r.getGlobalContext());
            }
            panel_scores = jessList2ArrayList(val.getSlotValue("sh-scores").listValue(r.getGlobalContext()));

            ArrayList<Fact> subobj_facts = qb.makeQuery("AGGREGATION::SUBOBJECTIVE");
            for (int n = 0; n < subobj_facts.size(); n++) {
                Fact f = subobj_facts.get(n);
                String subobj = f.getSlotValue("id").stringValue(r.getGlobalContext());
                Double subobj_score = f.getSlotValue("satisfaction").floatValue(r.getGlobalContext());
                Double current_subobj_score = tm.get(subobj);
                if (current_subobj_score != null && subobj_score > current_subobj_score
                        || current_subobj_score == null) {
                    tm.put(subobj, subobj_score);
                }
                explanations.put(subobj, qb.makeQuery("AGGREGATION::SUBOBJECTIVE (id " + subobj + ")"));
            }
            for (Iterator<String> name = tm.keySet().iterator(); name.hasNext();) {
                subobj_scores.add(tm.get(name.next()));
            }
            //TO DO: obj_score and subobj_scores.
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES")) {
            arch.setFuzzyObjective(0, fuzzy_science);
        }
        if (explanation) {
            arch.setExplanation(0, explanations);
            arch.setCapabilities(qb.makeQuery("REQUIREMENTS::Measurement"));
        }
    }

    private double evaluateCostEONRules(EOSSArchitecture arch) throws JessException {
        r.setFocus("MANIFEST");
        r.run();

        double cost = 0.0;
        Explanation costFacts = new Explanation();
        if ((Params.req_mode.equalsIgnoreCase("FUZZY-CASES"))
                || (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES"))) {
            r.setFocus("FUZZY-CUBESAT-COST");
            r.run();

            ArrayList<Fact> missions = qb.makeQuery("MANIFEST::Mission");
            costFacts.put("cost", missions);
            FuzzyValue fzcost = new FuzzyValue("Cost", new Interval("delta", 0, 0), "FY04$M");
            for (Fact mission : missions) {
                cost += mission.getSlotValue("mission-cost#").floatValue(r.getGlobalContext());
                fzcost = fzcost.add(
                        (FuzzyValue) mission.getSlotValue("mission-cost").javaObjectValue(r.getGlobalContext()));
            }
            arch.setFuzzyObjective(0, fzcost);
            arch.setExplanation(0, costFacts);
        } else {
            r.setFocus("CUBESAT-COST");
            r.run();
            ArrayList<Fact> missions = qb.makeQuery("MANIFEST::Mission");
            costFacts.put("cost", missions);
            for (Fact mission : missions) {
                cost += mission.getSlotValue("mission-cost#").floatValue(r.getGlobalContext());
            }
            arch.setExplanation(0, costFacts);
        }
        arch.setObjective(1, cost);
        return cost;
    }

    private double evaluateCost(EOSSArchitecture arch) {
        double cost = 0.0;
        try {
            //
            r.eval("(focus MANIFEST)");
            r.run();

            designSpacecraft();
            r.eval("(focus SAT-CONFIGURATION)");
            r.run();

            r.eval("(focus LV-SELECTION0)");
            r.run();
            r.eval("(focus LV-SELECTION1)");
            r.run();
            r.eval("(focus LV-SELECTION2)");
            r.run();
            r.eval("(focus LV-SELECTION3)");
            r.run();

            if ((Params.req_mode.equalsIgnoreCase("FUZZY-CASES"))
                    || (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES"))) {
                r.setFocus("FUZZY-COST-ESTIMATION0"); //applies NICM cost model to all instruments without computed costs
                r.run();
                r.setFocus("FUZZY-COST-ESTIMATION");
            } else {
                r.setFocus("COST-ESTIMATION");
            }
            r.run();

            ArrayList<Fact> missions = qb.makeQuery("MANIFEST::Mission");
            for (Fact mission : missions) {
                cost = cost + mission.getSlotValue("lifecycle-cost#").floatValue(r.getGlobalContext());
            }

            if (explanation) {
                Explanation explanations = new Explanation();
                explanations.put("cost", missions);
                arch.setExplanation(1, explanations);
            }
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
        //System.out.println("Arch " + arch.toBitString() + ": Science = " + res.getScience() + "; Cost = " + res.getCost());
        return cost;
    }

    private void designSpacecraft() {
        try {
            r.eval("(focus PRELIM-MASS-BUDGET)");
            r.run();

            ArrayList<Fact> missions = qb.makeQuery("MANIFEST::Mission");
            Double[] oldmasses = new Double[missions.size()];
            for (int i = 0; i < missions.size(); i++) {
                oldmasses[i] = missions.get(i).getSlotValue("satellite-dry-mass").floatValue(r.getGlobalContext());
            }
            Double[] diffs = new Double[missions.size()];
            double tolerance = 10 * missions.size();
            boolean converged = false;
            while (!converged) {
                r.eval("(focus CLEAN1)");
                r.run();

                r.eval("(focus MASS-BUDGET)");
                r.run();

                r.eval("(focus CLEAN2)");
                r.run();

                r.eval("(focus UPDATE-MASS-BUDGET)");
                r.run();

                Double[] drymasses = new Double[missions.size()];
                double sumdiff = 0.0;
                double summasses = 0.0;
                for (int i = 0; i < missions.size(); i++) {
                    drymasses[i] = missions.get(i).getSlotValue("satellite-dry-mass")
                            .floatValue(r.getGlobalContext());
                    diffs[i] = Math.abs(drymasses[i] - oldmasses[i]);
                    sumdiff = sumdiff + diffs[i];
                    summasses = summasses + drymasses[i];
                }
                converged = sumdiff < tolerance || summasses == 0;
                oldmasses = drymasses;

            }
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void assertMissions(EOSSArchitecture arch) {
        try {
            for (int i = 0; i < EOSSDatabase.getOrbits().size(); i++) {
                Orbit orbit = EOSSDatabase.getOrbits().get(i);
                ArrayList<Instrument> instruments = arch.getInstrumentsInOrbit(orbit);
                if (instruments.size() > 0) {
                    String payload = "";
                    double payloadMass = 0;
                    double characteristicPower = 0;
                    double dataRate = 0;
                    ArrayList<Double> payloadDimensions = new ArrayList<>();
                    payloadDimensions.add(0, 0.0); //max dimension in x, y, and z
                    payloadDimensions.add(1, 0.0); //nadir-area
                    payloadDimensions.add(2, 0.0); //max z dimension
                    String call = "(assert (MANIFEST::Mission (Name " + orbit + ") ";
                    for (Instrument inst : instruments) {
                        payload = payload + " " + inst.getName();
                        payloadMass += Double.parseDouble(inst.getProperty("mass#"));
                        characteristicPower += Double.parseDouble(inst.getProperty("characteristic-power#"));
                        dataRate += Double.parseDouble(inst.getProperty("average-data-rate#"));
                        double dx = Double.parseDouble(inst.getProperty("dimension-x#"));
                        double dy = Double.parseDouble(inst.getProperty("dimension-y#"));
                        double dz = Double.parseDouble(inst.getProperty("dimension-z#"));
                        payloadDimensions.set(0,
                                Math.max(payloadDimensions.get(0), Math.max(Math.max(dx, dy), dz)));
                        payloadDimensions.set(1, payloadDimensions.get(1) + dx * dy);
                        payloadDimensions.set(2, Math.max(payloadDimensions.get(2), dz));

                        //manifest the instrument
                        String callManifestInstrument = "(assert (CAPABILITIES::Manifested-instrument ";
                        Iterator iter = inst.getProperties().iterator();
                        while (iter.hasNext()) {
                            String propertyName = (String) iter.next();
                            callManifestInstrument += "(" + propertyName + " " + inst.getProperty(propertyName)
                                    + ")";
                        }
                        callManifestInstrument += "(flies-in " + orbit.getName() + ")";
                        callManifestInstrument += "(orbit-altitude# " + String.valueOf((int) orbit.getAltitude())
                                + ")";
                        callManifestInstrument += "(orbit-inclination " + orbit.getInclination() + ")";
                        callManifestInstrument += "))";
                        r.eval(callManifestInstrument);
                    }
                    call += "(instruments " + payload + ") (launch-date 2015) (lifetime 5) (select-orbit no) "
                            + orbit.toJessSlots();
                    call += "(payload-mass# " + String.valueOf(payloadMass) + ")";
                    call += "(payload-power# " + String.valueOf(characteristicPower) + ")";
                    call += "(payload-peak-power# " + String.valueOf(characteristicPower) + ")";
                    call += "(payload-data-rate# " + String.valueOf(dataRate) + ")";
                    double perOrbit = (dataRate * 1.2 * orbit.getPeriod()) / (1024 * 8); //(GByte/orbit) 20% overhead
                    call += "(payload-dimensions# " + String.valueOf(payloadDimensions.get(0)) + " "
                            + String.valueOf(payloadDimensions.get(1)) + " "
                            + String.valueOf(payloadDimensions.get(2)) + ")";
                    call += "(sat-data-rate-per-orbit# " + String.valueOf(perOrbit) + ")";
                    call += "(num-of-sats-per-plane# " + String.valueOf(arch.getNumberOfSatellitesPerOrbit())
                            + ")))";
                    call += "(assert (SYNERGY::cross-registered-instruments " + " (instruments " + payload
                            + ") (degree-of-cross-registration spacecraft) " + " (platform " + orbit + " )))";
                    r.eval(call);
                }
            }
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private double evaluatePerformance(EOSSArchitecture arch) {
        double science = 0;
        try {
            r.eval("(bind ?*science-multiplier* 1.0)");
            r.eval("(defadvice before (create$ >= <= < >) (foreach ?xxx $?argv (if (eq ?xxx nil) then (return FALSE))))");
            r.eval("(defadvice before (create$ sqrt + * **) (foreach ?xxx $?argv (if (eq ?xxx nil) then (bind ?xxx 0))))");

            Explanation explanations = new Explanation();

            r.setFocus("MANIFEST");
            r.run();

            //                ArrayList<String> extraRules = addExtraRules(r);
            //                r.setFocus("CHANNELS");
            //                r.run();
            //                Iterator<String> iter = extraRules.iterator();
            //                while (iter.hasNext()) {
            //                    r.removeDefrule(iter.next());
            //                }
            r.setFocus("FUZZY-CAPABILITY-ATTRIBUTE");
            r.run();

            //checks to see if a manifested-instrument cannot take a measurement or upgrades or downgrades it capabilities depending on LHS of rules in CAPABILITIES-CHECK
            r.setFocus("CAPABILITIES-CHECK");
            r.run();

            //computes values for some slots in CAPABILITIES::Manifested-instrument
            r.setFocus("CAPABILITIES");
            r.run();

            //generates the measurement capabilities (REQUIREMENT::Measurement)
            r.setFocus("CAPABILITIES-GENERATE");
            r.run();

            //This synergy rule call creates new measurement facts that may arise from interactions between instruments 
            if (withSynergy) {
                r.setFocus("SYNERGY");
                r.run();
            }

            //Revisit times
            for (String measurement : Params.measurements) {
                Value v = r.eval("(update-fovs " + measurement + " (create$ "
                        + StringUtils.join(EOSSDatabase.getOrbits(), " ") + "))");
                if (RU.getTypeName(v.type()).equalsIgnoreCase("LIST")) {
                    ValueVector thefovs = v.listValue(r.getGlobalContext());
                    ArrayList<String> fovs = new ArrayList<>(thefovs.size());
                    for (int i = 0; i < thefovs.size(); i++) {
                        int tmp = thefovs.get(i).intValue(r.getGlobalContext());
                        fovs.add(i, String.valueOf(tmp));
                    }
                    String key = arch.getNumberOfSatellitesPerOrbit() + "x" + StringUtils.join(fovs, ",");
                    //if(!key.equals("5 x -1  -1  -1  -1  50")){
                    //System.out.println(param);
                    //key = "5 x -1  -1  -1  -1  50";
                    //}
                    HashMap<String, Double> therevtimes = Params.revtimes.get(key); //key: 'Global' or 'US', value Double

                    //there were two different maps at one point. one with spaces and the other without spaces and commas
                    if (therevtimes == null) {
                        key = arch.getNumberOfSatellitesPerOrbit() + " x " + StringUtils.join(fovs, "  ");
                        therevtimes = Params.revtimes.get(key); //key: 'Global' or 'US', value Double
                    }
                    String call = "(assert (ASSIMILATION::UPDATE-REV-TIME (parameter " + measurement
                            + ") (avg-revisit-time-global# " + therevtimes.get("Global") + ") "
                            + "(avg-revisit-time-US# " + therevtimes.get("US") + ")))";
                    r.eval(call);
                }
            }
            r.setFocus("ASSIMILATION");
            r.run();

            r.setFocus("FUZZY-REQUIREMENT-ATTRIBUTE");
            r.run();

            if (withSynergy) {
                r.setFocus("SYNERGY");
                r.run();

                r.setFocus("SYNERGY-ACROSS-ORBITS");
                r.run();
            }

            if ((Params.req_mode.equalsIgnoreCase("FUZZY-CASES"))
                    || (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES"))) {
                r.setFocus("FUZZY-REQUIREMENTS");
            } else {
                r.setFocus("REQUIREMENTS");
            }
            r.run();

            if ((Params.req_mode.equalsIgnoreCase("FUZZY-CASES"))
                    || (Params.req_mode.equalsIgnoreCase("FUZZY-ATTRIBUTES"))) {
                r.setFocus("FUZZY-AGGREGATION");
            } else {
                r.setFocus("AGGREGATION");
            }
            r.run();

            ArrayList<Fact> vals = qb.makeQuery("AGGREGATION::VALUE");
            Fact val = vals.get(0);
            science = val.getSlotValue("satisfaction").floatValue(r.getGlobalContext());

            aggregate_performance_score_facts(arch);

            if (explanation) {
                explanations.put("partials", qb.makeQuery("REASONING::partially-satisfied"));
                explanations.put("full", qb.makeQuery("REASONING::fully-satisfied"));
                arch.setExplanation(0, explanations);
            }
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
        }
        return science;
    }

    //    /**
    //     * TODO had to put the rules here instead of clp file because the rules were
    //     * firing when they shouldn't have been...
    //     */
    //    private ArrayList<String> addExtraRules(Rete r) {
    //        ArrayList<String> out = new ArrayList();
    //        try {
    //            String rule1name = "CHANNELS::compute-EON-vertical-spatial-resolution1";
    //            String call1 = "(defrule " + rule1name
    //                    + " ?s <- (SYNERGIES::cross-registered-instruments (platform ?plat) (total-num-channels 0)) "
    //                    + "?c <- (accumulate (bind ?countss 0) "
    //                    + "(bind ?countss (+ ?countss ?num)) "
    //                    + "?countss "
    //                    + "(CAPABILITIES::Manifested-instrument (orbit-string ?plat)(num-of-mmwave-band-channels ?num) )) "
    //                    + "=> "
    //                    + "(modify ?s (total-num-channels ?c)))";
    //
    //            String rule2name = "CHANNELS::compute-EON-vertical-spatial-resolution2";
    //            String call2 = "(defrule " + rule2name
    //                    + " ?EON <- (CAPABILITIES::Manifested-instrument  (Vertical-Spatial-Resolution# nil) (orbit-string ?orbs)) "
    //                    + "(SYNERGIES::cross-registered-instruments (total-num-channels ?c&~nil)(platform ?orbs)) "
    //                    + "=> "
    //                    + "(modify ?EON (Vertical-Spatial-Resolution# (compute-vertical-spatial-resolution-EON ?c))))";
    //            r.eval(call1);
    //            r.eval(call2);
    //
    //            out.add(rule1name);
    //            out.add(rule2name);
    //        } catch (JessException ex) {
    //            System.err.println("ExtraRules are wrong...");
    //            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
    //        }
    //        return out;
    //    }
    private ArrayList jessList2ArrayList(ValueVector vv) {
        ArrayList al = new ArrayList();
        try {
            for (int i = 0; i < vv.size(); i++) {
                al.add(vv.get(i).stringValue(r.getGlobalContext()));
            }
        } catch (JessException ex) {
            Logger.getLogger(EOSSProblem.class.getName()).log(Level.SEVERE, null, ex);
            al = null;
        }
        return al;
    }

    /**
     * Takes two vectors (as an arraylist) and multiplies the elements
     *
     * @param a
     * @param b
     * @return
     * @throws Exception
     */
    private ArrayList<Double> elementMult(ArrayList<Double> a, ArrayList<Double> b) {
        int n = a.size();
        int n2 = b.size();
        if (n != n2) {
            throw new IllegalArgumentException("dotSum: Arrays of different sizes");
        }
        ArrayList c = new ArrayList(n);
        for (int i = 0; i < n; i++) {
            Double t = a.get(i) * b.get(i);
            c.add(t);
        }
        return c;
    }

    /**
     * Takes the inner product or dot product of two vectors
     *
     * @param a
     * @param b
     * @return a scalar value equal to the inner product of two vectors
     */
    private double innerProduct(ArrayList a, ArrayList b) {
        ArrayList<Double> vector = elementMult(a, b);
        int n = vector.size();
        double res = 0.0;
        for (Double val : vector) {
            res += val;
        }
        return res;
    }

}