/* * ------------------------------------------------------------------------- * $Id: Basis.java,v 1.3 2004/05/26 18:00:47 estewart Exp $ * ------------------------------------------------------------------------- * Copyright (c) 2002 Visual Numerics Inc. All Rights Reserved. * * This software is confidential information which is proprietary to * and a trade secret of Visual Numerics, Inc. Use, duplication or * disclosure is subject to the terms of an appropriate license * agreement. * * VISUAL NUMERICS MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. VISUAL * NUMERICS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR * ITS DERIVATIVES. * -------------------------------------------------------------------------- */ package com.imsl.demo.Basis; import com.imsl.stat.*; import com.imsl.math.*; import com.imsl.chart.*; import javax.swing.*; /** * Basis creates a Chart where the user can select data to fit with several * different user basis functions. * *@author Ed Stewart *@created September 25, 2002 */ public class Basis extends JFrameChart { private JComboBox jComboBoxUser; private JComboBox jComboBoxFunc; private JTextArea displayText; private JLabel jLabelSNC; private JScrollBar jScrollCoef; private Chart chart; private AxisXY axis, axis2; private Data lineUser, lineFunc; private UserBasisRegression ubr; private final int npoints = 100; private final int defCoef = 4; private final double[] xrange = {0.0, 10.0}; private final double[] yrange = {-15.0, 15.0}; private String textFunc, textUser; private double x[], y[], f[], rand[]; /** * Constructor for the Basis object sets default values and calls methods * to create the chart, draw the graph and build the user interface. * *@param exitOnClose If false, remove the WindowListener installed by * JFrameChart. */ private Basis(boolean exitOnClose) { if (!exitOnClose) { Object l[] = getListeners(java.awt.event.WindowListener.class); for (int k = 0; k < l.length; k++) { removeWindowListener((java.awt.event.WindowListener) l[k]); } } com.imsl.demo.gallery.Describe des = new com.imsl.demo.gallery.Describe(this, "/com/imsl/demo/Basis/Basis.html"); des.show(); java.awt.Dimension dess = des.getSize(); java.awt.Dimension ss = getToolkit().getScreenSize(); int h = Math.min(ss.width/2, ss.height-dess.height-32); int w = (int)(h/0.8); setSize(w, h); setLocation(ss.width-dess.width, dess.height); setTitle("User Basis Regression"); // Set default values final double pi = Physical.constant("PI").doubleValue(); int ncoef = defCoef; double[] coef = new double[ncoef]; x = new double[npoints]; rand = new double[npoints]; Random r = new Random(); for (int i = 0; i < npoints; i++) { x[i] = 3 * pi * (double) i / npoints; rand[i] = r.nextDouble(); } createChart(); drawGraph(); initComponents(); } /** Spawns the Basis class by calling show() */ public static void main(String args[]) { boolean exitOnClose = true; if (args.length > 0 && args[0].equals("-noexit")) { exitOnClose = false; } new Basis(exitOnClose).show(); } /** Pop up a dialog with the coefficients. */ public void detailButtonActionPerformed(java.awt.event.ActionEvent event) { int width = 35; java.text.MessageFormat mf = new java.text.MessageFormat(textUser); JPanel cPanel = new JPanel(new java.awt.BorderLayout()); JTextArea tArea = new JTextArea(" ", 2, width); Object kargs[] = {new String("k")}; String kusr = mf.format(kargs); tArea.setText("Leading coefficients of " + kusr + " to fit " + textFunc); int ncoef = jScrollCoef.getValue(); JTextArea cArea = new JTextArea(" ", ncoef+1, width); StringBuffer sb = new StringBuffer("\n"); double[] coef = new double[ncoef]; coef = ubr.getCoefficients(); java.text.DecimalFormat fmt = new java.text.DecimalFormat("##0.0000"); for (int i = 0; i < ncoef; i++) { sb.append("Coefficient #" + (i+1) + " = " + fmt.format(coef[i]) + "\n"); } cArea.setText(sb.toString()); cArea.setEditable(false); cArea.setBackground(cPanel.getBackground()); JTextArea eArea = new JTextArea(" ", 2, width); sb = new StringBuffer("Analytical equation of the estimate:\ny = "); boolean addText = false; int addLine = 0; java.text.DecimalFormat shortfmt = new java.text.DecimalFormat("##0.####"); for (int i = 0; i < ncoef; i++) { Object args[] = {new Integer(i+1)}; String usr = mf.format(args); String z = fmt.format(JMath.abs(coef[i])); if (z.compareTo("0.0000") > 0) { if (addText) { sb.append(" + "); } if (sb.length() > (width*(addLine+1))*2) { sb.append("\n "); addLine++; } if (textUser.indexOf(" ") == -1) { sb.append(shortfmt.format(coef[i]) + "*" + usr); } else { sb.append(shortfmt.format(coef[i]) + "*[" + usr +"]"); } addText = true; } } if (!addText) { if (textUser.indexOf(" ") == -1) { sb.append("0 * " + kusr); } else { sb.append("0 * [" + kusr +"]"); } } eArea.setText(sb.toString()); cPanel.add(tArea, java.awt.BorderLayout.NORTH); cPanel.add(cArea, java.awt.BorderLayout.CENTER); cPanel.add(eArea, java.awt.BorderLayout.SOUTH); JOptionPane.showMessageDialog(this, cPanel, "Coefficients", JOptionPane.INFORMATION_MESSAGE); } private String getDescription() { StringBuffer sb = new StringBuffer(); sb.append("Analytical Function: " + textFunc); java.text.MessageFormat mf = new java.text.MessageFormat(textUser); Object kargs[] = {new String("k")}; String kusr = mf.format(kargs); sb.append("\nUser Basis Function: " + kusr); return sb.toString(); } private void createChart() { // Chart chart = getChart(); axis = new AxisXY(chart); axis.setViewport(0.05, 0.98, 0.05, 0.95); chart.getLegend().setPaint(true); chart.getLegend().setViewport(0.70, 0.90, 0.10, 0.05); // Set x-axis propteries axis.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisX().setWindow(xrange); axis.getAxisX().setDensity(2); axis.getAxisX().setNumber(11); axis.getAxisX().setTickLength(-1); axis.getAxisX().setTextFormat(new java.text.DecimalFormat("#0")); // Set y-axis properties axis.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis.getAxisY().setWindow(yrange); axis.getAxisY().setDensity(2); axis.getAxisY().setNumber(7); axis.getAxisY().setTextFormat(new java.text.DecimalFormat("##0")); axis.getAxisY().setTickLength(-1); // Add another AxisXY for the boxed look axis2 = new AxisXY(chart); axis2.setViewport(0.05, 0.98, 0.05, 0.95); axis2.getAxisX().setType(AxisXY.AXIS_X_TOP); axis2.getAxisX().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis2.getAxisX().setWindow(xrange); axis2.getAxisX().setDensity(2); axis2.getAxisX().setNumber(11); axis2.getAxisX().setTickLength(-1); axis2.getAxisX().setTextColor(java.awt.Color.white); axis2.getAxisY().setType(AxisXY.AXIS_Y_RIGHT); axis2.getAxisY().setAutoscaleInput(AxisXY.AUTOSCALE_OFF); axis2.getAxisY().setWindow(yrange); axis2.getAxisY().setDensity(2); axis2.getAxisY().setNumber(11); axis2.setCross(xrange[1], yrange[1]); axis2.getAxisY().setTickLength(-1); axis2.getAxisY().setTextColor(java.awt.Color.white); } private void initComponents() { java.awt.Container cp = getContentPane(); JPanel msgPanel = new JPanel(); displayText = new JTextArea(getDescription(), 2, 20); displayText.setEditable(false); JButton detailButton = new JButton("Show Coefficients"); detailButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { detailButtonActionPerformed(evt); } }); msgPanel.add(displayText); msgPanel.add(detailButton); cp.add(msgPanel, java.awt.BorderLayout.NORTH); JPanel southPanel = new JPanel(); // Function selection ComboBox Label labelFn[] = { new Label("Function 1 (sin)", 0), new Label("Function 2 (cos)", 1), new Label("Function 3 (sin*cos)", 2), new Label("Function 4 (sin*Random)", 3) }; jComboBoxFunc = new JComboBox(); for (int i = 0; i < labelFn.length; i++) { jComboBoxFunc.addItem(labelFn[i]); } jComboBoxFunc.setSelectedIndex(0); jComboBoxFunc.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jComboBoxFuncActionPerformed(evt); } }); // User Basis Function selection ComboBox Label labelUs[] = { new Label("sin(kx)", 0), new Label("cos(kx)", 1), new Label("sin(kx) * cos(kx)", 2), new Label("sin(kx) + cos(kx)", 3) //new Label("sinh(kx)", 4), //new Label("cosh(kx)", 5) }; jComboBoxUser = new JComboBox(); for (int i = 0; i < labelUs.length; i++) { jComboBoxUser.addItem(labelUs[i]); } jComboBoxUser.setSelectedIndex(0); jComboBoxUser.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jComboBoxUserActionPerformed(evt); } }); jLabelSNC = new JLabel(); jLabelSNC.setText("# Coefficients = " + defCoef); jScrollCoef = new JScrollBar(java.awt.Scrollbar.HORIZONTAL); jScrollCoef.setValues(defCoef, 1, 1, 9); jScrollCoef.setBlockIncrement(1); jScrollCoef.setPreferredSize(new java.awt.Dimension(100,15)); jScrollCoef.addAdjustmentListener(new java.awt.event.AdjustmentListener() { public void adjustmentValueChanged(java.awt.event.AdjustmentEvent avt) { jScrollCoefValueChanged(avt); } }); // Add components to the panel southPanel.add(jComboBoxFunc); southPanel.add(jComboBoxUser); southPanel.add(jLabelSNC); southPanel.add(jScrollCoef); cp.add(southPanel, java.awt.BorderLayout.SOUTH); } /** Draw the graph in the chart. The input data and the Basis Regression * computed from the coefficients are plotted. */ private void drawGraph() { // Get number of coefficients to use int ncoef = defCoef; if (jScrollCoef != null) { ncoef = jScrollCoef.getValue(); } // Defined the UserBasis here int val = 0; if (jComboBoxUser != null) { val = ((Label) jComboBoxUser.getSelectedItem()).index; } switch (val) { case 0: /* Sin */ ubr = new UserBasisRegression(new BasisSin(), ncoef, false); textUser = "sin({0}x)"; break; case 1: /* Cos */ ubr = new UserBasisRegression(new BasisCos(), ncoef, false); textUser = "cos({0}x)"; break; case 2: /* Prod */ ubr = new UserBasisRegression(new BasisProd(), ncoef, false); textUser = "sin({0}x) * cos({0}x)"; break; case 3: /* Sum */ ubr = new UserBasisRegression(new BasisSum(), ncoef, false); textUser = "sin({0}x) + cos({0}x)"; break; case 4: /* Sinh */ ubr = new UserBasisRegression(new BasisSinh(), ncoef, false); textUser = "sinh({0}x)"; break; case 5: /* Cosh */ ubr = new UserBasisRegression(new BasisCosh(), ncoef, false); textUser = "cosh({0}x)"; break; } // Draw the function f = computeFunc(x); // computeFunc updates the ubr lineFunc = new Data(axis, x, f); lineFunc.setLineColor(java.awt.Color.blue); lineFunc.setLineWidth(2.0); lineFunc.setTitle("Analytical Function"); // Draw the estime y = computeUser(x); // computeUser retrives coefs from ubr lineUser = new Data(axis, x, y); lineUser.setLineColor(java.awt.Color.red); lineUser.setLineWidth(0.5); lineUser.setLineDashPattern(Data.DASH_PATTERN_DOT); lineUser.setTitle("User Basis Regression"); } /** Compute the line for the function to plot * *@param xx The independent values *@return The dependent values for the input function f(x) */ private double[] computeFunc(double[] xx) { double[] ff = new double[xx.length]; int val = 0; if (jComboBoxFunc != null) { val = ((Label) jComboBoxFunc.getSelectedItem()).index; } switch (val) { case 0: /* function 1 */ for (int i = 0; i < npoints; i++) { ff[i] = JMath.sin(xx[i]) + 7.0 * JMath.sin(3.0 * xx[i]); ubr.update(xx[i], ff[i], 1.0); } textFunc = "sin(x) + 7sin(3x)"; break; case 1: /* function 2 */ for (int i = 0; i < npoints; i++) { ff[i] = JMath.cos(xx[i]) + 7.0 * JMath.cos(3.0 * xx[i]); ubr.update(xx[i], ff[i], 1.0); } textFunc = "cos(x) + 7cos(3x)"; break; case 2: /* function 3 */ for (int i = 0; i < npoints; i++) { ff[i] = 10.0 * JMath.cos(xx[i]) * JMath.sin(xx[i]); ubr.update(xx[i], ff[i], 1.0); } textFunc = "10 * cos(x) * sin(x)"; break; case 3: /* function 4 */ for (int i = 0; i < npoints; i++) { ff[i] = 8.0 * JMath.sin(2.0 * xx[i]) * rand[i]; ubr.update(xx[i], ff[i], 1.0); } textFunc = "8sin(2x) * Uniform Random [0,1]"; break; //case 4: /* file */ /* An original part of the demo. It would be easy to read * in your own file to extend the functionality of this * demonstration textFunc = "file y.dat"; java.io.File file = new java.io.File("y.dat"); try { java.io.BufferedReader br = new java.io.BufferedReader( new java.io.InputStreamReader( new java.io.BufferedInputStream( new java.io.FileInputStream(file)))); for (int i = 0; i < npoints; i++) { String s = br.readLine(); try { ff[i] = Double.valueOf(s.trim()).doubleValue(); } catch (NumberFormatException nfe) { System.out.println("NumberFormatException: " + nfe.getMessage()); } } br.close(); } catch (java.io.IOException e) { System.err.println("FileIO: " + e); } break; **/ } return ff; } /** Compute the user basis function estimate to plot * *@param xx The independent values *@return The dependent values for the user basis function y(x) */ private double[] computeUser(double[] xx) { double[] yy = new double[xx.length]; int ncoef = defCoef; if (jScrollCoef != null) { ncoef = jScrollCoef.getValue(); } double[] coef = new double[ncoef]; coef = ubr.getCoefficients(); int val = 0; if (jComboBoxUser != null) { val = ((Label) jComboBoxUser.getSelectedItem()).index; } for (int i = 0; i < npoints; i++) { double sum = 0.0; double tmp = 0.0; for (int j = 0; j < ncoef; j++) { switch (val) { case 0: /* Sin */ tmp = JMath.sin((double) (j + 1) * x[i]); break; case 1: /* Cos */ tmp = JMath.cos((double) (j + 1) * x[i]); break; case 2: /* Prod */ tmp = JMath.sin((double) (j + 1) * x[i]) * JMath.cos((double) (j + 1) * x[i]); break; case 3: /* Sum */ tmp = JMath.sin((double) (j + 1) * x[i]) * JMath.sin((double) (j + 1) * x[i]); break; case 4: /* Sinh */ tmp = Hyperbolic.sinh((double) (j + 1) * x[i]); break; case 5: /* Cosh */ tmp = Hyperbolic.sinh((double) (j + 1) * x[i]); break; } sum = sum + coef[j] * tmp; } yy[i] = sum; } return yy; } /** Update the chart by removing all the Data objects, then calling * drawGraph() and repaint(). Finally update the displayText. */ private void update() { if (lineFunc != null) { lineFunc.remove(); } if (lineUser != null) { lineUser.remove(); } drawGraph(); repaint(); displayText.setText(getDescription()); } /** Update when a new function is selected */ private void jComboBoxFuncActionPerformed(java.awt.event.ActionEvent evt) { update(); } /** Update when a new user basis is selected */ private void jComboBoxUserActionPerformed(java.awt.event.ActionEvent evt) { update(); } /** Adjusting scrollbar changes the number of coefficients, so update() */ private void jScrollCoefValueChanged(java.awt.event.AdjustmentEvent event) { jLabelSNC.setText("# Coefficients = " + jScrollCoef.getValue()); update(); } /** Label objects are used in conjunction with the JComboBox. */ private static class Label { String label; int index; Label(String label, int index) { this.label = label; this.index = index; } public String toString() { return label; } } /** Basis functions are below this point * Each function is best summarized by these docs where * f is the basis function to use (e.g., JMath.sin()) * * Compute f(kx) * *@param index value of k-1 *@param x independent value *@return f(k*x) */ /** Sine basis function. */ class BasisSin implements RegressionBasis { public double basis(int index, double x) { return JMath.sin((index + 1) * x); } } /** Cosine basis function. */ class BasisCos implements RegressionBasis { public double basis(int index, double x) { return JMath.cos((index + 1) * x); } } /** Product of sine and cosine basis function. */ class BasisProd implements RegressionBasis { public double basis(int index, double x) { return JMath.cos((index + 1) * x) * JMath.sin((index + 1) * x); } } /** Sum of sine and cosine basis function*/ class BasisSum implements RegressionBasis { public double basis(int index, double x) { return JMath.cos((index + 1) * x) + JMath.sin((index + 1) * x); } } /** Exponential basis function. */ class BasisExp implements RegressionBasis { public double basis(int index, double x) { return JMath.exp((index + 1) * x); } } /** Natural log basis function. */ class BasisLog implements RegressionBasis { public double basis(int index, double x) { return JMath.log((index + 1) * x); } } /** Hyperbolic sine basis function. */ class BasisSinh implements RegressionBasis { public double basis(int index, double x) { return Hyperbolic.sinh((index + 1) * x); } } /** Hyperbolic cosine basis function. */ class BasisCosh implements RegressionBasis { public double basis(int index, double x) { return Hyperbolic.cosh((index + 1) * x); } } }