-- In diesem Modul werden eine Reihe von \begriff{worker}-Funktionen definiert die alle einen übergebenen Wert verändern und die geänderte -- Variante zurückliefern. module System.ArrowVHDL.Circuit.Workers where -- Zur Funktionsdefinition werden Funktionen aus folgenden Modulen benötigt. import Data.List (nub, (\\)) import GHC.Exts (sortWith) import System.ArrowVHDL.Circuit.Descriptor import System.ArrowVHDL.Circuit.Sensors import System.ArrowVHDL.Circuit.Tests -- \subsection{CircuitDescriptor Funktionen} -- Dieser Abschnitt befasst sich mit Funktionen, die auf \hsSource{CircuitDescriptor}en arbeiten. -- Mit der Funktion \hsSource{alterCompIDs} lassen sich alle Komponenten IDs innerhalb eines \hsSource{CircuitDescriptor}s verändern. Der erste -- Parameter legt dabei die kleinst mögliche ID fest. alterCompIDs :: Int -> CircuitDescriptor -> CircuitDescriptor alterCompIDs i sg = sg { nodeDesc = nd { nodeId = nodeId nd + i } , nodes = map (alterCompIDs i) $ nodes sg , edges = map (\ (MkEdge (ci,pi) (co,po)) -> (MkEdge (maybe ci (Just.(+i)) $ ci ,pi) (maybe co (Just.(+i)) $ co ,po)) ) $ edges sg } where nd = nodeDesc sg -- Die Funktion \hsSource{dropCircuit} ermöglicht es, einzelne Schaltkreis-Beschreibungen aus dem \hsSource{CircuitDescriptor} zu entfernen. -- Hierzu wird eine match-Funktion als erster Parameter erwartet. dropCircuit :: (CircuitDescriptor -> Bool) -> CircuitDescriptor -> CircuitDescriptor dropCircuit f sg = sg { nodes = newNodes , edges = newEdges } where specific = filter f (nodes sg) newEdges = foldl (flip dropEdgesBordering) (edges sg) (map (nodeId.nodeDesc) specific) newNodes = map (dropCircuit f) $ nodes sg \\ specific -- flatten} ist eine Funktion, welche die interne Struktur des \hsSource{CircuitDescriptor}s \begriff{glättet}. Jeder -- CircuitDescriptor} der nicht Atomar ist, enthält weitere Unterstrukturen. Diese beschreiben, woraus dieser -- CircuitDescriptor} aufgebaut wird. Enthält der \hsSource{CircuitDescriptor} unnötige Verschachtelungen, werden diese mittels -- flatten} entfernt. -- Als Sonderfall gelten die Schaltungen, die Schleifen darstellen. Hier gibt es keine überflüssigen Verschachtelungen, mindestens aber muss -- der Algorithmus zum erkennen solcher ein anderer sein, so dass \hsSource{flatten} auf diese Teilbereiche zunächst nicht angewandt werden -- sollte. flatten :: CircuitDescriptor -> CircuitDescriptor flatten g | isLoop g = g | otherwise = g { nodes = nub $ atomCIDs , edges = esBetweenAtoms } where atomCIDs = filter isAtomic $ allCircuits g esFromAtoms = concat $ map (fromCompEdges g . nodeId . nodeDesc) atomCIDs esFromOuter = filter isFromOuter $ edges g esBetweenAtoms = zipWith MkEdge (map sourceInfo $ esFromOuter ++ esFromAtoms) (map nextAtomOrOut $ esFromOuter ++ esFromAtoms) nextAtomOrOut = (\e -> let (c, p) = nextAtomic g e in if c == mainID then (Nothing, p) else (Just c, p)) mainID = nodeId.nodeDesc $ g -- Die Funktionen \hsSource{dropGenerated} sowie \hsSource{dropID} stellen Spezialfälle der \hsSource{dropCircuit} Funktion dar. -- dropGenerated} löscht sämtliche \hsSource{CircuitDescriptor}en, die automatisch generiert wurden. Ebenso löscht \hsSource{dropID} -- CircuitDescriptor}en, die den \hsSource{isID}-Test bestehen. \hsSource{isID} sowie \hsSource{isGenerated} sind im Modul -- \ref{mod:Circuit.Tests} beschrieben. dropGenerated :: CircuitDescriptor -> CircuitDescriptor dropGenerated = dropCircuit isGenerated dropID :: CircuitDescriptor -> CircuitDescriptor dropID = dropCircuit isID -- Diese Funktionen arbeiten auf \hsSource{CircuitDescriptor}en, und erzeugen Kanten, oder es handelt sich um Funktionen, die aus bestehenden -- Kanten neue generieren. -- Mit der Funktion \hsSource{connectCID} lassen sich zwei \hsSource{CircuitDescriptor}en miteinander verbinden. Dabei werden zwei -- \hsSource{CircuitDescriptor}en übergeben, sowie die Quell-Komponenten ID und die Ziel-Komponenten ID zusammen mit einer Ziel-Pin ID. Erzeugt -- wird eine Kante, welche die Verbindung zwischen beiden \hsSource{CircuitDescriptor}en darstellt. Von der Quelle wird keine \hsSource{PinID} -- benötigt, da hier auf den nächst freien Pin zurückgegriffen wird. Auf der Ziel-Seite ist es dann aber notwendig, einen Ziel-Pin zu -- definieren. connectCID :: CircuitDescriptor -> CircuitDescriptor -> CompID -> (CompID, PinID) -> Edge connectCID old_g g cidF (cidT,pidT) = MkEdge (Just cidF, nextFpin) (Just cidT, pidT) where nextFpin = head $ drop cntEsFrom $ sources.nodeDesc $ getComp old_g cidF cntEsFrom = length $ filter (\x -> (not.isFromOuter $ x) && (srcComp x == cidF)) $ edges g -- Zum entfernen von Kanten die an eine Komponente angrenzen, ist die Funktion \hsSource{dropEdgesBordering} da. Übergeben wird die ID der -- Komponente, die heraus gelöst werden soll, sowie die Liste mit den betroffenen Kanten. Es wird dann eine neue List mit Kanten erstellt, die -- nicht mehr zu der Komponente mit der besagten ID führen. Alle Kanten die nicht mehr an einer Komponente andocken, werden zusammengefügt. -- Diese Funktion kann nur dann funktionieren, wenn die zu lösende Komponente genausoviele eingehende Pins, wie ausgehende Pins besitzt. -- %%% TODO : Components with different InPinCount and OutPinCount have a PROBLEM dropEdgesBordering :: CompID -> [Edge] -> [Edge] dropEdgesBordering cid es = (es ++ mergeEdges (toIt, fromIt)) \\ (toIt ++ fromIt) where toIt = filter ((== (Just cid)).fst.sinkInfo) $ es fromIt = filter ((== (Just cid)).fst.sourceInfo) $ es -- \hsSource{mergeEdges} ist eine Funktion, die zwei Listen mit Kanten entgegennimmt und diese beiden zusammenfasst. Kanten die auf einen Pin -- enden und Kanten die vom gleichen Pin starten, werden zu einer Kante zusammengefasst. mergeEdges :: ([Edge], [Edge]) -> [Edge] mergeEdges (xs, ys) = zipWith (\x y -> MkEdge (sourceInfo x) (sinkInfo y)) xs' ys' where x_snkPins = map snkPin xs y_srcPins = map srcPin ys xs' = sortWith snkPin $ filter (\edg -> (snkPin edg) `elem` y_srcPins) xs ys' = sortWith srcPin $ filter (\edg -> (srcPin edg) `elem` x_snkPins) ys -- Mit der \hsSource{fillEdgeInfoCompID} Funktion, lassen sich die Quell- und Ziel-Komponenten IDs in Kanten setzen, in denen bis dahin -- \hsSource{Nothing} als Wert gespeichert ist. Dies ist dann notwendig, wenn eine neue Komponente in eine bestehende Struktur eingefügt wird. -- Dies wird dann benötigt, wenn eine Komponente in eine Struktur eingefügt werden soll. Eine noch nicht integrierte Komponente bekommt ihre %% TODO : Werte ist sicher nicht das richtige wort hier -- Werte von einer unbekannte Komponente (\hsSource{Nothing}) und liefert die Ergebnisse auch an \hsSource{Nothing}. Wird sie nun eine -- Unterkomponente, so kann das \hsSource{Nothing} durch eine tatsächliche Komponenten ID ersetzt werden. fillEdgeInfoCompID :: CompID -> Edge -> Edge fillEdgeInfoCompID cid (MkEdge (Nothing, srcPid) (snkInfo)) = (MkEdge (Just cid, srcPid) (snkInfo)) fillEdgeInfoCompID cid (MkEdge (srcInfo) (Nothing, snkPid)) = (MkEdge (srcInfo) (Just cid, snkPid)) fillEdgeInfoCompID _ e = e -- Ein ähnliches Problem wie \hsSource{fillEdgeInfoCompID} wird auch von den Funktionen \hsSource{fillSrcInfoCompID} und -- \hsSource{fillSnkInfoCompID} gelöst. Diese unterscheiden sich lediglich darin, dass diese Funktionen jeweils nur die Quell-Pins oder nur die -- Ziel-Pins betreffen. fillSrcInfoCompID :: CompID -> Edge -> Edge fillSrcInfoCompID cid (MkEdge (Nothing, srcPid) (snkCid, snkPid)) = (MkEdge (Just cid, srcPid) (snkCid, snkPid)) fillSnkInfoCompID :: CompID -> Edge -> Edge fillSnkInfoCompID cid (MkEdge (srcCid, srcPid) (Nothing, snkPid)) = (MkEdge (srcCid, srcPid) (Just cid, snkPid))