// MatrixApp.java import java.awt.*; import java.awt.event.*; import java.util.Vector; public class MatrixApp extends Frame implements ActionListener, ItemListener { private static final int MAX_MATRICES = 26; private MatrixStarter ms; private boolean runsFromApplet, errorPresent; private TextArea commandArea; private TextField sequenceField, optimalField, lrField, optField; private Button computeButton; private int sequenceNumber; private int[] dimSizes = {5, 10, 15, 20, 25, 50, 100}; private int[][] m, s; private Vector matrixVector; private ScrollPane arrayPaneM, arrayPaneS; private ArrayCanvas arrayCanvasM, arrayCanvasS; private String alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private Checkbox cbValues, cbDims, cbRandom; private CheckboxGroup cbGroup; private Choice numChoice, dimChoice; private MatrixDialog md; public MatrixApp(MatrixStarter _ms, boolean _runsFromApplet) { super("Matrix Chain Multiplier"); ms = _ms; runsFromApplet = _runsFromApplet; setBackground(SystemColor.control); commandArea = new TextArea("", 2, 40, TextArea.SCROLLBARS_VERTICAL_ONLY); commandArea.setFont(new Font("Times-Roman", Font.BOLD, 11)); commandArea.setBackground(Color.white); computeButton = new Button("Compute"); computeButton.addActionListener(this); Panel okPanel = new Panel(); okPanel.setLayout(new FlowLayout()); okPanel.add(computeButton); Panel inputPanel = new Panel(); inputPanel.setLayout(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(0, 5, 0, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.weighty = 100; gbc.fill = GridBagConstraints.BOTH; inputPanel.add(commandArea, gbc); gbc.weighty = 0; gbc.fill = GridBagConstraints.HORIZONTAL; inputPanel.add(okPanel, gbc); numChoice = new Choice(); for(int i = 2; i <= MAX_MATRICES; i++) numChoice.add(Integer.toString(i)); numChoice.setEnabled(false); numChoice.addItemListener(this); dimChoice = new Choice(); for(int i = 0; i < dimSizes.length; i++) dimChoice.add("1.." + Integer.toString(dimSizes[i])); dimChoice.setEnabled(false); dimChoice.addItemListener(this); cbGroup = new CheckboxGroup(); cbValues = new Checkbox("User define with matrix dimensions and values", cbGroup, true); cbValues.addItemListener(this); cbDims = new Checkbox("User define with matrix dimensions only", cbGroup, false); cbDims.addItemListener(this); cbRandom = new Checkbox("Random", cbGroup, false); cbRandom.addItemListener(this); Panel cbValuesPanel = new Panel(); cbValuesPanel.setLayout(new GridBagLayout()); gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(0, 5, 0, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.HORIZONTAL; cbValuesPanel.add(cbValues, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; cbValuesPanel.add(new Canvas(), gbc); Panel cbDimsPanel = new Panel(); cbDimsPanel.setLayout(new GridBagLayout()); gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(0, 5, 0, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.HORIZONTAL; cbDimsPanel.add(cbDims, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; cbDimsPanel.add(new Canvas(), gbc); Panel extRandomPanel = new Panel(); extRandomPanel.setLayout(new FlowLayout(FlowLayout.LEFT)); extRandomPanel.add(new Label("Quantity:", Label.RIGHT)); extRandomPanel.add(numChoice); extRandomPanel.add(new Label("Dimensions:", Label.RIGHT)); extRandomPanel.add(dimChoice); Panel cbRandomPanel = new Panel(); cbRandomPanel.setLayout(new GridBagLayout()); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.NONE; cbRandomPanel.add(cbRandom, gbc); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.weighty = 0; gbc.fill = GridBagConstraints.HORIZONTAL; cbRandomPanel.add(extRandomPanel, gbc); Panel optionsPanel = new Panel(); optionsPanel.setLayout(new GridLayout(3, 1)); optionsPanel.add(cbValuesPanel); optionsPanel.add(cbDimsPanel); optionsPanel.add(cbRandomPanel); Panel northPanel = new Panel(); northPanel.setLayout(new GridLayout(1, 2)); northPanel.add(optionsPanel); northPanel.add(inputPanel); arrayCanvasM = new ArrayCanvas(ArrayCanvas.M); arrayPaneM = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); arrayPaneM.setBackground(Color.white); arrayPaneM.add(arrayCanvasM); arrayPaneM.setSize(30, 200); Panel mPanel = new Panel(); mPanel.setLayout(new GridBagLayout()); gbc.insets = new Insets(0, 5, 5, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.weighty = 100; gbc.fill = GridBagConstraints.BOTH; mPanel.add(arrayPaneM, gbc); arrayCanvasS = new ArrayCanvas(ArrayCanvas.S); arrayPaneS = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); arrayPaneS.setBackground(Color.white); arrayPaneS.add(arrayCanvasS); arrayPaneS.setSize(300, 200); Panel sPanel = new Panel(); sPanel.setLayout(new GridBagLayout()); sPanel.add(arrayPaneS, gbc); Panel arrayPanel = new Panel(); arrayPanel.setLayout(new GridLayout(1, 2)); arrayPanel.add(new Box(mPanel, "Table of Scalar Multiplications", Box.LEFT)); arrayPanel.add(new Box(sPanel, "Table of Split Indices", Box.LEFT)); sequenceField = new TextField(25); sequenceField.setEditable(false); sequenceField.setBackground(Color.white); sequenceField.setFont(new Font("Monospaced", Font.PLAIN, 11)); optimalField = new TextField(25); optimalField.setEditable(false); optimalField.setBackground(Color.white); optimalField.setFont(new Font("Monospaced", Font.PLAIN, 11)); Panel bottomLeftPanel = new Panel(); bottomLeftPanel.setLayout(new GridBagLayout()); gbc.anchor = GridBagConstraints.WEST; gbc.insets = new Insets(0, 5, 5, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.NONE; bottomLeftPanel.add(new Label("Sequence of Dimensions:"), gbc); gbc.insets = new Insets(0, 0, 5, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.fill = GridBagConstraints.HORIZONTAL; bottomLeftPanel.add(sequenceField, gbc); gbc.insets = new Insets(5, 5, 5, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.fill = GridBagConstraints.NONE; bottomLeftPanel.add(new Label("Optimal Parenthesization:"), gbc); gbc.insets = new Insets(5, 0, 5, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.fill = GridBagConstraints.HORIZONTAL; bottomLeftPanel.add(optimalField, gbc); lrField = new TextField(10); lrField.setEditable(false); lrField.setBackground(Color.white); optField = new TextField(10); optField.setEditable(false); optField.setBackground(Color.white); Panel bottomRightPanel = new Panel(); bottomRightPanel.setLayout(new GridBagLayout()); gbc.insets = new Insets(0, 5, 5, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.weighty = 0; gbc.fill = GridBagConstraints.NONE; bottomRightPanel.add(new Label("Left-to-Right Scalar Multiplications:"), gbc); gbc.insets = new Insets(0, 0, 5, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.fill = GridBagConstraints.HORIZONTAL; bottomRightPanel.add(lrField, gbc); gbc.insets = new Insets(5, 5, 5, 0); gbc.gridwidth = 1; gbc.weightx = 0; gbc.fill = GridBagConstraints.NONE; bottomRightPanel.add(new Label("Optimized Scalar Multiplications:"), gbc); gbc.insets = new Insets(5, 0, 5, 5); gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.weightx = 100; gbc.fill = GridBagConstraints.HORIZONTAL; bottomRightPanel.add(optField, gbc); Panel southPanel = new Panel(); southPanel.setLayout(new GridLayout(1, 2)); southPanel.add(bottomLeftPanel); southPanel.add(bottomRightPanel); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (runsFromApplet) ms.close(); else System.exit(0); } }); setLayout(new BorderLayout()); add("North", new Box(northPanel, "Input & Options", Box.LEFT)); add("Center", arrayPanel); add("South", new Box(southPanel, "Statistics", Box.LEFT)); validate(); pack(); setSize(800, 500); Dimension d = Toolkit.getDefaultToolkit().getScreenSize(); Point p = new Point((int)((d.getWidth() - this.getWidth())/2), (int)((d.getHeight() - this.getHeight())/2)); setLocation(p); setVisible(true); commandArea.requestFocus(); } private void getValues(int numOfEntries, String input, int[] entries, int sequenceNumber) { int entryNumber = 0; while ((input.length() > 0) && (!errorPresent)) { if (entryNumber == numOfEntries) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Too many entries for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else { int posOfComma = input.indexOf(","); String numberString; if (posOfComma == -1) numberString = input; else numberString = input.substring(0, posOfComma); try { entries[entryNumber] = Integer.parseInt(numberString); } catch (NumberFormatException nfe) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Invalid input for matrix element at entry " + (sequenceNumber + 1) + ".", "exclaim.gif"); } if (!errorPresent) { if (posOfComma == -1) input = ""; else input = input.substring(posOfComma + 1); entryNumber++; } } } if ((!errorPresent) && (entryNumber != numOfEntries)) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Too few entries for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } } private void parseInput(String text, int sequenceNumber) { errorPresent = false; int rows = 0, cols = 0; if (text.indexOf("matrix") != 0) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Missing keyword 'matrix' for entry " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else if (sequenceNumber == MAX_MATRICES) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "More than " + MAX_MATRICES + " matrices have been entered.", "exclaim.gif"); } else { int openParensPos = text.indexOf("("), closeParensPos = text.indexOf(")"); if (openParensPos == -1) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Missing opening parenthesis for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else if (closeParensPos == -1) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Missing closing parenthesis for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else { String inputParams = text.substring(openParensPos + 1, closeParensPos); int firstCommaPos = inputParams.indexOf(","); if (firstCommaPos != -1) { try { rows = Integer.parseInt(inputParams.substring(0, firstCommaPos)); if (rows == 0) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Row cannot be 0 for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else inputParams = inputParams.substring(firstCommaPos + 1); } catch (NumberFormatException nfe) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Invalid input for number of rows in matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } if (!errorPresent) { if (cbGroup.getSelectedCheckbox() == cbValues) { int secondCommaPos = inputParams.indexOf(","); if (secondCommaPos != -1) { try { cols = Integer.parseInt(inputParams.substring( 0, secondCommaPos)); if (cols == 0) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Column cannot be 0 for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else inputParams = inputParams.substring( secondCommaPos + 1); } catch (NumberFormatException nfe) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Invalid input for number of columns in matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } if (!errorPresent) { int openBracketsPos = inputParams.indexOf("["), closeBracketsPos = inputParams.indexOf("]"); if (openBracketsPos == -1) { MessageBox mb = new MessageBox(ms, this, "Error", "Missing opening bracket for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else if (closeBracketsPos == -1) { MessageBox mb = new MessageBox(ms, this, "Error", "Missing closing bracket for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } else { inputParams = inputParams.substring(openBracketsPos + 1, closeBracketsPos); int numOfEntries = rows * cols; int[] entries = new int[numOfEntries]; getValues(numOfEntries, inputParams, entries, sequenceNumber); if (!errorPresent) { Matrix matrix = new Matrix(sequenceNumber, rows, cols, entries); matrixVector.insertElementAt(matrix, sequenceNumber); if (closeParensPos + 1 != text.length()) { if (text.charAt(closeParensPos + 1) == '*') parseInput(text.substring(closeParensPos + 2), ++sequenceNumber); else { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Syntax error in expression after matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } } } } } } else { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Missing second comma or input parameters not present for matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } } else { try { cols = Integer.parseInt(inputParams); } catch (NumberFormatException nfe) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Invalid input for number of columns in matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } if (!errorPresent) { Matrix matrix = new Matrix(sequenceNumber, rows, cols); matrixVector.insertElementAt(matrix, sequenceNumber); if (closeParensPos + 1 != text.length()) { if (text.charAt(closeParensPos + 1) == '*') parseInput(text.substring(closeParensPos + 2), ++sequenceNumber); else { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", "Syntax error in expression after matrix " + (sequenceNumber + 1) + ".", "exclaim.gif"); } } } } } } else { errorPresent = true; String errStr; if (cbGroup.getSelectedCheckbox() == cbValues) errStr = "Missing first"; else errStr = "Missing"; errStr += " comma or input parameters not present for matrix " + (sequenceNumber + 1) + "."; MessageBox mb = new MessageBox(ms, this, "Error", errStr, "exclaim.gif"); } } } } private String print_Optimal_Parens(int a, int b, int i, int j) { if (j - i == 1) return alpha.substring(a, b+1); else if (s[i][j] == i) return alpha.substring(a, a+1) + '(' + print_Optimal_Parens(a+1, b, i+1, j) + ')'; else if (s[i][j] == j-1) return '(' + print_Optimal_Parens(a, b-1, i, j-1) + ')' + alpha.substring(b, b+1); else { int x = s[i][j]; return '(' + print_Optimal_Parens(a, x-1, i, x) + ')' + '(' + print_Optimal_Parens(x, b, x+1, j) + ')'; } } private void processCommand() { String text = commandArea.getText().trim(); commandArea.requestFocus(); if (text.equals("")) { commandArea.setText(""); MessageBox mb = new MessageBox(ms, this, "Error", "You must enter an expression.", "exclaim.gif"); } else if (text.length() > CharArray.MAXLENGTH) { commandArea.selectAll(); MessageBox mb = new MessageBox(ms, this, "Error", "Characters entered exceeds " + CharArray.MAXLENGTH + " limit.", "exclaim.gif"); } else { text = Utilities.removeSpaces(text); commandArea.setText(text); commandArea.selectAll(); sequenceNumber = 0; matrixVector = new Vector(); parseInput(text, sequenceNumber); if (md != null) md.close(); if ((!errorPresent) && (matrixVector.size() > 1)) { try { int[] seq = Utilities.matrix_sequence(matrixVector); Utilities.matrix_chain_order(seq); sequenceField.setText(Utilities.seqToString()); m = Utilities.getTableM(); s = Utilities.getTableS(); arrayCanvasM.setData(m, arrayPaneM); arrayCanvasS.setData(s, arrayPaneS); optimalField.setText(print_Optimal_Parens(0, matrixVector.size() - 1, 1, matrixVector.size())); Utilities.initScalarMults(); Matrix lrRes = Utilities.multiply_left_right(matrixVector); int lrScalarMults = Utilities.getScalarMults(); lrField.setText(Integer.toString(lrScalarMults)); if (cbGroup.getSelectedCheckbox() == cbValues) { Matrix res = Utilities.matrix_chain_multiply(matrixVector); md = new MatrixDialog(this, res); } int optScalarMults = m[1][m[0].length - 2]; optField.setText(Integer.toString(optScalarMults)); } catch (MatrixException me) { errorPresent = true; MessageBox mb = new MessageBox(ms, this, "Error", me.getMsg(), "exclaim.gif"); } } else if ((!errorPresent) && (matrixVector.size() == 1)) { arrayCanvasM.clear(); arrayCanvasS.clear(); Matrix m = (Matrix)matrixVector.elementAt(0); if (cbGroup.getSelectedCheckbox() == cbValues) md = new MatrixDialog(this, m); sequenceField.setText("<" + m.getRows() + ">"); optimalField.setText("A"); } } } private int randomNotZero(int multiplier) { int rand; do rand = (int)Math.round((Math.random() * multiplier)); while (rand == 0); return rand; } private String makeExpression(int size, int dim) { StringBuffer sb = new StringBuffer(); int previous = Integer.MAX_VALUE; for(int i = 0; i < size; i++) { sb.append("matrix("); if (previous == Integer.MAX_VALUE) sb.append(randomNotZero(dim)); else sb.append(previous); sb.append(','); previous = randomNotZero(dim); sb.append(previous); sb.append(')'); if (i != size - 1) sb.append('*'); } return sb.toString(); } public void actionPerformed(ActionEvent ae) { if (ae.getSource() == computeButton) processCommand(); } public void itemStateChanged(ItemEvent ie) { if ((ie.getSource() == cbRandom) || (ie.getSource() == numChoice) || (ie.getSource() == dimChoice)) { if (ie.getSource() == cbRandom) { numChoice.setEnabled(true); dimChoice.setEnabled(true); numChoice.requestFocus(); } int size = Integer.parseInt(numChoice.getSelectedItem()), dim = dimSizes[dimChoice.getSelectedIndex()]; String exp = makeExpression(size, dim); commandArea.setText(exp); } else { numChoice.setEnabled(false); dimChoice.setEnabled(false); commandArea.setText(""); commandArea.requestFocus(); } } public static void main(String[] args) { MatrixApp ma = new MatrixApp(null, false); } }