/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: SweptSample.java * * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. * * Electric(tm) is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Electric(tm) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Electric(tm); see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, Mass 02111-1307, USA. */ package com.sun.electric.tool.simulation; import com.sun.electric.database.geometry.PolyBase; import com.sun.electric.tool.user.waveform.Panel; import com.sun.electric.tool.user.waveform.WaveSignal; import com.sun.electric.tool.user.waveform.Panel.WaveSelection; import java.awt.Color; import java.awt.Graphics; import java.awt.geom.Rectangle2D; import java.util.HashSet; import java.util.List; import java.util.TreeMap; /** * A sweep of many Signal<S> is represented as a single * Signal<SweptSample<S>>. */ public class SweptSample<S extends Sample> implements Sample { private final Sample[] vals; public SweptSample(Sample[] vals) { this.vals = new Sample[vals.length]; for(int i=0; i<vals.length; i++) { // if (vals[i] == null) throw new RuntimeException("null values not allowed in sweeps"); this.vals[i] = vals[i]; } } public int getWidth() { return vals.length; } public S getSweep(int i) { return (S)vals[i]; } public double getMin() { double minVal = Double.MAX_VALUE; for(int i=0; i<vals.length; i++) if (vals[i] != null) minVal = Math.min(minVal, ((ScalarSample)vals[i]).getValue()); return minVal; } public double getMax() { double maxVal = -Double.MAX_VALUE; for(int i=0; i<vals.length; i++) if (vals[i] != null) maxVal = Math.max(maxVal, ((ScalarSample)vals[i]).getValue()); return maxVal; } public boolean equals(Object o) { if (o==null) return false; if (!(o instanceof SweptSample<?>)) return false; SweptSample<?> bo = (SweptSample<?>)o; if (bo.vals.length != vals.length) return false; for(int i=0; i<vals.length; i++) { if (vals[i] == null) { if (bo.vals[i] == null) continue; return false; } if (bo.vals[i] == null) return false; if (!vals[i].equals(bo.vals[i])) return false; } return true; } public int hashCode() { int ret = 0; for(int i=0; i<vals.length; i++) if (vals[i] != null) ret ^= vals[i].hashCode(); return ret; } public boolean isLogicX() { return false; } public boolean isLogicZ() { return false; } public Sample lub(Sample s) { if (!(s instanceof SweptSample<?>)) throw new RuntimeException("tried to call SweptSample.lub("+s.getClass().getName()+")"); SweptSample<?> ds = (SweptSample<?>)s; if (ds.vals.length != vals.length) throw new RuntimeException("tried to call lub() on SweptSamples of different width"); Sample[] ret = new Sample[vals.length]; for(int i=0; i<ret.length; i++) if (vals[i] != null && ds.vals[i] != null) ret[i] = vals[i].lub(ds.vals[i]); return new SweptSample<ScalarSample>(ret); } public Sample glb(Sample s) { if (!(s instanceof SweptSample<?>)) throw new RuntimeException("tried to call SweptSample.glb("+s.getClass().getName()+")"); SweptSample<?> ds = (SweptSample<?>)s; if (ds.vals.length != vals.length) throw new RuntimeException("tried to call glb() on SweptSamples of different width"); Sample[] ret = new Sample[vals.length]; for(int i=0; i<ret.length; i++) if (vals[i] != null && ds.vals[i] != null) ret[i] = vals[i].glb(ds.vals[i]); return new SweptSample<ScalarSample>(ret); } public double getMinValue() { double min = Double.MAX_VALUE; for(int i=0; i<vals.length; i++) min = Math.min(min, vals[i].getMinValue()); return min; } public double getMaxValue() { double max = -Double.MAX_VALUE; for(int i=0; i<vals.length; i++) max = Math.max(max, vals[i].getMaxValue()); return max; } /** create a MutableSignal<SweptSample<SS>> */ public static <SS extends Sample> Signal<SweptSample<SS>> createSignal(SignalCollection sc, Stimuli sd, String signalName, String signalContext, int width) { /* final Unboxed<SweptSample<SS>> unboxer = new Unboxed<SweptSample<SS>>() { public int getSize() { return 1; } public DigitalSample deserialize(byte[] buf, int ofs) { return fromByteRepresentation(buf[ofs]); } public void serialize(DigitalSample v, byte[] buf, int ofs) { buf[ofs] = v.getByteRepresentation(); } public int compare(byte[] buf1, int ofs1, byte[] buf2, int ofs2) { return (buf1[ofs1]&0xff)-(buf2[ofs2]&0xff); } }; Signal<ScalarSample> ret = new BTreeSignal<ScalarSample>(an, signalName, signalContext, BTreeSignal.getTree(unboxer, latticeOp)) { public boolean isAnalog() { return true; } }; an.addSignal(ret); return ret; */ throw new RuntimeException("not implemented"); } /** create a Signal<SweptSample<S>> from preexisting Signal<S>'s */ public static <SS extends Sample> Signal<SweptSample<SS>> createSignal(SignalCollection sc, Stimuli sd, String signalName, String signalContext, boolean digital, final Signal<SS>[] subsignals) { final String scName = sc.getName(); return new Signal<SweptSample<SS>>(sc, sd, signalName, signalContext, digital) { public boolean isEmpty() { for(Signal<SS> sig : subsignals) if (!sig.isEmpty()) return false; return true; } public Signal.View<RangeSample<SweptSample<SS>>> getRasterView(final double t0, final double t1, final int numPixels) { final Signal.View<RangeSample<SS>>[] subviews = new Signal.View[subsignals.length]; for(int i=0; i<subviews.length; i++) subviews[i] = subsignals[i].getRasterView(t0, t1, numPixels); // the subviews' getRasterView() methods might have differing getNumEvents() values or different // getTime() values for a given index. Therefore, we must "collate" them. By using a sorted treemap // here we ensure that this takes only O(n log n) time. // INVARIANT: tm.get(t).contains(i) ==> (exists j such that subviews[i].getTime(j)==t) TreeMap<Double,HashSet<Integer>> tm = new TreeMap<Double,HashSet<Integer>>(); for (int i=0; i<subviews.length; i++) { Signal.View<RangeSample<SS>> view = subviews[i]; for(int j=0; j<view.getNumEvents(); j++) { double t = view.getTime(j); HashSet<Integer> hs = tm.get(t); if (hs==null) tm.put(t, hs = new HashSet<Integer>()); hs.add(i); } } // now we know, for each point in time, which signals changed at that point final double[] times = new double[tm.size()]; final RangeSample<SweptSample<SS>>[] vals = new RangeSample[tm.size()]; int i = 0; int[] event = new int[subviews.length]; SS[] minvals = (SS[])new Sample[subviews.length]; SS[] maxvals = (SS[])new Sample[subviews.length]; for(double t : tm.keySet()) { times[i] = t; HashSet<Integer> hs = tm.get(t); for(int v : hs) { assert subviews[v].getTime(event[v])==t; // sanity check RangeSample<SS> rs = subviews[v].getSample(event[v]); if (rs != null) { minvals[v] = rs.getMin(); maxvals[v] = rs.getMax(); } event[v]++; } //for(int j=0; j<subviews.length; j++) //{ // boolean debug = false; // if (minvals[j] == null) // { System.out.println(">>>>>>>>>>>>>>> MINVALS["+j+"] NULL (ARRAY IS "+subviews.length+" LONG)"); debug = true; } // if (maxvals[j] == null) // { System.out.println(">>>>>>>>>>>>>>> MAXVALS["+j+"] NULL (ARRAY IS "+subviews.length+" LONG)"); debug = true; } // if (debug) // { // System.out.println(" TIMES FOUND:"); // for(double tt : tm.keySet()) // { // System.out.print(" " + tt + " IN"); // HashSet<Integer> hss = tm.get(t); // for(int vv : hss) System.out.print(" " + vv); // System.out.println(); // } // System.out.println(); // } //} vals[i] = new RangeSample<SweptSample<SS>>( new SweptSample<SS>(minvals), new SweptSample<SS>(maxvals) ); i++; } return new Signal.View<RangeSample<SweptSample<SS>>>() { public int getNumEvents() { return times.length; } public double getTime(int event) { return times[event]; } public RangeSample<SweptSample<SS>> getSample(int event) { return vals[event]; } }; } public Signal.View<SweptSample<SS>> getExactView() { final Signal.View<SS>[] subviews = new Signal.View[subsignals.length]; for(int i=0; i<subviews.length; i++) subviews[i] = subsignals[i].getExactView(); // the subviews' getRasterView() methods might have differing getNumEvents() values or different // getTime() values for a given index. Therefore, we must "collate" them. By using a sorted treemap // here we ensure that this takes only O(n log n) time. // INVARIANT: tm.get(t).contains(i) ==> (exists j such that subviews[i].getTime(j)==t) TreeMap<Double,HashSet<Integer>> tm = new TreeMap<Double,HashSet<Integer>>(); for (int i=0; i<subviews.length; i++) { Signal.View<SS> view = subviews[i]; for(int j=0; j<view.getNumEvents(); j++) { double t = view.getTime(j); HashSet<Integer> hs = tm.get(t); if (hs == null) tm.put(t, hs = new HashSet<Integer>()); hs.add(i); } } // now we know, for each point in time, which signals changed at that point final double[] times = new double[tm.size()]; final SweptSample<SS>[] vals = new SweptSample[tm.size()]; int i = 0; int[] event = new int[subviews.length]; SS[] sampleVals = (SS[])new Sample[subviews.length]; for(double t : tm.keySet()) { times[i] = t; HashSet<Integer> hs = tm.get(t); for(int v : hs) { assert subviews[v].getTime(event[v])==t; // sanity check SS rs = subviews[v].getSample(event[v]); if (rs != null) sampleVals[v] = rs; event[v]++; } vals[i] = new SweptSample<SS>(sampleVals); i++; } return new Signal.View<SweptSample<SS>>() { public int getNumEvents() { return times.length; } public double getTime(int event) { return times[event]; } public SweptSample<SS> getSample(int event) { return vals[event]; } }; } public double getMinTime() { double min = Double.MAX_VALUE; for(Signal<SS> sig : subsignals) min = Math.min(min, sig.getMinTime()); return min; } public double getMaxTime() { double max = -Double.MAX_VALUE; for(Signal<SS> sig : subsignals) max = Math.max(max, sig.getMaxTime()); return max; } public double getMinValue() { double min = Double.MAX_VALUE; for(Signal<SS> sig : subsignals) min = Math.min(min, sig.getMinValue()); return min; } public double getMaxValue() { double max = -Double.MAX_VALUE; for(Signal<SS> sig : subsignals) max = Math.max(max, sig.getMaxValue()); return max; } public void plot(Panel panel, Graphics g, WaveSignal ws, Color light, List<PolyBase> forPs, Rectangle2D bounds, List<WaveSelection> selectedObjects, Signal<?> xAxisSignal) { for(int i=0; i<subsignals.length; i++) { if (!panel.getWaveWindow().isSweepSignalIncluded(scName, i)) continue; ScalarSample.plotSig((MutableSignal<ScalarSample>)subsignals[i], panel, g, ws, light, forPs, bounds, selectedObjects, xAxisSignal); } } }; } }