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