EnglishFranceseCorsi

Favicon di OnWorks

PDL::Indicizzazionep - Online nel cloud

Esegui PDL::Indexingp nel provider di hosting gratuito OnWorks su Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

Questo è il comando PDL::Indexingp che può essere eseguito nel provider di hosting gratuito OnWorks utilizzando una delle nostre molteplici workstation online gratuite come Ubuntu Online, Fedora Online, emulatore online Windows o emulatore online MAC OS

PROGRAMMA:

NOME


PDL::Indicizzazione - Introduzione all'indicizzazione e all'affettatura dei piddles.

OVERVIEW


Questa pagina man dovrebbe servire come primo tutorial sulle funzionalità di indicizzazione e threading di
PDL.

Come tutti i linguaggi vettorizzati, PDL automatizza il loop su array utilizzando una variante di
notazione matematica vettoriale. Il loop automatico è chiamato "threading", in parte
perché alla fine PDL implementerà l'elaborazione parallela per accelerare i loop.

Gran parte della flessibilità e della potenza del PDL si basa sulle funzionalità di indicizzazione e threading di
l'estensione Perl. L'indicizzazione consente l'accesso ai dati di un piddle in modo molto flessibile
modo. Il threading fornisce una vettorizzazione efficiente di operazioni semplici.

I valori di un piddle sono memorizzati in modo compatto come valori digitati in un singolo blocco di memoria,
not (come in un normale elenco di elenchi Perl) come scalari Perl individuali.

Nelle sezioni che seguono vengono richiamati molti "metodi" -- questi sono operatori Perl che
applicare ai PDL. Dalla shell perldl (o pdl2), puoi scoprire di più su ciascun metodo
digitando "?" seguito dal nome del metodo.

Dimensioni list
Un piddle (variabile PDL), in generale, è un array N-dimensionale dove N può essere 0 (per a
scalare), 1 (ad es. per un campione sonoro), o valori più alti per immagini e più complesse
strutture. Ogni dimensione del piddle ha una dimensione intera positiva. Il "perla"
interprete tratta ogni piddle come un tipo speciale di scalare Perl (un benedetto oggetto Perl,
in realtà -- ma non devi saperlo per usarli) che possono essere usati ovunque tu possa
metti uno scalare normale.

Puoi accedere alle dimensioni di un piddle come un elenco Perl e altrimenti determinare la dimensione
di un piddle con diversi metodi. Gli importanti sono:

nelem - il numero totale di elementi in un PDL
ndims - restituisce il numero di dimensioni in un PDL
dims - restituisce l'elenco delle dimensioni di un PDL come elenco Perl
dim - restituisce la dimensione di una particolare dimensione di un PDL

Indicizzazione e Flusso di dati
PDL mantiene una nozione di "dataflow" tra un piddle e sottocampi indicizzati di quello
piscio. Quando produci un sottocampo indicizzato o un singolo elemento di un piddle genitore, il
figlio e genitore rimangono collegati fino a quando non li disconnetti manualmente. Questo ti permette
rappresentare gli stessi dati in modi diversi all'interno del tuo codice, ad esempio puoi considerare
un'immagine RGB contemporaneamente come una raccolta di valori (R,G,B) in un'immagine 3 x 1000 x 1000,
e come tre piani di colore 1000 x 1000 separati memorizzati in variabili diverse. Modifica
una qualsiasi delle variabili modifica la memoria sottostante e le modifiche si riflettono in tutto
rappresentazioni dei dati.

Esistono due metodi importanti che ti consentono di controllare le connessioni del flusso di dati tra un bambino
e capogruppo PDL:

copy - forza una copia esplicita di un PDL
sever - interrompe la connessione del flusso di dati tra un PDL e i suoi genitori (se presenti)

Threading e Dimensioni Ordine
La maggior parte delle operazioni del PDL agisce sulle prime dimensioni dei loro argomenti piddle. Per
Ad esempio, "sumover" somma tutti gli elementi lungo la prima dimensione nell'elenco (dimensione 0).
Se ti nutri in un piddle tridimensionale, allora la prima dimensione è considerata la
dimensione "attiva" e le dimensioni successive sono dimensioni "filo" perché sono
semplicemente in loop. Esistono diversi modi per trasporre o riordinare l'elenco delle dimensioni
un Pdl. Queste tecniche sono molto veloci poiché non toccano i dati sottostanti, solo
cambiare il modo in cui PDL accede ai dati. Le principali funzioni di ordinamento delle dimensioni sono:

mv - sposta una particolare dimensione da qualche altra parte nell'elenco delle dimensioni
xchg - scambia due dimensioni nell'elenco delle dimensioni, lasciando il resto da solo
riordina - consente la miscelazione all'ingrosso delle dimensioni
clump - raggruppa due o più piccole dimensioni in una più grande
comprimi - elimina qualsiasi dimensione della taglia 1

Fisico e Manichino Dimensioni
· documento threading a livello di Perl

· threadidi

· aggiornamento e descrizione corretta della fetta

· nuove funzioni in slice.pd (affine, lag, splitdim)

· rielaborazione del paragrafo sul threading esplicito

Indicizzazione e threading con PDL


Gran parte della flessibilità e della potenza di PDL si basa sulle funzionalità di indicizzazione e loop di
l'estensione Perl. L'indicizzazione consente l'accesso ai dati di un oggetto pdl in modo molto flessibile
modo. Il threading fornisce un'efficiente funzionalità di loop implicito (poiché i loop sono
implementato come codice C ottimizzato).

Gli oggetti Pdl (in seguito spesso chiamati "pdls") sono oggetti Perl che rappresentano multidimensionali
array e operazioni su di essi. In contrasto con il semplice stile Perl @x elenca i dati dell'array
è memorizzato in modo compatto in un singolo blocco di memoria, quindi occupa molta meno memoria e
consentire l'uso di codice C veloce per implementare operazioni (ad es. addizione, ecc.) su pdls.

pdl può avere bambini
Al centro di molte delle capacità di indicizzazione di PDL sono le relazioni di "genitore" e
"bambino" tra pdls. Molti dei comandi di indicizzazione creano un nuovo pdl da un pdl esistente.
Il nuovo pdl è il "figlio" e quello vecchio è il "genitore". I dati del nuovo pdl sono
definito da una trasformazione che specifica come generare (calcolare) i suoi dati dal
i dati del genitore. Le relazioni tra il figlio pdl e il suo genitore sono spesso bidirezionali,
il che significa che le modifiche ai dati del bambino vengono propagate al genitore. (Nota: tu
vedi, stiamo già puntando nella nostra terminologia verso le nuove funzionalità del flusso di dati. Il tipo
del flusso di dati utilizzato dai comandi di indicizzazione (di cui imparerai tra un minuto)
è sempre in funzione, non solo quando hai attivato esplicitamente il flusso di dati nel tuo pdl
dicendo "$a->doflow". Per ulteriori informazioni sul flusso di dati controllare il man del flusso di dati
pagina.)

Un altro modo per interpretare i pdls creati dai nostri comandi di indicizzazione è visualizzarli come a
tipo di puntatore intelligente che punta a una parte oa tutti i dati del genitore.
Pertanto, non sorprende che i dati del genitore (o una parte di essi) cambino quando
manipolato attraverso questo "puntatore". Dopo queste osservazioni introduttive che si spera
ti ha preparato per quello che sta arrivando (piuttosto che confonderti troppo) ci tufferemo
subito e inizia con una descrizione dei comandi di indicizzazione e alcuni esempi tipici
come potrebbero essere utilizzati nei programmi PDL. Illustreremo ulteriormente il puntatore/dataflow
analogie nel contesto di alcuni degli esempi successivi.

Ci sono due diverse implementazioni di questa relazione di ``puntatore intelligente'': la prima
uno, che è un po' più lento ma funziona per qualsiasi trasformazione è semplicemente quello di fare il
trasformazione in avanti e indietro, se necessario. L'altro è considerare il bambino
piddle un piddle ``virtuale'', che memorizza solo un puntatore al genitore e l'accesso
informazioni in modo che le routine che utilizzano il piddle bambino accedano effettivamente direttamente ai dati
nel genitore. Se il piddle virtuale viene dato a una routine che non può usarlo, PDL
fisicizza in modo trasparente il piddle virtuale prima di lasciare che la routine lo usi.

Attualmente (1.94_01) tutte le trasformazioni che sono ``affine'', cioè gli indici dei dati
elemento nel piddle genitore sono determinati da una trasformazione lineare (+ costante) da
gli indici del piddle bambino risultano in piddle virtuali. Tutte le altre routine di indicizzazione (es
"->index(...)") risulta in piddle fisici. Tutte le routine compilate da PP possono accettare affini
piddles (eccetto quelle routine che passano puntatori a funzioni di librerie esterne).

Nota che se qualcosa è affine o no non influisce sulla semantica di ciò che fai
in ogni modo: entrambi

$a->indice(...) .= 5;
$a->fetta(...) .= 5;

cambia i dati in $a. L'affinità, tuttavia, ha un impatto significativo sulla memoria
utilizzo e prestazioni.

Affettare pdl
Probabilmente l'applicazione più importante del concetto di pdls genitore/figlio è il
rappresentazione di fette rettangolari di un pdl fisico da parte di un pdl virtuale. dopo aver parlato
abbastanza a lungo sui concetti diventiamo più specifici. Supponiamo di lavorare con un pdl 2D
che rappresenta un'immagine 5x5 (è insolitamente piccola in modo che possiamo stamparla senza riempirla
diverse schermate piene di cifre ;).

pdl> $im = sequenza(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> aiuto vars
Variabili PDL nel pacchetto principale::

Nome Tipo Dimensione Flusso Stato Mem
-------------------------------------------------- --------------
$im Doppia D [5,5] P 0.20Kb

[ qui potrebbe essere opportuno parlare rapidamente del comando "help vars" che fornisce
informazioni su pdls nella shell interattiva "perldl" o "pdl2" fornita con PDL. ]

Supponiamo ora di voler creare un pdl 1-D che faccia riferimento solo a una riga dell'immagine, diciamo
linea 2; o un pdl che rappresenta tutte le linee pari dell'immagine (immagina di aver a che fare con
frame pari e dispari di un'immagine interlacciata a causa di un comportamento peculiare del nostro frame
afferratore). Come un'altra applicazione frequente di slice, potremmo voler creare un pdl che
rappresenta una regione rettangolare dell'immagine con la parte superiore e inferiore invertite. Tutti questi
effetti (e molti altri) possono essere facilmente ottenuti con la potente funzione slice:

pdl> $line = $im->slice(':,(2)')
pdl> $even = $im->slice(':,1:-1:2')
pdl> $area = $im->slice('3:4,3:1')
pdl> help vars # o solo PDL->vars
Variabili PDL nel pacchetto principale::

Nome Tipo Dimensione Flusso Stato Mem
-------------------------------------------------- --------------
$pari Doppia D [5,2] -C 0.00Kb
$im Doppia D [5,5] P 0.20Kb
$linea Doppia D [5] -C 0.00Kb
$area Doppia D [2,3] -C 0.00Kb

Tutti e tre i pdl "figli" sono figli di $im o nell'altro (in gran parte equivalenti)
puntatori di interpretazione ai dati di $im. Le operazioni su quei pdls virtuali accedono solo
quelle parti dei dati come specificato dall'argomento da affettare. Quindi possiamo semplicemente stampare
linea 2:

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

Notare anche la differenza nello "Stato del flusso" dell'area $ sopra e sotto:

pdl> p $area
pdl> aiuto $area
Questa variabile è Double D [2,3] VC 0.00Kb

Quanto segue dimostra che $im e $line si comportano davvero come ci si aspetterebbe da a
oggetto simile a un puntatore (o nell'immagine del flusso di dati: le modifiche nei dati di $line sono
propagato a $im):

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]
]

Nota come le operazioni di assegnazione sul pdl virtuale figlio cambiano il pdl fisico padre
e viceversa (tuttavia, l'assegnazione di base "=" non lo fa, usa ".=" per ottenere quell'effetto.
Vedi sotto per le ragioni). I pdls figlio virtuali sono qualcosa come "collegamenti in tempo reale" al
padre "originale" pdl. Come detto in precedenza, si può pensare che funzionino in modo simile a a
C-puntatore. Ma a differenza di un puntatore a C, trasportano molte più informazioni. In primo luogo, loro
specificare la struttura dei dati che rappresentano (la dimensionalità del nuovo pdl) e
in secondo luogo, specifica come creare questa struttura dai suoi dati genitori (il modo in cui funziona
è sepolto nelle viscere del PDL e non è importante che tu lo sappia comunque (a meno che tu
vuole hackerare il nucleo in futuro o vorrebbe diventare un guru del PDL in generale (per a
definizione di questa strana creatura vedi PDL::Internals)).

Gli esempi precedenti hanno dimostrato l'utilizzo tipico della funzione slice. Dal momento che
la funzionalità di affettatura è così importante ecco una spiegazione della sintassi per la stringa
argomento per affettare:

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

dove "ind0" specifica cosa fare con l'indice No 0 del pdl $a, ecc. Ogni elemento del
l'elenco separato da virgole può avere una delle seguenti forme:

':' Usa l'intera dimensione

'n' Usa solo l'indice "n". La dimensione di questo indice nel pdl virtuale risultante è 1.
Un esempio che coinvolge quei primi due formati di indice:

pdl> $colonna = $im->slice('2,:')
pdl> $riga = $im->slice(':,0')
pdl> p $colonna

[
[3]
[8]
,
,
,
]

pdl> p $riga

[
[1 2 3 4 5]
]

pdl> aiuto $colonna
Questa variabile è Double D [1,5] VC 0.00Kb

pdl> aiuto $riga
Questa variabile è Double D [5,1] VC 0.00Kb

'(n)' Usa solo l'indice "n". Questa dimensione viene rimossa dal pdl risultante (basandosi sul
fatto che una dimensione di taglia 1 può sempre essere rimossa). La distinzione tra questo
caso e il precedente diventa importante negli incarichi in cui la mano sinistra e quella destra
lato devono avere dimensioni adeguate.

pdl> $line = $im->slice(':,(0)')
pdl> aiuto $line
Questa variabile è Double D [5] -C 0.00Kb

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

Trovare la differenza con l'esempio precedente?

'n1:n2' or 'n1:n2:n3'
Prendi l'intervallo di indici da "n1" a "n2" o (seconda forma) prendi l'intervallo di
indici da "n1" a "n2" con passo "n3". Un esempio per l'uso di questo formato è
la precedente definizione della sottoimmagine composta da linee pari.

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

Questo esempio dimostra anche che gli indici negativi funzionano come in condizioni normali
Array in stile Perl contando all'indietro dalla fine della dimensione. Se "n2" è
minore di "n1" (nell'esempio -1 è equivalente all'indice 4) gli elementi nel
pdl virtuale vengono effettivamente ripristinati rispetto al suo genitore.

'*[n]'
Aggiungi una dimensione fittizia. La dimensione di questa dimensione sarà 1 per impostazione predefinita o uguale a
"n" se viene fornito l'argomento numerico opzionale.

Ora, questo è davvero qualcosa di un po' strano a prima vista. Cos'è un manichino?
dimensione? Una dimensione fittizia inserisce una dimensione dove prima non c'era. Come
è fatto? Bene, nel caso della nuova dimensione con taglia 1 può essere facilmente
spiegato dal modo in cui è possibile identificare un vettore (con elementi "m") con an
Matrice "(1,m)" o "(m,1)". Lo stesso vale ovviamente per gli oggetti di dimensione superiore.
Più interessante è il caso di un manichino di dimensioni maggiori di uno (es
"fetta('*5,:')"). Funziona allo stesso modo della creazione di una chiamata alla funzione fittizia
una nuova dimensione fittizia. Quindi continua a leggere e controlla la sua spiegazione di seguito.

'([n1:n2[:n3]]=i)'
[Non ancora implementato ??????] Con un argomento come questo fai generalizzata
diagonali. diagonale sarà la dimensione n. "i" del nuovo output pdl e (se
parte facoltativa tra parentesi specificata) si estenderà lungo l'intervallo degli indici
specificata della rispettiva dimensione del pdl padre. In generale un argomento come questo
ha senso solo se ci sono altri argomenti come questo nella stessa chiamata a slice.
La parte tra parentesi è facoltativa per questo tipo di argomento. Tutti gli argomenti di questo
tipo che specificano la stessa dimensione target "i" devono riferirsi allo stesso numero di
indici nella loro dimensione genitore. Il modo migliore per spiegarlo è probabilmente dare un
esempio, qui facciamo un pdl che si riferisce agli elementi lungo la diagonale dello spazio di
il suo genitore pdl (un cubo):

$cubo = zeri(5,5,5);
$sdiag = $cubo->slice('(=0),(=0),(=0)');

Il comando precedente crea un pdl virtuale che rappresenta la diagonale lungo il
dimensione genitori n. 0, 1 e 2 e rende la sua dimensione 0 (l'unica dimensione) di
esso. Utilizzi la sintassi estesa se le dimensioni delle dimensioni padre
vuoi costruire la diagonale da avere dimensioni diverse o vuoi invertire il
sequenza di elementi nella diagonale, ad es

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

Quindi gli elementi di $vpdl saranno quindi correlati a quelli del suo genitore nel modo in cui possiamo
esprimere come:

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

[ lavora nella nuova funzione indice: "$b = $a->indice($c);" ???? ]

Ci sono diverso tipi of assegnazioni in PDL
Gli esempi precedenti hanno già mostrato che i pdls virtuali possono essere usati per operare su or
accedere a porzioni di dati di un genitore pdl. Possono anche essere usati come lvalue nelle assegnazioni
(come ha già dimostrato l'uso di "++" in alcuni degli esempi precedenti). Per esplicito
assegnazioni ai dati rappresentati da un pdl virtuale devi usare l'overload ".="
operatore (che in questo contesto chiamiamo propagato assegnazione). Perché non puoi usare il
operatore di assegnazione normale "="?

Bene, sicuramente puoi ancora usare l'operatore '=' ma non farebbe quello che vuoi. Questo
è dovuto al fatto che l'operatore '=' non può essere sovraccaricato allo stesso modo degli altri
operatori di assegnazione. Se provassimo a usare '=' per provare ad assegnare dati a una porzione di a
pdl fisico attraverso un pdl virtuale non otterremmo l'effetto desiderato (invece il
variabile che rappresenta il pdl virtuale (un riferimento a una cosa benedetta) sarebbe dopo il
l'incarico contiene solo il riferimento a un'altra cosa benedetta a cui si comporterebbe
assegnazioni future come copia "fisica" dell'rvalue originale [questo in realtà non è ancora
chiaro e oggetto di discussione nella mailing list degli sviluppatori PDL]. In questo senso
interromperebbe la connessione del pdl al genitore [non è questo comportamento in un certo senso il
opposto di ciò che accade nel flusso di dati, dove ".=" interrompe la connessione al genitore? ].

Per esempio

pdl> $line = $im->slice(':,(2)')
pdl> $line = zero(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]

Ma usando ".="

pdl> $line = $im->slice(':,(2)')
pdl> $line .= zero(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> stampa $riga
[1 1 1 1 1]

Inoltre, puoi sostituire

pdl> $riga .= 0;

per l'assegnazione di cui sopra (lo zero viene convertito in un piddle scalare, senza dimensioni quindi
può essere assegnato a qualsiasi piddle).

Una caratteristica interessante nelle recenti versioni di perl sono le subroutine lvalue (cioè le versioni 5.6.x e
superiore, inclusi tutti i perl attualmente supportati da PDL). Ciò consente di utilizzare il
sintassi affettare su entrambi i lati dell'assegnazione:

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

Relativo alla funzione di subassegnazione lvalue è una piccola trappola per gli incauti: perls recenti
ha introdotto una "caratteristica" che interrompe l'uso da parte di PDL dei sub lvalue per le assegnazioni delle sezioni quando
in esecuzione sotto il debugger perl, "perl -d". Sotto il debugger, l'utilizzo di cui sopra fornisce un
errore come: "Impossibile restituire una subroutine temporanea da lvalue... " Quindi devi usare la sintassi
come questo:

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

che funziona sia con che senza il debugger, ma è probabilmente goffo e scomodo da leggere.

Nota che può esserci un problema con assegnazioni come questa quando lvalue e rvalue pdls
fare riferimento a porzioni di dati sovrapposte nel pdl padre:

# ripristina gli elementi della prima riga di $a
($tmp = $a->slice(':,(1)')) .= $a->slice('-1:0,(1)');

Attualmente, i dati principali sul lato destro delle assegnazioni non vengono copiati prima del
il ciclo di assegnazione (interno) procede. Pertanto, l'esito di questo incarico dipenderà
sulla sequenza in cui vengono assegnati gli elementi e quasi certamente non è un fai quello che vuoi
ricercato. Quindi la semantica è attualmente indefinito per ora e suscettibile di cambiare in qualsiasi momento. a
ottenere il comportamento desiderato, utilizzare

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

che fa una copia fisica della fetta o

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

che restituisce la stessa fetta ma interrompe la connessione della fetta al suo genitore.

Altri funzioni che manipolare dimensioni
Avendo parlato ampiamente della funzione slice va notato che questa non è la
solo funzione di indicizzazione PDL. Ci sono funzioni di indicizzazione aggiuntive che sono anche utili
(soprattutto nel contesto del threading di cui parleremo più avanti). Ecco una lista
e alcuni esempi su come usarli.

"manichino"
inserisce una dimensione fittizia della dimensione specificata (impostazione predefinita 1) nella posizione scelta.
Non vedi l'ora di sapere come si ottiene? Bene, tutti gli elementi con indice "(X,x,Y)"
("0<=x
pdl (dove "X" e "Y" si riferiscono al gruppo di indici prima e dopo la posizione
dove è stata inserita la dimensione fittizia.)

Questo esempio calcola la coordinata x del baricentro di un'immagine (più avanti lo faremo
scopri che in realtà non avevamo bisogno della dimensione fittizia grazie alla magia dell'implicito
filettatura; ma usando dimensioni fittizie il codice funzionerebbe anche in un mondo senza thread;
anche se una volta che hai lavorato con i thread PDL non vorresti vivere senza di loro
ancora).

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

Spieghiamo come funziona in modo un po' più dettagliato. Innanzitutto, il prodotto:

$xvs = xvals(zeri($xd));
print $xvs->dummy(1,$yd); # ripeti la riga $yd volte
$prod = $im*xvs->dummy(1,$yd); # forma il prodotto pixel-wise con
# la riga ripetuta dei valori x

Il resto è quindi sommare i risultati del prodotto pixel-wise insieme e
normalizzando con la somma di tutti i valori dei pixel nell'immagine originale calcolando così
la coordinata x del "centro di massa" dell'immagine (interpretando i valori dei pixel come
massa locale) che è noto come baricentro di un'immagine.

La prossima è una conversione (dal punto di vista del consumo di memoria) molto economica da
scala di grigi in RGB, cioè ogni pixel ora contiene una tripla di valori invece di uno scalare.
I tre valori nella tripla sono, fortunatamente, tutti uguali per un'immagine grigia, quindi
che il nostro trucco funziona bene in quanto mappa tutti e tre i membri della tripla al
stesso elemento sorgente:

# una conversione economica da scala di grigi a RGB
$rgb = $grigio->manichino(0,3)

Sfortunatamente questo trucco non può essere usato per convertire le tue vecchie foto in bianco e nero in quelle a colori
nel modo che vorresti. :(

Si noti che l'utilizzo della memoria dei piddle con dimensioni fittizie è particolarmente sensibile a
la rappresentazione interna. Se il piddle può essere rappresentato come un affine virtuale
(``vaffine'') piddle, vengono memorizzate solo le strutture di controllo. Ma se $b in

$un = zero(10000);
$b = $a->fittizio(1,10000);

è reso fisico da qualche routine, scoprirai che l'utilizzo della memoria del tuo programma
è cresciuto improvvisamente di 100Mb.

"diagonale"
sostituisce due dimensioni (che devono essere della stessa dimensione) con una dimensione che
fa riferimento a tutti gli elementi lungo la "diagonale" lungo quelle due dimensioni. Qui noi
avere due esempi che dovrebbero sembrare familiari a chiunque abbia mai fatto qualcosa di lineare
algebra. Innanzitutto, crea una matrice unitaria:

# matrice unitaria
$e = zeri(float, 3, 3); # azzera tutto
($tmp = $e->diagonale(0,1)) .= 1; # imposta gli elementi lungo la diagonale a 1
stampa $e;

Oppure l'altra diagonale:

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

(Hai notato come abbiamo usato la funzione slice per ripristinare la sequenza di linee prima?
impostando la diagonale del nuovo bambino, impostando così la diagonale trasversale del
genitore ?) O una mappatura dallo spazio delle matrici diagonali al campo su cui
le matrici sono definite, la traccia di una matrice:

# traccia di una matrice
$traccia = sum($mat->diagonal(0,1)); # somma tutti gli elementi diagonali

"xchg" e "mv"
xchg scambia o "traspone" le due dimensioni specificate. Un semplice
esempio:

# trasporre una matrice (senza rimescolamento esplicito dei dati e
# fare una copia)
$prod = $ax $a->xchg(0,1);

$prod dovrebbe ora essere abbastanza vicino alla matrice unitaria se $a è una matrice ortogonale.
Spesso "xchg" verrà utilizzato nel contesto del threading, ma ne parleremo più avanti.

mv funziona in modo simile. Sposta una dimensione (specificata dal suo numero nel
genitore) a una nuova posizione nel nuovo figlio pdl:

$b = $a->mv(4,0); # rende la quinta dimensione di $a la prima in
# nuovo figlio $b

La differenza tra "xchg" e "mv" è che "xchg" cambia solo la posizione di due
dimensioni tra loro, mentre "mv" inserisce la prima dimensione al posto di
secondo, spostando di conseguenza le altre dimensioni.

"grumo"
comprime diverse dimensioni in una. Il suo unico argomento specifica quante dimensioni
del pdl sorgente dovrebbe essere compresso (a partire dal primo). Un (ammesso
irrealistico) l'esempio è un pdl 3D che contiene i dati da una pila di file di immagine che tu
ho appena letto. Tuttavia, i dati di ciascuna immagine rappresentano davvero un tempo 1D
serie ed è stato organizzato in questo modo solo perché è stato digitalizzato con una cornice
afferratore. Quindi per averlo di nuovo come una serie di sequenze temporali dici

pdl> $seqs = $stack->ciuffo(2)
pdl> aiuto vars
Variabili PDL nel pacchetto principale::

Nome Tipo Dimensione Flusso Stato Mem
-------------------------------------------------- --------------
$seqs Doppia D [8000,50] -C 0.00Kb
$stack Doppia D [100,80,50] P 3.05Mb

Per quanto irrealistico possa sembrare, il nostro software per microscopio confocale scrive dati (a volte)
Da questa parte. Ma più spesso usi il ciuffo per ottenere un certo effetto quando usi l'implicito
o threading esplicito.

Bandi a indicizzazione funzioni può be incatenato
Come avrai notato in alcuni degli esempi precedenti, le chiamate alle funzioni di indicizzazione
può essere ben concatenato poiché tutte queste funzioni restituiscono un oggetto figlio appena creato.
Tuttavia, quando si eseguono manipolazioni estese dell'indice in una catena, assicurarsi di tenere traccia di cosa
stai facendo, ad es

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

sposta la quota 1 di $a alla posizione 4 poiché quando viene eseguito il secondo comando il
la dimensione originale 1 è stata spostata nella posizione 0 del nuovo figlio che chiama "mv"
funzione. Penso che tu abbia reso l'idea (nonostante le mie spiegazioni contorte).

Propagato assegnazioni ('.=') e manichino dimensioni
Una sottocategoria relativa all'indicizzazione è l'assegnazione a pdls contenente dimensioni fittizie di
dimensione maggiore di 1. Queste assegnazioni (usando ".=") sono vietate poiché diversi elementi
di lvalue pdl puntano allo stesso elemento del genitore. Di conseguenza il valore di
quegli elementi genitori sono potenzialmente ambigui e dipenderebbero dalla sequenza in cui
l'implementazione esegue le assegnazioni agli elementi. Pertanto, un incarico come questo:

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

può produrre risultati inaspettati e i risultati sono esplicitamente indefinito dal PDL perché
quando PDL ottiene funzionalità di elaborazione parallela, il risultato attuale potrebbe cambiare.

Dal punto di vista del flusso di dati l'introduzione di manichini di dimensioni maggiori di uno
dimensioni è considerata come una trasformazione irreversibile (simile alla terminologia in
termodinamica) che preclude la propagazione all'indietro dell'assegnazione a un genitore (che tu
aveva esplicitamente richiesto utilizzando l'assegnazione ".="). Un problema simile a cui prestare attenzione
si verifica nel contesto del threading in cui a volte le dimensioni fittizie vengono create implicitamente
durante il ciclo del filo (vedi sotto).

Motivi per , il genitore/figlio (o "puntatore") concetto
[questo dovrà aspettare un po']

XXXXX è efficiente in termini di memoria
XXXXX nel contesto del threading
XXXXX modo molto flessibile e potente di accedere a porzioni di dati pdl
(in un modo molto più generale di sec, ecc consenti)
XXXXX implementazione efficiente
XXXXX differenza con la sezione/at, ecc.

Come a make cose Fisico ancora
[ XXXXX compilare più tardi quando tutto si sarà sistemato un po' di più ]

** Quando necessario (routine xsub che interfaccia la funzione C lib)
** Come raggiunto (->fisico)
** Come testare (èfisico (spiega come funziona attualmente))
** ->copia e ->separa

Threading


Nel paragrafo precedente sull'indicizzazione abbiamo già accennato occasionalmente al termine ma
ora è davvero il momento di parlare esplicitamente di "threading" con pdls. Il termine threading ha
significati diversi in diversi campi dell'informatica. Nell'ambito del PDL si
potrebbe probabilmente essere vagamente definito come una struttura di loop implicita. È implicito perché
non specifichi nulla come racchiudere for-loops ma piuttosto i loop sono automaticamente
(o 'magicamente') generati dal PDL in base alle dimensioni dei pdl coinvolti. Questo
dovrebbe darti una prima idea del perché le funzioni di manipolazione di indice/dimensione che hai incontrato
nei paragrafi precedenti sono particolarmente importanti e utili nel contesto di
filettatura. L'altro ingrediente per l'infilatura (a parte i pdls coinvolti) è un
funzione che riconosce il threading (in genere si tratta di funzioni compilate PDL::PP) e
che i pdls siano "infilati". Tanto sulla terminologia e ora proviamo a
far luce su cosa significa tutto questo.

Implicito threading - a prima di tutto esempio
Esistono due varianti leggermente diverse di filettatura. Iniziamo con quello che chiamiamo
"filo implicito". Prendiamo un esempio pratico che coinvolge il ciclo di una funzione
su molti elementi di un pdl. Supponiamo di avere un'immagine RGB che vogliamo convertire in grigio-
scala. L'immagine RGB è rappresentata da un pdl 3-dim "im(3,x,y)" dove la prima dimensione
contiene i tre componenti di colore di ciascun pixel e "x" e "y" sono larghezza e altezza di
l'immagine, rispettivamente. Quindi dobbiamo specificare come convertire un triplo colore in un dato
pixel in un valore di grigio (per essere un esempio realistico dovrebbe rappresentare il relativo
intensità con cui le nostre cellule oculari insensibili al colore rileverebbero quel colore da raggiungere
quella che chiameremmo una conversione naturale dal colore alla scala di grigi). Un'approssimazione che
funziona abbastanza bene è calcolare l'intensità del grigio da ogni tripletta RGB (r,g,b) come a
somma ponderata

valore-grigio = 77/256*r + 150/256*g + 29/256*b =
interno([77,150,29]/256, [r,g,b])

dove l'ultima forma indica che possiamo scrivere questo come prodotto interno del 3-vettore
comprendente i pesi per i componenti rosso, verde e blu con il vettore 3-che contiene il
componenti di colore. Tradizionalmente, potremmo aver scritto una funzione come la seguente in
elaborare l'intera immagine:

my @dims=$im->dims;
# qui normalmente controlla che il primo dim abbia la dimensione corretta (3), ecc
$grigio=zero(@dims[1,2]); # crea il pdl per l'immagine grigia risultante
$w = pdl [77,150,29] / 256; # il vettore dei pesi
per ($j=0;$j
per ($i=0;$i
# calcola il valore in pixel
$tmp = inner($w,$im->slice(':,(i),(j)'));
set($grigio,$i,$j,$tmp); # e impostalo nell'immagine in scala di grigi
}
}

Ora scriviamo lo stesso usando il threading (notando che "inner" è una funzione che riconosce il threading
definito nel PDL::Pacchetto Primitivo)

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

Abbiamo finito con un one-liner che crea automaticamente il pdl $grey con la destra
numero e dimensione delle dimensioni ed esegue automaticamente i loop (questi loop sono
implementato come codice C veloce all'interno del PDL). Bene, ti dobbiamo ancora un
spiegazione di come si ottiene questa "magia".

Come effettua , il esempio lavoro ?
La prima cosa da notare è che ogni funzione che è a conoscenza del threading (questi sono senza
funzioni di eccezione compilate da descrizioni concise da PDL::PP, in seguito semplicemente chiamate PP-
funzioni) si aspetta un numero definito (minimo) di dimensioni (le chiamiamo dimensioni principali)
da ciascuno dei suoi argomenti pdl. La funzione interna prevede due unidimensionali (input)
parametri da cui calcola un parametro a dimensione zero (uscita). Lo scriviamo
simbolicamente come "inner((n),(n),[o]()))" e chiamalo "inner" firma, dove n rappresenta
la dimensione di quella dimensione. n essendo uguale nel primo e nel secondo parametro significa che
quelle dimensioni devono essere della stessa dimensione in ogni chiamata. Come esempio diverso, prendi il
prodotto esterno che richiede due vettori 1D per generare una matrice 2D, scritta simbolicamente come
"esterno((n),(m),[o](n,m))". La "[o]" in entrambi gli esempi indica che questo (qui terzo)
argomento è un argomento di output. In quest'ultimo esempio le dimensioni di prima e seconda
argomento non devono essere d'accordo ma vedi come determinano la dimensione delle due dimensioni
dell'uscita pdl.

Ecco il punto in cui il threading entra finalmente in gioco. Se chiami le funzioni PP con
pdls che hanno Scopri di più rispetto alle dimensioni del nucleo richieste le prime dimensioni del pdl
gli argomenti vengono utilizzati come dimensioni principali e le dimensioni extra aggiuntive sono filettate
Sopra. Dimostriamolo prima con il nostro esempio sopra

$grigio = interno($im,$w); # w è il vettore del peso dall'alto

In questo caso $w è 1D e quindi fornita solo la dimensione centrale, $im è 3D, altro
in particolare "(3,x,y)". La prima dimensione (della misura 3) è la dimensione centrale richiesta
che corrisponde (come richiesto da inner) alla prima (e unica) dimensione di $w. Il secondo
la dimensione è la prima dimensione del filo (della dimensione "x") e la terza è qui la seconda
dimensione del filo (della dimensione "y"). L'output pdl viene creato automaticamente (come richiesto da
impostando $grey su "null" prima dell'invocazione). Le dimensioni di uscita sono ottenute da
aggiungendo il loop dimensioni (qui "(x,y)") alle dimensioni di uscita del core (qui 0D) a
produrre le dimensioni finali del pdl creato automaticamente (qui "0D+2D=2D" per ottenere un output 2D
di dimensione "(x,y)").

Quindi il comando precedente chiama la funzionalità principale che calcola il prodotto interno di due
Vettori 1D "x*y" volte con $w e tutte le sezioni 1D della forma "(':,(i),(j)')" di $im e
imposta i rispettivi elementi dell'output pdl "$grey(i,j)" al risultato di ciascuno
calcolo. Potremmo scriverlo simbolicamente come

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

Ma questo viene fatto automaticamente da PDL senza scrivere alcun ciclo Perl esplicito. Vediamo
che il comando crei davvero un output pdl con le giuste dimensioni e imposti il
elementi infatti al risultato del calcolo per ogni pixel dell'immagine in ingresso.

Quando sono coinvolti ancora più pdl e dimensioni extra, le cose si fanno un po' più complicate.
Daremo prima le regole generali su come le dimensioni del filo dipendono dalle dimensioni di
input pdls che ti consente di capire la dimensionalità di un output pdl creato automaticamente
(per ogni dato insieme di input pdls e dimensioni fondamentali della funzione PP in questione). Il
le regole generali molto probabilmente sembreranno un po' confuse a prima vista in modo che inizieremo
per illustrare l'uso con una serie di ulteriori esempi (che si spera anche
dimostrare che ci sono davvero molte situazioni pratiche in cui entra in gioco il threading
estremamente pratico).

A chiamata per codifica disciplina
Prima di evidenziare gli altri dettagli tecnici del threading, si prega di notare questa chiamata per
disciplina di programmazione quando si utilizza il threading:

Per preservare la leggibilità umana, PER FAVORE commenta qualsiasi espressione non banale nel tuo
codice che coinvolge il threading. La cosa più importante, per qualsiasi subroutine, includere le informazioni in
l'inizio su ciò che si prevede rappresentino le dimensioni (o gli intervalli di dimensioni).

Come avvertimento, guarda questa funzione non documentata e prova a indovinare cosa potrebbe succedere:

ricerca secondaria {
mia ($im,$palette) = @_;
il mio $res;
index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=nullo));
restituisce $res;
}

Sei d'accordo che potrebbe essere difficile capire le dimensioni previste, lo scopo di?
la routine, ecc? (Se vuoi scoprire cosa fa questo pezzo di codice, vedi sotto)

Come a figura su , il loop dimensioni
Ci sono un paio di regole che ti permettono di capire il numero e la dimensione del loop
dimensioni (e se la dimensione dei tuoi pdls di input è conforme alle regole di threading).
Le dimensioni di qualsiasi argomento pdl sono suddivise in due gruppi come segue: Core
dimensioni (come definito dalla funzione PP, vedere Appendice B per un elenco di primitive PDL)
e dimensioni extra che comprende tutte le restanti dimensioni di quel pdl. Per esempio
chiamare una funzione "func" con la firma "func((n,m),[o](n))" con un pdl
"a(2,4,7,1,3)" come "f($a,($o = null))" risulta nella divisione semantica delle dimensioni di a
in: dimensioni principali "(2,4)" e dimensioni extra "(7,1,3)".

R0 Le dimensioni del nucleo sono identificate con le prime N dimensioni del rispettivo pdl
argomento (e sono obbligatori). Eventuali ulteriori dimensioni sono dimensioni extra e utilizzate per
determinare le dimensioni del ciclo.

R1 Il numero di dimensioni (implicite) del ciclo è uguale al numero massimo di extra
dimensioni prese sull'insieme di argomenti pdl.

R2 La dimensione di ciascuna delle dimensioni del ciclo è derivata dalla dimensione del rispettivo
dimensioni degli argomenti pdl. La dimensione di una dimensione del ciclo è data da
dimensione massima trovata in uno qualsiasi dei pdl aventi questa dimensione extra.

R3 Per tutti i pdl che hanno una data dimensione extra la dimensione deve essere uguale alla dimensione di
la dimensione del ciclo (come determinato dalla regola precedente) o 1; altrimenti alzi a
eccezione di runtime. Se la dimensione della dimensione extra in un pdl è una, lo è
trattata implicitamente come una dimensione fittizia di dimensione uguale a quella dimensione dim del ciclo quando
eseguire il ciclo del filo.

R4 Se un pdl non ha una dimensione di loop, nel thread loop questo pdl viene trattato come se
avente una dimensione fittizia di dimensione uguale alla dimensione di quella dimensione del ciclo.

R5 Se viene utilizzata la creazione automatica dell'output (impostando il relativo pdl su "PDL->null" prima
invocazione) il numero di dimensioni del pdl creato è uguale alla somma dei
numero di dimensioni core output + numero di dimensioni loop. La dimensione del nucleo
le dimensioni di output sono derivate dalla dimensione pertinente di input pdls (come specificato
nella definizione della funzione) e le dimensioni delle altre dimensioni sono uguali alla
dimensione della dimensione del ciclo da cui deriva. Il pdl creato automaticamente sarà
fisico (a meno che il flusso di dati non sia in funzione).

In questo contesto, nota che puoi incontrare il problema con l'assegnazione a pdls che contiene
dimensioni fittizie maggiori di una (vedi sopra). Sebbene il tuo output pdl (s) non contenga
qualsiasi dimensione fittizia in primo luogo potrebbe finire con un fittizio creato implicitamente
dimensioni secondo R4.

Ad esempio, supponiamo di avere una funzione PP (qui non specificata) con la firma:

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

e lo chiami con 3 pdls "a(5,3,10,11)", "b(5,3,2,10,1,12)" e "c(5,1,11,12)" come

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

quindi il numero di dimensioni del ciclo è 3 (da "R0+R1" da $b e $c) con dimensioni
"(10,11,12)" (da R2); le due dimensioni del nucleo di uscita sono "(5,2)" (dalla firma di
func) risultante in un output a 5 dimensioni pdl $c di dimensione "(5,2,10,11,12)" (vedi R5) e
(il creato automaticamente) $d è derivato da "($a,$b,$c)" in un modo che può essere espresso
in pdl pseudo-codice as

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

Se analizziamo nuovamente la conversione da colore a scala di grigi con queste regole in mente, notiamo
un altro grande vantaggio del threading implicito. Possiamo chiamare la conversione con un pdl
che rappresenta un pixel (im(3)), una linea di pixel rgb ("im(3,x)"), un'immagine a colori adeguata
("im(3,x,y)") o un'intera pila di immagini RGB ("im(3,x,y,z)"). Finché $im è di
form "(3,...)" l'output pdl creato automaticamente conterrà il giusto numero di
dimensioni e contenere i dati di intensità come ci aspettiamo poiché i loop sono stati
implicitamente eseguito grazie a implicito threading. Puoi facilmente convincerti che
chiamando con un pixel di colore $grigio è 0D, con una linea risulta 1D grigio(x), con un'immagine
otteniamo "grey(x,y)" e infine otteniamo uno stack di immagini convertito "grey(x,y,z)".

Riempiamo queste regole generali con un po' di vita in più passandone un paio in più
esempi. Il lettore può cercare di escogitare formulazioni equivalenti con espliciti
loop e confrontare la flessibilità di quelle routine che utilizzano il threading implicito al
formulazione esplicita. Inoltre, specialmente quando si utilizzano diverse dimensioni di filettatura, è a
esercizio utile per verificare la velocità relativa effettuando dei benchmark test (che continuiamo
c'è da fare).

Il primo della riga è un esempio di centroide leggermente rielaborato, ora codificato con threading in
mente.

# mult filettato per calcolare le coordinate del centroide, funziona anche per gli stack
$xc = sumover(($im*xvals(($im->dims)[0]))->ciuffo(2)) /
sumover($im->ciuffo(2));

Analizziamo passo passo cosa sta succedendo. Innanzitutto il prodotto:

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

Questo funzionerà effettivamente per $im di una, due, tre e dimensioni superiori. Se $im è
unidimensionale è solo un prodotto ordinario (nel senso che ogni elemento di $im è
moltiplicato con il rispettivo elemento di "xvals(...)"), se $im ha più dimensioni
l'ulteriore filettatura viene eseguita aggiungendo dimensioni fittizie appropriate a "xvals(...)"
secondo R4. Ancora più importante, le due operazioni di sumover mostrano un primo esempio di come
per utilizzare i comandi di manipolazione delle quote. Una rapida occhiata alla firma di sumover
ti ricorderà che "divorerà" solo la prima dimensione di un dato input pdl.
Ma cosa succede se volessimo calcolare davvero la somma su tutti gli elementi dei primi due?
dimensioni? Ebbene, nulla ci impedisce di passare un pdl virtuale in sumover che in questo
caso è formato aggregando le prime due dimensioni del "padre pdl" in una. Dal
punto di vista del genitore pdl la somma viene ora calcolata sulle prime due dimensioni,
proprio come volevamo, anche se sumover ha appena svolto il lavoro come specificato dalla sua firma. Avuto
vero?

Un'altra piccola finezza di scrivere il codice in questo modo: l'abbiamo usato intenzionalmente
"sumover($pdl->ciuffo(2))" invece di "sum($pdl)" in modo che possiamo passare solo un'immagine
"(x,y)" o una pila di immagini "(x,y,t)" in questa routine e ottieni solo uno
x-coordiante o un vettore di ascisse (di dimensione t) in cambio.

Un altro insieme di operazioni comuni sono quelle che si potrebbero chiamare "operazioni di proiezione". Queste
le operazioni prendono un pdl ND come input e restituiscono un pdl "proiettato" (N-1)-D. Queste operazioni
vengono spesso eseguite con funzioni come sumover, prodover, minimo e massimo. Usando
ancora immagini come esempi potremmo voler calcolare il valore massimo dei pixel per ogni riga
di un'immagine o di una pila di immagini. Sappiamo come farlo

# massimi di righe (in funzione del numero di riga e del tempo)
massimo($pila,($ret=null));

Ma cosa succede se si desidera calcolare i massimi per colonna quando si applica sempre il threading implicito?
la funzionalità principale alla prima dimensione e le discussioni su tutte le altre? Come possiamo
ottenere che invece la funzionalità di base venga applicata alla seconda dimensione e
il threading è fatto sugli altri. Riesci a indovinarlo? Sì, facciamo un pdl virtuale che ha
la seconda dimensione del "padre pdl" come prima dimensione utilizzando il comando "mv".

# massimi di colonne (in funzione del numero di colonna e dell'ora)
massimo($pila->mv(1,0),($ret=null));

e calcolare tutte le somme delle sottosezioni sulla terza dimensione ora è fin troppo facile

# somme di pixel nel tempo (supponendo che il tempo sia il terzo dim)
sumover($stack->mv(2,0),($ret=null));

Infine, se vuoi applicare l'operazione a tutti gli elementi (come max su tutti gli elementi o
somma su tutti gli elementi) indipendentemente dalle dimensioni del pdl in questione viene "ciuffo"
utile. Ad esempio, guarda la definizione di "sum" (come definita in "Ufunc.pm"):

sottosomma {
PDL::Ufunc::sumover($name->clump(-1),($tmp=null));
return $tmp->at(); # restituisce un numero Perl, non un pdl 0D
}

Abbiamo già detto che tutte le operazioni di base supportano il threading e l'assegnazione è no
eccezione. Quindi ecco un paio di compiti in thread

pdl> $im = zeri(byte, 10,20)
pdl> $line = exp(-rivali(10)**2/9)
# assegnazione filettata
pdl> $im .= $riga # imposta ogni riga di $im su $riga
pdl> $im2 .= 5 # imposta ogni elemento di $im2 a 5

Ormai avrete probabilmente visto come funziona e cosa fa, vero?

Per finire gli esempi in questo paragrafo ecco una funzione per creare un'immagine RGB da
quella che viene chiamata un'immagine tavolozza. L'immagine della tavolozza è composta da due parti: un'immagine di
indici in una tabella di ricerca del colore e la tabella di ricerca del colore stessa. [ descrivi come
funziona ] Useremo una funzione PP che non abbiamo ancora incontrato in precedenza
esempi. È la funzione indice giustamente chiamata, firma "((n),(),[o]())" (vedi Appendice
B) con la funzionalità di base che "index(pdl (0,2,4,5),2,($ret=null))" restituirà il
elemento con indice 2 del primo input pdl. In questo caso, $ret conterrà il valore 4.
Quindi ecco l'esempio:

# una ricerca nell'indice filettato per generare un'immagine RGB, o RGBA o YMCK
# da un'immagine della tavolozza (rappresentata da una tabella di ricerca $palette e
# un'immagine con indice di colore $im)
# puoi dire solo manichino(0) poiché le regole del threading lo rendono adatto
pdl> index($palette->xchg(0,1),
$im->long->dummy(0,($palette->dim)[0]),
($res=nullo));

Esaminiamolo e spieghiamo i passaggi coinvolti. Supponendo di avere a che fare con un RGB
lookup-table $palette ha le dimensioni "(3,x)". Per prima cosa scambiamo le dimensioni della tavolozza
in modo che il ciclo venga eseguito sulla prima dimensione di $palette (di dimensione 3 che rappresenta r,
componenti g e b). Ora guardando $im, aggiungiamo una dimensione fittizia di dimensione uguale a
lunghezza del numero di componenti (nel caso di cui stiamo discutendo qui avremmo potuto semplicemente
usato il numero 3 poiché abbiamo 3 componenti di colore). Possiamo usare una dimensione fittizia poiché
per i componenti di colore rosso, verde e blu utilizziamo lo stesso indice dell'immagine originale,
ad esempio supponendo che un certo pixel di $im avesse il valore 4, la ricerca dovrebbe produrre il
triplo

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

per i nuovi componenti rosso, verde e blu dell'immagine di output. Spero che ormai tu l'abbia fatto
una sorta di idea di cosa dovrebbe fare il pezzo di codice sopra (spesso in realtà lo è
abbastanza complicato descrivere in dettaglio come funziona un pezzo di codice di threading; vai avanti
e sperimenta un po' per farti un'idea migliore).

Se hai letto attentamente le regole di threading, potresti aver notato che non l'abbiamo fatto
dobbiamo dichiarare esplicitamente la dimensione della dimensione fittizia che abbiamo creato per $im; quando noi
crealo con la dimensione 1 (il default) le regole di threading lo fanno adattare automaticamente a
la dimensione desiderata (per la regola R3, nel nostro esempio la dimensione sarebbe 3 assumendo una tavolozza di
dimensione "(3,x)"). Poiché situazioni come questa si verificano spesso nella pratica, questo è in realtà il motivo
è stata introdotta la regola R3 (la parte che fa combaciare le dimensioni della taglia 1 al filetto
dimensione del ciclo dim). Quindi possiamo solo dire

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

Di nuovo, puoi convincerti che questa routine creerà l'output giusto se chiamata
con un pixel ($im è 0D), una linea ($im è 1D), un'immagine ($im è 2D), ..., una ricerca RGB
table (la tavolozza è "(3,x)") e la tabella di ricerca RGBA (la tavolozza è "(4,x)", vedi ad esempio OpenGL).
Questa flessibilità è ottenuta dalle regole di filettatura che sono fatte per fare il giusto
cosa nella maggior parte delle situazioni.

Per concludere tutto ancora una volta, l'idea generale è la seguente. Se vuoi raggiungere
loop su determinate dimensioni e avere il core funzionalità applicato a un altro
insieme specificato di quote si utilizzano i comandi di manipolazione delle quote per creare un (o
parecchi) virtuale pdl(s) in modo che dal punto di vista del genitore pdl(s) ottieni cosa
vuoi (avendo sempre in mente la firma della funzione in questione e R1-R5!).
Facile, no?

Uscita creazione automatica e Funzione PP chiamata convenzioni
A questo punto dobbiamo deviare su qualche dettaglio tecnico che ha a che fare con il generale
convenzioni di chiamata delle funzioni PP e la creazione automatica di argomenti di output.
Fondamentalmente, ci sono due modi per invocare le routine pdl, vale a dire

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

e

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

Se stai usando solo il threading implicito, la variabile di output può essere automaticamente
creato dal Pdl. Lo contrassegni alla funzione PP impostando l'argomento di output su a
tipo speciale di pdl restituito da una chiamata alla funzione "PDL->null" che restituisce
un pdl essenzialmente "vuoto" (per chi fosse interessato ai dettagli c'è un flag nel C pdl
struttura per questo). Le dimensioni del pdl creato sono determinate dalle regole di
threading implicito: le prime dimensioni sono le dimensioni core di output a cui
vengono aggiunte le dimensioni della filettatura (che sono a loro volta determinate dalle dimensioni del
input pdls come descritto sopra). Quindi puoi dire

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

or

$risultato = funzione($a,$b)

che sono di preciso equivalente.

Tieni presente che puoi non è un usa la creazione automatica dell'output quando usi il threading esplicito (per
ragioni spiegate nella sezione seguente su esplicito threading, la seconda variante di
filettatura).

Nei cicli "stretti" probabilmente vorrai evitare la creazione implicita di un pdl temporaneo in
ogni passaggio del ciclo che accompagna lo stile "funzionale" ma piuttosto dire

# crea output pdl di dimensioni appropriate solo alla prima chiamata
$risultato = nullo;
per (0...$n) {
func($a,$b,$risultato); # in tutti tranne la prima invocazione $risultato
funzione2($b); # è definito e ha la dimensione giusta per
# prendi l'output a condizione che i dim di $b non cambino
twiddle($risultato,$a); # fai qualcosa da $risultato a $a per l'iterazione
}

Il messaggio da portare a casa di questa sezione ancora una volta: sii consapevole della limitazione sull'output
creazione durante l'utilizzo esplicito threading.

Esplicito threading
Avendo finora parlato solo del primo sapore di threading, è giunto il momento di
introdurre la seconda variante. Invece di mischiare continuamente le dimensioni e
fare affidamento sulle regole del threading implicito per ottenere tutto bene a volte potresti volerlo
specificare in modo più esplicito come eseguire il ciclo del thread. Probabilmente non lo è troppo
sorprendente che questa variante del gioco si chiami esplicito threading. Ora, prima di noi
creare l'impressione sbagliata: non lo è neanche implicito or esplicito; i due gusti sì
mescolare. Ma ne parleremo più avanti.

Le due funzioni più utilizzate con threading esplicito sono thread e unthread. Iniziamo
con un esempio che illustra l'uso tipico del primo:

[ # ** questo è il peggior esempio possibile per iniziare]
# ma può essere usato per mostrare che $mat += $line è diverso da
# $mat->filo(0) += $riga
# threading esplicito per aggiungere un vettore a ciascuna colonna di una matrice
pdl> $mat = zeri(4,3)
pdl> $line = pdl (3.1416,2,-2)
pdl> ($tmp = $mat->filo(0)) += $riga

In questo esempio, "$mat->filo(0)" dice a PDL che vuoi la seconda dimensione di questo
pdl da infilare per primo portando a un ciclo di thread che può essere espresso come

for (j=0; j<3; j++) {
per (i=0; i<4; i++) {
mat(i,j) += src(j);
}
}

"thread" accetta una lista di numeri come argomenti che specificano esplicitamente quali dimensioni
infilare prima. Con l'introduzione del threading esplicito le dimensioni di un pdl sono
concettualmente suddiviso in tre diversi gruppi di cui gli ultimi due li abbiamo già
incontrate: dimensioni del filetto, dimensioni del nucleo e dimensioni extra.

Concettualmente, è meglio pensare a quelle dimensioni di un pdl che sono state specificate in
una chiamata al "filo" come essere tolto dall'insieme delle dimensioni normali e messo su a
pila separata. Quindi supponendo di avere un pdl "a(4,7,2,8)" che dice

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

crea un nuovo pdl virtuale di dimensione "b(4,8)" (che chiamiamo le rimanenti dim) che
ha anche 2 dimensioni di filettatura della dimensione "(2,7)". Ai fini di questo documento scriviamo
che simbolicamente come "b(4,8){2,7}". Una differenza importante rispetto agli esempi precedenti dove
è stato utilizzato solo il threading implicito è il fatto che le dimensioni principali sono abbinate a
, il rimanente dimensioni che non sono necessariamente le prime dimensioni del pdl. Noi
ora specificherà come la presenza delle dimensioni del filo cambia le regole R1-R5 per il filo
loop (che si applicano al caso speciale in cui nessuno degli argomenti pdl ha thread
dimensioni).

T0 Le dimensioni del nucleo sono confrontate con il primo n rimanente dimensioni del pdl
argomento (notare la differenza con R1). Ulteriori rimanente dimensioni sono extra
dimensioni e sono usati per determinare il implicito loop dimensioni.

T1a Il numero di implicito loop dimensioni è uguale al numero massimo di extra
dimensioni prese sull'insieme di argomenti pdl.

T1b Il numero di esplicito loop dimensioni è uguale al numero massimo di thread
dimensioni prese sull'insieme di argomenti pdl.

T1c Il numero totale di loop dimensioni è uguale alla somma di esplicito loop dimensioni
e implicito loop dimensioni. Nel ciclo del filo, esplicito loop dimensioni sono
prima filettato seguito da implicito loop dimensioni.

T2 La dimensione di ciascuno dei loop dimensioni è derivato dalla dimensione del rispettivo
dimensioni degli argomenti pdl. È dato dalla dimensione massima trovata in qualsiasi pdls
avente questa dimensione del filo (per esplicito loop dimensioni) o dimensione extra (per
implicito loop dimensioni).

T3 Questa regola si applica a qualsiasi esplicito loop dimensione così come qualsiasi implicito loop
dimensione. Per tutti i pdls che hanno un dato filo/extra dimensione la dimensione deve essere
uguale alla dimensione del rispettivo esplicito implicito loop dimensione o 1; altrimenti
si solleva un'eccezione di runtime. Se la dimensione di a filo/extra dimensione di un pdl è uno
è implicitamente trattata come una dimensione fittizia di dimensione pari a esplicito implicito
loop dimensione.

T4 Se un pdl non ha a filo/extra dimensione che corrisponde ad un
esplicito implicito loop dimensione, nel ciclo del thread questo pdl viene trattato come se avesse
una dimensione fittizia di dimensione uguale alla dimensione di quella dimensione del ciclo.

T4a Tutti i pdl che hanno filo dimensioni deve avere lo stesso numero di thread
dimensioni.

T5 La creazione automatica dell'output non può essere utilizzata se uno qualsiasi degli argomenti pdl ne ha filo
dimensioni. Altrimenti si applica R5.

Le stesse restrizioni si applicano per quanto riguarda le dimensioni fittizie implicite (create da
applicazione di T4) come già menzionato nella sezione sul threading implicito: se presente
l'output pdls ha una dimensione fittizia (esplicita o creata implicitamente) maggiore di una a
verrà sollevata un'eccezione di runtime.

Dimostriamo queste regole all'opera in un caso generico. Supponiamo di avere un (qui
non specificato) funzione PP con la firma:

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

e lo chiami con 3 pdls "a(5,3,10,11)", "b(3,5,10,1,12)", "c(10)" e un'uscita pdl
"d(3,11,5,10,12)" (che può qui non è un essere creato automaticamente) come

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

Dalla firma di func e dalla suddetta chiamata i pdls si dividono nei seguenti gruppi di
core, dimensioni extra e thread (scritte nella forma "pdl(core dims){thread dims}[extra
attenua]"):

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

Con questo per aiutarci (in generale è utile scrivere gli argomenti in questo modo
quando inizi a giocare con il threading e vuoi tenere traccia di cosa sta succedendo) noi
dedurre ulteriormente che il numero di dimensioni del ciclo esplicite è 2 (di T1b da $a e $b)
con taglie "(3,11)" (da T2); 2 dimensioni implicite del ciclo (di T1a da $b e $d) di dimensione
"(10,12)" (da T2) e gli elementi di sono calcolati dall'input pdls in un modo che può
essere espresso in pseudocodice pdl as

per (l=0;l<12;l++)
per (k=0;k<10;k++)
for (j=0;j<11;j++) effetto di trattarlo come fittizio dim (indice j)
per (i=0;i<3;i++) |
d(i,j,:,k,l) ​​= func(a(:,i,:,j),b(i,:,k,0,l),c(k))

Ugh, questo esempio non è stato davvero facile in termini di contabilità. Serve principalmente come un
esempio come capire cosa sta succedendo quando incontri uno sguardo complicato
espressione. Ma ora è davvero il momento di dimostrare che il threading è utile dando qualcosa in più
dei nostri cosiddetti esempi "pratici".

[ I seguenti esempi avranno bisogno di ulteriori spiegazioni in futuro. Per il
momento per favore prova a convivere con i commenti nei frammenti di codice. ]

Esempio 1:

*** inversa della matrice rappresentata da eigvecs e eigvals
** data una matrice simmetrica M = A^T x diag(lambda_i) x A
** => inversa M^-1 = A^T x diag(1/lambda_i) x A
** primo $tmp = diag(1/lambda_i)*A
** poi A^T * $tmp per prodotto interno filettato
# gestione degli indici in modo che le matrici vengano stampate correttamente sotto pdl
$inv .= $evec*0; # basta copiare per ottenere un output di dimensioni appropriate
$tmp .= $evec; # inizializzazione, nessuna retropropagazione
($tmp2 = $tmp->filo(0)) /= $val; # divisione filettata
# e ora una moltiplicazione di matrici sotto mentite spoglie
PDL::Primitive::inner($evecs->xchg(0,1)->thread(-1,1),
$tmp->thread(0,-1),
$inv->thread(0,1));
# alternativa per matrix multi utilizzando il threading implicito,
# primo xchg solo per la trasposizione
PDL::Primitive::inner($evecs->xchg(0,1)->manichino(1),
$tmp->xchg(0,1)->manichino(2),
($inv=nullo));

Esempio 2:

# prodotto esterno per moltiplicazione filettata
# sottolinea che dobbiamo farlo con una chiamata esplicita a my_biop1
# quando si utilizza il threading esplicito
$res=zeroes(($a->dim)[0],($b->dim)[0]);
my_biop1($a->thread(0,-1),$b->thread(-1,0),$res->(0,1),"*");
# cosa simile per threading implicito con pdl creato automaticamente
$res = $a->manichino(1) * $b->manichino(0);

Esempio 3:

# uso diverso di thread e unthread per mescolare un numero di
# dimensioni in una volta senza molte chiamate a ->xchg e ->mv

# usa thread/unthread per riordinare le dimensioni
# provalo e confronta il pdl figlio con il suo genitore
$trans = $a->thread(4,1,0,3,2)->unthread;

Esempio 4:

# calcola un paio di riquadri di delimitazione
# $bb manterrà BB come [xmin,xmax],[ymin,ymax],[zmin,zmax]
# usiamo di nuovo thread e unthread per mescolare le dimensioni in giro
pdl> $bb = zeri(doppio, 2,3 );
pdl> minimo($vertici->filo(0)->grumo->sfilare(1), $bb->slice('(0),:'));
pdl> massimo($vertici->filo(0)->grumo->sfilare(1), $bb->slice('(1),:'));

Esempio 5:

# calcola una sequenza di immagini auto-razionata (cioè autonormalizzata)
# utilizza thread espliciti e una divisione thread implicitamente
$pila = read_image_stack();
# calcola la media (media per pixel) delle prime $n+1 immagini
$aver = zeroes([stack->dims]->[0,1]); # crea l'output pdl
sumover($stack->slice(":,:,0:$n")->thread(0,1),$aver);
$media /= ($n+1);
$pila /= $aver; # normalizza lo stack eseguendo una divisione in thread
# implicito contro esplicito
# in alternativa calcola $aver con threading implicito e creazione automatica
sumover($stack->slice(":,:,0:$n")->mv(2,0),($aver=null));
$media /= ($n+1);
#

Implicito esplicito threading
In questo paragrafo illustreremo quando il threading esplicito è preferibile rispetto a
threading implicito e viceversa. Ma poi di nuovo, questo probabilmente non è il modo migliore per
mettendo il caso poiché già lo sai: i due sapori si mescolano. Quindi, si tratta più di come
per ottenere il meglio da entrambi i mondi e, comunque, nella migliore tradizione Perl: TIMTOWTDI !

[ Spiacenti, questo deve ancora essere compilato in una versione successiva; o fare riferimento agli esempi sopra
o scegline di nuove ]

Infine, questo potrebbe essere un buon posto per giustificare tutti i dettagli tecnici che stiamo andando
su circa per un paio di pagine: perché threading?

Bene, il codice che utilizza il threading dovrebbe essere (notevolmente) più veloce del codice che utilizza
cicli for espliciti (o costrutti Perl simili) per ottenere la stessa funzionalità.
Soprattutto sui supercomputer (con strutture di calcolo vettoriale/elaborazione parallela) PDL
il threading sarà implementato in modo da sfruttare le strutture aggiuntive
di queste macchine. Inoltre, è un costrutto concettualmente semplice (sebbene tecnico
i dettagli potrebbero essere coinvolti a volte) e può molto ridurre la complessità sintattica di
Codice PDL (ma tieni presente l'ammonimento per la documentazione). Una volta che ti senti a tuo agio
con la threading modo di pensare (e codificare) non dovrebbe essere troppo difficile da fare
capire il codice che qualcun altro ha scritto di (ammesso che ti abbia dato un'idea di cosa
le dimensioni di input previste sono, ecc.). Come consiglio generale per aumentare le prestazioni del tuo
codice: se devi introdurre un ciclo nel tuo codice prova a riformulare il problema così
che puoi usare il threading per eseguire il ciclo (come con qualsiasi cosa ci siano eccezioni a
questa regola pratica; ma gli autori di questo documento tendono a pensare che questi siano rari
casi ;).

PDL::PP


An facile modo a definire funzioni che sono consapevole of indicizzazione e threading (E , il universo e
Tutto quanto)
PDL:PP fa parte della distribuzione PDL. È usato per generare funzioni che sono a conoscenza di
regole di indicizzazione e threading da descrizioni molto concise. Può esserti utile se
vuoi scrivere le tue funzioni o se vuoi interfacciare funzioni da un
libreria esterna in modo che supportino l'indicizzazione e il threading (e forse anche il flusso di dati,
vedere PDL::Dataflow). Per ulteriori dettagli controllare PDL::PP.

Appendice A


affine trasformazioni - a la nostra speciale classe of semplice e potente trasformazioni
[Questo è anche qualcosa da aggiungere nelle versioni future. Abbiamo già il generale?
routine make_affine in PDL ? È possibile che faremo riferimento a un altro uomo appropriato
pagina da qui]

Appendice B


firme of Standard PDL::PP compilato funzioni
Una selezione di firme di primitive PDL per mostrare quante dimensioni PP compilate
le funzioni divorano (e quindi puoi capire su cosa verrà threadato). La maggior parte
quelle funzioni sono quelle di base definite in "primitive.pd"

# funzioni in primitive.pd
#
somma ((n),[o]())
prodotto ((n),[o]())
valori dell'asse ((n)) al posto
interno ((n),(n),[o]())
esterno ((n),(m),[o](n,m))
peso interno ((n),(n),(n),[o]())
interno2 ((m),(m,n),(n),[o]())
inner2t ((j,n),(n,m),(m,k),[o]())
indice (1D,0D,[o])
minimo (1D,[o])
massimo (1D,[o])
wstat ((n),(n),(),[o],())
assegna ((),())

# operazioni di base
operazioni binarie ((),(),[o]())
operazioni unarie ((),[o]())

AUTORE & COPYRIGHT


Copyright (C) 1997 Christian Soeller ([email protected]) & Tuomas J. Lukka
([email protected]). Tutti i diritti riservati. Sebbene destinato al rilascio come pagina man
con la distribuzione PDL standard, non è di pubblico dominio. Il permesso è concesso a
distribuire liberamente copie letterali di questo documento a condizione che non vengano apportate modifiche all'esterno
di formattazione e che questo avviso rimanga intatto. Sei autorizzato e
incoraggiato a usare il suo codice e i suoi derivati ​​nel tuo codice sorgente per divertimento o per
profitto come meglio credi.

Usa PDL::Indexingp online utilizzando i servizi onworks.net


Server e workstation gratuiti

Scarica app per Windows e Linux

  • 1
    KDiff3
    KDiff3
    Questo repository non è più mantenuto
    ed è conservata a scopo di archivio. Vedere
    https://invent.kde.org/sdk/kdiff3 for
    il codice più recente e
    https://download.kde.o...
    Scarica KDiff3
  • 2
    USB LoaderGX
    USB LoaderGX
    USBLoaderGX è una GUI per
    Caricatore USB di Waninkoko, basato su
    libwiigui. Consente la quotazione e
    lancio di giochi Wii, giochi Gamecube e
    homebrew su Wii e WiiU...
    Scarica USBLoaderGX
  • 3
    Firebird
    Firebird
    Firebird RDBMS offre funzionalità ANSI SQL
    e funziona su Linux, Windows e
    diverse piattaforme Unix. Caratteristiche
    concorrenza e prestazioni eccellenti
    & potenza...
    Scarica l'uccello di fuoco
  • 4
    KompoZer
    KompoZer
    KompoZer è un editor HTML wysiwyg che utilizza
    la base di codice di Mozilla Composer. Come
    Lo sviluppo di Nvu è stato interrotto
    nel 2005, KompoZer risolve molti bug e
    aggiunge una f...
    Scarica KompoZer
  • 5
    Downloader di manga gratuito
    Downloader di manga gratuito
    Il Free Manga Downloader (FMD) è un
    applicazione open source scritta
    Object-Pascal per la gestione e
    scaricare manga da vari siti web.
    Questo è uno specchio...
    Scarica il downloader manga gratuito
  • 6
    UNetbootin
    UNetbootin
    UNetbootin ti consente di creare bootable
    Unità USB live per Ubuntu, Fedora e
    altre distribuzioni Linux senza
    masterizzare un CD. Funziona su Windows, Linux,
    e ...
    Scarica UNetbootin
  • Di Più "

Comandi Linux

Ad