{- New implementation of minimum degree ordering (more efficient). Algorithm from Duff86. XZ, 19/2/92 -} module Min_degree (min_degree) where import Defs import S_Array -- not needed w/ proper module handling import Norm -- ditto import List(nub,partition)--1.3 -- minimum degree ordering -- the entry lists in old_rows must be in assending order min_degree :: (My_Array Int [Int]) -> [Int] min_degree old_rows = find_min init_counts [] [] [] where -- initial row degree counts init_counts = s_accumArray (++) ([]::[Int]) (s_bounds old_rows) (map (\(x,y)->(length y,[x])) (s_assocs old_rows)) -- find rows with minimum degrees (recursive) find_min counts cliques pro res = if remaining == [] then res else find_min new_counts new_cliques processed new_pivots where -- updated result new_pivots = res ++ [pivot_i] -- processed rows processed = mg_line pro [pivot_i] -- updated row counts new_counts = s_accumArray mg_line ([]::[Int]) (s_bounds counts) ((map (\(i,js)->(i,rm_list chgd js)) (sparse_assocs counts)) ++ updt) where chgd = mg_lines ([pivot_i]:[ js | (_, js) <- updt ]) updt = count_update new_cols [] -- counts of remaining rows remaining = sparse_assocs counts (_, (pivot_i:_)) = head remaining -- (List of) cliques with the processed column removed. -- Also, whole clique is removed if there is less -- 2 entries in it. rmed = do_rm cliques [] -- the function does the removal do_rm (cli:clis) rmd = do_rm clis ( if (l2 == []) || (head l2) /= pivot_i then cli:rmd else case r of (r1:r2:_) -> r:rmd _ -> rmd ) where r = l1 ++ (tail l2) (l1,l2) = partition ((<) pivot_i) cli do_rm _ res = res -- new cliques new_cliques = nub (new_cols:rmed) -- new clique new_cols = remove pivot_i (get_cols pivot_i cliques) where remove x = filter ((/=) x) -- old haskell 1.0 function -- the function which updates the row counts count_update (r:rs) res = count_update rs (((length (get_cols r (new_cols:cliques)))-1,[r]):res) count_update _ res = res -- find nonzero entries get_cols = \i cli -> rm_list pro (mg_lines ((old_rows!^i):(filter (elem i) cli))) -- the following functions assum lists are in assending order -- check if two lists have something in common inter_sec x@(x1:xs) y@(y1:ys) | x1 == y1 = True | x1 < y1 = inter_sec xs y | otherwise = inter_sec x ys inter_sec _ _ = False -- remove entries in the 1st list from the 2nd list rm_list x@(x1:xs) y@(y1:ys) | x1 == y1 = rm_list xs ys | x1 < y1 = rm_list xs y | otherwise = y1:rm_list x ys rm_list _ y = y -- morge two lists mg_line x@(x1:xs) y@(y1:ys) | x1 == y1 = x1:mg_line xs ys | x1 < y1 = x1:mg_line xs y | otherwise = y1:mg_line x ys mg_line x y = x ++ y -- merge many lists mg_lines :: Ord a => [[a]] -> [a] mg_lines = foldl1 mg_line