PDL::Indexingp – Online in der Cloud

Dies ist der Befehl PDL::Indexingp, der beim kostenlosen Hosting-Anbieter OnWorks mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, dem Windows-Online-Emulator oder dem MAC OS-Online-Emulator ausgeführt werden kann

PROGRAMM:

NAME/FUNKTION


PDL::Indexing – Einführung in das Indexieren und Slicing von Rätseln.

Überblick


Diese Manpage soll als erstes Tutorial zu den Indizierungs- und Threading-Funktionen von dienen
PDL.

Wie alle vektorisierten Sprachen automatisiert PDL das Durchlaufen von Arrays mithilfe einer Variante von
mathematische Vektornotation. Die automatische Schleife wird teilweise auch „Threading“ genannt
denn letztendlich wird PDL eine Parallelverarbeitung implementieren, um die Schleifen zu beschleunigen.

Ein Großteil der Flexibilität und Leistungsfähigkeit von PDL beruht auf den Indexierungs- und Threading-Funktionen von
die Perl-Erweiterung. Die Indizierung ermöglicht den Zugriff auf die Daten eines Piddles auf sehr flexible Weise
Weg. Threading ermöglicht eine effiziente Vektorisierung einfacher Operationen.

Die Werte eines Piddles werden kompakt als typisierte Werte in einem einzigen Speicherblock gespeichert.
nicht (wie in einer normalen Perl-Liste von Listen) als einzelne Perl-Skalare.

In den folgenden Abschnitten werden viele „Methoden“ genannt – dabei handelt es sich um Perl-Operatoren
gelten für PDLs. In der perldl- (oder pdl2-)Shell können Sie mehr über die einzelnen Methoden erfahren
durch Eingabe von "?" gefolgt vom Methodennamen.

Abmessungen Listen
Ein Piddle (PDL-Variable) ist im Allgemeinen ein N-dimensionales Array, wobei N 0 sein kann (für a
Skalar), 1 (z. B. für ein Tonbeispiel), oder höhere Werte für Bilder und komplexer
Strukturen. Jede Dimension des Piddles hat eine positive ganzzahlige Größe. Die „Perle“
Der Interpreter behandelt jedes Piddle als einen speziellen Typ von Perl-Skalaren (ein gesegnetes Perl-Objekt,
eigentlich – aber man muss das nicht wissen, um sie zu verwenden), die überall verwendet werden können
Setzen Sie einen normalen Skalar.

Sie können die Abmessungen eines Piddles als Perl-Liste abrufen und ansonsten die Größe bestimmen
eines Pudels mit mehreren Methoden. Die wichtigsten sind:

nelem – die Gesamtzahl der Elemente in einer PDL
ndims – gibt die Anzahl der Dimensionen in einer PDL zurück
dims – gibt die Dimensionsliste einer PDL als Perl-Liste zurück
dim – gibt die Größe einer bestimmten Dimension einer PDL zurück

Indizierung und Datenfluss
PDL verfolgt die Vorstellung eines „Datenflusses“ zwischen einem Piddle und indizierten Unterfeldern davon
pinkeln. Wenn Sie ein indiziertes Unterfeld oder ein einzelnes Element eines übergeordneten Piddles erstellen, wird das
Kind und Eltern bleiben verbunden, bis Sie sie manuell trennen. Dies ermöglicht Ihnen
Stellen Sie dieselben Daten in Ihrem Code auf unterschiedliche Weise dar. Sie können beispielsweise Folgendes in Betracht ziehen
ein RGB-Bild gleichzeitig als Sammlung von (R,G,B)-Werten in einem 3 x 1000 x 1000-Bild,
und als drei separate 1000 x 1000-Farbebenen, die in verschiedenen Variablen gespeichert sind. Ändern
Jede der Variablen verändert den zugrunde liegenden Speicher, und die Änderungen werden in allen widergespiegelt
Darstellungen der Daten.

Es gibt zwei wichtige Methoden, mit denen Sie Datenflussverbindungen zwischen einem untergeordneten Element steuern können
und übergeordnete PDL:

copy – erzwingt eine explizite Kopie einer PDL
Sever – unterbricht die Datenflussverbindung zwischen einer PDL und ihren übergeordneten Dateien (sofern vorhanden).

Threading und Abmessungen Order
Die meisten PDL-Operationen wirken sich auf die ersten paar Dimensionen ihrer Piddle-Argumente aus. Für
„sumover“ summiert beispielsweise alle Elemente entlang der ersten Dimension in der Liste (Dimension 0).
Wenn Sie ein dreidimensionales Piddle einspeisen, wird die erste Dimension berücksichtigt
„aktive“ Dimension und die späteren Dimensionen sind „Gewinde“-Dimensionen, weil sie es sind
einfach durchgeschleift. Es gibt mehrere Möglichkeiten, die Dimensionsliste von zu transponieren oder neu anzuordnen
eine PDL. Diese Techniken sind sehr schnell, da sie nicht nur die zugrunde liegenden Daten berühren
Ändern Sie die Art und Weise, wie PDL auf die Daten zugreift. Die wichtigsten Dimensionsreihenfolgefunktionen sind:

mv – verschiebt eine bestimmte Dimension an eine andere Stelle in der Dimensionsliste
xchg – tauscht zwei Dimensionen in der Dimensionsliste aus und lässt den Rest in Ruhe
Neu anordnen – ermöglicht das umfassende Mischen der Abmessungen
Clump – fasst zwei oder mehr kleine Dimensionen zu einer größeren zusammen
Squeeze – eliminiert alle Dimensionen der Größe 1

Physik und Papiermuster ABMESSUNGEN
· Dokumentieren Sie Threading auf Perl-Ebene

· Thread-IDs

· Aktualisierung und korrekte Beschreibung des Slice

· neue Funktionen in Slice.pd (affine, lag, splitdim)

· Überarbeitung des Absatzes zum expliziten Threading

Indizierung und einfädeln mit PDL


Ein Großteil der Flexibilität und Leistungsfähigkeit von PDL beruht auf den Indizierungs- und Schleifenfunktionen von
die Perl-Erweiterung. Die Indizierung ermöglicht den Zugriff auf die Daten eines PDL-Objekts auf sehr flexible Weise
Weg. Threading bietet effiziente implizite Schleifenfunktionen (da die Schleifen vorhanden sind).
als optimierter C-Code implementiert).

PDL-Objekte (später oft „PDLs“ genannt) sind Perl-Objekte, die mehrdimensional darstellen
Arrays und Operationen auf diesen. Im Gegensatz zum einfachen Perl-@x-Stil werden die Array-Daten aufgelistet
wird kompakt in einem einzigen Speicherblock gespeichert und beansprucht somit viel weniger Speicher und
Ermöglicht die Verwendung von schnellem C-Code zur Implementierung von Operationen (z. B. Addition usw.) auf PDLs.

pdls können. haben und Kindern
Im Mittelpunkt vieler Indizierungsfunktionen von PDL steht die Beziehung zwischen „Parent“ und „Parent“.
„Kind“ zwischen pdls. Viele der Indizierungsbefehle erstellen eine neue PDL aus einer vorhandenen PDL.
Das neue PDL ist das „Kind“ und das alte ist das „Elternteil“. Die Daten des neuen PDL sind
definiert durch eine Transformation, die angibt, wie ihre Daten aus generiert (berechnet) werden
Daten der Eltern. Die Beziehung zwischen dem untergeordneten PDL und seinem übergeordneten Element ist häufig bidirektional.
Dies bedeutet, dass Änderungen in den Daten des untergeordneten Elements an das übergeordnete Element weitergegeben werden. (Hinweis: Sie
Sehen Sie, wir zielen in unserer Terminologie bereits auf die neuen Datenflussfunktionen ab. Die Art
des Datenflusses, der von den Indizierungsbefehlen verwendet wird (mehr erfahren Sie gleich)
ist immer in Betrieb, nicht nur, wenn Sie den Datenfluss in Ihrem PDL explizit aktiviert haben
indem Sie „$a->doflow“ sagen. Weitere Informationen zum Datenfluss finden Sie im Datenfluss-Man
Seite.)

Eine andere Möglichkeit, die von unseren Indizierungsbefehlen erstellten PDLs zu interpretieren, besteht darin, sie als anzuzeigen
Eine Art intelligenter Zeiger, der auf einen Teil oder alle Daten seines übergeordneten Elements verweist.
Daher ist es nicht verwunderlich, dass sich die Daten des übergeordneten Elements (oder ein Teil davon) ändern, wenn
durch diesen „Zeiger“ manipuliert werden. Nach diesen einleitenden Bemerkungen hoffentlich
Wir haben Sie auf das Kommende vorbereitet (anstatt Sie zu sehr zu verwirren). Wir werden tauchen
Beginnen Sie mit einer Beschreibung der Indizierungsbefehle und einigen typischen Beispielen
wie sie in PDL-Programmen verwendet werden könnten. Wir werden den Zeiger/Datenfluss weiter veranschaulichen
Analogien im Kontext einiger Beispiele später.

Es gibt zwei verschiedene Implementierungen dieser „Smart Pointer“-Beziehung: die erste
Eine, die etwas langsamer ist, aber für jede Transformation funktioniert, besteht einfach darin, Folgendes auszuführen
Transformation nach Bedarf vorwärts und rückwärts. Die andere besteht darin, an das Kind zu denken
piddle ist ein „virtuelles“ Piddle, das nur einen Zeiger auf das übergeordnete Element und den Zugriff speichert
Informationen, sodass Routinen, die das untergeordnete Piddle verwenden, tatsächlich direkt auf die Daten zugreifen
im Elternteil. Wenn das virtuelle Piddle einer Routine übergeben wird, die es nicht verwenden kann, PDL
physischisiert das virtuelle Piddle transparent, bevor es von der Routine verwendet wird.

Derzeit (1.94_01) alle Transformationen, die „affin“ sind, also die Indizes der Daten
Das Element im übergeordneten Piddle wird durch eine lineare Transformation (+ Konstante) aus dem bestimmt
Indizes des untergeordneten Puzzles führen zu virtuellen Puzzles. Alle anderen Indizierungsroutinen (z
„->index(...)“) führen zu physischen Rätseln. Alle von PP kompilierten Routinen können affine akzeptieren
Piddles (mit Ausnahme der Routinen, die Zeiger auf externe Bibliotheksfunktionen übergeben).

Beachten Sie, dass die Frage, ob etwas affin ist oder nicht, keinen Einfluss auf die Semantik Ihrer Handlungen hat
jedenfalls: beides

$a->index(...) .= 5;
$a->slice(...) .= 5;

Ändern Sie die Daten in $a. Die Affinität hat jedoch einen erheblichen Einfluss auf das Gedächtnis
Nutzung und Leistung.

Slicing pdls
Die wahrscheinlich wichtigste Anwendung des Konzepts der Eltern-/Kind-PDLs ist die
Darstellung rechteckiger Abschnitte einer physischen PDL durch eine virtuelle PDL. Nachdem ich gesprochen habe
Lange genug über Konzepte, lasst uns genauer werden. Angenommen, wir arbeiten mit einem 2D-PDL
stellt ein 5x5-Bild dar (es ist ungewöhnlich klein, sodass wir es ohne Füllung drucken können).
mehrere Bildschirme voller Ziffern ;).

pdl> $im = sequence(5,5)
pdl> p $im

[
[ 0 1 2 3 4]
[ 5 6 7 8 9]
[10 11 12 13 14]
[15 16 17 18 19]
[20 21 22 23 24]
]

pdl> help vars
PDL-Variablen im Paket main::

Name Typ Dimension Flow State Mem
-------------------------------------------------- --------------
$im Double D [5,5] P 0.20Kb

[ Hier könnte es angebracht sein, kurz über den Befehl „help vars“ zu sprechen, der Folgendes bereitstellt
Informationen zu PDLs in der interaktiven Shell „perldl“ oder „pdl2“, die mit PDL geliefert wird. ]

Nehmen wir nun an, wir möchten ein 1D-PDL erstellen, das beispielsweise nur auf eine Zeile des Bildes verweist
Zeile 2; oder ein PDL, das alle geraden Zeilen des Bildes darstellt (stellen Sie sich vor, wir müssen uns damit befassen
gerade und ungerade Frames eines Interlaced-Bildes aufgrund eines besonderen Verhaltens unseres Frames
Greifer). Als weitere häufige Anwendung von Slices möchten wir möglicherweise ein PDL erstellen
stellt einen rechteckigen Bereich des Bildes dar, bei dem Ober- und Unterseite vertauscht sind. All diese
Effekte (und viele mehr) lassen sich ganz einfach mit der leistungsstarken Slice-Funktion erzielen:

pdl> $line = $im->slice(':,(2)')
pdl> $even = $im->slice(':,1:-1:2')
pdl> $area = $im->slice('3:4,3:1')
pdl> help vars # oder einfach PDL->vars
PDL-Variablen im Paket main::

Name Typ Dimension Flow State Mem
-------------------------------------------------- --------------
$even Double D [5,2] -C 0.00 Kb
$im Double D [5,5] P 0.20Kb
$line Double D [5] -C 0.00 KB
$area Double D [2,3] -C 0.00 Kb

Alle drei „untergeordneten“ PDLs sind Kinder von $im oder im anderen (weitgehend gleichwertig)
Interpretationshinweise auf Daten von $im. Vorgänge auf diesen virtuellen PDLs greifen nur zu
diejenigen Teile der Daten, die durch das zu segmentierende Argument angegeben werden. Wir können also einfach drucken
Zeile 2:

pdl> p $line
[10 11 12 13 14]

Beachten Sie auch den Unterschied im „Flow State“ von $area oben und unten:

pdl> p $area
pdl> help $area
Diese Variable ist Double D [2,3] VC 0.00 KB

Das Folgende zeigt, dass sich $im und $line wirklich so verhalten, wie man es von a erwarten würde
Zeigerähnliches Objekt (oder im Datenflussbild: Die Änderungen in den Daten von $line sind
zurück an $im weitergegeben):

pdl> $im++
pdl> p $line
[11 12 13 14 15]
pdl> $line += 2
pdl> p $im

[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[13 14 15 16 17]
[16 17 18 19 20]
[21 22 23 24 25]
]

Beachten Sie, wie Zuweisungsvorgänge an den untergeordneten virtuellen PDLs das übergeordnete physische PDL ändern
und umgekehrt (die grundlegende „="-Zuweisung tut dies jedoch nicht, verwenden Sie „.=", um diesen Effekt zu erzielen).
Die Gründe finden Sie weiter unten. Die virtuellen Kinder-PDLs sind so etwas wie „Live-Links“ zum
„ursprüngliches“ übergeordnetes PDL. Wie bereits erwähnt, kann man sich vorstellen, dass sie ähnlich funktionieren wie a
C-Zeiger. Im Gegensatz zu einem C-Zeiger tragen sie jedoch viel mehr Informationen. Erstens, sie
Geben Sie die Struktur der Daten an, die sie darstellen (die Dimensionalität des neuen PDL) und
Zweitens geben Sie an, wie diese Struktur aus den übergeordneten Daten erstellt werden soll (wie dies funktioniert).
ist in den Interna von PDL vergraben und für Sie ohnehin nicht wichtig (es sei denn, Sie
in Zukunft den Kern hacken wollen oder allgemein ein PDL-Guru werden möchten (für einen
Definition dieser seltsamen Kreatur siehe PDL::Internals)).

Die vorherigen Beispiele haben die typische Verwendung der Slice-Funktion demonstriert. Seit der
Da die Slicing-Funktionalität so wichtig ist, finden Sie hier eine Erläuterung der Syntax für die Zeichenfolge
Argument zum Schneiden:

$vpdl = $a->slice('ind0,ind1...')

Dabei gibt „ind0“ an, was mit Index Nr. 0 des pdl $a usw. geschehen soll. Jedes Element von
Eine durch Kommas getrennte Liste kann eine der folgenden Formen haben:

':' Die gesamte Dimension verwenden

'n' Verwenden Sie nur den Index „n“. Die Dimension dieses Index im resultierenden virtuellen PDL ist 1.
Ein Beispiel mit den ersten beiden Indexformaten:

pdl> $column = $im->slice('2,:')
pdl> $row = $im->slice(':,0')
pdl> p $column

[
[3]
[8]
[15]
[18]
[23]
]

pdl> p $row

[
[1 2 3 4 5]
]

pdl> help $column
Diese Variable ist Double D [1,5] VC 0.00 KB

pdl> help $row
Diese Variable ist Double D [5,1] VC 0.00 KB

'(n)' Verwenden Sie nur den Index „n“. Diese Dimension wird aus dem resultierenden PDL entfernt (basierend auf dem
Tatsache, dass ein Maß der Größe 1 immer entfernt werden kann). Der Unterschied zwischen diesem
Der Fall und der vorherige werden bei Aufgaben wichtig, bei denen die linke und die rechte Hand vorhanden sind
Seite müssen entsprechende Abmessungen haben.

pdl> $line = $im->slice(':,(0)')
pdl> help $line
Diese Variable ist Double D [5] -C 0.00 KB

pdl> p $line
[1 2 3 4 5]

Erkennen Sie den Unterschied zum vorherigen Beispiel?

'n1:n2' or 'n1:n2:n3'
Nehmen Sie den Indexbereich von „n1“ bis „n2“ oder (zweite Form) den Bereich von
Indizes von „n1“ bis „n2“ mit Schritt „n3“. Ein Beispiel für die Verwendung dieses Formats ist
Die vorherige Definition des Teilbildes besteht aus geraden Linien.

pdl> $even = $im->slice(':,1:-1:2')

Dieses Beispiel zeigt auch, dass negative Indizes genauso funktionieren wie normale
Arrays im Perl-Stil durch Rückwärtszählen vom Ende der Dimension. Wenn „n2“ ist
kleiner als „n1“ (im Beispiel entspricht -1 dem Index 4) die Elemente in der
virtuelle pdl werden effektiv in Bezug auf ihr übergeordnetes Element zurückgesetzt.

'*[N]'
Fügen Sie eine Dummy-Dimension hinzu. Die Größe dieser Dimension beträgt standardmäßig 1 oder gleich
„n“, wenn das optionale numerische Argument angegeben ist.

Nun, das ist auf den ersten Blick wirklich etwas seltsam. Was ist ein Dummy?
Abmessungen? Eine Dummy-Dimension fügt eine Dimension ein, wo zuvor keine vorhanden war. Wie
Ist das erledigt ? Nun, im Fall der neuen Dimension mit der Größe 1 ist das problemlos möglich
erklärt durch die Art und Weise, wie Sie einen Vektor (mit „m“ Elementen) mit einem identifizieren können
„(1,m)“- oder „(m,1)“-Matrix. Das Gleiche gilt offensichtlich auch für höherdimensionale Objekte.
Interessanter ist der Fall einer Dummy-Dimension mit einer Größe von mehr als eins (z. B
"slice('*5,:')"). Dies funktioniert auf die gleiche Weise, wie ein Aufruf der Dummy-Funktion erstellt
eine neue Dummy-Dimension. Lesen Sie also weiter und sehen Sie sich die Erklärung unten an.

'([n1:n2[:n3]]=i)'
[Noch nicht implementiert ??????] Mit einem solchen Argument machen Sie verallgemeinert
Diagonalendem „Vermischten Geschmack“. Seine Diagonale wird Dimension Nr. sein. „i“ des neuen Ausgabe-PDL und (falls
optionaler Teil in Klammern angegeben) erstreckt sich entlang des Indexbereichs
angegebene Dimension der jeweiligen übergeordneten PDL. Im Allgemeinen ein Argument wie dieses
macht nur dann Sinn, wenn es im selben Slice-Aufruf weitere Argumente wie dieses gibt.
Der Teil in Klammern ist für diese Art von Argument optional. Alle Argumente dazu
Typen, die die gleiche Zieldimension „i“ angeben, müssen sich auf die gleiche Anzahl beziehen
Indizes in ihrer übergeordneten Dimension. Der beste Weg, es zu erklären, ist wahrscheinlich, eine zu geben
Beispiel: Hier erstellen wir eine PDL, die sich auf die Elemente entlang der Raumdiagonale von bezieht
sein übergeordnetes PDL (ein Würfel):

$cube = Nullen(5,5,5);
$sdiag = $cube->slice('(=0),(=0),(=0)');

Der obige Befehl erstellt eine virtuelle PDL, die die Diagonale entlang der darstellt
Elterndimension Nr. 0, 1 und 2 und macht seine Dimension 0 (die einzige Dimension) von
Es. Sie verwenden die erweiterte Syntax, wenn Sie die Dimensionsgrößen der übergeordneten Dimensionen verwenden
Sie möchten die Diagonale aus unterschiedlichen Größen aufbauen oder sie umkehren
Folge von Elementen in der Diagonale, z

$rect = Nullen(12,3,5,6,2);
$vpdl = $rect->slice('2:7,(0:1=1),(4),(5:4=1),(=1)');

Die Elemente von $vpdl werden dann auf die von uns mögliche Weise mit denen des übergeordneten Elements verknüpft
ausdrücken als:

vpdl(i,j) = rect(i+2,j,4,5-j,j) 0<=i<5, 0<=j<2

[ in der neuen Indexfunktion arbeiten: „$b = $a->index($c);“ ???? ]

Es sind anders sein kann oder ander sein wird Arten of Zuordnungen in PDL
Die vorherigen Beispiele haben bereits gezeigt, dass virtuelle PDLs zum Betrieb auf oder verwendet werden können
Zugriff auf Teile der Daten einer übergeordneten PDL. Sie können auch als L-Werte in Zuweisungen verwendet werden
(wie die Verwendung von „++“ in einigen der obigen Beispiele bereits gezeigt hat). Für explizit
Zuweisungen zu den Daten, die durch ein virtuelles PDL dargestellt werden, müssen Sie das überladene „.=" verwenden.
Operator (den wir in diesem Zusammenhang nennen vermehrt Zuordnung). Warum können Sie das nicht verwenden?
normaler Zuweisungsoperator „="?

Nun, Sie können den Operator „=“ auf jeden Fall immer noch verwenden, aber er würde nicht das bewirken, was Sie wollen. Das
liegt daran, dass der Operator „=“ nicht auf die gleiche Weise wie andere überladen werden kann
Zuweisungsoperatoren. Wenn wir versuchen würden, „=“ zu verwenden, um Daten einem Teil von a zuzuordnen
Wenn wir ein physisches PDL durch ein virtuelles PDL ersetzen würden, würden wir nicht den gewünschten Effekt erzielen (stattdessen
Variable, die das virtuelle PDL (ein Verweis auf ein gesegnetes Ding) darstellt, würde nach dem
Die Aufgabe enthält nur den Verweis auf ein anderes gesegnetes Ding, das sich so verhalten würde
Zukünftige Zuweisungen als „physische“ Kopie des ursprünglichen R-Werts [dies ist eigentlich noch nicht der Fall
klar und Gegenstand von Diskussionen in der Mailingliste der PDL-Entwickler]. In diesem Sinne ist es
würde die Verbindung des PDL zum übergeordneten Element unterbrechen [ist dieses Verhalten nicht in gewisser Weise das
Gegenteil von dem, was im Datenfluss passiert, wo „.=" die Verbindung zum übergeordneten Element unterbricht? ].

zB

pdl> $line = $im->slice(':,(2)')
pdl> $line = Nullen(5);
pdl> $line++;
pdl> p $im

[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[13 14 15 16 17]
[16 17 18 19 20]
[21 22 23 24 25]
]

pdl> p $line
[1 1 1 1 1]

Aber mit „.="

pdl> $line = $im->slice(':,(2)')
pdl> $line .= Nullen(5)
pdl> $line++
pdl> p $im

[
[ 1 2 3 4 5]
[ 6 7 8 9 10]
[ 1 1 1 1 1]
[16 17 18 19 20]
[21 22 23 24 25]
]

pdl> $zeile drucken
[1 1 1 1 1]

Sie können es auch ersetzen

pdl> $line .= 0;

für die obige Aufgabe (die Null wird in ein skalares Piddle umgewandelt, also ohne Dimensionen).
es kann jedem beliebigen Rätsel zugeordnet werden).

Eine nette Funktion in neueren Perl-Versionen sind Lvalue-Unterroutinen (z. B. Versionen 5.6.x und
höher, einschließlich aller Perls, die derzeit von PDL unterstützt werden). Das ermöglicht es einem, das zu verwenden
Slicing-Syntax auf beiden Seiten der Zuweisung:

pdl> $im->slice(':,(2)') .= Nullen(5)->xvals->float

Im Zusammenhang mit der Lvalue-Unterzuweisungsfunktion gibt es eine kleine Falle für Unvorsichtige: aktuelle Perls
führte eine „Funktion“ ein, die die Verwendung von Lvalue-Subs für Slice-Zuweisungen durch PDL unterbricht, wenn
Läuft unter dem Perl-Debugger „perl -d“. Unter dem Debugger ergibt die obige Verwendung eine
Fehler wie: „Kann kein temporäres L-Wert-Unterprogramm zurückgeben...“ Sie müssen also die Syntax verwenden
so was:

pdl> ($pdl = $im->slice(':,(2)')) .= Nullen(5)->xvals->float

Das funktioniert sowohl mit als auch ohne Debugger, ist aber wohl umständlich und umständlich zu lesen.

Beachten Sie, dass bei Zuweisungen wie dieser ein Problem auftreten kann, wenn L-Wert- und R-Wert-PDLs verwendet werden
Verweisen Sie auf überlappende Datenabschnitte im übergeordneten PDL:

# die Elemente der ersten Zeile von $a zurücksetzen
($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)');

Derzeit werden die übergeordneten Daten auf der rechten Seite der Aufgaben nicht vor kopiert
(interne) Zuweisungsschleife läuft weiter. Daher wird das Ergebnis dieser Aufgabe davon abhängen
von der Reihenfolge, in der Elemente zugewiesen werden, und mit ziemlicher Sicherheit nicht Tu, was du tust
gesucht. Die Semantik ist also aktuell undefiniert vorerst und kann jederzeit geändert werden. Zu
das gewünschte Verhalten erreichen, nutzen

($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)')->copy;

wodurch eine physische Kopie des Slice erstellt wird oder

($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)')->sever;

Dies gibt das gleiche Slice zurück, trennt jedoch die Verbindung des Slice zu seinem übergeordneten Slice.

Andere Funktionen zur Abwicklung, Integrierung, Speicherung und manipulieren Größe
Nachdem ich ausführlich über die Slice-Funktion gesprochen habe, sollte angemerkt werden, dass dies nicht der Fall ist
Nur PDL-Indizierungsfunktion. Es gibt zusätzliche Indizierungsfunktionen, die ebenfalls nützlich sind
(insbesondere im Zusammenhang mit dem Threading, über das wir später sprechen werden). Hier ist eine Liste
und einige Beispiele für deren Verwendung.

"Dummy"
fügt an der gewählten Stelle eine Dummy-Abmessung der von Ihnen angegebenen Größe (Standard 1) ein.
Sie können es kaum erwarten zu hören, wie das gelingt? Nun, alle Elemente mit dem Index „(X,x,Y)“
("0<=x
pdl (wobei „X“ und „Y“ sich auf die Gruppe der Indizes vor und nach dem Standort beziehen
wo die Dummy-Dimension eingefügt wurde.)

In diesem Beispiel wird die x-Koordinate des Schwerpunkts eines Bildes berechnet (wir werden es später tun).
Erfahren Sie, dass wir dank der Magie des Impliziten die Dummy-Dimension eigentlich nicht brauchten
Einfädeln; aber mit Dummy-Dimensionen würde der Code auch in einer Thread-losen Welt funktionieren;
Wenn Sie jedoch einmal mit PDL-Threads gearbeitet haben, möchten Sie nicht mehr ohne sie leben
nochmal).

# Schwerpunkt
($xd,$yd) = $im->dims;
$xc = sum($im*xvals(zeroes($xd))->dummy(1,$yd))/sum($im);

Lassen Sie uns etwas genauer erklären, wie das funktioniert. Zuerst das Produkt:

$xvs = xvals(zeroes($xd));
print $xvs->dummy(1,$yd); # Wiederholen Sie die Zeile $yd Mal
$prod = $im*xvs->dummy(1,$yd); # Bilde das pixelweise Produkt mit
# die wiederholte Zeile von x-Werten

Der Rest besteht dann darin, die Ergebnisse des pixelweisen Produkts zu summieren und
Normalisierung mit der Summe aller Pixelwerte im Originalbild und somit Berechnung
die x-Koordinate des „Massenschwerpunkts“ des Bildes (Pixelwerte werden interpretiert als).
lokale Masse), der als Schwerpunkt eines Bildes bekannt ist.

Als nächstes folgt eine (aus Sicht des Speicherverbrauchs) sehr günstige Konvertierung
Graustufen zu RGB, dh jedes Pixel enthält jetzt ein Wertetripel anstelle eines Skalars.
Die drei Werte im Tripel sind für ein Graubild glücklicherweise alle gleich, also
dass unser Trick insofern gut funktioniert, als er alle drei Mitglieder des Tripels dem zuordnet
gleiches Quellelement:

# eine kostengünstige Konvertierung von Graustufen in RGB
$rgb = $grey->dummy(0,3)

Leider können Sie mit diesem Trick Ihre alten S/W-Fotos nicht in Farbfotos umwandeln
auf die Art und Weise, wie Sie es möchten. :(

Beachten Sie, dass die Speichernutzung von Piddles mit Dummy-Dimensionen besonders empfindlich ist
die interne Darstellung. Wenn das Piddle als virtuelles Affin dargestellt werden kann
(„vaffine“) piddle werden nur die Kontrollstrukturen gespeichert. Aber wenn $b rein

$a = Nullen(10000);
$b = $a->dummy(1,10000);

durch eine Routine physisch gemacht wird, werden Sie feststellen, dass die Speichernutzung Ihres Programms zunimmt
ist plötzlich um 100 MB gewachsen.

"Diagonale"
ersetzt zwei Dimensionen (die gleich groß sein müssen) durch eine Dimension, die
verweist auf alle Elemente entlang der „Diagonale“ entlang dieser beiden Dimensionen. Hier, wir
Ich habe zwei Beispiele, die jedem bekannt vorkommen sollten, der jemals etwas Lineares gemacht hat
Algebra. Erstellen Sie zunächst eine Einheitsmatrix:

# Einheitsmatrix
$e = Nullen(float, 3, 3); # alles auf Null setzen
($tmp = $e->diagonal(0,1)) .= 1; # setze die Elemente entlang der Diagonale auf 1
$e drucken;

Oder die andere Diagonale:

($tmp = $e->slice(':-1:0')->diagonal(0,1)) .= 2;
$e drucken;

(Ist Ihnen aufgefallen, wie wir zuvor die Slice-Funktion verwendet haben, um die Zeilenfolge umzukehren?
Festlegen der Diagonale des neuen Kindes und damit Festlegen der Kreuzdiagonale des
parent ?) Oder eine Abbildung vom Raum der Diagonalmatrizen auf das Feld darüber
Die Matrizen sind definiert, die Spur einer Matrix:

# Spur einer Matrix
$trace = sum($mat->diagonal(0,1)); # Summiere alle Diagonalelemente

„xchg“ und „mv“
xchg tauscht oder „transponiert“ die beiden angegebenen Dimensionen. Eine unkomplizierte
Beispiel:

# eine Matrix transponieren (ohne die Daten explizit neu zu mischen und
# eine Kopie erstellen)
$prod = $ax $a->xchg(0,1);

$prod sollte jetzt ziemlich nahe an der Einheitsmatrix liegen, wenn $a eine orthogonale Matrix ist.
Oft wird „xchg“ im Zusammenhang mit Threading verwendet, aber dazu später mehr.

mv funktioniert auf ähnliche Weise. Es verschiebt eine Dimension (angegeben durch ihre Nummer im
parent) an eine neue Position im neuen untergeordneten PDL:

$b = $a->mv(4,0); # Machen Sie die 5. Dimension von $a zur ersten im
# neues Kind $b

Der Unterschied zwischen „xchg“ und „mv“ besteht darin, dass „xchg“ nur die Position von zwei ändert
Dimensionen untereinander, wobei „mv“ die erste Dimension an der Stelle von einfügt
Zweitens, die anderen Dimensionen entsprechend verschieben.

"Büschel"
fasst mehrere Dimensionen zu einer zusammen. Sein einziges Argument gibt an, wie viele Dimensionen es gibt
der Quell-PDL sollte minimiert werden (beginnend mit der ersten). Ein (zugegebenermaßen
(unrealistisch) Beispiel ist ein 3D-PDL, das Daten aus einem Stapel von Bilddateien enthält, die Sie haben
habe gerade eingelesen. Allerdings stellen die Daten von jedem Bild tatsächlich eine 1D-Zeit dar
Serie und ist nur deshalb so angeordnet, weil es mit einem Rahmen digitalisiert wurde
Greifer. Also, um es wieder als eine Reihe von Zeitsequenzen zu haben, sagen Sie

pdl> $seqs = $stack->Büschel(2)
pdl> help vars
PDL-Variablen im Paket main::

Name Typ Dimension Flow State Mem
-------------------------------------------------- --------------
$seqs Double D [8000,50] -C 0.00 KB
$stack Double D [100,80,50] P 3.05 MB

So unrealistisch es auch erscheinen mag, unsere Software für konfokale Mikroskope schreibt Daten (manchmal)
Hier entlang. Bei der impliziten Verwendung verwenden Sie jedoch häufiger Clump, um einen bestimmten Effekt zu erzielen
oder explizites Threading.

Aufrufe zu Indizierung Funktionen können. be angekettet
Wie Sie vielleicht in einigen der obigen Beispiele bemerkt haben, werden Aufrufe der Indizierungsfunktionen aufgerufen
kann gut verkettet werden, da alle diese Funktionen ein neu erstelltes untergeordnetes Objekt zurückgeben.
Wenn Sie jedoch umfangreiche Indexmanipulationen in einer Kette durchführen, achten Sie darauf, den Überblick darüber zu behalten, was passiert
was du tust, z.B

$a->xchg(0,1)->mv(0,4)

Verschiebt die Dimension 1 von $a auf Position 4, da der zweite Befehl ausgeführt wird
Die ursprüngliche Dimension 1 wurde an Position 0 des neuen untergeordneten Elements verschoben, das „mv“ aufruft.
Funktion. Ich denke, Sie haben die Idee verstanden (trotz meiner komplizierten Erklärungen).

Vermehrt Zuordnungen ('.=') und Attrappe Größe
Eine Feinheit im Zusammenhang mit der Indizierung ist die Zuweisung zu PDLs, die Dummy-Dimensionen von enthalten
Größe größer als 1. Diese Zuweisungen (mittels „.=") sind aufgrund mehrerer Elemente verboten
Der L-Wert pdl zeigt auf dasselbe Element des übergeordneten Elements. Infolgedessen ist der Wert von
Diese übergeordneten Elemente sind möglicherweise mehrdeutig und hängen von der Reihenfolge ab, in der sie eingefügt werden
Die Implementierung nimmt die Zuweisungen zu Elementen vor. Daher eine Aufgabe wie diese:

$a = pdl [1,2,3];
$b = $a->dummy(1,4);
$b .= yvals(zeroes(3,4));

kann zu unerwarteten Ergebnissen führen und die Ergebnisse sind explizit undefiniert von PDL, weil
Wenn PDL Funktionen für paralleles Rechnen erhält, kann sich das aktuelle Ergebnis durchaus ändern.

Aus Sicht des Datenflusses die Einführung eines Dummys, der größer als eins ist
Dimensionen wird als irreversible Transformation angesehen (ähnlich der Terminologie in
Thermodynamik), was eine Rückwärtspropagierung der Zuordnung zu einem übergeordneten Element ausschließt (das Sie
explizit mit der Zuweisung „.=" angefordert hatte). Ein ähnliches Problem, auf das man achten sollte
Tritt im Zusammenhang mit dem Threading auf, bei dem manchmal implizit Dummy-Dimensionen erstellt werden
während der Fadenschleife (siehe unten).

Gründe für die Eltern/Kind (oder "Zeiger") konzept
[Das muss noch etwas warten]

XXXXX ist speichereffizient
XXXXX im Kontext des Threadings
XXXXX Sehr flexible und leistungsstarke Möglichkeit, auf Teile von PDL-Daten zuzugreifen
(auf eine viel allgemeinere Art und Weise, als es sec usw. zulassen)
XXXXX effiziente Umsetzung
XXXXX Differenz zum Abschnitt/bei usw.

Wie zu um physikalisch aufs Neue
[XXXXX später ausfüllen, wenn sich alles etwas geklärt hat]

** Bei Bedarf (xsub-Routine als Schnittstelle zur C-lib-Funktion)
** Wie erreicht (->physisch)
** So testen Sie (isphysical (erklären Sie, wie es derzeit funktioniert))
** ->kopieren und ->trennen

Threading


Im vorherigen Absatz zur Indizierung haben wir den Begriff bereits gelegentlich erwähnt
Jetzt ist es wirklich an der Zeit, explizit über das „Threading“ mit PDLs zu sprechen. Der Begriff Threading hat
viele verschiedene Bedeutungen in verschiedenen Bereichen der Informatik. Im Rahmen von PDL it
könnte wahrscheinlich grob als implizite Schleifenfunktion definiert werden. Es ist implizit, weil
Sie geben nichts wie das Einschließen von For-Schleifen an, sondern die Schleifen werden automatisch ausgeführt
(oder „magisch“), das von PDL basierend auf den Abmessungen der beteiligten PDLs generiert wird. Das
sollte Ihnen eine erste Vorstellung davon geben, warum die Funktionen zur Index-/Dimensionsmanipulation Sie kennengelernt haben
in den vorherigen Absätzen sind besonders wichtig und nützlich im Zusammenhang mit
Einfädeln. Die andere Zutat zum Einfädeln (abgesehen von den beteiligten PDLs) ist a
Funktion, die Threading-fähig ist (im Allgemeinen sind dies PDL::PP-kompilierte Funktionen) und
dass die PDLs „überfädelt“ werden. So viel zur Terminologie und jetzt versuchen wir es
Bringen Sie etwas Licht ins Dunkel, was das alles bedeutet.

Implizit einfädeln - a zuerst Beispiel
Es gibt zwei leicht unterschiedliche Varianten des Einfädelns. Wir beginnen mit dem, was wir nennen
„implizites Threading“. Wählen wir ein praktisches Beispiel aus, bei dem eine Funktion in einer Schleife ausgeführt wird
über viele Elemente einer pdl. Angenommen, wir haben ein RGB-Bild, das wir in Grau umwandeln möchten.
Skala. Das RGB-Bild wird durch ein 3-Dim-PDL „im(3,x,y)“ dargestellt, wobei die erste Dimension ist
enthält die drei Farbkomponenten jedes Pixels und „x“ und „y“ sind Breite und Höhe von
das Bild bzw. Als nächstes müssen wir angeben, wie ein Farbtripel zu einem bestimmten Zeitpunkt konvertiert wird
Pixel in einen Grauwert umwandeln (um ein realistisches Beispiel zu sein, sollte es den Relativen darstellen).
Intensität, mit der unsere farbunempfindlichen Augenzellen diese Farbe erkennen würden, um sie zu erreichen
was wir eine natürliche Umwandlung von Farbe in Graustufen nennen würden). Eine Annäherung daran
Ganz gut funktioniert die Berechnung der Grauintensität aus jedem RGB-Triplett (r,g,b) als a
gewichtete Summe

Grauwert = 77/256*r + 150/256*g + 29/256*b =
inner([77,150,29]/256, [r,g,b])

wobei die letzte Form darauf hinweist, dass wir dies als inneres Produkt des 3-Vektors schreiben können
bestehend aus den Gewichten für rote, grüne und blaue Komponenten, wobei der 3-Vektor die enthält
Farbkomponenten. Traditionell hätten wir möglicherweise eine Funktion wie die folgende geschrieben
Verarbeiten Sie das gesamte Bild:

meine @dims=$im->dims;
# Überprüfen Sie hier normalerweise, ob das erste Dim die richtige Größe hat (3) usw
$grey=zeroes(@dims[1,2]); # Erstelle die PDL für das resultierende graue Bild
$w = pdl [77,150,29] / 256; # der Vektor der Gewichte
für ($j=0;$j
für ($i=0;$i
# Berechne den Pixelwert
$tmp = inner($w,$im->slice(':,(i),(j)'));
set($grey,$i,$j,$tmp); # und legen Sie es im Graustufenbild fest
}
}

Jetzt schreiben wir dasselbe mit Threading (beachten Sie, dass „inner“ eine Threading-fähige Funktion ist).
definiert im PDL::Primitive-Paket)

$grey = inner($im,pdl([77,150,29]/256));

Am Ende haben wir einen Einzeiler erhalten, der mit der rechten Maustaste automatisch das pdl $grey erstellt
Anzahl und Größe der Dimensionen und führt die Schleifen automatisch aus (diese Schleifen sind
als schneller C-Code in den Interna von PDL implementiert). Nun, wir schulden dir noch etwas
Erklärung, wie diese „Magie“ erreicht wird.

Wie die die Beispiel Arbeit ?
Das erste, was zu beachten ist, ist, dass jede Funktion, die Threading-fähig ist (diese sind ohne).
Ausnahmefunktionen, zusammengestellt aus prägnanten Beschreibungen von PDL::PP, später nur noch PP genannt.
Funktionen) erwartet eine definierte (Mindest-)Anzahl an Dimensionen (wir nennen sie Kerndimensionen)
aus jedem seiner pdl-Argumente. Die innere Funktion erwartet zwei eindimensionale (Eingabe-)
Parameter, aus denen es einen nulldimensionalen (Ausgabe-)Parameter berechnet. Das schreiben wir
symbolisch als „inner((n),(n),[o]())“ und nennen es „inner“. Stempel, Unterschrift, wobei n darstellt
die Größe dieser Dimension. Das bedeutet, dass n im ersten und zweiten Parameter gleich ist
Diese Dimensionen müssen in jedem Aufruf gleich groß sein. Als anderes Beispiel nehmen Sie die
äußeres Produkt, das zwei 1D-Vektoren benötigt, um eine 2D-Matrix zu erzeugen, symbolisch geschrieben als
„outer((n),(m),[o](n,m))“. Das „[o]“ in beiden Beispielen weist darauf hin, dass dies (hier drittes)
Argument ist ein Ausgabeargument. Im letzteren Beispiel die Dimensionen von erstem und zweitem
Argumente müssen nicht übereinstimmen, aber Sie sehen, wie sie die Größe der beiden Dimensionen bestimmen
des Ausgangs-PDL.

Hier kommt der Punkt, an dem das Einfädeln endlich ins Spiel kommt. Wenn Sie PP-Funktionen mit aufrufen
pdls, die haben mehr als die erforderlichen Kernabmessungen die ersten Abmessungen des PDL
Argumente werden als Kerndimensionen verwendet und die zusätzlichen Extradimensionen werden eingefädelt
über. Lassen Sie uns dies zunächst anhand unseres obigen Beispiels demonstrieren

$grey = inner($im,$w); # w ist der Gewichtsvektor von oben

In diesem Fall ist $w 1D und wird daher nur mit der Kerndimension geliefert, $im ist 3D, mehr
speziell „(3,x,y)“. Das erste Maß (der Größe 3) ist das erforderliche Kernmaß
das entspricht (wie von inner gefordert) der ersten (und einzigen) Dimension von $w. Der Zweite
Dimension ist die erste Gewindedimension (der Größe „x“) und die dritte ist hier die zweite
Gewindemaß (der Größe „y“). Die Ausgabe-PDL wird automatisch erstellt (wie von angefordert).
Setzen von $grey auf „null“ vor dem Aufruf). Die Ausgabeabmessungen werden erhalten durch
Anhängen der Schleife Größe (hier „(x,y)“) zu den Kernausgabedimensionen (hier 0D) zu
Ergibt die endgültigen Abmessungen des automatisch erstellten PDL (hier „0D+2D=2D“, um eine 2D-Ausgabe zu erhalten
der Größe „(x,y)“).

Der obige Befehl ruft also die Kernfunktionalität auf, die das innere Produkt von zwei berechnet
1D-Vektoren „x*y“ mal mit $w und allen 1D-Scheiben der Form „(':,(i),(j)')“ von $im und
setzt die jeweiligen Elemente des Ausgabe-PDL „$grey(i,j)“ auf das jeweilige Ergebnis
Berechnung. Wir könnten das symbolisch schreiben als

$grey(0,0) = f($w,$im(:,(0),(0)))
$grey(1,0) = f($w,$im(:,(1),(0)))
.
.
.
$grey(x-2,y-1) = f($w,$im(:,(x-2),(y-1)))
$grey(x-1,y-1) = f($w,$im(:,(x-1),(y-1)))

Dies geschieht jedoch automatisch durch PDL, ohne dass explizite Perl-Schleifen geschrieben werden müssen. Wir sehen
dass der Befehl wirklich eine Ausgabe-PDL mit den richtigen Abmessungen erstellt und festlegt
Elemente tatsächlich zum Ergebnis der Berechnung für jedes Pixel des Eingabebildes.

Wenn noch mehr PDLs und zusätzliche Dimensionen beteiligt sind, wird die Sache etwas komplizierter.
Wir geben zunächst die allgemeinen Regeln an, wie die Gewindeabmessungen von den Abmessungen abhängen
Eingabe-PDLs, mit denen Sie die Dimensionalität eines automatisch erstellten Ausgabe-PDL ermitteln können
(für jeden gegebenen Satz von Eingabe-PDLs und Kerndimensionen der betreffenden PP-Funktion). Der
Allgemeine Regeln werden auf den ersten Blick wahrscheinlich etwas verwirrend erscheinen, deshalb machen wir uns an die Arbeit
um die Verwendung anhand einer Reihe weiterer Beispiele zu veranschaulichen (die hoffentlich auch funktionieren).
zeigen, dass es tatsächlich viele praktische Situationen gibt, in denen das Einfädeln eine Rolle spielt
äußerst praktisch).

A rufen Sie uns an! für Verschlüsselung Disziplin
Bevor wir auf die weiteren technischen Details des Einfädelns hinweisen, beachten Sie bitte diesen Aufruf
Programmierdisziplin bei Verwendung von Threading:

Um die menschliche Lesbarkeit zu wahren, BITTE Kommentieren Sie jeden nichttrivialen Ausdruck in Ihrem
Code mit Threading. Am wichtigsten ist, dass Sie für jede Unterroutine Informationen unter angeben
Am Anfang geht es darum, was die Dimensionen (oder Dimensionsbereiche) Ihrer Meinung nach darstellen sollen.

Schauen Sie sich als Warnung diese undokumentierte Funktion an und versuchen Sie zu erraten, was möglicherweise vor sich geht:

Untersuche {
my ($im,$palette) = @_;
mein $res;
index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=null));
return $res;
}

Würden Sie zustimmen, dass es schwierig sein könnte, die erwarteten Abmessungen und den Zweck herauszufinden?
die Routine usw.? (Wenn Sie herausfinden möchten, was dieser Code bewirkt, lesen Sie weiter unten)

Wie zu Abbildung die Schleife Größe
Es gibt einige Regeln, mit denen Sie die Anzahl und Größe der Schleife ermitteln können
Abmessungen (und ob die Größe Ihrer Eingabe-PDLs den Threading-Regeln entspricht).
Die Dimensionen jedes pdl-Arguments werden im Folgenden in zwei Gruppen unterteilt: Kern
Dimensionen (wie durch die PP-Funktion definiert, siehe Anhang B für eine Liste der PDL-Primitive)
und zusätzliche Dimensionen, die alle verbleibenden Dimensionen dieses PDL umfassen. Zum Beispiel
Aufrufen einer Funktion „func“ mit der Signatur „func((n,m),[o](n))“ mit einem pdl
„a(2,4,7,1,3)“ als „f($a,($o = null))“ führt zur semantischen Aufteilung der Dimensionen von a
in: Kerndimensionen „(2,4)“ und zusätzliche Dimensionen „(7,1,3)“.

R0-Kernabmessungen werden mit den ersten N-Abmessungen des jeweiligen PDL identifiziert
Argument (und sind erforderlich). Alle weiteren Maße sind Sondermaße und gebräuchlich
Bestimmen Sie die Schleifenabmessungen.

R1 Die Anzahl der (impliziten) Schleifendimensionen ist gleich der maximalen Anzahl zusätzlicher
Dimensionen, die über die Menge der pdl-Argumente übernommen wurden.

R2 Die Größe der einzelnen Schleifendimensionen ergibt sich aus der Größe der jeweiligen
Dimensionen der pdl-Argumente. Die Größe einer Schleifendimension wird durch angegeben
Maximale Größe, die in einem der PDLs mit dieser zusätzlichen Dimension gefunden wurde.

R3 Für alle PDLs, die eine bestimmte zusätzliche Dimension haben, muss die Größe gleich der Größe von sein
die Schleifendimension (wie durch die vorherige Regel bestimmt) oder 1; andernfalls erhöhen Sie a
Laufzeitausnahme. Wenn die Größe der zusätzlichen Dimension in einem PDL eins ist, ist dies der Fall
wird implizit als Dummy-Dimension behandelt, deren Größe der Dim-Größe der Schleife entspricht, wenn
Durchführen der Thread-Schleife.

R4 Wenn ein PDL keine Schleifendimension hat, wird dieses PDL in der Thread-Schleife so behandelt, als ob
mit einer Dummy-Dimension, deren Größe der Größe dieser Schleifendimension entspricht.

R5 Wenn die automatische Ausgabeerstellung verwendet wird (indem zuvor die entsprechende PDL auf „PDL->null“ gesetzt wird).
Aufruf) ist die Anzahl der Dimensionen des erstellten PDL gleich der Summe der
Anzahl der Kernausgangsdimensionen + Anzahl der Schleifendimensionen. Die Größe des Kerns
Die Ausgabedimensionen werden von der relevanten Dimension der Eingabe-PDLs abgeleitet (wie angegeben).
in der Funktionsdefinition) und die Größen der anderen Dimensionen sind gleich
Größe der Schleifendimension, von der es abgeleitet ist. Die automatisch erstellte pdl wird sein
physisch (es sei denn, der Datenfluss ist in Betrieb).

Beachten Sie in diesem Zusammenhang, dass bei der Zuweisung zu enthaltenden pdls Probleme auftreten können
Dummy-Abmessungen größer als eins (siehe oben). Obwohl Ihre Ausgabe-PDL(s) nicht enthielten
Bei allen Dummy-Dimensionen handelt es sich zunächst möglicherweise um implizit erstellte Dummy-Dimensionen
Abmessungen gem R4.

Nehmen wir als Beispiel an, wir hätten eine (hier nicht spezifizierte) PP-Funktion mit der Signatur:

func((m,n),(m,n,o),(m),[o](m,o))

und Sie nennen es mit 3 pdls „a(5,3,10,11)“, „b(5,3,2,10,1,12)“ und „c(5,1,11,12)“ als

func($a,$b,$c,($d=null))

dann ist die Anzahl der Schleifendimensionen 3 (durch „R0+R1“ von $b und $c) mit Größen
„(10,11,12)“ (durch R2); Die beiden Ausgabekerndimensionen sind „(5,2)“ (aus der Signatur von
func), was zu einem 5-dimensionalen Ausgabe-pdl $c der Größe „(5,2,10,11,12)“ führt (siehe R5) und
(das automatisch erstellte) $d wird auf eine ausdrückbare Weise von „($a,$b,$c)“ abgeleitet
im PDL-Pseudocode als

$d(:,:,i,j,k) .= func($a(:,:,i,j),$b(:,:,:,i,0,k),$c(:, 0,j,k))
mit 0<=i<10, 0<=j<=11, 0<=k<12

Wenn wir die Umwandlung von Farbe in Graustufen noch einmal unter Berücksichtigung dieser Regeln analysieren, stellen wir Folgendes fest:
Ein weiterer großer Vorteil des impliziten Threadings. Wir können die Konvertierung mit einem pdl aufrufen
stellt ein Pixel dar (im(3)), eine Reihe von RGB-Pixeln („im(3,x)“), ein richtiges Farbbild
("im(3,x,y)") oder einen ganzen Stapel von RGB-Bildern ("im(3,x,y,z)"). Solange $im von dem ist
Form „(3,...)“ enthält die automatisch erstellte Ausgabe-PDL die richtige Anzahl von
Dimensionen und enthalten die Intensitätsdaten, wie wir sie seit den Schleifen erwarten
implizit durchgeführt dank implizit einfädeln. Davon können Sie sich leicht überzeugen
Der Aufruf mit einem Farbpixel $grey ist 0D, mit einer Linie ergibt sich 1D grey(x), mit einem Bild
wir erhalten „grey(x,y)“ und schließlich erhalten wir einen konvertierten Bildstapel „grey(x,y,z)“.

Füllen wir diese allgemeinen Regeln mit etwas mehr Leben, indem wir noch ein paar weitere durchgehen
Beispiele. Der Leser kann versuchen, äquivalente Formulierungen mit expliziten For-
Schleifen und vergleichen Sie die Flexibilität dieser Routinen, die implizites Threading verwenden, mit der
explizite Formulierung. Darüber hinaus ist es insbesondere bei der Verwendung mehrerer Gewindedimensionen eine
Nützliche Übung zur Überprüfung der relativen Geschwindigkeit durch Durchführung einiger Benchmark-Tests (die wir noch durchführen).
zu tun haben).

Zuerst in der Reihe ist ein leicht überarbeitetes Schwerpunktbeispiel, jetzt mit Einfädeln codiert
Verstand.

# Threaded Mult zur Berechnung der Schwerpunktkoordinaten, funktioniert auch für Stapel
$xc = sumover(($im*xvals(($im->dims)[0]))->Büschel(2)) /
sumover($im->Büschel(2));

Lassen Sie uns Schritt für Schritt analysieren, was vor sich geht. Zuerst das Produkt:

$prod = $im*xvals(zeroes(($im->dims)[0]))

Dies wird tatsächlich funktionieren, wenn $im ein-, zwei-, drei- und höherdimensional ist. Wenn $im es ist
eindimensional ist es nur ein gewöhnliches Produkt (in dem Sinne, dass jedes Element von $im es ist).
multipliziert mit dem jeweiligen Element von „xvals(...)“), wenn $im mehr Dimensionen hat
Weiteres Threading erfolgt durch Hinzufügen geeigneter Dummy-Dimensionen zu „xvals(...)“
nach R4. Noch wichtiger ist, dass die beiden Summover-Operationen ein erstes Beispiel dafür sind
um die Bemaßungsmanipulationsbefehle zu nutzen. Ein kurzer Blick auf die Unterschrift von sumover
wird Sie daran erinnern, dass es nur die erste Dimension einer bestimmten Eingabe-PDL „verschlingt“.
Was aber, wenn wir wirklich die Summe über alle Elemente der ersten beiden berechnen wollen?
Maße? Nun, nichts hält uns davon ab, ein virtuelles PDL in Sumover zu übergeben
Der Fall wird gebildet, indem die ersten beiden Dimensionen des „übergeordneten PDL“ zu einer zusammengefasst werden. Von dem
Aus Sicht des übergeordneten pdl wird nun die Summe über die ersten beiden Dimensionen berechnet,
genau wie wir es wollten, obwohl sumover gerade die in seiner Unterschrift festgelegte Aufgabe erfüllt hat. Bekommen
es?

Eine weitere kleine Raffinesse beim Schreiben des Codes auf diese Weise: Wir haben ihn absichtlich verwendet
"sumover($pdl->Büschel(2))“ anstelle von „sum($pdl)“, sodass wir entweder nur ein Bild übergeben können
„(x,y)“ oder einen Stapel von Bildern „(x,y,t)“ in diese Routine ein und erhalte entweder nur eines
x-Koordinate oder ein Vektor von x-Koordinaten (der Größe t) als Rückgabe.

Eine weitere Reihe gängiger Operationen sind sogenannte „Projektionsoperationen“. Diese
Operationen nehmen einen ND-PDL als Eingabe und geben einen (N-1)-D „projizierten“ PDL zurück. Diese Operationen
werden häufig mit Funktionen wie Summover, Prodover, Minimum und Maximum ausgeführt. Benutzen
Wiederum Bilder als Beispiele, möchten wir möglicherweise den maximalen Pixelwert für jede Zeile berechnen
eines Bildes oder Bildstapels. Wir wissen, wie das geht

# Maxima der Zeilen (als Funktion von Zeilennummer und Zeit)
Maximum($stack,($ret=null));

Was aber, wenn Sie Maxima pro Spalte berechnen möchten, wenn implizites Threading immer gilt?
die Kernfunktionalität auf die erste Dimension und Threads über alle anderen? Wie können wir
erreichen, dass stattdessen die Kernfunktionalität auf die zweite Dimension angewendet wird und
Das Einfädeln erfolgt über die anderen. Können Sie es erraten? Ja, wir machen ein virtuelles PDL, das hat
die zweite Dimension des „parent pdl“ als erste Dimension mit dem Befehl „mv“.

# Maxima der Spalten (als Funktion von Spaltennummer und Zeit)
Maximum($stack->mv(1,0),($ret=null));

und die Berechnung aller Summen der Teilscheiben über die dritte Dimension ist jetzt fast zu einfach

# Summen von Pixeln im Zeitverlauf (vorausgesetzt, die Zeit ist das dritte Dimm)
sumover($stack->mv(2,0),($ret=null));

Wenn Sie schließlich die Operation auf alle Elemente anwenden möchten (z. B. max über alle Elemente oder
Summe über alle Elemente) unabhängig von den Abmessungen des betreffenden pdl kommt es zu einem „Klumpen“.
praktisch. Schauen Sie sich als Beispiel die Definition von „sum“ (wie in „Ufunc.pm“ definiert) an:

Teilsumme {
PDL::Ufunc::sumover($name->clump(-1),($tmp=null));
return $tmp->at(); # gibt eine Perl-Zahl zurück, kein 0D-PDL
}

Wir haben bereits erwähnt, dass alle grundlegenden Operationen Threading unterstützen und die Zuweisung nicht unterstützt wird
Ausnahme. Hier sind also ein paar Thread-Aufgaben

pdl> $im = Nullen(Byte, 10,20)
pdl> $line = exp(-rvals(10)**2/9)
# Thread-Aufgabe
pdl> $im .= $line # jede Zeile von $im auf $line setzen
pdl> $im2 .= 5 # jedes Element von $im2 auf 5 setzen

Sie wissen jetzt wahrscheinlich, wie es funktioniert und was es bewirkt, nicht wahr?

Zum Abschluss der Beispiele in diesem Absatz finden Sie hier eine Funktion zum Erstellen eines RGB-Bilds
was man ein Palettenbild nennt. Das Palettenbild besteht aus zwei Teilen: einem Bild von
Indizes in eine Farb-Nachschlagetabelle und die Farb-Nachschlagetabelle selbst. [Beschreibe, wie es ist
funktioniert ] Wir werden eine PP-Funktion verwenden, die uns bisher noch nicht begegnet ist
Beispiele. Es handelt sich um die treffend benannte Indexfunktion, Signatur „((n),(),[o]())“ (siehe Anhang
B) mit der Kernfunktionalität, die „index(pdl (0,2,4,5),2,($ret=null))“ zurückgibt
Element mit Index 2 des ersten Eingabe-PDL. In diesem Fall enthält $ret den Wert 4.
Hier also das Beispiel:

# eine Thread-Indexsuche zum Generieren eines RGB-, RGBA- oder YMCK-Bildes
# aus einem Palettenbild (dargestellt durch eine Nachschlagetabelle $palette und
# ein Farbindexbild $im)
# kann man einfach sagen Attrappe(0) da es aufgrund der Threading-Regeln passt
pdl> index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=null));

Lassen Sie uns es durchgehen und die einzelnen Schritte erklären. Angenommen, wir haben es mit einem RGB zu tun
Nachschlagetabelle $palette hat die Größe „(3,x)“. Zuerst tauschen wir die Maße der Palette aus
so dass die Schleife über die erste Dimension von $palette (der Größe 3, die r darstellt,
g- und b-Komponenten). Wenn wir uns nun $im ansehen, fügen wir eine Dummy-Dimension mit der Größe hinzu
Länge der Anzahl der Komponenten (in dem Fall, den wir hier besprechen, könnten wir gerade haben
habe die Nummer 3 verwendet, da wir 3 Farbkomponenten haben). Wir können seitdem eine Dummy-Dimension verwenden
Für die Farbkomponenten Rot, Grün und Blau verwenden wir denselben Index wie im Originalbild.
Angenommen, ein bestimmtes Pixel von $im hätte den Wert 4, dann sollte die Suche Folgendes ergeben
dreifach

[Palette(0,4),Palette(1,4),Palette(2,4)]

für die neuen roten, grünen und blauen Komponenten des Ausgabebildes. Hoffentlich haben Sie es inzwischen geschafft
eine Art Idee, was der obige Code tun soll (was er oft tatsächlich tut).
Es ist ziemlich kompliziert, im Detail zu beschreiben, wie ein Teil des Threading-Codes funktioniert. fahre einfach fort
und experimentieren Sie ein wenig, um ein besseres Gefühl dafür zu bekommen).

Wenn Sie die Threading-Regeln sorgfältig gelesen haben, ist Ihnen vielleicht aufgefallen, dass wir dies nicht getan haben
müssen explizit die Größe der Dummy-Dimension angeben, die wir für $im erstellt haben; wenn wir
Erstellen Sie es mit Größe 1 (Standardeinstellung). Die Threading-Regeln sorgen dafür, dass es automatisch angepasst wird
die gewünschte Größe (nach Regel R3, in unserem Beispiel wäre die Größe 3 unter der Annahme einer Palette von
Größe „(3,x)“). Da solche Situationen in der Praxis häufig vorkommen, ist dies der eigentliche Grund
Regel R3 wurde eingeführt (der Teil, der die Maße der Größe 1 an das Gewinde anpasst).
Schleifendimmgröße). Also können wir einfach sagen

pdl> index($palette->xchg(0,1),$im->long->Attrappe(0),($res=null));

Auch hier können Sie sich davon überzeugen, dass diese Routine beim Aufruf die richtige Ausgabe erzeugt
mit einem Pixel ($im ist 0D), einer Linie ($im ist 1D), einem Bild ($im ist 2D), ..., einer RGB-Suche
Tabelle (Palette ist „(3,x)“) und RGBA-Nachschlagetabelle (Palette ist „(4,x)“, siehe z. B. OpenGL).
Diese Flexibilität wird durch die Threading-Regeln erreicht, die darauf ausgelegt sind, das Richtige zu tun
Sache in den meisten Situationen.

Um das Ganze noch einmal zusammenzufassen: Die allgemeine Idee ist wie folgt. Wenn Sie etwas erreichen wollen
Schleifen über bestimmte Dimensionen und haben die Core Funktionalität auf einen anderen angewendet
Für den angegebenen Satz von Bemaßungen verwenden Sie die Bemaßungsmanipulationsbefehle, um einen (oder) zu erstellen
mehrere) virtuell pdl(s) so dass aus Sicht der Elternteil pdl(s) du verstehst was
Sie möchten (immer die Signatur der betreffenden Funktion und R1-R5 im Hinterkopf behalten!).
Einfach, nicht wahr?

Ausgang automatische Erstellung und PP-Funktion Aufruf Conventions
An dieser Stelle müssen wir auf einige technische Details eingehen, die mit dem Allgemeinen zu tun haben
Aufrufkonventionen von PP-Funktionen und die automatische Erstellung von Ausgabeargumenten.
Grundsätzlich gibt es zwei Möglichkeiten, PDL-Routinen aufzurufen, nämlich

$result = func($a,$b);

und

func($a,$b,$result);

Wenn Sie nur implizites Threading verwenden, kann die Ausgabevariable automatisch erfolgen
erstellt von PDL. Sie kennzeichnen dies der PP-Funktion, indem Sie das Ausgabeargument auf a setzen
spezielle Art von PDL, die von einem Aufruf der zurückgegebenen Funktion „PDL->null“ zurückgegeben wird
eine im Wesentlichen „leere“ PDL (für diejenigen, die sich für Details interessieren, gibt es eine Flagge in der C-PDL
Struktur dafür). Die Abmessungen des erstellten PDL werden durch die Regeln von bestimmt
Implizites Threading: Die ersten Dimensionen sind die Kernausgabedimensionen, zu denen die
Gewindemaße sind beigefügt (die wiederum durch die Maße des Gewindes bestimmt werden).
Eingabe-PDLs wie oben beschrieben). So kann man sagen

func($a,$b,($result=PDL->null));

or

$result = func($a,$b)

davon sind genau gleichwertig.

Seien Sie gewarnt, dass Sie es können nicht Verwenden Sie die automatische Ausgabeerstellung, wenn Sie explizites Threading verwenden (z
Gründe dafür werden im folgenden Abschnitt erläutert explizit einfädeln, die zweite Variante von
Einfädeln).

In „engen“ Schleifen möchten Sie wahrscheinlich die implizite Erstellung einer temporären PDL vermeiden
Jeder Schritt der Schleife, der mit dem „funktionalen“ Stil einhergeht, sagt aber eher

# Ausgabe-PDL mit geeigneter Größe nur beim ersten Aufruf erstellen
$result = null;
für (0...$n) {
func($a,$b,$result); # in allen außer dem ersten Aufruf $result
func2($b); # ist definiert und hat die richtige Größe
# nimm die Ausgabe, sofern sich die Dimmwerte von $b nicht ändern
twiddle($result,$a); # etwas von $result zu $a für die Iteration tun
}

Noch einmal die Botschaft dieses Abschnitts: Seien Sie sich der Einschränkungen bei der Ausgabe bewusst
Erstellung bei der Verwendung explizit einfädeln.

Explicit einfädeln
Nachdem wir bisher nur über die erste Variante des Einfädelns gesprochen haben, ist es nun an der Zeit, dies zu tun
die zweite Variante vorstellen. Anstatt ständig in den Dimensionen herumzuwühlen und
Sich auf die Regeln des impliziten Threadings zu verlassen, um alles richtig zu machen, möchte man manchmal vielleicht
Geben Sie expliziter an, wie die Thread-Schleife ausgeführt werden soll. Das ist es wahrscheinlich auch nicht
Überraschend, dass diese Spielvariante so heißt explizit einfädeln. Nun, bevor wir
den falschen Eindruck erwecken: Das ist es auch nicht implizit or explizit; Die beiden Geschmacksrichtungen tun es
mischen. Aber dazu später mehr.

Die beiden am häufigsten verwendeten Funktionen mit explizitem Threading sind Thread und Unthread. Wir starten
mit einem Beispiel, das die typische Verwendung des ersteren veranschaulicht:

[ # ** Dies ist das schlechteste mögliche Beispiel für den Anfang ]
#, kann aber verwendet werden, um zu zeigen, dass sich $mat += $line von unterscheidet
# $mat->Faden(0) += $line
# explizites Threading, um jeder Spalte einer Matrix einen Vektor hinzuzufügen
pdl> $mat = Nullen(4,3)
pdl> $line = pdl (3.1416,2,-2)
pdl> ($tmp = $mat->Faden(0)) += $zeile

In diesem Beispiel „$mat->Faden(0)“ teilt PDL mit, dass Sie die zweite Dimension davon wünschen
pdl, das zuerst eingefädelt werden soll, was zu einer Thread-Schleife führt, die ausgedrückt werden kann als

für (j=0; j<3; j++) {
für (i=0; i<4; i++) {
mat(i,j) += src(j);
}
}

„thread“ verwendet eine Liste von Zahlen als Argumente, die explizit angeben, welche Dimensionen verwendet werden sollen
zuerst einfädeln. Mit der Einführung des expliziten Threadings ändern sich die Abmessungen eines PDL
konzeptionell in drei verschiedene Gruppen unterteilt, von denen wir die beiden letzteren bereits kennen
angetroffen: Gewindemaße, Kernmaße und Zusatzmaße.

Konzeptionell ist es am besten, an die Abmessungen eines PDL zu denken, die in spezifiziert wurden
ein Aufruf zum „Einfädeln“, da er aus der Menge der normalen Dimensionen herausgenommen und auf a gesetzt wird
separater Stapel. Nehmen wir also an, wir haben ein pdl „a(4,7,2,8)“, das sagt

$b = $a->thread(2,1)

erstellt eine neue virtuelle PDL der Dimension „b(4,8)“ (die wir die verbleibenden Dims nennen).
verfügt außerdem über 2 Gewindeabmessungen der Größe „(2,7)“. Für die Zwecke dieses Dokuments schreiben wir
das symbolisch als „b(4,8){2,7}“. Ein wichtiger Unterschied zu den vorherigen Beispielen wo
Es wurde nur implizites Gewinde verwendet, da die Kernabmessungen aufeinander abgestimmt sind
die verbleibenden Größe Dies sind nicht unbedingt die ersten Dimensionen des PDL. Wir
wird nun angeben, wie das Vorhandensein von Gewindeabmessungen die Regeln R1-R5 für Gewinde ändert
Schleifen (die für den Sonderfall gelten, in dem keines der pdl-Argumente einen Thread hat
Maße).

Die T0-Kernabmessungen werden mit dem ersten n abgeglichen verbleibenden Größe des pdl
Argument (beachten Sie den Unterschied zu R1). Noch weiter verbleibenden Größe sind extra
Größe und dienen zur Ermittlung der implizit Schleife Größe.

T1a Die Anzahl der implizit Schleife Größe ist gleich der maximalen Anzahl von Extras
Dimensionen, die über die Menge der pdl-Argumente übernommen wurden.

T1b Die Anzahl der explizit Schleife Größe ist gleich der maximalen Anzahl von Threads
Dimensionen, die über die Menge der pdl-Argumente übernommen wurden.

T1c Die Gesamtzahl von Schleife Größe ist gleich der Summe von explizit Schleife Größe
und implizit Schleife Größe. In der Thread-Schleife, explizit Schleife Größe sind
zuerst eingefädelt, gefolgt von implizit Schleife Größe.

T2 Die Größe jedes einzelnen Schleife Größe ergibt sich aus der Größe des jeweiligen
Dimensionen der pdl-Argumente. Sie wird durch die maximale Größe in allen PDLs angegeben
mit diesem Gewindemaß (z explizit Schleife Größe) oder zusätzliche Dimension (z
implizit Schleife Größe).

T3 Diese Regel gilt für alle explizit Schleife Dimension sowie alle implizit Schleife
Dimension. Für alle PDLs, die eine bestimmte haben Thread/extra Dimension Die Größe muss sein
gleich der Größe des jeweiligen explizit implizit Schleife Dimension oder 1; ansonsten
Sie lösen eine Laufzeitausnahme aus. Wenn die Größe eines Thread/extra Dimension eines pdl ist eins
Es wird implizit als Dummy-Dimension mit der gleichen Größe behandelt explizit implizit
Schleife Dimension.

T4 Wenn ein PDL kein hat Thread/extra Dimension das entspricht einem
explizit implizit Schleife Dimension, in der Thread-Schleife wird dieses PDL so behandelt, als ob es vorhanden wäre
eine Dummy-Dimension mit einer Größe, die der Größe dieser Schleifendimension entspricht.

T4a Alle PDLs, die das haben Faden Größe muss die gleiche Anzahl an Threads haben
Abmessungen.

Die automatische Erstellung von T5-Ausgaben kann nicht verwendet werden, wenn eines der pdl-Argumente über eines verfügt Faden
Größe. Ansonsten gilt R5.

Die gleichen Einschränkungen gelten für implizite Dummy-Dimensionen (erstellt von
Anwendung von T4), wie bereits im Abschnitt über implizites Threading erwähnt: falls vorhanden
Die Ausgabe-PDLs haben eine (explizit oder implizit erstellte) Dummy-Dimension a, die größer als eins ist
Es wird eine Laufzeitausnahme ausgelöst.

Lassen Sie uns diese Regeln in einem generischen Fall demonstrieren. Angenommen, wir haben ein (hier
nicht spezifiziert) PP-Funktion mit der Signatur:

func((m,n),(m),(),[o](m))

und Sie nennen es mit 3 pdls „a(5,3,10,11)“, „b(3,5,10,1,12)“, „c(10)“ und ein Ausgabe-PDL
„d(3,11,5,10,12)“ (was hier möglich ist nicht automatisch erstellt werden) als

func($a->thread(1,3),$b->thread(0,3),$c,$d->thread(0,1))

Aus der Signatur von func und dem obigen Aufruf werden die PDLs in die folgenden Gruppen aufgeteilt
Kern-, Extra- und Thread-Abmessungen (geschrieben in der Form „pdl(core dims){thread dims}[extra
dimmt]"):

a(5,10){3,11}[] b(5){3,1}[10,12] c(){}[10] d(5){3,11}[10,12]

Dies soll uns weiterhelfen (im Allgemeinen ist es hilfreich, die Argumente so aufzuschreiben).
wenn Sie anfangen, mit dem Einfädeln zu spielen und den Überblick behalten möchten, was vor sich geht) wir
Leiten Sie weiter ab, dass die Anzahl der expliziten Schleifendimensionen 2 beträgt (durch T1b aus $a und $b).
mit Größen „(3,11)“ (von T2); 2 implizite Schleifendimensionen (durch T1a von $b und $d) der Größe
„(10,12)“ (von T2) und die Elemente von werden aus den Eingabe-PDLs auf eine Weise berechnet, die dies ermöglicht
im PDL-Pseudocode ausgedrückt werden als

für (l=0;l<12;l++)
für (k=0;k<10;k++)
für (j=0;j<11;j++) Effekt der Behandlung als Dummy-Dim (Index j)
für (i=0;i<3;i++) |
d(i,j,:,k,l) ​​= func(a(:,i,:,j),b(i,:,k,0,l),c(k))

Puh, dieses Beispiel war buchhalterisch wirklich nicht einfach. Es dient hauptsächlich als
Beispiel, wie Sie herausfinden, was los ist, wenn Sie auf ein kompliziertes Aussehen stoßen
Ausdruck. Aber jetzt ist es wirklich an der Zeit zu zeigen, dass Threading nützlich ist, indem wir noch mehr geben
unserer sogenannten „Praxisbeispiele“.

[ Die folgenden Beispiele erfordern in Zukunft einige zusätzliche Erklärungen. Für die
Bitte versuchen Sie im Moment, mit den Kommentaren in den Codefragmenten zu leben. ]

Beispiel 1:

*** Umkehrung der durch Eigvecs und Eigvals dargestellten Matrix
** bei gegebener symmetrischer Matrix M = A^T x diag(lambda_i) x A
** => invers M^-1 = A^T x diag(1/lambda_i) x A
** zuerst $tmp = diag(1/lambda_i)*A
** dann A^T * $tmp durch inneres Gewindeprodukt
# Indexbehandlung, damit Matrizen unter pdl korrekt gedruckt werden
$inv .= $evecs*0; # einfach kopieren, um eine Ausgabe in angemessener Größe zu erhalten
$tmp .= $evecs; # initialisieren, keine Rückausbreitung
($tmp2 = $tmp->Faden(0)) /= $evals; # Gewindeteilung
# und jetzt eine getarnte Matrixmultiplikation
PDL::Primitive::inner($evecs->xchg(0,1)->thread(-1,1),
$tmp->thread(0,-1),
$inv->thread(0,1));
# Alternative für Matrix Mult mit implizitem Threading,
# erstes xchg nur zum Transponieren
PDL::Primitive::inner($evecs->xchg(0,1)->Attrappe(1)
$tmp->xchg(0,1)->Attrappe(2)
($inv=null));

Beispiel 2:

# äußeres Produkt durch Thread-Multiplikation
# Betonen Sie, dass wir dies mit einem expliziten Aufruf von my_biop1 tun müssen
# bei Verwendung von explizitem Threading
$res=zeroes(($a->dims)[0],($b->dims)[0]);
my_biop1($a->thread(0,-1),$b->thread(-1,0),$res->(0,1),"*");
# Ähnliches durch implizites Threading mit automatisch erstelltem PDL
$res = $a->Attrappe(1) * $b->Attrappe(0);

Beispiel 3:

# unterschiedliche Verwendung von Thread und Unthread, um mehrere zu mischen
# Dimensionen auf einmal ohne viele Aufrufe von ->xchg und ->mv

# Verwenden Sie „Einfädeln/Ausfädeln“, um die Abmessungen zu verschieben
# Probieren Sie es einfach aus und vergleichen Sie die untergeordnete PDL mit der übergeordneten
$trans = $a->thread(4,1,0,3,2)->unthread;

Beispiel 4:

# Berechne ein paar Begrenzungsrahmen
# $bb hält BB als [xmin,xmax],[ymin,ymax],[zmin,zmax]
# Wir verwenden erneut „Einfädeln“ und „Ausfädeln“, um die Abmessungen zu verschieben
pdl> $bb = Nullen(double, 2,3 );
pdl> Minimum($vertices->Faden(0)->klumpen->ausfädeln(1), $bb->slice('(0),:'));
pdl> Maximum($vertices->Faden(0)->klumpen->ausfädeln(1), $bb->slice('(1),:'));

Beispiel 5:

# eine selbstrationierte (dh selbstnormalisierte) Bildfolge berechnen
# verwendet explizites Threading und eine implizite Thread-Division
$stapel = read_image_stack();
# Berechnen Sie den Durchschnitt (pro Pixel-Durchschnitt) der ersten $n+1 Bilder
$aver = zeroes([stack->dims]->[0,1]); # Ausgabe-PDL erstellen
sumover($stack->slice(":,:,0:$n")->thread(0,1),$aver);
$aver /= ($n+1);
$stack /= $aver; # Normalisieren Sie den Stapel, indem Sie eine Thread-Division durchführen
# implizit versus explizit
# Alternativ $aver mit implizitem Threading und automatischer Erstellung berechnen
sumover($stack->slice(":,:,0:$n")->mv(2,0),($aver=null));
$aver /= ($n+1);
#

Implizit Während explizit einfädeln
In diesem Absatz werden wir veranschaulichen, wann explizites Threading vorzuziehen ist
implizites Threading und umgekehrt. Aber andererseits ist dies wahrscheinlich nicht der beste Weg
Wenn Sie den Fall ansprechen, wissen Sie bereits: Die beiden Geschmacksrichtungen vermischen sich. Es kommt also mehr darauf an, wie
um das Beste aus beiden Welten zu bekommen und auf jeden Fall in der besten Perl-Tradition: TIMTOWTDI !

[ Leider muss dies in einer späteren Version noch ausgefüllt werden; beziehen Sie sich entweder auf die obigen Beispiele
oder wählen Sie einige neue aus]

Abschließend könnte dies ein guter Ort sein, um alle technischen Details zu rechtfertigen, auf die wir eingegangen sind
Ein paar Seiten lang geht es weiter: Warum Threading?

Nun, Code, der Threading verwendet, sollte (erheblich) schneller sein als Code, der Threading verwendet
explizite For-Schleifen (oder ähnliche Perl-Konstrukte), um die gleiche Funktionalität zu erreichen.
Insbesondere auf Supercomputern (mit Vektorrechenfunktionen/Parallelverarbeitung) PDL
Das Threading wird so implementiert, dass die zusätzlichen Möglichkeiten genutzt werden
dieser Maschinen. Darüber hinaus handelt es sich um ein konzeptionell einfaches (wenn auch technisches) Konstrukt
Details können manchmal eine Rolle spielen) und können sehr Reduzieren Sie die syntaktische Komplexität von
PDL-Code (aber beachten Sie den Hinweis zur Dokumentation). Sobald Sie sich wohl fühlen
an. Nach der Installation können Sie HEIC-Dateien mit der einfädeln Denkweise (und Codierung) sollte nicht allzu schwierig sein
Code verstehen, den jemand anderes geschrieben hat (vorausgesetzt, er hat Ihnen eine Idee gegeben, was).
erwartete Eingabeabmessungen usw.). Als allgemeiner Tipp zur Steigerung der Leistung Ihres
Code: Wenn Sie eine Schleife in Ihren Code einfügen müssen, versuchen Sie, das Problem so umzuformulieren
dass Sie Threading verwenden können, um die Schleife auszuführen (wie bei allem, wovon es Ausnahmen gibt).
diese Faustregel; aber die Autoren dieses Dokuments neigen dazu, zu glauben, dass diese selten sind
Fälle ;).

PDL::PP


An Einfache Weg, zu definieren Funktionen zur Abwicklung, Integrierung, Speicherung und sind bewusst of Indizierung und einfädeln (und die Universum und
alles)
PDL:PP ist Teil der PDL-Distribution. Es wird verwendet, um Funktionen zu generieren, die sich dessen bewusst sind
Indizierungs- und Threading-Regeln aus sehr prägnanten Beschreibungen. Es kann für Sie nützlich sein, wenn
Sie möchten Ihre eigenen Funktionen schreiben oder Funktionen von einer Schnittstelle anbinden
externe Bibliothek, damit sie Indizierung und Threading (und möglicherweise auch Datenfluss) unterstützt.
siehe PDL::Dataflow). Weitere Details finden Sie unter PDL::PP.

Anhang A


affine Transformationen - a besondere Klasse of einfach und größte treibende Transformationen
[ Dies soll auch in zukünftigen Versionen hinzugefügt werden. Haben wir schon den General?
make_affine-Routine in PDL? Es ist möglich, dass wir einen anderen geeigneten Mann empfehlen
Seite von hier]

Anhang B


Unterschriften of Standard PDL::PP kompiliert Funktionen
Eine Auswahl von Signaturen von PDL-Primitiven, um zu zeigen, wie viele Dimensionen PP kompiliert hat
Funktionen verschlingen (und daher können Sie herausfinden, was eingefädelt wird). Die meisten davon
Diese Funktionen sind die grundlegenden, die in „primitive.pd“ definiert sind.

# Funktionen in primitive.pd
#
sumover ((n),[o]())
prodover ((n),[o]())
Achsenwerte ((n)) vorhanden
inner ((n),(n),[o]())
äußere ((n),(m),[o](n,m))
innerwt ((n),(n),(n),[o]())
inner2 ((m),(m,n),(n),[o]())
inner2t ((j,n),(n,m),(m,k),[o]())
Index (1D,0D,[o])
Minimum (1D,[o])
maximal (1D,[o])
wstat ((n),(n),(),[o],())
asgn ((),())

# Grundoperationen
Binäre Operationen ((),(),[o]())
unäre Operationen ((),[o]())

AUTOR & URHEBERRECHT


Copyright (C) 1997 Christian Soeller (c.soeller@auckland.ac.nz) & Tuomas J. Lukka
(lukka@fas.harvard.edu). Alle Rechte vorbehalten. Obwohl zur Veröffentlichung als Manpage vorgesehen
Mit der Standard-PDL-Distribution ist es nicht gemeinfrei. Die Erlaubnis wird erteilt
Verteilen Sie frei wörtliche Kopien dieses Dokuments, sofern keine Änderungen vorgenommen wurden
der Formatierung vorgenommen werden und dass dieser Hinweis intakt bleibt. Es ist Ihnen gestattet und
Wir empfehlen Ihnen, den Code und Derivate davon zum Spaß oder zum Spaß in Ihrem eigenen Quellcode zu verwenden
Profitieren Sie, wie Sie es für richtig halten.

Verwenden Sie PDL::Indexingp online über die Dienste von onworks.net



Neueste Linux- und Windows-Online-Programme