Search in sources :

Example 1 with Conversion

use of gov.sandia.n2a.backend.internal.InternalBackendData.Conversion in project n2a by frothga.

the class Part method finish.

public boolean finish(Simulator simulator) {
    InternalBackendData bed = (InternalBackendData) equations.backendData;
    int populations = equations.parts.size();
    for (int i = 0; i < populations; i++) ((Population) valuesObject[i]).finish(simulator);
    if (bed.liveStorage == InternalBackendData.LIVE_STORED) {
        // early-out if we are already dead, to avoid another call to die()
        if (((Scalar) get(bed.live)).value == 0)
            return false;
    }
    // Events
    for (EventSource es : bed.eventSources) {
        @SuppressWarnings("unchecked") List<Instance> monitors = (ArrayList<Instance>) valuesObject[es.monitorIndex];
        if (monitors.size() == 0)
            continue;
        EventTarget eventType = es.target;
        if (es.testEach) {
            for (Instance i : monitors) {
                if (i == null)
                    continue;
                double delay = eventType.test(i, simulator);
                // the trigger condition was not satisfied
                if (delay < -1)
                    continue;
                EventSpikeSingle spike;
                if (// event was triggered, but timing is no-care
                delay < 0) {
                    spike = new EventSpikeSingleLatch();
                    // queue immediately after current cycle, so latches get set for next full cycle
                    spike.t = simulator.currentEvent.t;
                } else if (// process as close to current cycle as possible
                delay == 0) {
                    // fully execute the event (not latch it)
                    spike = new EventSpikeSingle();
                    // queue immediately
                    spike.t = simulator.currentEvent.t;
                } else {
                    // Is delay an quantum number of $t' steps?
                    double ratio = delay / event.dt;
                    int step = (int) Math.round(ratio);
                    if (Math.abs(ratio - step) < 1e-3) {
                        if (simulator.eventMode == Simulator.DURING)
                            spike = new EventSpikeSingleLatch();
                        else
                            spike = new EventSpikeSingle();
                        if (simulator.eventMode == Simulator.AFTER)
                            delay = (step + 1e-6) * event.dt;
                        else
                            delay = (step - 1e-6) * event.dt;
                    } else {
                        spike = new EventSpikeSingle();
                    }
                    spike.t = simulator.currentEvent.t + delay;
                }
                spike.eventType = eventType;
                spike.target = i;
                simulator.queueEvent.add(spike);
            }
        } else // All monitors share same condition, so only test one.
        {
            double delay = -2;
            for (Instance i : monitors) {
                if (i == null)
                    continue;
                delay = eventType.test(i, simulator);
                break;
            }
            // the trigger condition was not satisfied
            if (delay < -1)
                continue;
            if (// Each target instance may require a different delay.
            es.delayEach) {
                for (Instance i : monitors) {
                    if (i == null)
                        continue;
                    // This results in one redundant eval, of first entry in monitors. Not clear if it's worth the work to avoid this.
                    delay = eventType.delay(i, simulator);
                    EventSpikeSingle spike;
                    if (delay < 0) {
                        spike = new EventSpikeSingleLatch();
                        spike.t = simulator.currentEvent.t;
                    } else if (delay == 0) {
                        spike = new EventSpikeSingle();
                        spike.t = simulator.currentEvent.t;
                    } else {
                        double ratio = delay / event.dt;
                        int step = (int) Math.round(ratio);
                        if (Math.abs(ratio - step) < 1e-3) {
                            if (simulator.eventMode == Simulator.DURING)
                                spike = new EventSpikeSingleLatch();
                            else
                                spike = new EventSpikeSingle();
                            if (simulator.eventMode == Simulator.AFTER)
                                delay = (step + 1e-6) * event.dt;
                            else
                                delay = (step - 1e-6) * event.dt;
                        } else {
                            spike = new EventSpikeSingle();
                        }
                        spike.t = simulator.currentEvent.t + delay;
                    }
                    spike.eventType = eventType;
                    spike.target = i;
                    simulator.queueEvent.add(spike);
                }
            } else // All delays are the same.
            {
                EventSpikeMulti spike;
                if (delay < 0) {
                    spike = new EventSpikeMultiLatch();
                    spike.t = simulator.currentEvent.t;
                } else if (delay == 0) {
                    spike = new EventSpikeMulti();
                    spike.t = simulator.currentEvent.t;
                } else {
                    double ratio = delay / event.dt;
                    int step = (int) Math.round(ratio);
                    if (Math.abs(ratio - step) < 1e-3) {
                        if (simulator.eventMode == Simulator.DURING)
                            spike = new EventSpikeMultiLatch();
                        else
                            spike = new EventSpikeMulti();
                        if (simulator.eventMode == Simulator.AFTER)
                            delay = (step + 1e-6) * event.dt;
                        else
                            delay = (step - 1e-6) * event.dt;
                    } else {
                        spike = new EventSpikeMulti();
                    }
                    spike.t = simulator.currentEvent.t + delay;
                }
                spike.eventType = eventType;
                // We don't copy the array, just keep a reference to it. What could go wrong with this?
                // If a part dies and tries to remove itself from the list while it is being used to deliver spikes,
                // then we could get a null pointer exception. Solution is to synchronize access to the list.
                // If a connection is born while the spike is in flight, one could argue that it shouldn't
                // receive it, but one could also argue that it should. In nature these two things (spikes
                // and synapse creation) occur at vastly different timescales. Wouldn't a nascent synapse
                // receive spikes even as it is forming?
                spike.targets = monitors;
                simulator.queueEvent.add(spike);
            }
        }
    }
    // Other stuff
    if (bed.lastT != null)
        setFinal(bed.lastT, new Scalar(simulator.currentEvent.t));
    for (Variable v : bed.localBufferedExternal) setFinal(v, getFinal(v));
    for (Integer i : bed.eventLatches) valuesFloat[i] = 0;
    for (Variable v : bed.localBufferedExternalWrite) {
        switch(v.assignment) {
            case Variable.ADD:
                // initial value is zero-equivalent (additive identity)
                set(v, v.type);
                break;
            case Variable.MULTIPLY:
            case Variable.DIVIDE:
                // multiplicative identity
                if (v.type instanceof Matrix)
                    set(v, ((Matrix) v.type).identity());
                else
                    set(v, new Scalar(1));
                break;
            case Variable.MIN:
                if (v.type instanceof Matrix)
                    set(v, ((Matrix) v.type).clear(Double.POSITIVE_INFINITY));
                else
                    set(v, new Scalar(Double.POSITIVE_INFINITY));
                break;
            case Variable.MAX:
                if (v.type instanceof Matrix)
                    set(v, ((Matrix) v.type).clear(Double.NEGATIVE_INFINITY));
                else
                    set(v, new Scalar(Double.NEGATIVE_INFINITY));
                break;
        }
    }
    if (bed.type != null) {
        int type = (int) ((Scalar) get(bed.type)).value;
        if (type > 0) {
            ArrayList<EquationSet> split = equations.splits.get(type - 1);
            if (// Make sure $type != me. Otherwise it's a null operation
            split.size() > 1 || split.get(0) != equations) {
                // indicates that this instance is one of the resulting parts
                boolean used = false;
                int countParts = split.size();
                for (int i = 0; i < countParts; i++) {
                    EquationSet other = split.get(i);
                    Scalar splitPosition = new Scalar(i + 1);
                    if (other == equations && !used) {
                        used = true;
                        setFinal(bed.type, splitPosition);
                    } else {
                        InternalBackendData otherBed = (InternalBackendData) other.backendData;
                        Part p = new Part(other, (Part) container);
                        // If this is a connection, keep the same bindings
                        Conversion conversion = bed.conversions.get(other);
                        if (conversion.bindings != null) {
                            for (int j = 0; j < conversion.bindings.length; j++) {
                                p.valuesObject[otherBed.endpoints + conversion.bindings[j]] = valuesObject[bed.endpoints + j];
                            }
                        }
                        event.enqueue(p);
                        p.resolve();
                        // accountable connections are updated here
                        p.init(simulator);
                        // Copy over variables
                        int count = conversion.from.size();
                        for (int v = 0; v < count; v++) {
                            Variable from = conversion.from.get(v);
                            Variable to = conversion.to.get(v);
                            p.setFinal(to, get(from));
                        }
                        // Set $type to be our position in the split
                        p.setFinal(otherBed.type, splitPosition);
                    }
                }
                if (!used) {
                    die();
                    return false;
                }
            }
        }
    }
    if (equations.lethalP) {
        double p;
        if (bed.p.hasAttribute("temporary")) {
            InstanceTemporaries temp = new InstanceTemporaries(this, simulator, false);
            for (Variable v : bed.Pdependencies) {
                Type result = v.eval(temp);
                if (result != null && v.writeIndex >= 0)
                    temp.set(v, result);
            }
            Type result = bed.p.eval(temp);
            if (result == null)
                p = 1;
            else
                p = ((Scalar) result).value;
        } else {
            p = ((Scalar) get(bed.p)).value;
        }
        if (p == 0 || p < 1 && p < simulator.random.nextDouble()) {
            die();
            return false;
        }
    }
    if (equations.lethalConnection) {
        int count = equations.connectionBindings.size();
        for (int i = 0; i < count; i++) {
            if (!getPart(i).getLive()) {
                die();
                return false;
            }
        }
    }
    if (equations.lethalContainer) {
        if (!((Part) container).getLive()) {
            die();
            return false;
        }
    }
    return true;
}
Also used : EquationSet(gov.sandia.n2a.eqset.EquationSet) Variable(gov.sandia.n2a.eqset.Variable) Instance(gov.sandia.n2a.language.type.Instance) ArrayList(java.util.ArrayList) Conversion(gov.sandia.n2a.backend.internal.InternalBackendData.Conversion) Scalar(gov.sandia.n2a.language.type.Scalar) EventSource(gov.sandia.n2a.backend.internal.InternalBackendData.EventSource) Type(gov.sandia.n2a.language.Type) Matrix(gov.sandia.n2a.language.type.Matrix) EventTarget(gov.sandia.n2a.backend.internal.InternalBackendData.EventTarget)

Aggregations

Conversion (gov.sandia.n2a.backend.internal.InternalBackendData.Conversion)1 EventSource (gov.sandia.n2a.backend.internal.InternalBackendData.EventSource)1 EventTarget (gov.sandia.n2a.backend.internal.InternalBackendData.EventTarget)1 EquationSet (gov.sandia.n2a.eqset.EquationSet)1 Variable (gov.sandia.n2a.eqset.Variable)1 Type (gov.sandia.n2a.language.Type)1 Instance (gov.sandia.n2a.language.type.Instance)1 Matrix (gov.sandia.n2a.language.type.Matrix)1 Scalar (gov.sandia.n2a.language.type.Scalar)1 ArrayList (java.util.ArrayList)1