home *** CD-ROM | disk | FTP | other *** search
/ CD Ware Multimedia 1999 February / CDW0299.iso / Demos / Cafe / Source.bin / Matrix.java < prev    next >
Encoding:
Java Source  |  1998-03-18  |  16.0 KB  |  656 lines

  1. package symantec.itools.awt;
  2.  
  3. import java.util.ResourceBundle;
  4.  
  5. // ===================================================================================
  6. // = Revision History
  7. // ===================================================================================
  8.  
  9. // Matrix
  10. //        This class implements a sparse matrix of objects
  11. //
  12.  
  13. //  03/20/97    RKM    Made the class public as per customer request
  14. //                    Removed bogus debugging code
  15. //                    Removed compaction of empty rows code
  16. //  03/27/97    RKM    Made class final (this class is not made to be extended)
  17. //                    Followed example of Vector, and added JavaDoc, throws, & synchronized
  18. //                    Made final
  19. //                    Tried to make some sense of protection on methods & members
  20. //  03/28/97    RKM    Un-privitized members
  21. //  05/02/97    RKM    Fixed removeRow - made it actually work
  22. //  05/02/97    RKM    Fixed insertRow - one of the loops was not checking for null
  23. //  05/13/97    TNM    Added new interface CompareFuncCB to fix MultiList to not lose selection when sorting
  24. //  05/30/97    RKM    Moved CompareFunc interface into it's own file, at compiler's request
  25. //  07/19/97    LAB    Moved CompareFuncCB interface into it's own file, at compiler's request
  26. //  07/23/97    CAR added java.io.Serializable interface
  27.  
  28. /**
  29.  * This class implements a sparse matrix of objects.
  30.  * @version 1.0, Nov 26, 1996
  31.  * @author    Symantec
  32.  */
  33. public final class Matrix implements java.io.Serializable
  34. {
  35.     //--------------------------------------------------
  36.     // public constructors
  37.     //--------------------------------------------------
  38.  
  39.     /**
  40.      * Constructs an empty matrix.
  41.      */
  42.     public Matrix()
  43.     {
  44.         rowHead = this;
  45.         errors = ResourceBundle.getBundle("symantec.itools.resources.ErrorsBundle");
  46.     }
  47.  
  48.     //--------------------------------------------------
  49.     // private constructors
  50.     //--------------------------------------------------
  51.  
  52.     private Matrix(int r, int c, Object obj)
  53.     {
  54.         this(r, c, obj, null);
  55.     }
  56.  
  57.     private Matrix(int r, int c, Object obj, Matrix rh, Matrix nr, Matrix ne)
  58.     {
  59.         errors = ResourceBundle.getBundle("symantec.itools.resources.ErrorsBundle");
  60.         if (rh == null)
  61.         {
  62.             if (c != 0)
  63.             {
  64.                 rowHead = new Matrix(r, 0, null, null, nr, this);
  65.             }
  66.             else
  67.             {
  68.                 rowHead = this;
  69.             }
  70.         }
  71.         else
  72.         {
  73.             rowHead = rh;
  74.         }
  75.  
  76.         row = r;
  77.         col = c;
  78.         o = obj;
  79.         nextRow = nr;
  80.         nextElt = ne;
  81.     }
  82.  
  83.     private Matrix(int r, int c, Object obj, Matrix nr, Matrix ne)
  84.     {
  85.         this(r, c, obj, null, nr, ne);
  86.     }
  87.  
  88.     private Matrix(int r, int c, Object obj, Matrix nr)
  89.     {
  90.         this(r, c, obj, null, nr, null);
  91.     }
  92.  
  93.     //--------------------------------------------------
  94.     // public methods
  95.     //--------------------------------------------------
  96.  
  97.     /**
  98.      * Adds the given element to this matrix at the specified row and column.
  99.      * @param r the row of the element to be added
  100.      * @param c the column of the element to added
  101.      * @param o the element to be added
  102.      * @exception IllegalArgumentException if an element is already allocated
  103.      * at [r,c]
  104.      * @see #updateElement
  105.      * @see #removeElementAt
  106.      */
  107.     public synchronized void addElement(int r, int c, Object o)
  108.         throws IllegalArgumentException
  109.     {
  110.         //find the correct row
  111.         Matrix m = nearest(r, c);
  112.  
  113.         if (m.row != r)
  114.         {
  115.             m.setNextRow(new Matrix(r, c, o, m.nextRow).rowHead);
  116.             return;
  117.         }
  118.  
  119.         //m must equal row
  120.         if (c == m.col && c == 0)
  121.         {
  122.             if (m.o != null)
  123.             {
  124.                 //exception - should call update
  125.                 throw new IllegalArgumentException(errors.getString("ElementAlreadyInMatrix"));
  126.             }
  127.             else
  128.             {
  129.                 m.o = o;
  130.                 return;
  131.             }
  132.         }
  133.  
  134.         m.nextElt = new Matrix(r, c, o, m.rowHead, m.nextRow, m.nextElt);
  135.     }
  136.  
  137.     /**
  138.      * Adds or updates the element at the specified row and column, as needed.
  139.      * @param r the row of the element to be updated
  140.      * @param c the column of the element to updated
  141.      * @param o the new element
  142.      * @see #addElement
  143.      * @see #removeElementAt
  144.      */
  145.     public synchronized void updateElement(int r, int c, Object obj)
  146.     {
  147.         Matrix m = nearest(r, c);
  148.  
  149.         try
  150.         {
  151.             if (m == null)
  152.             {
  153.                 //first element in matrix
  154.                 addElement(r, c, obj);
  155.             }
  156.             else if (m.row != r || m.col != c)
  157.             {
  158.                 m.addElement(r, c, obj);
  159.             }
  160.             else
  161.             {
  162.                 //must be the element
  163.                 m.o = obj;
  164.             }
  165.         }
  166.         catch(IllegalArgumentException iae)
  167.         {
  168.             iae.printStackTrace();
  169.         }
  170.     }
  171.  
  172.     /**
  173.      * Removes all elements of the matrix. The matrix becomes empty.
  174.      * @see #addElement
  175.      * @see #removeElementAt
  176.      */
  177.     public synchronized void removeAllElements()
  178.     {
  179.         nextRow = null;
  180.         nextElt = null;
  181.         o = null;
  182.     }
  183.  
  184.     /**
  185.      * Returns the element at the specified row and column.
  186.      * @param r the row of the element to return
  187.      * @param c the column of the element to return
  188.      * @return the element at [r,c]
  189.      * @exception ArrayIndexOutOfBoundsException if an invalid
  190.      * row and/or column was given
  191.      */
  192.     public synchronized Object elementAt(int r, int c)
  193.         throws ArrayIndexOutOfBoundsException
  194.     {
  195.         Matrix m = nearest(r, c);
  196.  
  197.         if (m == null || m.row != r || m.col != c || m.o == null){
  198.             Object[] args = { new Integer(r), new Integer(c) };
  199.             throw new ArrayIndexOutOfBoundsException(java.text.MessageFormat.format(errors.getString("ElementNotInMatrix"), args));
  200.         }
  201.  
  202.         return m.o;
  203.     }
  204.  
  205.     /**
  206.      * Deletes the element at the specified row and column.
  207.      * @param r the row of the element to remove
  208.      * @param c the column of the element to remove
  209.      * @exception ArrayIndexOutOfBoundsException if an invalid
  210.      * row and/or column was given
  211.      */
  212.     public synchronized void removeElementAt(int r, int c)
  213.         throws ArrayIndexOutOfBoundsException
  214.     {
  215.         Matrix m = nearest(r, c);
  216.  
  217.         if (m == null || m.row != r || m.col != c) {
  218.             Object[] args = { new Integer(r), new Integer(c) };
  219.             throw new ArrayIndexOutOfBoundsException(java.text.MessageFormat.format(errors.getString("ElementNotInMatrix"), args));
  220.         }
  221.  
  222.         if (c == 0)
  223.         {
  224.             m.o = null;
  225.             return;
  226.         }
  227.  
  228.         Matrix prev = m = m.rowHead;
  229.  
  230.         while(m.col != c)
  231.         {
  232.             prev = m;
  233.             m = m.nextElt;
  234.         }
  235.  
  236.         prev.nextElt = m.nextElt;
  237.     }
  238.  
  239.     /**
  240.      * Deletes all elements on the specified row.
  241.      * @param r the row of the elements to remove
  242.      * @see #insertRow
  243.      * @see #removeElementAt
  244.      */
  245.     public synchronized void removeRow(int r)
  246.     {
  247.         //Removing zero is a special case, essentially we have to change this
  248.         if (r == 0)
  249.         {
  250.             this.o            = null;
  251.             this.nextElt    = null;
  252.             if (this.nextRow != null)
  253.             {
  254.                 //Remove new zero elem from the row list and assign its data into this
  255.                 Matrix newZeroElem = this.nextRow;
  256.                 this.nextRow    = newZeroElem.nextRow;
  257.                 this.nextElt    = newZeroElem.nextElt;
  258.                 this.row        = newZeroElem.row;
  259.                 this.col        = newZeroElem.col;
  260.                 this.o            = newZeroElem.o;
  261.  
  262.                 //Hook up rowHeads of the elements in zero elem (since it's now this)
  263.                 {
  264.                     Matrix elemMatrix = this.nextElt;
  265.                     while (elemMatrix != null)
  266.                     {
  267.                         elemMatrix.rowHead = this;
  268.                         elemMatrix = elemMatrix.nextElt;
  269.                     }
  270.                 }
  271.  
  272.                 //Decrement row of all matrixs
  273.                 Matrix stepMatrix = this;
  274.                 while (stepMatrix != null)
  275.                 {
  276.                     stepMatrix.updateRowNum(stepMatrix.row - 1);
  277.                     stepMatrix = stepMatrix.nextRow;
  278.                 }
  279.             }
  280.         }
  281.         else
  282.         {
  283.             //Find the matrix that comes before the row, if it exists
  284.             Matrix stepMatrix = this.nextRow;
  285.             Matrix lastRow = this;
  286.             while (stepMatrix != null && stepMatrix.row < r)
  287.             {
  288.                 lastRow = stepMatrix;
  289.                 stepMatrix = stepMatrix.nextRow;
  290.             }
  291.  
  292.             if (stepMatrix != null)
  293.             {
  294.                 //We have an explicit row matrix
  295.                 if (stepMatrix.row == r)
  296.                 {
  297.                     //Skip it in the chain
  298.                     lastRow.nextRow = stepMatrix.nextRow;
  299.  
  300.                     //???RKM??? I thought I understood this class, until this was required
  301.                     //???RKM??? This is chicken blood - I don't know why it's here !!!
  302.                     stepMatrix.o = null;
  303.                     stepMatrix.nextElt = null;
  304.  
  305.                     //Advance a row (number changing purposes)
  306.                     stepMatrix = stepMatrix.nextRow;
  307.                 }
  308.  
  309.                 //Change the row numbers of all the remaining rows
  310.                 while (stepMatrix != null)
  311.                 {
  312.                     stepMatrix.updateRowNum(stepMatrix.row - 1);
  313.                     stepMatrix = stepMatrix.nextRow;
  314.                 }
  315.             }
  316.         }
  317.  
  318.         /* RKM Was
  319.         Matrix m = nearest(r, 0);
  320.  
  321.         if (m.row == r)
  322.         {
  323.             m = m.rowHead;
  324.             m.o = null;
  325.             m.nextElt = null;
  326.         }
  327.         */
  328.     }
  329.  
  330.     /**
  331.      * Inserts a new row at the given location.
  332.      * It does this by incrementing the row number of all elements with
  333.      * row indexes >= given row number.
  334.      * @param r the number of the row to insert
  335.      * @see #removeRow
  336.      */
  337.     public synchronized void insertRow(int r)
  338.     {
  339.         Matrix m, n;
  340.  
  341.         if (r == 0)
  342.         {
  343.             //???RKM??? I don't see how this can work ???
  344.  
  345.             //want to insert into first row
  346.             m = new Matrix();
  347.             m.setNextRow(this);
  348.         }
  349.         else
  350.         {
  351.             m = nearest(r-1, 0);
  352.             n = new Matrix(r, 0, null, m.nextRow);
  353.             m.setNextRow(n);
  354.             m = n;
  355.         }
  356.  
  357.         if (m.nextRow.row == r)
  358.         {
  359.             //slip and increment row numbers
  360.             m = m.nextRow;
  361.  
  362.             while(m != null)
  363.             {
  364.                 m.updateRowNum(++r);
  365.                 m = m.nextRow;
  366.                 if (m != null && m.row != r) return;
  367.             }
  368.         }
  369.     }
  370.  
  371.     /**
  372.      * Sorts all rows into ascending order.
  373.      * It does this by comparing elements at the given
  374.      * column number using the provided CompareFunc.
  375.      * @param f compares two objects and determines which one is less than the other
  376.      * @param c the column number of elements to compare
  377.      */
  378.     public synchronized void sort(CompareFunc f, int c)
  379.     {
  380.         boolean first = true;
  381.         Matrix  m = this,
  382.                 n = null;
  383.  
  384.         while(m != null)
  385.         {
  386.             n = findLeast(f, m, c, first);
  387.  
  388.             if (n != null)
  389.             {
  390.                 if (m.row == 0 && first)
  391.                 {
  392.                     first = false;
  393.                     if(f instanceof CompareFuncCB)
  394.                         ((CompareFuncCB)f).callBackSwap(m, n.nextRow);
  395.                     swapRows(n);
  396.                     m = this;
  397.                     continue;
  398.                  }
  399.                  else
  400.                  {
  401.                     if(f instanceof CompareFuncCB)
  402.                         ((CompareFuncCB)f).callBackSwap(m.nextRow, n.nextRow);
  403.                     swapRows(m, n);
  404.                  }
  405.             }
  406.  
  407.             if (first)
  408.             {
  409.                 first = false;
  410.                 continue;
  411.             }
  412.  
  413.             m = m.nextRow;
  414.         }
  415.     }
  416.  
  417.     /**
  418.      * Prints the specified row to System.out.
  419.      * This can be handy for debugging purposes.
  420.      * @param r the row to print
  421.      */
  422.     public synchronized void printRow(int r)
  423.     {
  424.         Matrix m = nearest(r, 0);
  425.  
  426.         if (m.row != r)
  427.         {
  428.             m = m.nextRow;
  429.             if (m.row != r)
  430.             {
  431.                 Object[] args = { new Integer(r) };
  432.                 System.out.println(java.text.MessageFormat.format(errors.getString("RowNotInMatrix"), args));
  433.                 return;
  434.             }
  435.         }
  436.  
  437.         System.out.println("-------- Printing row " + r + " ----------");
  438.         while(m != null)
  439.         {
  440.             System.out.println("Row=" + m.row + "  Col=" + m.col + "  value=" + m.o);
  441.             m = m.nextElt;
  442.         }
  443.     }
  444.  
  445.     /**
  446.      * Returns the number of rows in the matrix.
  447.      */
  448.     public synchronized int rows()
  449.     {
  450.         Matrix m = this;
  451.  
  452.         while(m.nextRow != null)
  453.         {
  454.             m = m.nextRow;
  455.         }
  456.  
  457.         return (m.nextElt == null && m.o == null ? m.row : m.row+1);
  458.     }
  459.  
  460.     //only call on row head
  461.     private synchronized void updateRowNum(int r)
  462.     {
  463.         Matrix m = this;
  464.  
  465.         while(m != null)
  466.         {
  467.             m.row = r;
  468.             m = m.nextElt;
  469.         }
  470.     }
  471.  
  472.     /**
  473.      * Returns an enumeration of all the elements. Use the enumeration methods
  474.      * of the returned object to fetch the elements sequentially.
  475.      */
  476.     public synchronized MatrixEnumeration elements()
  477.     {
  478.         return new MatrixEnumeration(this);
  479.     }
  480.  
  481.     /**
  482.      * Returns a string representation of this component.
  483.      * This is a standard Java AWT method which gets called to generate
  484.      * a string that represents this component.
  485.      *
  486.      * @return a meaningful string about this object
  487.      */
  488.     public synchronized String toString()
  489.     {
  490.         return "Matrix: row=" + row + " col=" + col + " o=" + o;
  491.     }
  492.  
  493.     //--------------------------------------------------
  494.     // private members
  495.     //--------------------------------------------------
  496.  
  497.     private synchronized Matrix nearest(int r, int c)
  498.     {
  499.         //find the correct row
  500.         Matrix m = this;
  501.  
  502.         while (r > m.row)
  503.         {
  504.             if (m.nextRow != null && m.nextRow.row <= r)
  505.             {
  506.                 //further down pike so keep climbing
  507.                 m = m.nextRow;
  508.             }
  509.             else
  510.             {
  511.                 return m;
  512.             }
  513.         }
  514.  
  515.         //m must equal row
  516.         while (m.nextElt != null && c >= m.nextElt.col)
  517.         {
  518.             //further down the line
  519.             m = m.nextElt;
  520.         }
  521.  
  522.         return m;
  523.     }
  524.  
  525.     private synchronized void setRowHead()
  526.     {
  527.         Matrix m = nextElt;
  528.         Matrix h = this;
  529.  
  530.         while (m != null)
  531.         {
  532.             m.rowHead = h;
  533.             m = m.nextElt;
  534.         }
  535.     }
  536.  
  537.     private synchronized void setNextRow(Matrix nr)
  538.     {
  539.         Matrix m = this;
  540.  
  541.         while(m != null)
  542.         {
  543.             m.nextRow = nr;
  544.             m = m.nextElt;
  545.         }
  546.     }
  547.  
  548.     //m1 & m2 preceed the two rows to be switched.
  549.     private synchronized void swapRows(Matrix p1, Matrix p2)
  550.     {
  551.         Matrix t1 = p1.nextRow;
  552.         Matrix t1NextRow = t1.nextRow;
  553.         Matrix t2 = p2.nextRow;
  554.         Matrix t2NextRow = t2.nextRow;
  555.  
  556.         p1.setNextRow(t2);
  557.         p2.setNextRow(t1);
  558.  
  559.         if (p2 == t1)
  560.         {
  561.             t2.setNextRow(t1);
  562.         }
  563.         else
  564.         {
  565.             t2.setNextRow(t1NextRow);
  566.         }
  567.  
  568.         t1.setNextRow(t2NextRow);
  569.         int t1Row = t1.row;
  570.         t1.updateRowNum(t2.row);
  571.         t2.updateRowNum(t1Row);
  572.     }
  573.  
  574.     //swap the current row (must be the first) with the row following m2
  575.     private synchronized void swapRows(Matrix m2)
  576.     {
  577.         Matrix t2 = m2.nextRow;
  578.         Matrix t1 = new Matrix(-1, t2.col, o, null, nextElt);
  579.         m2.rowHead.setNextRow(t1);
  580.         t1.setNextRow(t2.nextRow);
  581.         t1.updateRowNum(t2.row);
  582.         t1.setRowHead();
  583.  
  584.         //fixup root node (that is this)
  585.         nextElt = t2.nextElt;
  586.         o = t2.o;
  587.         setNextRow(nextRow);  //this.nextRow never changed so can use for update
  588.         updateRowNum(0);
  589.         setRowHead();
  590.     }
  591.  
  592.     private synchronized Matrix findLeast(CompareFunc f, Matrix m, int c, boolean first)
  593.     {
  594.         //m is row previous to one to be compared to when m.row != 0
  595.         if (!first)
  596.             m = m.nextRow;
  597.  
  598.         if(m == null || m.nextRow == null)
  599.             return null;
  600.  
  601.         Matrix n = m.nextRow.rowHead;
  602.         Matrix prevToN = m.rowHead;
  603.         Matrix prevToLeast = null;
  604.  
  605.         m = m.nearest(m.row, c);
  606.  
  607.         while (n != null)
  608.         {
  609.             n = n.nearest(n.row, c);
  610.  
  611.             if (n.col != c)
  612.             {
  613.                 //no item for column on next row so keep searching
  614.                 prevToN = n.rowHead;
  615.                 n = n.nextRow;
  616.                 continue;
  617.             }
  618.             else if (m.col != c)
  619.             {
  620.                 //no item for first column so automatically sent down
  621.                 m = n;
  622.                 prevToLeast = prevToN;
  623.                 continue;
  624.             }
  625.  
  626.             if (f.lessThan(n.o, m.o))
  627.             {
  628.                 //n < m so put n in for least
  629.                 m = n;
  630.                 prevToLeast = prevToN;
  631.             }
  632.  
  633.             prevToN = n.rowHead;
  634.             n = n.nextRow;
  635.         }
  636.  
  637.         return prevToLeast;
  638.     }
  639.  
  640.     /**
  641.      * Error strings.
  642.      */
  643.     transient protected ResourceBundle errors;
  644.  
  645.     //--------------------------------------------------
  646.     // private members
  647.     //--------------------------------------------------
  648.  
  649.     Matrix        rowHead;
  650.     Matrix        nextRow;
  651.     Matrix        nextElt;
  652.     int            row;
  653.     int            col;
  654.     Object        o;
  655. }
  656.