AnglaisFrançaisEspagnol

Icône de favori OnWorks

PDL::PPp - En ligne dans le Cloud

Exécutez PDL::PPp dans le fournisseur d'hébergement gratuit OnWorks sur Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

Il s'agit de la commande PDL::PPp qui peut être exécutée dans le fournisseur d'hébergement gratuit OnWorks en utilisant l'un de nos multiples postes de travail en ligne gratuits tels que Ubuntu Online, Fedora Online, l'émulateur en ligne Windows ou l'émulateur en ligne MAC OS

PROGRAMME:

Nom


PDL::PP - Génère des routines PDL à partir de descriptions concises

SYNOPSIS


par exemple

pp_def(
'sommet',
Pars => 'a(n); [o]b();',
Code => q{
tmp double=0 ;
boucle(n) %{
tmp += $a();
%}
$b() = tmp;
},
);

pp_done();

FONCTIONS


Voici une liste de référence rapide des fonctions fournies par PDL::PP.

pp_add_boot
Ajouter du code à la section BOOT du fichier XS généré

pp_add_exported
Ajouter des fonctions à la liste des fonctions exportées

pp_add_isa
Ajouter des entrées à la liste @ISA

pp_addbegin
Définit le code à ajouter en haut du fichier .pm généré

pp_addhdr
Ajouter du code et inclure à la section C du fichier XS généré

pp_addpm
Ajouter du code au fichier .pm généré

pp_addxs
Ajouter du code XS supplémentaire au fichier XS généré

pp_beginwrap
Ajouter un wrapping de bloc BEGIN au code pour le fichier .pm généré

pp_bless
Définit le package auquel le code XS est ajouté (la valeur par défaut est PDL)

pp_boundscheck
État de contrôle de l'activité de vérification des limites PDL

pp_core_importList
Spécifiez ce qui est importé de PDL::Core

pp_def
Définir une nouvelle fonction PDL

pp_deprecate_module
Ajouter des avertissements d'exécution et de POD concernant un module obsolète

pp_fait
Marquer la fin des définitions PDL::PP dans le fichier

pp_export_nothing
Effacer la liste d'exportation pour votre module généré

pp_line_numbers
Ajoutez des informations sur le numéro de ligne pour simplifier le débogage du code PDL::PP

pp_setversion
Définir la version des fichiers .pm et .xs

APERÇU


Pourquoi avons-nous besoin de PP ? Plusieurs raisons : premièrement, nous voulons pouvoir générer des sous-programmes
code pour chacun des types de données PDL (PDL_Byte, PDL_Short,. etc). AUTOMATIQUEMENT. Deuxièmement,
en se référant à des tranches de tableaux PDL en Perl (par exemple "$a->slice('0:10:2,:')" ou autre
des choses comme la transposition), c'est bien de pouvoir le faire de manière transparente et de pouvoir
pour le faire 'sur place' - c'est-à-dire ne pas avoir à faire une copie mémoire de la section. poignées PP
tous les éléments et décalages arithmétiques nécessaires pour vous. Il y a aussi les notions de
threading (appel répété de la même routine pour plusieurs tranches, voir PDL::Indexing)
et dataflow (voir PDL::Dataflow) que permet l'utilisation de PP.

Dans une grande partie de ce qui suit, nous supposerons que le lecteur est familiarisé avec les concepts de
les threads implicites et explicites et les manipulations d'index dans PDL. Si vous n'avez pas encore
entendu parler de ces concepts ou ne sont pas très à l'aise avec eux, il est temps de vérifier
PDL::Indexation.

Comme vous pouvez l'apprécier d'après son nom PDL::PP est un préprocesseur, c'est-à-dire qu'il étend le code via
substitutions pour créer un véritable code C. Techniquement, la sortie est du code XS (voir perlxs) mais
qui est très proche de C.

Alors, comment utilisez-vous PP? Eh bien, la plupart du temps, vous écrivez simplement du code C ordinaire, à l'exception de
constructions spéciales de PP qui prennent la forme :

$quelque chose (autre chose)

ou:

PPfonction %{

%}

La construction PP la plus importante est la forme "$array()". Considérez le PP très simple
fonction pour additionner les éléments d'un vecteur 1D (en fait, c'est très similaire à la réelle
code utilisé par 'sumover'):

pp_def('sommet',
Pars => 'a(n); [o]b();',
Code => q{
temp double ;
tmp = 0 ;
boucle(n) %{
tmp += $a();
%}
$b() = tmp;
}
);

Ce qui se passe? La ligne "Pars =>" est très importante pour PP - elle spécifie tous les
arguments et leur dimensionnalité. Nous appelons cela le Signature de la fonction PP (comparer
aussi les explications dans PDL::Indexing). Dans ce cas, la routine prend une fonction 1-D comme
entrée et renvoie un scalaire 0-D en sortie. La construction PP "$a()" est utilisée pour accéder
éléments du tableau a(n) pour vous - PP remplit tout le code C requis.

Vous remarquerez que nous utilisons l'opérateur guillemet simple "q{}". Ce n'est pas un
accident. Vous souhaitez généralement utiliser des guillemets simples pour désigner vos sections de code PP. PDL::PP
utilise "$var()" pour son analyse et si vous n'utilisez pas de guillemets simples, Perl essaiera de
interpolez "$var()". De plus, l'utilisation de l'opérateur apostrophe "q" avec des accolades permet de
on dirait que vous créez un bloc de code, ce que vous voulez dire. (Perl est assez intelligent pour
recherchez les accolades imbriquées et ne fermez pas la citation jusqu'à ce qu'elle trouve le bouclé correspondant
accolade, il est donc sûr d'avoir des blocs imbriqués.) Dans d'autres circonstances, comme lorsque vous êtes
assembler un bloc de code à l'aide de concaténations de chaînes, il est souvent plus facile à utiliser
de vraies guillemets simples comme

Code => 'quelque chose'.$interpolable.'quelquechose d'autre;'

Dans le cas simple ici où tous les éléments sont accessibles, la construction PP "loop(n) %{ ...
%}" est utilisé pour boucler sur tous les éléments de la dimension "n". Notez cette caractéristique de PP : ALL
LES DIMENSIONS SONT SPÉCIFIÉES PAR NOM.

Ceci est rendu plus clair si nous évitons le PP boucle() construire et écrire la boucle explicitement
en utilisant le C conventionnel :

pp_def('sommet',
Pars => 'a(n); [o]b();',
Code => q{
int i,n_size ;
temp double ;
n_taille = $TAILLE(n);
tmp = 0 ;
pour(i=0; je
tmp += $a(n=>i);
}
$b() = tmp;
},
);

qui fait la même chose que précédemment, mais est plus long. Vous pouvez voir pour obtenir l'élément "i" de
a() nous disons "$a(n=>i)" - nous spécifions la dimension par le nom "n". En 2D on peut dire :

Pars=>'a(m,n);',

tmp += $a(m=>i,n=>j);


La syntaxe "m=>i" emprunte aux hachages Perl, qui sont en fait utilisés dans l'implémentation
de PP. On pourrait aussi dire "$a(n=>j,m=>i)" car l'ordre n'est pas important.

Vous pouvez également voir dans l'exemple ci-dessus l'utilisation d'une autre construction PP - $SIZE(n) pour obtenir
la longueur de la dimension "n".

Il convient cependant de noter que vous ne devriez pas écrire une boucle C explicite lorsque vous pourriez
ont utilisé la construction PP "loop" puisque PDL::PP vérifie automatiquement les limites de boucle pour
vous, l'utilisation de "loop" rend le code plus concis, etc. Mais il y a certainement des situations
où vous avez besoin d'un contrôle explicite de la boucle et maintenant vous savez comment le faire ;).

Pour revoir « Pourquoi PP ? » - le code ci-dessus pour sommet() sera généré pour chaque type de données. Ce
fonctionnera sur des tranches de tableaux « en place ». Il s'enfilera automatiquement - par exemple si un 2D
array est donné, il sera appelé à plusieurs reprises pour chaque ligne 1D (vérifiez à nouveau PDL::Indexing for
les détails de l'enfilage). Et puis b() sera un tableau 1D des sommes de chaque ligne. Nous pourrions
appelez-le avec $a->xchg(0,1) pour additionner les colonnes à la place. Et le traçage des flux de données, etc. sera
disponible.

Vous pouvez voir que PP évite au programmeur d'écrire beaucoup de code C inutilement répétitif --
à notre avis, c'est l'une des meilleures fonctionnalités de PDL permettant d'écrire de nouvelles sous-routines C
pour PDL un exercice étonnamment concis. Une deuxième raison est la capacité de faire étendre le PP
vos définitions de code concises dans différents codes C en fonction des besoins de l'ordinateur
architecturale en question. Imaginez par exemple que vous avez la chance d'avoir un supercalculateur à
tes mains; dans ce cas, vous voulez que PDL::PP génère certainement du code qui profite
des fonctionnalités de vectorisation/calcul parallèle de votre machine (il s'agit d'un projet pour le
futur). Dans tous les cas, l'essentiel est que votre code inchangé devrait toujours s'étendre à
code XS fonctionnel même si les éléments internes de PDL ont changé.

De plus, parce que vous générez le code dans un script Perl réel, il y a beaucoup de plaisir
choses que vous pouvez faire. Disons que vous devez écrire à la fois sumit (comme ci-dessus) et multit.
Avec un peu de créativité, nous pouvons faire

for({Name => 'sumit', Init => '0', Op => '+='},
{Name => 'multit', Init => '1', Op => '*='}) {
pp_def($_->{Nom},
Pars => 'a(n); [o]b();',
Code => '
temp double ;
tmp = '.$_->{Init}.';
boucle(n) %{
tmp '.$_->{Op}.' $a();
%}
$b() = tmp;
');
}

qui définit les deux fonctions facilement. Maintenant, si vous devez plus tard modifier la signature ou
dimensionnalité ou autre, vous n'avez besoin de changer qu'un seul endroit dans votre code. Oui bien sûr,
votre éditeur a 'couper-coller' et 'rechercher et remplacer' mais c'est quand même moins
gênant et certainement plus difficile d'oublier un seul endroit et d'avoir des bugs étranges
s'infiltrer. De plus, l'ajout de « orit » (au niveau du bit ou) plus tard est une simple ligne.

Et rappelez-vous, vous avez vraiment toutes les capacités de Perl avec vous - vous pouvez très facilement lire
n'importe quel fichier d'entrée et créer des routines à partir des informations contenues dans ce fichier. Pour des cas simples comme
ci-dessus, l'auteur (Tjl) privilégie actuellement la syntaxe de hachage comme ci-dessus - ce n'est pas trop
beaucoup plus de caractères que la syntaxe de tableau correspondante mais beaucoup plus facile à comprendre et
changer.

Nous devons mentionner ici également la possibilité d'obtenir le pointeur vers le début des données dans
mémoire - une condition préalable à l'interfaçage de PDL avec certaines bibliothèques. Ceci est géré avec le
directive "$P(var)", voir ci-dessous.

Lorsque vous commencez à travailler sur une nouvelle fonction pp_def'ined, si vous faites une erreur, vous
trouver une pile d'erreurs du compilateur indiquant les numéros de ligne dans le fichier XS généré. Si tu
savoir lire les fichiers XS (ou si vous voulez apprendre à la dure), vous pouvez ouvrir le
XS généré et recherchez le numéro de ligne avec l'erreur. Cependant, une récente
en plus de PDL::PP aide à signaler le numéro de ligne correct de vos erreurs :
"pp_line_numbers". En travaillant avec l'exemple original du sommet, si vous aviez une faute d'orthographe de
tmp dans votre code, vous pouvez changer le code (erroneos) en quelque chose comme ceci et le
le compilateur vous donnerait beaucoup plus d'informations utiles :

pp_def('sommet',
Pars => 'a(n); [o]b();',
Code => pp_line_numbers(__LINE__, q{
temp double ;
tmp = 0 ;
boucle(n) %{
tmp += $a();
%}
$b() = rmp;
})
);

Pour la situation ci-dessus, mon compilateur me dit :


test.pd:15 : erreur : 'rmp' non déclaré (première utilisation dans cette fonction)


Dans mon exemple de script (appelé test.pd), la ligne 15 est exactement la ligne à laquelle j'ai fait mon
faute de frappe : "rmp" au lieu de "tmp".

Ainsi, après cet aperçu rapide de la saveur générale de la programmation de routines PDL en utilisant
PDL::PP résumons dans quelles circonstances vous devriez réellement l'utiliser
préprocesseur/précompilateur. Vous devez utiliser PDL::PP si vous voulez

· interface PDL vers une bibliothèque externe

· écrivez un algorithme qui serait lent s'il était codé en Perl (ce n'est pas aussi souvent que vous
pense; jetez d'abord un œil au threading et au flux de données).

· être développeur PDL (et même là ce n'est pas obligatoire)

ATTENTION


De par son architecture, PDL::PP peut être à la fois flexible et simple d'utilisation, d'une part,
pourtant exubérante compliquée en même temps. Actuellement, une partie du problème est cette erreur
les messages ne sont pas très informatifs et si quelque chose ne va pas, vous feriez mieux de savoir ce que vous
font et être capable de se frayer un chemin à travers les internes (ou être capable de comprendre par
essai et erreur ce qui ne va pas avec vos arguments à "pp_def"). Bien que des travaux soient en cours pour
produire de meilleurs avertissements, n'ayez pas peur d'envoyer vos questions à la liste de diffusion si
vous rencontrez des problèmes.

DESCRIPTION


Maintenant que vous savez comment utiliser "pp_def" pour définir de nouvelles fonctions PDL, il est temps de
expliquer la syntaxe générale de "pp_def". "pp_def" prend comme arguments d'abord le nom du
fonction que vous définissez, puis une liste de hachage pouvant contenir différentes clés.

Sur la base de ces clés, PP génère un code XS et un fichier .pm. La fonction "pp_done" (voir
exemple dans le SYNOPSIS) est utilisé pour indiquer à PDL::PP qu'il n'y a plus de définitions dans
ce fichier et il est temps de générer le .xs et
fichier .pm.

En conséquence, il peut y avoir plusieurs pp_def() appels à l'intérieur d'un fichier (par convention fichiers
avec le code PP ont l'extension .pd ou .pp) mais généralement une seule pp_done().

Il existe deux principaux types d'utilisation de pp_def(), l'« opération de données » et la « tranche
prototypes d'opération.

L'« opération de données » est utilisée pour prendre des données, les déformer et produire d'autres données ; cette
comprend par exemple l'opération '+', la matrice inverse, le sumover etc et tous les exemples
nous en avons parlé dans ce document jusqu'à présent. Threading implicite et explicite et le
la création du résultat est prise en charge automatiquement dans ces opérations. Vous pouvez même
faire un flux de données avec "sumit", "sumover", etc (ne soyez pas consterné si vous ne comprenez pas le
concept de flux de données en PDL très bien encore ; c'est encore très expérimental).

L'« opération de découpage » est un autre type d'opération : dans une opération de découpage, vous n'êtes pas
modifier des données, vous définissez des correspondances entre différents éléments de deux
piddles (les exemples incluent les définitions de fonction de manipulation d'index/tranchage dans le fichier
tranches.pd cela fait partie de la distribution PDL ; mais attention, ce n'est pas un niveau d'initiation
truc).

Si PDL a été compilé avec la prise en charge des mauvaises valeurs (c'est-à-dire "WITH_BADVAL => 1"), alors des
des clés sont requises pour "pp_def", comme expliqué ci-dessous.

Si vous souhaitez simplement communiquer avec une bibliothèque externe (par exemple, certaines
bibliothèque d'algèbre/matrice linéaire), vous aurez généralement besoin de « l'opération sur les données », nous allons donc
pour en discuter d'abord.

Sauvegarde de opération


A simple exemple
Dans l'exploitation des données, vous devez savoir de quelles dimensions de données vous avez besoin. Tout d'abord, un exemple
avec des scalaires :

pp_def('ajouter',
Pars => 'a(); b(); [o]c();',
Code => '$c() = $a() + $b();'
);

Cela semble un peu étrange mais disséquons-le. La première ligne est simple : nous définissons un
routine avec le nom 'ajouter'. La deuxième ligne déclare simplement nos paramètres et le
les parenthèses signifient qu'il s'agit de scalaires. Nous appelons la chaîne qui définit nos paramètres et
leur dimensionnalité la Signature de cette fonction. Pour sa pertinence par rapport à
les threads et les manipulations d'index vérifient la page de manuel PDL::Indexing.

La troisième ligne est l'opération proprement dite. Vous devez utiliser les signes dollar et les parenthèses
faire référence à vos paramètres (cela changera probablement à un moment donné dans le futur, une fois qu'un
bonne syntaxe est trouvée).

Ces lignes sont tout ce qui est nécessaire pour définir réellement la fonction pour PDL (enfin,
en fait ce n'est pas le cas ; vous devez en plus écrire un Makefile.PL (voir ci-dessous) et construire le
module (quelque chose comme 'perl Makefile.PL; make'); mais ignorons cela pour le moment).
Alors maintenant tu peux faire

utiliser MonModule ;
$a = pdl 2,3,4 ;
$b = pdl 5 ;

$c = ajouter($a,$b);
# ou
add($a,$b,($c=null)); # Forme alternative, utile si $c a été
# prédéfini sur quelque chose de gros, pas utile ici.

et que le threading fonctionne correctement (le résultat est $c == [7 8 9]).

La Pars section: le Signature of a PP fonction
En voyant l'exemple de code ci-dessus, vous vous demanderez probablement : quel est cet étrange "$c=null"
syntaxe dans le deuxième appel à notre nouvelle fonction « add » ? Si vous jetez un autre coup d'œil à la
définition de "ajouter", vous remarquerez que le troisième argument "c" est marqué avec le
qualificateur "[o]" qui indique à PDL::PP qu'il s'agit d'un argument de sortie. Donc, l'appel ci-dessus à
add signifie "créer un nouveau $c à partir de zéro avec des dimensions correctes" - "null" est une valeur spéciale
jeton pour 'vide piddle' (vous pourriez demander pourquoi nous n'avons pas utilisé la valeur "undef" pour signaler cela
au lieu du "null" spécifique au PDL ; nous y réfléchissons actuellement ;).

[Cela devrait également être expliqué dans une autre section du manuel !!] La raison pour laquelle
avoir cette syntaxe comme alternative est que si vous avez vraiment d'énormes piddles, vous pouvez faire

$c = PDL->null ;
for (une longue boucle) {
# munge a,b
ajouter($a,$b,$c);
# munge c, remettre quelque chose à a,b
}

et évitez d'allouer et de désallouer $c à chaque fois. Il est attribué une fois au premier
ajouter() et ensuite la mémoire reste jusqu'à ce que $c soit détruit.

Si tu dis juste

$c = ajouter($a,$b);

le code généré par PP remplira automatiquement "$c=null" et renverra le résultat. Si
vous voulez en savoir plus sur les raisons pour lesquelles PDL::PP prend en charge ce style où la sortie
les arguments sont donnés comme derniers arguments, vérifiez la page de manuel PDL::Indexing.

"[o]" n'est pas le seul qualificatif qu'un argument pdl peut avoir dans la signature. Un autre
Le qualificatif important est l'option "[t]" qui marque un pdl comme temporaire. Qu'est ce que ça
moyenne? Vous dites à PDL::PP que ce pdl n'est utilisé que pour des résultats temporaires au cours de
le calcul et vous n'êtes pas intéressé par sa valeur après que le calcul a été
complété. Mais pourquoi PDL::PP voudrait-il savoir cela en premier lieu ? La raison
est étroitement lié aux concepts de création automatique de pdl (vous en avez entendu parler ci-dessus) et
filetage implicite. Si vous utilisez le filetage implicite, la dimensionnalité de automatiquement
pdls créé est en fait plus grand que celui spécifié dans la signature. Avec "[o]" marqué
Les pdls seront créés pour qu'ils aient les dimensions supplémentaires requises par le nombre
des dimensions de filetage implicites. Cependant, lors de la création d'un fichier pdl temporaire, il ne sera toujours que
être assez grand pour qu'il puisse contenir le résultat pendant une itération dans une boucle de thread, c'est-à-dire
aussi grand que requis par la signature. Donc moins de mémoire est gaspillée lorsque vous marquez un pdl comme
temporaire. Deuxièmement, vous pouvez utiliser la création automatique de sortie avec des pdls temporaires même lorsque vous
utilisent des threads explicites qui sont interdits pour les pdls de sortie normaux signalés par "[o]"
(voir PDL::Indexation).

Voici un exemple où nous utilisons le qualificateur [t]. On définit la fonction "callf" qui
appelle une routine C "f" qui a besoin d'un tableau temporaire de la même taille et du même type que le tableau
"a" (désolé pour la référence directe pour $P ; c'est un accès par pointeur, voir ci-dessous) :

pp_def('appel',
Pars => 'a(n); [t] tmp(n); [o] b()',
Code => 'int ns = $SIZE(n);
f($P(a),$P(b),$P(tmp),ns);
'
);

Argument dimensions et le Signature
Nous venons de parler des dimensions des pdls et de la signature. Comment sont-ils liés?
Disons que nous voulons ajouter un scalaire + le numéro d'index à un vecteur :

pp_def('add2',
Pars => 'a(n); b(); [o]c(n);',
Code => 'boucle(n) %{
$c() = $a() + $b() + n ;
%}'
);

Il y a plusieurs points à remarquer ici : d'abord, l'argument "Pars" contient maintenant le n
arguments pour montrer que nous avons une seule dimension dans a et c. Il est important de noter
que les dimensions sont des entités réelles auxquelles on accède par nom, donc cela déclare a et c à
avoir la même premières dimensions. Dans la plupart des définitions de PP, la taille des dimensions nommées sera
être défini à partir des dimensions respectives des pdls sans sortie (ceux sans indicateur "[o]") mais
Parfois, vous voudrez peut-être définir la taille d'une dimension nommée explicitement via un
paramètre entier. Voir ci-dessous dans la description de la section "OtherPars" comment cela fonctionne.

Constante argument dimensions in le Signature
Supposons que vous vouliez qu'un piddle de sortie soit créé automatiquement et que vous sachiez qu'à chaque
appeler sa dimension aura la même taille (disons 9) quelles que soient les dimensions de la
piques d'entrée. Dans ce cas, vous utilisez la syntaxe suivante dans la section Pars pour spécifier
la taille de la dimension:

' [o] y(n=9) ; '

Comme prévu, des dimensions supplémentaires requises par le filetage seront créées si nécessaire. Si tu
besoin d'attribuer une dimension nommée selon une formule plus compliquée (qu'une constante)
vous devez utiliser la clé "RedoDimsCode" décrite ci-dessous.

Type conversions et le Signature
La signature détermine également les conversions de type qui seront effectuées lorsqu'un PP
la fonction est invoquée. Alors, que se passe-t-il lorsque nous invoquons l'un de nos
fonctions avec des pdls de type différent, par exemple

add2($a,$b,($ret=null));

où $a est de type "PDL_Float" et $b de type "PDL_Short" ? Avec la signature comme indiqué dans
la définition de "add2" au-dessus du type de données de l'opération (tel que déterminé au moment de l'exécution) est
celui de la pdl avec le type 'le plus élevé' (la séquence est byte < short < ushort < long < float
< double). Dans l'exemple add2 le type de données de l'opération est float ($a a que
Type de données). Tous les arguments pdl sont ensuite convertis en ce type de données (ils ne sont pas
converti sur place mais une copie avec le bon type est créée si un argument pdl n'a pas
le type d'opération). Les pdls nuls ne contribuent pas à un type dans la détermination du
type d'opération. Cependant, ils seront créés avec le type de données de l'opération ;
ici, par exemple, $ret sera de type float. Vous devez connaître ces règles lorsque
appeler des fonctions PP avec des pdls de différents types pour prendre le stockage supplémentaire et
les exigences d'exécution en compte.

Ces conversions de type sont correctes pour la plupart des fonctions que vous définissez normalement avec "pp_def".
Cependant, il existe certains cas où le comportement de conversion de type légèrement modifié est
voulu. Dans ces cas, des qualificateurs supplémentaires dans la signature peuvent être utilisés pour spécifier le
propriétés souhaitées en ce qui concerne la conversion de type. Ces qualificatifs peuvent être combinés avec
ceux que nous avons déjà rencontrés (le création qualificatifs "[o]" et "[t]"). Allons-y
via la liste des qualificatifs qui modifient le comportement de conversion de type.

Le plus important est le qualificateur "int" qui est pratique lorsqu'un argument pdl
représente les indices dans un autre pdl. Regardons un exemple de "PDL::Ufunc":

pp_def('maximum_ind',
Pars => 'a(n); int [o] b()',
Code => '$GENERIC() cur;
int curin;
boucle(n) %{
if (!n || $a() > cur) {cur = $a(); curind = n;}
%}
$b() = curind;',
);

La fonction "maximum_ind" trouve l'indice du plus grand élément d'un vecteur. Si tu regardes
à la signature, vous remarquez que l'argument de sortie "b" a été déclaré avec le
qualificatif "int" supplémentaire. Cela a les conséquences suivantes pour les conversions de type :
quel que soit le type de la pdl d'entrée "a" la pdl de sortie "b" sera de type "PDL_Long"
ce qui est logique puisque "b" représentera un indice dans "a". De plus, si vous appelez le
fonction avec une sortie existante pdl "b" son type n'influencera pas le type de données du
fonctionnement (voir ci-dessus). Par conséquent, même si "a" est d'un type plus petit que "b", il ne sera pas
converti pour correspondre au type de "b" mais reste inchangé, ce qui économise de la mémoire et des cycles CPU
et est la bonne chose à faire lorsque "b" représente des indices. Notez également que vous pouvez utiliser le
qualificateur 'int' avec d'autres qualificatifs (les qualificatifs "[o]" et "[t]"). La commande est
significatif -- les qualificatifs de type précèdent les qualificatifs de création ("[o]" et "[t]").

L'exemple ci-dessus illustre également l'utilisation typique de la macro "$GENERIC()". Il s'élargit
au type courant dans une boucle dite générique. Qu'est-ce qu'une boucle générique ? Comme vous déjà
entendu qu'une fonction PP a un type de données d'exécution déterminé par le type des arguments pdl
il a été invoqué avec. Le code XS généré par PP pour cette fonction contient donc un
switch comme "switch (type) {case PDL_Byte: ... case PDL_Double: ...}" qui sélectionne une case
basé sur le type de données d'exécution de la fonction (c'est ce qu'on appelle un type « boucle » parce qu'il y a
est une boucle dans le code PP qui génère les cas). Dans tous les cas votre code est inséré une fois
pour chaque type de PDL dans cette instruction switch. La macro "$GENERIC()" se développe simplement en
type respectif dans chaque copie de votre code analysé dans cette instruction "switch", par exemple, dans le
"case PDL_Byte" section "cur" se développera en "PDL_Byte" et ainsi de suite pour l'autre cas
déclarations. Je suppose que vous vous rendez compte qu'il s'agit d'une macro utile pour conserver les valeurs de pdls dans certains
code.

Il existe quelques autres qualificatifs avec des effets similaires à "int". Pour votre
commodité, il y a les qualificatifs « flotteur » et « double » avec des conséquences analogues sur
tapez les conversions comme "int". Supposons que vous ayez un très grand tableau pour lequel vous voulez
calculez les sommes des lignes et des colonnes avec un équivalent de la fonction "sumover". Cependant, avec
la définition normale de " sumover ", vous pourriez rencontrer des problèmes lorsque vos données sont, par exemple de
tapez court. Un appel comme

sumover($large_pdl,($sommes = null));

se traduira par $sums de type short et est donc sujet à des erreurs de débordement si
$large_pdl est un très grand tableau. d'autre part appeler

@dims = $large_pdl->dims ; décaler @dims ;
sumover($large_pdl,($sommes = zéros(double,@dims)));

n'est pas non plus une bonne alternative. Maintenant, nous n'avons pas de problèmes de débordement avec les sommes $ mais à
le coût d'une conversion de type de $large_pdl en double, quelque chose de mauvais si c'est vraiment
une grande pdl. C'est là que « double » est utile :

pp_def('sumoverd',
Pars => 'a(n); double [o] b()',
Code => 'double tmp=0;
boucle(n) %{ tmp += a(); %}
$b() = tmp;',
);

Cela nous permet de contourner les problèmes de conversion de type et de débordement. Encore une fois, analogue au
Le qualificateur "int" "double" fait que "b" est toujours de type double quel que soit le type
de « a » sans entraîner une conversion de type de « a » comme effet secondaire.

Enfin, il y a les qualificatifs "type+" où type est l'un des "int" ou "float". Quoi
est-ce que cela veut dire. Illustrons le qualificateur "int+" avec la définition réelle de
résumé :

pp_def('sumover',
Pars => 'a(n); int+ [o] b()',
Code => '$GENERIQUE(b) tmp=0;
boucle(n) %{ tmp += a(); %}
$b() = tmp;',
);

Comme nous l'avions déjà vu pour les qualificatifs "int", "float" et "double", un pdl marqué d'un
Le qualificatif "type+" n'influence pas le type de données de l'opération pdl. Sa signification est
"faites ce pdl au moins de type "type" ou supérieur, comme requis par le type de la
opération". Dans l'exemple de sumover, cela signifie que lorsque vous appelez la fonction avec un "a"
de type PDL_Short le pdl de sortie sera de type PDL_Long (comme cela aurait été le
cas avec le qualificateur "int"). Cela essaie à nouveau d'éviter les problèmes de débordement lors de l'utilisation
petits types de données (par exemple, images d'octets). Cependant, lorsque le type de données de l'opération est supérieur
que le type spécifié dans le qualificateur "type+" "b" sera créé avec le type de données de
l'opération, par exemple lorsque "a" est de type double alors "b" sera également double. Nous esperons
vous convenez que c'est un comportement raisonnable pour " sumover ". Il devrait être évident comment le
Le qualificatif "float+" fonctionne par analogie. Il peut devenir nécessaire de pouvoir spécifier un ensemble
de types alternatifs pour les paramètres. Cependant, cela ne sera probablement pas mis en œuvre
jusqu'à ce que quelqu'un en trouve une utilisation raisonnable.

Notez que nous devions maintenant spécifier la macro $GENERIC avec le nom du pdl pour dériver le
tapez à partir de cet argument. Pourquoi donc? Si vous avez scrupuleusement suivi nos explications, vous
ont réalisé que dans certains cas "b" aura un type différent du type du
opération. L'appel de la macro '$GENERIC' avec "b" comme argument garantit que le type
sera toujours le même que celui de "b" dans cette partie de la boucle générique.

C'est à peu près tout ce qu'il y a à dire sur la section "Pars" dans un appel "pp_def". Vous devriez
rappelez-vous que cette section définit le Signature d'une fonction définie par PP, vous pouvez utiliser
plusieurs options pour qualifier certains arguments en tant qu'arguments de sortie et temporaires et tous
les dimensions auxquelles vous pourrez vous référer ultérieurement dans la section "Code" sont définies par leur nom.

Il est important que vous compreniez la signification de la signature puisque dans la dernière PDL
versions, vous pouvez l'utiliser pour définir des fonctions threadées depuis Perl, c'est-à-dire ce que nous appelons
Perl niveau filetage. Veuillez vérifier PDL::Indexing pour plus de détails.

La Code
La section "Code" contient le code XS réel qui sera dans la partie la plus interne d'un
boucle de thread (si vous ne savez pas ce qu'est une boucle de thread, vous n'avez toujours pas lu
PDL::Indexation; faites-le maintenant ;) après que toutes les macros PP (comme $ GENERIC) et les fonctions PP aient été
étendu (comme la fonction "boucle" que nous allons expliquer ensuite).

Reprenons rapidement l'exemple du " sumover " :

pp_def('sumover',
Pars => 'a(n); int+ [o] b()',
Code => '$GENERIQUE(b) tmp=0;
boucle(n) %{ tmp += a(); %}
$b() = tmp;',
);

La construction « boucle » dans la section « Code » fait également référence au nom de la dimension afin que vous ne
besoin de préciser d'éventuelles limites : la boucle est correctement dimensionnée et tout est fait pour vous,
nouveau.

Ensuite, il y a le fait surprenant que "$a()" et "$b()" font ne sauraient contenir l'index. Cette
n'est pas nécessaire parce que nous bouclons n et les deux variables savent quelles dimensions
ils ont donc ils savent automatiquement qu'ils sont en boucle.

Cette fonctionnalité est très pratique dans de nombreux endroits et permet un code beaucoup plus court. De
bien sûr, il y a des moments où vous voulez contourner cela ; voici une fonction qui fait un
matrice symétrique et sert d'exemple pour coder une boucle explicite :

pp_def('symm',
Pars => 'a(n,n); [o]c(n,n);',
Code => 'boucle(n) %{
entier n2;
for(n2=n; n2<$SIZE(n); n2++) {
$c(n0 => n, n1 => n2) =
$c(n0 => n2, n1 => n) =
$a(n0 => n, n1 => n2) ;
}
%}
'
);

Décortiquons ce qui se passe. Premièrement, qu'est-ce que cette fonction est censée faire ? De son
signature, vous voyez qu'il faut une matrice 2D avec un nombre égal de colonnes et de lignes et
génère une matrice de la même taille. À partir d'une matrice d'entrée donnée $a, il calcule un
matrice de sortie $c (symétrique au sens matriciel où A^T = A où ^T signifie matrice
transposer, ou dans le jargon PDL $c == $c->xchg(0,1)). Il le fait en utilisant uniquement les valeurs
sur et en dessous de la diagonale de $a. Dans la matrice de sortie $c toutes les valeurs sur et en dessous du
diagonale sont les mêmes que celles de $a tandis que celles au-dessus de la diagonale sont une image miroir de
ceux au-dessous de la diagonale (au-dessus et au-dessous sont ici interprétés de la façon dont PDL imprime
pdf 2D). Si cette explication vous semble encore un peu étrange, allez-y, faites un petit fichier
dans laquelle vous écrivez cette définition, construisez la nouvelle extension PDL (voir la section sur
Makefiles pour le code PP) et essayez-le avec quelques exemples.

Après avoir expliqué ce que la fonction est censée faire, il y a quelques points qui valent la peine
notant du point de vue syntaxique. Tout d'abord, nous obtenons la taille de la dimension nommée
"n" à nouveau en utilisant la macro $SIZE. Deuxièmement, il y a soudain ces drôles de "n0" et "n1"
indexer les noms dans le code bien que la signature ne définisse que la dimension "n". Pourquoi ça? Les
la raison devient claire lorsque vous notez que la première et la deuxième dimension de $a et $b
sont nommés "n" dans la signature de "symm". Cela indique à PDL::PP que le premier et le deuxième
dimension de ces arguments doit avoir la même taille. Sinon la fonction générée
générera une erreur d'exécution. Cependant, maintenant dans un accès à $a et $c PDL::PP ne peut pas comprendre
à quel index "n" se réfère plus juste à partir du nom de l'index. Par conséquent, la
les indices avec des noms de dimension égaux sont numérotés de gauche à droite à partir de 0, par exemple dans
l'exemple ci-dessus "n0" fait référence à la première dimension de $a et $c, "n1" à la seconde et
bientôt.

Dans tous les exemples jusqu'à présent, nous n'avons utilisé que les membres "Pars" et "Code" du hachage qui
a été passé à "pp_def". Il existe certainement d'autres clés reconnues par PDL::PP et
nous en entendrons parler au cours de ce document. Trouvez un (non exhaustif)
liste des touches dans l'annexe A. Une liste de macros et de fonctions PP (nous n'avons rencontré que
certains de ceux dans les exemples ci-dessus encore) qui sont développés dans les valeurs de l'argument de hachage
à "pp_def" est résumé à l'annexe B.

À ce stade, il pourrait être approprié de mentionner que PDL::PP n'est pas complètement statique,
un ensemble de routines bien conçu (comme le dit Tuomas : « arrêtez de penser au PP comme un ensemble de
routines gravées dans la pierre") mais plutôt une collection de choses que l'auteur PDL::PP
(Tuomas J. Lukka) a estimé qu'il devrait souvent écrire dans ses routines d'extension PDL.
PP essaie d'être extensible afin qu'à l'avenir, à mesure que de nouveaux besoins apparaissent, un nouveau code commun puisse
y être abstrait. Si vous voulez en savoir plus sur les raisons pour lesquelles vous pourriez vouloir changer
PDL::PP et comment le faire consultez la section sur les internes de PDL::PP.

Maniabilité mauvais valeurs
Si vous n'avez pas compilé le support des mauvaises valeurs dans PDL, vous pouvez ignorer cette section et le
clés associées : "BadCode", "HandleBad", ... (essayez d'imprimer la valeur de
$PDL::Bad::Status - s'il est égal à 0, continuez tout droit).

Plusieurs touches et macros sont utilisées lors de l'écriture de code pour gérer les mauvaises valeurs. La première
l'une est la touche "HandleBad":

HandleBad => 0
Cela marque une routine pp comme ne pas gérer les mauvaises valeurs. Si cette routine est envoyée piddles
avec leur ensemble "badflag", puis un message d'avertissement est imprimé sur STDOUT et les piddles
sont traités comme si la valeur utilisée pour représenter les mauvaises valeurs était un nombre valide. Les
La valeur "badflag" n'est pas propagée aux piddles de sortie.

Un exemple d'utilisation est celui des routines FFT, qui n'ont généralement pas de moyen
d'ignorer une partie des données.

HandleBad => 1
Cela amène PDL::PP à écrire du code supplémentaire qui garantit que la section BadCode est utilisée, et
que la macro "$ISBAD()" (et ses confrères) fonctionne.

HandleBad n'est pas donné
Si l'un des piddles d'entrée a son "badflag" défini, alors les piddles de sortie seront
ont leur "badflag" défini, mais tout BadCode fourni est ignoré.

La valeur de "HandleBad" permet de définir le contenu de la clé "BadDoc", si elle n'est pas
donné.

Pour gérer les mauvaises valeurs, le code doit être écrit quelque peu différemment ; par exemple,

$c() = $a() + $b();

devient quelque chose comme

if ( $a() != BADVAL && $b() != BADVAL ) {
$c() = $a() + $b();
} Else {
$c() = MAUVAISVAL;
}

Cependant, nous ne voulons la deuxième version que si de mauvaises valeurs sont présentes dans les piddles d'entrée
(et cette prise en charge des mauvaises valeurs est souhaitée !) - sinon nous voulons en fait le code d'origine.
C'est là qu'intervient la clé "BadCode" ; vous l'utilisez pour spécifier le code à exécuter si mauvais
des valeurs peuvent être présentes, et PP l'utilise à la fois et la section "Code" pour créer quelque chose
comme:

si ( bad_values_are_present ) {
fantaisie_threadloop_stuff {
Code incorrect
}
} Else {
fantaisie_threadloop_stuff {
Code
}
}

Cette approche signifie qu'il n'y a pratiquement pas de surcharge lorsque de mauvaises valeurs ne sont pas présentes
(c'est-à-dire que la routine badflag renvoie 0).

La section BadCode peut utiliser les mêmes macros et constructions en boucle que la section Code.
Cependant, cela ne serait pas très utile sans les macros supplémentaires suivantes :

$ISBAD(var)
Pour vérifier si la valeur d'un piddle est mauvaise, utilisez la macro $ISBAD :

if ( $ISBAD(a()) ) { printf("a() est mauvais\n"); }

Vous pouvez également accéder à des éléments donnés d'un piddle :

if ( $ISBAD(a(n=>l)) ) { printf("l'élément %d de a() est mauvais\n", l); }

$ESTBON(var)
C'est l'opposé de la macro $ISBAD.

$SETBAD(var)
Pour quand vous voulez définir un élément d'un mauvais piddle.

$ISBADVAR(c_var,pdl)
Si vous avez mis en cache la valeur d'un piddle "$a()" dans une variable c ("foo" disons), alors pour
vérifiez si c'est mauvais, utilisez "$ISBADVAR(foo,a)".

$ISGOODVAR(c_var,pdl)
Comme ci-dessus, mais cette fois en vérifiant que la valeur mise en cache n'est pas mauvaise.

$SETBADVAR(c_var,pdl)
Pour copier la mauvaise valeur d'un piddle dans la variable ac, utilisez "$SETBADVAR(foo,a)".

FAIRE: mentionnez les macros "$PPISBAD()" etc.

En utilisant ces macros, le code ci-dessus pourrait être spécifié comme :

Code => '$c() = $a() + $b();',
BadCode => '
si ( $ISBAD(a()) || $ISBAD(b()) ) {
$SETBAD(c());
} Else {
$c() = $a() + $b();
}',

Puisqu'il s'agit de Perl, TMTOWTDI, vous pouvez donc aussi écrire :

BadCode => '
si ( $ISGOOD(a()) && $ISGOOD(b()) ) {
$c() = $a() + $b();
} Else {
$SETBAD(c());
}',

Si vous souhaitez accéder à la valeur du badflag pour un piddle donné, vous pouvez utiliser le
Macros "$PDLSTATExxxx()" :

$PDLSTATEISBAD(pdl)
$PDLSTATEISBON(pdl)
$PDLSTATESETBAD(pdl)
$PDLSTATESETGOOD(pdl)

FAIRE: mentionnez également les options « FindBadStatusCode » et « CopyBadStatusCode » à « pp_def »
comme la clé "BadDoc".

Interfacing Un flux efficace peut augmenter propre/bibliothèque fonctions en utilisant PP
Maintenant, considérez ce qui suit : vous avez votre propre fonction C (qui peut en fait faire partie de
une bibliothèque que vous souhaitez interfacer avec PDL) qui prend comme arguments deux pointeurs vers
vecteurs de double :

void myfunc(int n,double *v1,double *v2);

La façon correcte de définir la fonction PDL est

pp_def('myfunc',
Pars => 'a(n); [o]b(n);',
GenericTypes => ['D'],
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

Le "$P("parLa syntaxe ")" renvoie un pointeur vers le premier élément et les autres éléments sont
garanti de mentir après cela.

Notez qu'ici il est possible de faire beaucoup d'erreurs. Tout d'abord, $SIZE(n) doit être utilisé
au lieu de "n". Deuxièmement, vous ne devriez pas mettre de boucles dans ce code. Troisièmement, nous rencontrons ici
une nouvelle clé de hachage reconnue par PDL::PP : la déclaration "GenericTypes" indique à PDL::PP de
GÉNÉREZ UNIQUEMENT LE TYPELOOP FOP LA LISTE DES TYPES SPÉCIFIÉS. Dans ce cas "double". Ce
a deux avantages. Premièrement, la taille du code compilé est considérablement réduite, deuxièmement si
des arguments non doubles sont passés à "myfunc()" PDL les convertira automatiquement en
doubler avant de passer à la routine C externe et les reconvertir ensuite.

On peut aussi utiliser "Pars" pour qualifier les types d'arguments individuels. Ainsi on pourrait aussi
écrivez ceci comme :

pp_def('myfunc',
Pars => 'double a(n); double [o]b(n);',
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

La spécification de type dans "Pars" exempte l'argument de la variation dans la boucle de type -
au contraire, il est automatiquement converti aussi et à partir du type spécifié. C'est évidemment
utile dans un exemple plus général, par exemple :

void myfunc(int n,float *v1,long *v2);

pp_def('myfunc',
Pars => 'float a(n); long [o]b(n);',
GenericTypes => ['F'],
Code => 'myfunc($SIZE(n),$P(a),$P(b));'
);

Notez que nous utilisons toujours "GenericTypes" pour réduire la taille de la boucle de type, évidemment PP pourrait
en principe, détectez ceci et le faites automatiquement bien que le code n'ait pas encore atteint cet objectif
niveau de sophistication !

Notez enfin que lorsque les types sont convertis automatiquement, il FAUT utiliser le qualificateur "[o]" pour
les variables de sortie ou vos changements difficiles seront optimisés par PP !

Si vous interfacez une grande bibliothèque, vous pouvez automatiser encore plus l'interfaçage. Perl peut
vous aider à nouveau (!) à le faire. Dans de nombreuses bibliothèques, vous avez certaines conventions d'appel.
Cela peut être exploité. Bref, vous pouvez écrire un petit parser (ce qui n'est vraiment pas
difficile en Perl) qui génère ensuite les appels à "pp_def" à partir des descriptions analysées de
les fonctions de cette bibliothèque. Pour un exemple, veuillez vérifier le Slatec interface dans le
Arborescence "Lib" de la distribution PDL. Si vous voulez vérifier (pendant le débogage) quels appels à
PP fonctionne votre code Perl généré un petit package d'aide est pratique qui
remplace les fonctions PP par des fonctions du même nom qui déchargent leurs arguments sur stdout.

Dis le

perl -MPDL::PP::Dump monfichier.pd

pour voir les appels à "pp_def" et amis. Essayez avec ops.pd et slatec.pd. Si vous êtes
intéressé (ou que vous souhaitez l'améliorer), la source est dans Basic/Gen/PP/Dump.pm

Autre macros et fonctions in le Code
Macros : Jusqu'à présent, nous avons rencontré les macros $SIZE, $GENERIC et $P. Maintenant, nous allons
expliquer rapidement les autres macros qui sont développées dans la section "Code" de PDL::PP avec
avec des exemples de leur utilisation.

$T La macro $T est utilisée pour les changements de type. Ceci est très utile lorsque vous devez utiliser
différentes fonctions externes (par exemple une bibliothèque) selon le type d'entrée des arguments.
La syntaxe générale est

$Ttypeletters(type_alternatives)

où "typeletters" est une permutation d'un sous-ensemble des lettres "BSULFD" qui se trouvent
pour Byte, Short, Ushort, etc. et "type_alternatives" sont les extensions lorsque le type
de l'opération PP est égal à celui indiqué par la lettre respective. Faisons
illustrer cette description incompréhensible par un exemple. En supposant que vous ayez deux C
fonctions avec des prototypes

void float_func(float *in, float *out);
void double_func(double *in, double *out);

qui font fondamentalement la même chose mais l'un accepte le float et l'autre les doubles pointeurs.
Vous pouvez les interfacer avec PDL en définissant une fonction générique "foofunc" (qui
appeler la bonne fonction selon le type de transformation) :

pp_def('foofunc',
Pars => ' a(n); [o] b();',
Code => ' $TFD(float_func,double_func) ($P(a),$P(b));'
GenericTypes => [qw(FD)],
);

Veuillez noter que vous ne pouvez pas dire

Code => ' $TFD(float,double)_func ($P(a),$P(b));'

puisque la macro $T se développe avec des espaces de fin, de manière analogue aux macros du préprocesseur C.
La forme légèrement plus longue illustrée ci-dessus est correcte. Si vous voulez vraiment de la brièveté, vous
peut bien sûr faire

'$TBSULFD('.(join ',',map {"long_identifier_name_$_"}
qw/byt court salon non signé flotte dubble/).');'

$PP
La macro $PP est utilisée pour un soi-disant Physique aiguille accèsL’ Physique désigne
quelques optimisations internes de PDL (pour ceux qui sont familiers avec le noyau PDL nous sommes
parler des optimisations de vaffine). Cette macro est principalement à usage interne et vous
ne devrait pas avoir besoin de l'utiliser dans votre code normal.

$COMP (et la section "OtherPars")
La macro $COMP est utilisée pour accéder aux valeurs non pdl dans la section code. Son nom est
dérivé de la mise en œuvre de transformations en PDL. Les variables auxquelles vous pouvez vous référer
à l'aide de $COMP sont membres de la structure ``compilée'' qui représente le PDL
transformation en question mais ne contient pas encore d'informations sur les dimensions
(pour plus de détails, consultez PDL::Internals). Cependant, vous pouvez traiter $COMP comme un
boîte noire sans rien savoir de la mise en œuvre des transformations en PDL.
Alors, quand utiliseriez-vous cette macro ? Son utilisation principale est d'accéder aux valeurs des arguments qui
sont déclarés dans la section "OtherPars" d'une définition "pp_def". Mais alors tu n'as pas
entendu parler de la clé "OtherPars" ?! Prenons un autre exemple qui illustre
utilisation typique des deux nouvelles fonctionnalités :

pp_def('pnmout',
Pars => 'a(m)',
OtherPars => "char* fd",
GenericTypes => [qw(BUSL)],
Code => 'PerlIO *fp;
IO *io ;

io = GvIO(gv_fetchpv($COMP(fd),FALSE,SVt_PVIO));
si (!io || !(fp = IoIFP(io)))
croak("Impossible de comprendre FP");

si (PerlIO_write(fp,$P(a),len) != len)
croak("Erreur d'écriture du fichier pnm");
');

Cette fonction permet d'écrire des données d'un fichier pdl dans un fichier. Le descripteur de fichier est passé
comme une chaîne dans cette fonction. Ce paramètre ne rentre pas dans la section "Pars"
puisqu'il ne peut pas être utilement traité comme un pdl mais plutôt dans le bien nommé
Section "AutresPars". Les paramètres de la section "OtherPars" suivent ceux de la section "Pars"
section lors de l'appel de la fonction, c'est-à-dire

open FILE,">out.dat" ou die "impossible d'ouvrir out.dat" ;
pnmout($pdl,'FILE');

Lorsque vous souhaitez accéder à ce paramètre dans la section du code, vous devez le dire à PP en
en utilisant la macro $COMP, c'est-à-dire que vous écrivez "$COMP(fd)" comme dans l'exemple. Sinon PP
ne saurait pas que le "fd" auquel vous faites référence est le même que celui spécifié dans le
Section "AutresPars".

Une autre utilisation de la section "OtherPars" consiste à définir une dimension nommée dans la signature.
Ayons un exemple de la façon dont cela se fait :

pp_def('setdim',
Pars => '[o] a(n)',
OtherPars => 'int ns => n',
Code => 'loop(n) %{ $a() = n; %}',
);

Cela dit que la dimension nommée "n" sera initialisée à partir de la valeur du autre
paramètre "ns" qui est de type entier (je suppose que vous vous êtes rendu compte que nous utilisons le
Syntaxe "CType From => named_dim"). Vous pouvez maintenant appeler cette fonction de la manière habituelle :

setdim(($a=null),5) ;
imprimer $a ;
[ 0 1 ​​2 ​​3 ​​4 ​​]

Certes cette fonction n'est pas très utile mais elle montre bien son fonctionnement. Si tu
appelez la fonction avec un pdl existant et vous n'avez pas besoin de spécifier explicitement le
taille de "n" puisque PDL::PP peut le comprendre à partir des dimensions du pdl non nul. Dans
dans ce cas, vous donnez simplement le paramètre de dimension comme "-1":

$a = hist($b);
setdim($a,-1);

Cela devrait le faire.

La seule fonction PP que nous avons utilisée dans les exemples jusqu'à présent est "loop". En outre,
il existe actuellement deux autres fonctions qui sont reconnues dans la section "Code":

boucle de fil
Comme nous l'avons entendu ci-dessus, la signature d'une fonction définie par PP définit les dimensions de tous
les arguments pdl impliqués dans un primitif opération. Cependant, vous appelez souvent le
fonctions que vous avez définies avec PP avec des pdls qui ont plus de dimensions que celles
spécifié dans la signature. Dans ce cas, l'opération primitive est effectuée sur tous
des sous-tranches de dimensionnalité appropriée dans ce qu'on appelle un fil boucle (Voir aussi
aperçu ci-dessus et PDL::Indexing). En supposant que vous ayez une certaine notion de ce concept, vous
apprécieront probablement que l'opération spécifiée dans la section de code doit être
optimisé car il s'agit de la boucle la plus serrée à l'intérieur d'une boucle de thread. Cependant, si vous revisitez
l'exemple où l'on définit la fonction "pnmout", vous vous rendrez vite compte qu'en regardant
le descripteur de fichier "IO" dans la boucle de thread interne n'est pas très efficace lors de l'écriture
un pdl avec plusieurs lignes. Une meilleure approche serait de rechercher le descripteur "IO" une fois
en dehors de la boucle de fil et utilisez sa valeur puis à l'intérieur de la boucle de fil la plus serrée. C'est
exactement là où la fonction "threadloop" est utile. Voici une définition améliorée
de "pnmout" qui utilise cette fonction :

pp_def('pnmout',
Pars => 'a(m)',
OtherPars => "char* fd",
GenericTypes => [qw(BUSL)],
Code => 'PerlIO *fp;
IO *io ;
int len;

io = GvIO(gv_fetchpv($COMP(fd),FALSE,SVt_PVIO));
si (!io || !(fp = IoIFP(io)))
croak("Impossible de comprendre FP");

longueur = $TAILLE(m) * taillede($GENERIC());

boucle de thread %{
si (PerlIO_write(fp,$P(a),len) != len)
croak("Erreur d'écriture du fichier pnm");
%}
');

Cela fonctionne comme suit. Normalement, le code C que vous écrivez dans la section "Code" est placé
à l'intérieur d'une boucle de thread (c'est-à-dire que PP génère le code XS d'emballage approprié autour de lui).
Cependant, lorsque vous utilisez explicitement la fonction "threadloop", PDL::PP le reconnaît et
n'enveloppe pas votre code avec une boucle de thread supplémentaire. Cela a pour effet que vous codez
l'écriture en dehors de la boucle de thread n'est exécutée qu'une seule fois par transformation et uniquement le code
avec dans la paire "%{ ... %}" environnante est placé dans la boucle de thread la plus serrée. Cette
est également pratique lorsque vous souhaitez effectuer une décision (ou tout autre code, en particulier
code gourmand en CPU) une seule fois par thread, c'est-à-dire

pp_addhdr('
#définir RAW 0
#définir ASCII 1
');
pp_def('do_raworascii',
Pars => 'a(); b(); [o]c()',
OtherPars => 'mode int',
Code => ' commutateur ($COMP(mode)) {
cas RAW :
boucle de thread %{
/* faire des trucs bruts */
%}
break;
cas ASCII :
boucle de thread %{
/* faire des trucs ASCII */
%}
break;
par défaut:
croasser("mode inconnu");
}'
);

types
La fonction types fonctionne de manière similaire à la macro $T. Cependant, avec la fonction "types", le
le code dans le bloc suivant (délimité par "%{" et "%}" comme d'habitude) est exécuté pour tous
les cas dans lesquels le type de données de l'opération est tous of les types représentés par
les lettres dans l'argument pour "type", par exemple

Code => '...

types (BSUL) %{
/* fait une opération de type entier */
%}
types (FD) %{
/* effectuer une opération en virgule flottante */
%}
... »

La RedoDimsCodeRedoDimsCode Section
La clé "RedoDimsCode" est une clé facultative qui est utilisée pour calculer les dimensions des piddles à
runtime au cas où les règles standard de calcul des dimensions à partir de la signature ne sont pas
suffisant. Le contenu de l'entrée "RedoDimsCode" est interprété de la même manière que
la section Code est interprétée-- à, les macros PP sont développées et le résultat est
interprété comme du code C. Le but du code est de définir la taille de certaines dimensions qui
apparaissent dans la signature. L'allocation de stockage et les threads, etc. seront configurés comme
si la dimension calculée était apparue dans la signature. Dans votre code, vous calculez d'abord
la taille souhaitée d'une dimension nommée dans la signature selon vos besoins puis
attribuez-lui cette valeur via le $TAILLE() macro.

A titre d'exemple, considérons la situation suivante. Vous interfacez une bibliothèque externe
routine qui nécessite un tableau temporaire pour l'espace de travail à passer en tant qu'argument. Deux
les tableaux de données d'entrée qui sont passés sont p(m) et x(n). Le tableau de données de sortie est y(n). Les
la routine nécessite un tableau d'espace de travail d'une longueur de n+m*m, et vous souhaitez que le stockage
créé automatiquement comme il le serait pour n'importe quel piddle marqué avec [t] ou [o]. Quoi
vous voudriez, c'est dire quelque chose comme

pp_def( "myexternalfunc",
Pars => " p(m); x(n); [o] y ; [t] travail(n+m*m); ", ...

mais cela ne fonctionnera pas, car PP ne peut pas interpréter les expressions arithmétiques dans le
Signature. A la place tu écris

pp_def( "myexternalfunc",
Pars => " p(m); x(n); [o] y ; [t] travail(wn); ",
RedoDimsCode => "
int im = $PDL(p)->dims[0] ;
int dans = $PDL(x)->dims[0] ;
int min = dans + je suis * je suis;
int inw = $PDL(travail)->dims[0] ;
$TAILLE(wn) = inw >= min ? inw : min; ",
Code => "
fonctionexterne($P(p),$P(x),$TAILLE(m),$TAILLE(n),$P(travail));
" ;)

Ce code fonctionne comme suit : La macro $PDL(p) se développe en un pointeur vers la structure pdl pour
le pilon p. Vous ne voulez pas de pointeur vers les données ( c'est-à-dire $P ) dans ce cas, car vous
voulez accéder aux méthodes pour le piddle au niveau C. Vous obtenez la première dimension de
chacun des piddles et les stocker en nombres entiers. Ensuite, vous calculez la longueur minimale de
tableau de travail peut être. Si l'utilisateur a envoyé un piddle "travail" avec suffisamment de stockage, laissez-le
seul. Si l'utilisateur a envoyé, disons un pdl nul, ou pas de pdl du tout, alors la taille de wn sera
zéro et vous le réinitialisez à la valeur minimale. Avant que le code dans la section Code soit
PP exécuté créera le stockage approprié pour le "travail" s'il n'existe pas. Notez que vous
n'a pris que la première dimension de "p" et "x" car l'utilisateur a peut-être envoyé des piddles avec
dimensions de filetage supplémentaires. Bien sûr, le piddle temporaire "travaille" (notez le drapeau [t])
de toute façon, ne devrait pas recevoir de dimensions de filetage.

Vous pouvez également utiliser "RedoDimsCode" pour définir la dimension d'un piddle marqué avec [o]. Dans ce
cas où vous définissez les dimensions de la dimension nommée dans la signature à l'aide de $TAILLE() un péché
l'exemple précédent. Cependant, comme le piddle est signalé par [o] au lieu de [t],
les dimensions de filetage seront ajoutées si nécessaire, tout comme si la taille de la dimension était
calculé à partir de la signature selon les règles habituelles. Voici un exemple de
PDL::Maths

pp_def("polyracines",
Pars => 'cr(n); ci(n); [o]rr(m); [o]ri(m);',
RedoDimsCode => 'int sn = $PDL(cr)->dims[0]; $TAILLE(m) = sn-1;',

Les piddles d'entrée sont les parties réelles et imaginaires des coefficients complexes d'un
polynôme. Les piddles de sortie sont des parties réelles et imaginaires des racines. Il y a "n"
racines à un polynôme d'ordre "n" et un tel polynôme a des coefficients "n+1" (le
zeoreth par le "n"ème). Dans cet exemple, le threading fonctionnera correctement. C'est le
première dimension du piddle de sortie avec sa dimension ajustée, mais autre filetage
les dimensions seront attribuées comme s'il n'y avait pas de "RedoDimsCode".

Carte de type manipulation in le "AutresPars"
La section « OtherPars » discutée ci-dessus est très souvent absolument cruciale lorsque vous
interfacer des bibliothèques externes avec PDL. Cependant, dans de nombreux cas, les bibliothèques externes soit
utiliser des types dérivés ou des pointeurs de différents types.

La manière standard de gérer cela en Perl est d'utiliser un fichier "typemap". Ceci est discuté dans
quelques détails dans perlxs dans la documentation Perl standard. En PP, la fonctionnalité est très
similaire, vous pouvez donc créer un fichier "typemap" dans le répertoire où réside votre fichier PP
et quand il est construit, il est automatiquement lu pour trouver la traduction appropriée
entre le type C et le type intégré de Perl.

Cela dit, il existe quelques différences importantes par rapport à la gestion générale des types
en XS. La première, et probablement la plus importante, est qu'à l'heure actuelle, les pointeurs vers les types sont
non autorisé dans la section "OtherPars". Pour contourner cette limitation, vous devez utiliser le
Type "IV" (merci à Judd Taylor d'avoir souligné que cela est nécessaire pour la portabilité).

Il est probablement préférable d'illustrer cela avec quelques extraits de code :

Par exemple, la fonction "gsl_spline_init" a la déclaration C suivante :

int gsl_spline_init(gsl_spline * spline,
const double xa[], const double ya[], size_t size);

Il est clair que les tableaux "xa" et "ya" sont des candidats pour être transmis comme piddles et le
L'argument "taille" est juste la longueur de ces piddles afin qu'il puisse être géré par le
Macro "$SIZE()" en PP. Le problème est le pointeur vers le type "gsl_spline". Le naturel
la solution serait d'écrire une déclaration "OtherPars" de la forme

OtherPars => 'gsl_spline *spl'

et écrivez un court fichier "typemap" qui gère ce type. Cela ne fonctionne pas actuellement
toutefois! Donc, ce que vous devez faire, c'est contourner légèrement le problème (et d'une certaine manière
c'est plus facile aussi !):

La solution est de déclarer "spline" dans la section "OtherPars" en utilisant une "Integer Value",
"IV". Cela masque la nature de la variable de PP et vous devez alors (enfin pour éviter
avertissements du compilateur au moins !) effectuez un transtypage lorsque vous utilisez la variable dans votre code.
Ainsi, "OtherPars" devrait prendre la forme :

OtherPars => 'IV spl'

et quand vous l'utilisez dans le code, vous écrivez

INT2PTR(gsl_spline *, $COMP(spl))

où la macro de l'API Perl "INT2PTR" a été utilisée pour gérer le transtypage du pointeur afin d'éviter
avertissements et problèmes du compilateur pour les machines avec un mélange de Perl 32 bits et 64 bits
configuration. En rassemblant cela comme Andres Jordan l'a fait (avec la modification
en utilisant "IV" de Judd Taylor) dans le "gsl_interp.pd" dans la source de distribution, vous obtenez :

pp_def('init_meat',
Pars => 'double x(n); double y(n);',
OtherPars => 'IV spl',
Code =>'
gsl_spline_init,( INT2PTR(gsl_spline *, $COMP(spl)), $P(x),$P(y),$SIZE(n)));'
);

où j'ai supprimé un appel de wrapper de macro, mais cela obscurcirait la discussion.

L'autre différence mineure par rapport à la gestion standard de typemap en Perl, est que
l'utilisateur ne peut pas spécifier des emplacements de typemap non standard ou des noms de fichiers de typemap en utilisant le
Option "TYPEMAPS" dans MakeMaker... Ainsi, vous ne pouvez utiliser qu'un fichier appelé "typemap" et/ou le
Astuce "IV" ci-dessus.

Autre incontournable PP clés in données opération définitions
Vous avez déjà entendu parler de la clé "OtherPars". Actuellement, il n'y a pas beaucoup d'autres clés
pour une opération de données qui sera utile dans la programmation PP normale (quelle qu'elle soit). Dans
fait, il serait intéressant d'entendre parler d'un cas où vous pensez avoir besoin de plus que ce que
est fourni pour le moment. Veuillez vous exprimer sur l'une des listes de diffusion PDL. La plupart des autres
les clés reconnues par "pp_def" ne sont vraiment utiles que pour ce que nous appelons tranche (voir
aussi ci-dessus).

Une chose qui est fortement planifiée est le nombre variable d'arguments, qui sera un
peu délicat.

Une liste incomplète des clés disponibles :

En place
Le réglage de cette touche marque la routine comme fonctionnant sur place - c'est-à-dire l'entrée et la sortie
les piddles sont les mêmes. Un exemple est "$a->inplace->sqrt()" (ou "sqrt(inplace($a))").

En place => 1
À utiliser lorsque la routine est une fonction unaire, telle que "sqrt".

En place => ['a']
S'il y a plus d'un code d'entrée, spécifiez le nom de celui qui peut être
modifié sur place à l'aide d'une référence de tableau.

En place => ['a','b']
S'il y a plus d'un piddle de sortie, spécifiez le nom du piddle d'entrée et
piddle de sortie dans une référence de tableau à 2 éléments. Ce n'est probablement pas nécessaire, mais c'est parti
pour être complet.

Si de mauvaises valeurs sont utilisées, il faut veiller à assurer la propagation du
badflag lorsque inplace est utilisé ; considérer cet extrait de Basique/Mauvais/mauvais.pd:

pp_def('replacebad',HandleBad => 1,
Pars => 'a(); [o]b();',
OtherPars => 'double newval',
En place => 1,
CopierBadStatusCode =>
'/* propage le badflag s'il est en place ET il a changé */
si ( a == b && $ISPDLSTATEBAD(a) )
PDL->propogate_badflag( b, 0 );

/* toujours s'assurer que la sortie est "bonne" */
$SETPDLSTATEGOOD(b);
',


Étant donné que cette routine supprime toutes les mauvaises valeurs, le piddle de sortie avait son mauvais indicateur
effacé. Si exécuté sur place (donc "a == b"), alors nous devons dire à tous les enfants de "a"
que le bad flag a été effacé (pour gagner du temps, nous nous assurons d'appeler
"PDL->propogate_badgflag" uniquement si le piddle d'entrée avait son mauvais indicateur défini).

REMARQUE : une idée est que la documentation de la routine pourrait être automatiquement
signalé pour indiquer qu'il peut être exécuté sur place, c'est-à-dire quelque chose de similaire à la façon dont
"HandleBad" définit "BadDoc" s'il n'est pas fourni (ce n'est pas une solution idéale).

Autre PDL :: PP fonctions à Support concis paquet définition
Jusqu'à présent, nous avons décrit les fonctions "pp_def" et "pp_done". PDL::PP en exporte quelques-uns
d'autres fonctions pour vous aider à rédiger des définitions concises de packages d'extension PDL.

pp_addhdr

Souvent, lorsque vous interfacez des fonctions de bibliothèque comme dans l'exemple ci-dessus, vous devez inclure
fichiers d'inclusion C supplémentaires. Étant donné que le fichier XS est généré par PP, nous avons besoin de moyens pour
faire en sorte que PP insère les directives d'inclusion appropriées au bon endroit dans le XS généré
déposer. A cette fin, il existe la fonction "pp_addhdr". C'est aussi la fonction à utiliser
lorsque vous souhaitez définir des fonctions C à usage interne par certaines fonctions XS
(qui sont pour la plupart des fonctions définies par "pp_def"). En incluant ces fonctions ici, vous
assurez-vous que PDL::PP insère votre code avant le point où le module XS réel
section commence et sera donc laissée intacte par xsubpp (cf. perlxs et perlxstut
pages de manuel).

Un appel typique serait

pp_addhdr('
#comprendre /* nous avons besoin de defs de XXXX */
#include "libprotos.h" /* prototypes de fonctions de bibliothèque */
#include "mylocaldecs.h" /* Décs locaux */

static void do_the real_work(PDL_Byte * in, PDL_Byte * out, int n)
{
/* faire quelques calculs avec les données */
}
');

Cela garantit que toutes les constantes et prototypes dont vous avez besoin seront correctement inclus et
que vous pouvez utiliser les fonctions internes définies ici dans les "pp_def", par exemple :

pp_def('barfoo',
Pars => ' a(n); [o] b(n)',
Types Génériques => ['B'],
Code => ' int ns = $SIZE(n);
faire_le_vrai_travail($P(a),$P(b),ns);
',
);

pp_addpm

Dans de nombreux cas, le code PP réel (c'est-à-dire les arguments des appels "pp_def") n'est qu'une partie de
le package que vous implémentez actuellement. Il y a souvent du code Perl et XS supplémentaire
code que vous auriez normalement écrit dans les fichiers pm et XS qui sont maintenant automatiquement
généré par PP. Alors, comment intégrer ces éléments dans ces fichiers générés dynamiquement ?
Heureusement, il existe quelques fonctions, généralement appelées "pp_addXXX" qui vous assistent
En faisant cela.

Supposons que vous ayez du code Perl supplémentaire qui devrait aller dans le fichier généré pm-déposer. Cette
est facilement réalisable avec la commande "pp_addpm":

pp_addpm(<<'NEM');

=head1 NOM

PDL::Lib::Mylib -- une interface PDL vers la bibliothèque Mylib

=tête1 DESCRIPTION

Ce package implémente une interface vers le package Mylib avec
prise en charge du threading et de l'indexation (voir L ).

=couper

utiliser PGPLOT ;

=head2 use_myfunc
cette fonction applique l'opération myfunc à tous les
éléments du pdl d'entrée quelles que soient les dimensions
et renvoie la somme du résultat
=couper

sous use_myfunc {
mon $pdl = décalage;

myfunc($pdl->clump(-1),($res=null));

renvoie $res->sum ;
}

EOD

pp_add_exported

Vous avez probablement l'idée. Dans certains cas, vous souhaitez également exporter vos
les fonctions. Pour éviter d'avoir des ennuis avec PP qui déconne aussi avec le @EXPORT
tableau, vous venez de dire à PP d'ajouter vos fonctions à la liste des fonctions exportées :

pp_add_exported('use_myfunc gethynx');

pp_add_isa

La commande "pp_add_isa" fonctionne comme la fonction "pp_add_exported". Les arguments à
"pp_add_isa" sont ajoutés à la liste @ISA, par exemple

pp_add_isa(' Certains::Autres::Classe ');

pp_bless

Si vos routines pp_def doivent être utilisées comme méthodes objet, utilisez "pp_bless" pour spécifier le
package (c'est-à-dire classe) auquel votre pp_defDes méthodes d'édition seront ajoutées. Par exemple,
"pp_bless('PDL::MaClasse')". La valeur par défaut est "PDL" si cela est omis.

pp_addxs

Parfois, vous souhaitez ajouter votre propre code XS supplémentaire (qui n'est généralement pas impliqué avec
tout problème de thread/indexation, mais fournit d'autres fonctionnalités auxquelles vous souhaitez accéder
du côté Perl) vers le fichier XS généré, par exemple

pp_addxs('','

# Déterminer le boutisme de la machine

int
isbigendien()
CODE:
je court non signé ;
PDL_Byte *b ;

je = 42 ; b = (PDL_Byte*) (vide*) &i;

si (*b == 42)
RETVAL = 0 ;
sinon si (*(b+1) == 42)
RETVAL = 1 ;
d'autre
croak("Impossible - la machine n'est ni grand ni petit endian !!\n");
SORTIE:
RETOUR
');

En particulier, "pp_add_exported" et "pp_addxs" doivent être utilisés avec précaution. PP utilise
PDL::Exporter, donc laisser PP exporter votre fonction signifie qu'ils sont ajoutés au
liste standard de fonction exportée par défaut (la liste définie par la balise export
``:Func''). Si vous utilisez "pp_addxs", vous ne devriez pas essayer de faire quoi que ce soit qui implique le threading
ou en indexant directement. PP est bien meilleur pour générer le code approprié à partir de votre
définitions

pp_add_boot

Enfin, vous voudrez peut-être ajouter du code à la section BOOT du fichier XS (si vous ne
savoir ce que c'est vérifier perlxs). Cela se fait facilement avec la commande "pp_add_boot":

pp_add_boot(<
description = mylib_initialize(KEEP_OPEN);

if (décrire == NULL)
croak("Impossible d'initialiser la bibliothèque");

GlobalStruc->descrip = descrip;
GlobalStruc->maxfiles = 200 ;
EOB

pp_export_nothing

Par défaut, PP.pm met tous les sous-ensembles définis à l'aide de la fonction pp_def dans la sortie .pm
la liste d'EXPORTATION du fichier. Cela peut créer des problèmes si vous créez un objet sous-classé où
vous ne voulez pas exporter de méthodes. (c'est-à-dire que les méthodes ne seront appelées qu'en utilisant le
$objet->syntaxe de la méthode).

Pour ces cas, vous pouvez appeler pp_export_nothing() pour effacer la liste d'exportation. Exemple (à
la fin du fichier .pd) :

pp_export_nothing();
pp_done();

pp_core_importList

Par défaut, PP.pm met le 'use Core;' ligne dans le fichier de sortie .pm. Cela importe les Core
noms exportés dans l'espace de noms actuel, ce qui peut créer des problèmes si vous
chevauchant l'une des méthodes de Core dans le fichier actuel. Vous finissez par recevoir des messages comme
"Attention : sous sumover redéfini dans le fichier subclass.pm" lors de l'exécution du programme.

Pour ces cas, la pp_core_importList peut être utilisée pour changer ce qui est importé de
Noyau.pm. Par exemple:

pp_core_importList('()')

Cela se traduirait par

utiliser Core();

généré dans le fichier de sortie .pm. Il en résulterait qu'aucun nom n'est importé de
Noyau.pm. De même, appeler

pp_core_importList(' qw/ barf /')

entraînerait

utiliser Core qw/ barf/;

généré dans le fichier de sortie .pm. Cela entraînerait simplement l'importation de « barf »
de Core.pm.

pp_setversion

Je suis presque sûr que cela vous permet de définir simultanément les fichiers .pm et .xs'
versions, évitant ainsi un décalage de version inutile entre les deux. Pour l'utiliser, il suffit d'avoir
la ligne suivante à un moment donné de votre fichier .pd :

pp_setversion('0.0.3');

Cependant, ne l'utilisez pas si vous utilisez Module::Build::PDL. Voir la documentation de ce module pour
détails.

pp_deprecate_module

Si un module particulier est jugé obsolète, cette fonction peut être utilisée pour le marquer comme
obsolète. Cela a pour effet d'émettre un avertissement lorsqu'un utilisateur essaie d'"utiliser" le
module. Le POD généré pour ce module comporte également un avis de dépréciation. Les
module de remplacement peut être passé en argument comme ceci :

pp_deprecate_module( défavoriser => "PDL::NewNonDeprecatedModule" );

Notez que la fonction affecte uniquement l'avertissement d'exécution et le POD.

Fabrication Un flux efficace peut augmenter PP fonction "privé"


Disons que vous avez une fonction dans votre module appelée PDL::foo qui utilise le PP
fonction "bar_pp" pour faire le gros du travail. Mais vous ne voulez pas faire la publicité de ce "bar_pp"
existe. Pour cela, vous devez déplacer votre fonction PP en haut de votre fichier module, puis
Appelez-nous

pp_export_nothing()

pour effacer la liste "EXPORTER". Pour s'assurer qu'aucune documentation (même les documents PP par défaut) n'est
généré, défini

Doc => undef

et pour éviter que la fonction ne soit ajoutée à la table des mnémoniques, définissez

PMFunc => ''

dans votre déclaration pp_def (voir Image2D.pd pour un exemple). Cela rendra effectivement
votre fonction PP "privée". Cependant, il est toujours accessible via PDL::bar_pp grâce à Perl
conception de modules. Mais en le rendant privé, l'utilisateur ira très loin de son
façon de l'utiliser, pour qu'il en assume les conséquences !

Tranche opération


La section sur les opérations de tranche de ce manuel est fournie à l'aide de flux de données et d'une évaluation paresseuse :
quand vous en avez besoin, demandez à Tjl de l'écrire. une livraison dans une semaine à partir de la réception de l'email
est probable à 95 % et l'accouchement dans les deux semaines est probable à 99 %.

Et de toute façon, les opérations de découpage nécessitent une connaissance beaucoup plus intime des internes de PDL
que les opérations de données. De plus, la complexité des questions en jeu est
considérablement plus élevé que celui de l'opération de données moyenne. Si vous souhaitez convaincre
vous-même de ce fait jetez un oeil à la Basique/tranches/tranches.pd fichier dans le PDL
Distribution :-). Néanmoins, les fonctions générées à l'aide des opérations de tranche sont au
cœur des capacités de manipulation d'index et de flux de données de PDL.

De plus, il y a beaucoup de problèmes sales avec les piddles et les vaffines virtuels que nous allons
sauter complètement ici.

Tranches et mauvais valeurs
Les opérations de tranche doivent être capables de gérer les mauvaises valeurs (si la prise en charge est compilée dans PDL).
Le plus simple est de regarder Basique/tranches/tranches.pd pour voir comment cela fonctionne.

Outre "BadCode", il existe également les touches "BadBackCode" et "BadRedoDimsCode" pour
"pp_def". Cependant, tout "EquivCPOffsCode" doit ne sauraient besoin de changer, puisque tout changement est
absorbée dans la définition de la macro "$EQUIVCPOFFS()" (c'est-à-dire qu'elle est gérée
automatiquement par PDL::PP>.

A few note on écriture a tranchage routine...
Les quelques paragraphes suivants décrivent l'écriture d'une nouvelle routine de découpage (« range »); quelconque
les erreurs sont des DEC. (--CED 26-août-2002)

Maniabilité of "avertir" et "barf" in PP Code


Pour imprimer des messages d'avertissement ou abandonner/mourir, vous pouvez appeler "warn" ou "barf" depuis PP
code. Cependant, vous devez savoir que ces appels ont été redéfinis à l'aide de C
macros du préprocesseur vers "PDL->barf" et "PDL->warn". Ces redéfinitions sont en place pour
vous empêcher d'appeler par inadvertance « warn » ou « barf » de perl directement, ce qui peut provoquer
erreurs de segmentation pendant le pthreading (c'est-à-dire le multi-threading du processeur).

Les propres versions de "barf" et "warn" de PDL mettront en file d'attente les messages d'avertissement ou de barf jusqu'à après
pthreading est terminé, puis appelez les versions perl de ces routines.

Voir PDL::ParallelCPU pour plus d'informations sur le pthreading.

UTILE ROUTINE


La structure PDL "Core", définie dans Basique/Core/pdlcore.h.PL, contient des pointeurs vers un
nombre de routines qui peuvent vous être utiles. La plupart de ces routines traitent
manipuler des piddles, mais certains sont plus généraux :

PDL->qsort_B( PDL_Byte *xx, int a, int b )
Triez le tableau "xx" entre les indices "a" et "b". Il existe également des versions pour le
d'autres types de données PDL, avec le suffixe "_S", "_U", "_L", "_F" et "_D". Tout module utilisant
cela doit garantir que "PDL::Ufunc" est chargé.

PDL->qsort_ind_B( PDL_Byte *xx, int *ix, int a, int b )
Comme pour "PDL->qsort_B", mais cette fois en triant les indices plutôt que les données.

La routine "med2d" en Lib/Image2D/image2d.pd montre comment ces routines sont utilisées.

FAIRE DES FICHIERS POUR PP DES DOSSIERS


Si vous allez générer un package à partir de votre fichier PP (les extensions de fichier typiques sont
".pd" ou ".pp" pour les fichiers contenant du code PP) il est plus simple et plus sûr de quitter
génération des commandes appropriées au Makefile. Dans ce qui suit, nous décrirons
le format typique d'un Makefile Perl pour construire et installer automatiquement votre paquet à partir de
une description dans un fichier PP. La plupart des règles pour construire les xs, pm et autres fichiers requis
du fichier PP sont déjà prédéfinis dans le package PDL::Core::Dev. Nous devons juste
dites à MakeMaker de l'utiliser.

Dans la plupart des cas, vous pouvez définir votre Makefile comme

# Makefile.PL pour un package défini par le code PP.

utiliser PDL::Core::Dev; # Récupérer les utilitaires de développement
utilisez ExtUtils::MakeMaker ;

$package = ["malib.pd",Malib,PDL::Lib::Malib] ;
%hachage = pdlpp_stdargs($paquet);
$hash{OBJECT} .= ' additional_Ccode$(OBJ_EXT) ';
$hash{clean}->{FILES} .= 'todelete_Ccode$(OBJ_EXT) ';
$hash{'VERSION_FROM'} = 'malib.pd';
WriteMakefile(%hash);

sub MY::postamble { pdlpp_postamble($package); }

Ici, la liste dans $package est : d'abord : le nom du fichier source PP, puis le préfixe du
fichiers produits et enfin le nom complet du package. Vous pouvez modifier le hachage dans n'importe quel
comme vous l'aimez mais il serait raisonnable de rester dans certaines limites pour que votre colis
continuera à fonctionner avec les versions ultérieures de PDL.

Si vous ne voulez pas utiliser d'arguments pré-packagés, voici un générique Makefile.PL Que tu peux
adapter à vos propres besoins :

# Makefile.PL pour un package défini par le code PP.

utiliser PDL::Core::Dev; # Récupérer les utilitaires de développement
utilisez ExtUtils::MakeMaker ;

WriteMakefile(
'NAME' => 'PDL::Lib::Mylib',
'VERSION_FROM' => 'malib.pd',
'TYPEMAPS' => [&PDL_TYPEMAP()],
'OBJECT' => 'mylib$(OBJ_EXT) additional_Ccode$(OBJ_EXT)',
'PM' => { 'Malib.pm' => '$(INST_LIBDIR)/Malib.pm'},
'INC' => &PDL_INCLUDE(), # ajouter des répertoires d'inclusion comme requis par votre lib
'LIBS' => [''], # ajouter des directives de lien si nécessaire
'clean' => {'FILES' =>
'Malib.pm Malib.xs Malib$(OBJ_EXT)
additional_Ccode$(OBJ_EXT)'},
);

# Ajouter une règle genpp ; cela invoquera PDL::PP sur notre fichier PP
# l'argument est une référence de tableau où le tableau a trois éléments de chaîne :
# arg1 : nom du fichier source qui contient le code PP
# arg2 : nom de base des fichiers xs et pm à générer
# arg3 : nom du package à générer
sub MY::postamble { pdlpp_postamble(["malib.pd",Malib,PDL::Lib::Malib]); }

Pour rendre la vie encore plus facile PDL::Core::Dev définit la fonction "pdlpp_stdargs" qui renvoie
un hachage avec des valeurs par défaut qui peuvent être transmises (soit directement, soit après
modification) à un appel à WriteMakefile. Actuellement, "pdlpp_stdargs" renvoie un hachage où
les clés sont renseignées comme suit :

(
'NOM' => $mod,
'TYPEMAPS' => [&PDL_TYPEMAP()],
'OBJET' => "$pref\$(OBJ_EXT)",
PM => {"$pref.pm" => "\$(INST_LIBDIR)/$pref.pm"},
MAN3PODS => {"$src" => "\$(INST_MAN3DIR)/$mod.\$(MAN3EXT)"},
'INC' => &PDL_INCLUDE(),
'LIBS' => [''],
'clean' => {'FILES' => "$pref.xs $pref.pm $pref\$(OBJ_EXT)"},
)

Ici, $src est le nom du fichier source avec le code PP, $pref le préfixe du fichier généré
.pm et .xs et $mod le nom du module d'extension à générer.

INTERNES


Les internes de la version actuelle se composent d'un grand tableau qui donne les règles
selon quelles choses sont traduites et les sous-titres qui mettent en œuvre ces règles.

Plus tard, il serait bon de rendre le tableau modifiable par l'utilisateur afin que différents
les choses peuvent être tentées.

[Méta commentaire : ici, espérons-le, il y en aura plus à l'avenir ; actuellement, votre meilleur pari sera
pour lire le code source :-( ou demander sur la liste (essayez d'abord ce dernier) ]

Appendice A: Certain clés reconnu by PDL :: PP


Sauf indication contraire, les arguments sont des chaînes. Les clés marquées de (mauvais) ne sont
utilisé si le support de mauvaise valeur est compilé dans PDL.

Pars
définir la signature de votre fonction

AutrePars
arguments qui ne sont pas des pdls. Par défaut : rien. Ceci est une liste séparée par des points-virgules de
arguments, par exemple, "OtherPars=>'int k; valeur double; char* fd'". Voir $COMP(x) et aussi
la même entrée à l'annexe B.

Code
le code réel qui implémente la fonctionnalité ; plusieurs macros PP et fonctions PP
sont reconnus dans la valeur de chaîne

PoignéeMauvais (mauvais)
S'il est défini sur 1, la routine est supposée prendre en charge les mauvaises valeurs et le code dans le BadCode
la clé est utilisée si de mauvaises valeurs sont présentes ; il configure également les choses pour que le "$ISBAD()"
etc. des macros peuvent être utilisées. S'il est défini sur 0, la routine affiche un avertissement si l'un des
les piddles d'entrée ont leur mauvais indicateur défini.

BadCode (mauvais)
Donnez le code à utiliser si de mauvaises valeurs peuvent être présentes dans les piddles d'entrée. Seulement utilisé
si "HandleBad => 1".

Types Génériques
Une référence de tableau. Le tableau peut contenir n'importe quel sous-ensemble des chaînes à un caractère « B »,
« S », « U », « L », « Q », « F » et « D », qui spécifient les types que votre opération acceptera.
La signification de chaque type est :

B - octet signé (c'est-à-dire caractère signé)
S - signé court (entier de deux octets)
U - court non signé
L - signé long (entier de quatre octets, entier sur les systèmes 32 bits)
Q - signé long long (entier de huit octets)
F - flotteur
D - doublé

Ceci est très utile (et important !) lors de l'interfaçage d'une bibliothèque externe. Défaut:
[qw/BSULQFD/]

En place
Marquez une fonction comme pouvant fonctionner sur place.

Inplace => 1 if Pars => 'a(); [o]b();'
Inplace => ['a'] if Pars => 'a(); b(); [o]c();'
Inplace => ['a','b'] if Pars => 'a(); b(); [o]c(); [o]d();'

Si de mauvaises valeurs sont utilisées, il faut veiller à assurer la propagation du
badflag lorsque inplace est utilisé ; par exemple voir le code pour "replacebad" dans
Basique/Mauvais/mauvais.pd.

Doc Utilisé pour spécifier une chaîne de documentation au format Pod. Voir PDL::Doc pour plus d'informations sur
Conventions de documentation PDL. Remarque : dans le cas particulier où la chaîne PP 'Doc' est
une ligne est implicitement utilisée pour la référence rapide ET la documentation !

Si le champ Doc est omis, PP générera une documentation par défaut (après tout ce qu'il sait
à propos de la Signature).

Si vous voulez vraiment que la fonction ne soit PAS documentée de quelque façon que ce soit à ce stade (par exemple
pour une routine interne, ou parce que vous le faites ailleurs dans le code) explicitement
spécifiez "Doc=>undef".

BadDoc (mauvais)
Contient le texte renvoyé par la commande "badinfo" (dans "perldl") ou le commutateur "-b"
au script shell "pdldoc". Dans de nombreux cas, vous n'aurez pas besoin de le spécifier, car
les informations peuvent être créées automatiquement par PDL::PP. Cependant, comme il sied à l'ordinateur-
le texte généré, c'est plutôt guindé ; il vaut peut-être mieux le faire soi-même !

Pas de fil
Indicateur facultatif pour indiquer que la fonction PDL doit ne sauraient utiliser les threads du processeur (c'est-à-dire
pthreads ou threads POSIX) pour répartir le travail sur plusieurs cœurs de processeur. Cette option est
généralement défini sur 1 si la fonction PDL sous-jacente n'est pas threadsafe. Si cette option
n'est pas présent, alors la fonction est supposée être thread-safe. Cette option s'applique uniquement
si PDL a été compilé avec les threads POSIX activés.

Code PM
Les fonctions PDL vous permettent de passer un piddle dans lequel vous voulez que la sortie soit sauvegardée. Cette
est pratique car vous pouvez allouer un piddle de sortie une fois et le réutiliser plusieurs fois ; la
une alternative serait que PDL crée un nouveau piddle à chaque fois, ce qui peut gaspiller du calcul
cycles ou, plus probablement, RAM. Cette flexibilité accrue se fait au prix de plus
complexité : PDL::PP doit écrire des fonctions suffisamment intelligentes pour compter les
les arguments lui sont transmis et créent de nouveaux piddles à la volée, mais seulement si vous les voulez.

PDL::PP est assez intelligent pour faire cela, mais il y a des restrictions sur l'ordre des arguments et
le semblable. Si vous voulez une fonction plus flexible, vous pouvez écrire votre propre côté Perl
wrapper et spécifiez-le dans la clé PMCode. La chaîne que vous fournissez doit (devrait)
définir une fonction Perl avec un nom qui correspond à ce que vous avez donné à pp_def dans le premier
lieu. Lorsque vous souhaiterez éventuellement appeler la fonction générée par PP, vous devrez
fournir tous les piddles dans l'ordre exact spécifié dans la signature : les piddles de sortie sont
pas facultatif, et la fonction générée par PP ne renverra rien. L'obscurci
le nom que vous appellerez est _ _int.

Je pense que cette documentation a besoin de plus de précisions, mais cela devra faire l'affaire.
:-(

PMFunc
Lorsque pp_def génère des fonctions, il les définit généralement dans le package PDL. Puis,
dans le fichier .pm qu'il génère pour votre module, il ajoute généralement une ligne qui
copie essentiellement cette fonction dans la table des symboles de votre package actuel avec le code
ça ressemble à ça :

*func_name = \&PDL::func_name;

C'est un peu plus intelligent que ça (il sait quand envelopper ce genre de chose dans un
BEGIN, par exemple, et si vous avez spécifié quelque chose de différent pour pp_bless), mais
c'est l'essentiel. Si vous ne vous souciez pas d'importer la fonction dans votre
table des symboles du package, vous pouvez spécifier

PMFunc => '',

PMFunc n'a pas d'autres effets secondaires, vous pouvez donc l'utiliser pour insérer du code Perl arbitraire
dans votre module si vous le souhaitez. Cependant, vous devez utiliser pp_addpm si vous souhaitez ajouter Perl
code à votre module.

Appendice B: PP macros et fonctions


Macros
Les macros étiquetées par (mauvais) ne sont utilisées que si la prise en charge des valeurs incorrectes est compilée dans PDL.

$nom_variable_de_sig()
accéder à un pdl (par son nom) qui a été spécifié dans la signature

$COMP(x)
accéder à une valeur dans la structure de données privée de cette transformation (principalement utilisée pour
utiliser un argument spécifié dans la section "OtherPars")

$TAILLE(n)
remplacé à l'exécution par la taille réelle d'un nommé dimension (comme spécifié dans le
Signature)

$GÉNÉRIQUE()
remplacé par le type C qui est égal au type d'exécution de l'opération

$P(a) un pointeur d'accès au PDL nommé "a" dans la signature. Utile pour l'interfaçage avec C
fonctions

$PP(a) un pointeur physique d'accès à pdl "a" ; principalement à usage interne

$TXXX(Alternative,Alternative)
alternatives d'extension selon le type d'opération d'exécution, où XXX est un
chaîne qui correspond à "/[BSULFD+]/".

$PDL(a)
renvoie un pointeur vers la structure de données pdl (pdl *) de piddle "a"

$ISBAD(a()) (mauvais)
renvoie vrai si la valeur stockée dans "a()" est égale à la mauvaise valeur pour ce piddle.
Nécessite que "HandleBad" soit défini sur 1.

$ISGOOD(a()) (mauvais)
renvoie vrai si la valeur stockée dans "a()" n'est pas égale à la mauvaise valeur pour ce
faire pipi. Nécessite que "HandleBad" soit défini sur 1.

$SETBAD(a()) (mauvais)
Définit "a()" pour égaler la mauvaise valeur pour ce piddle. Nécessite la définition de "HandleBad"
à 1.

fonctions
"boucle(DIMS) %{ ... %}"
boucle sur les dimensions nommées ; les limites sont générées automatiquement par PP

"boucle de fil %{ ... %}"
insérez le code suivant dans une boucle de thread

"types(TYPES) ​​%{ ... %}"
exécuter le code suivant si le type d'opération est l'un des "TYPES"

Appendice C: Les fonctions importé by PDL :: PP


Un certain nombre de fonctions sont importées lorsque vous "utilisez PDL::PP". Il s'agit notamment de fonctions qui
contrôler le code C ou XS généré, les fonctions qui contrôlent le code Perl généré, et
fonctions qui manipulent les packages et les tables de symboles dans lesquels le code est créé.

Génération C et XS Code
L'objectif principal de PDL::PP est de vous permettre d'enrouler facilement le moteur de thread autour de votre
propre code C, mais vous pouvez également faire d'autres choses.

pp_def
Utilisé pour envelopper le moteur de thread autour de votre code C. Pratiquement tout ce document
discute de l'utilisation de pp_def.

pp_fait
Indique que vous avez terminé avec PDL::PP et qu'il doit générer ses fichiers .xs et .pm
basé sur les autres fonctions pp_* que vous avez appelées. Cette fonction ne prend pas
arguments.

pp_addxs
Cela vous permet d'ajouter du code XS à votre fichier .xs. Ceci est utile si vous voulez créer Perl-
fonctions accessibles qui invoquent du code C mais ne peuvent pas ou ne doivent pas invoquer le threading
moteur. XS est le moyen standard par lequel vous encapsulez du code C accessible à Perl. Tu peux
en savoir plus sur perlxs.

pp_add_boot
Cette fonction ajoute la chaîne que vous passez à la section XS BOOT. La section BOOT
est le code C qui est appelé par Perl lorsque votre module est chargé et est utile pour
initialisation automatique. Vous pouvez en savoir plus sur XS et la section BOOT sur perlxs.

pp_addhdr
Ajoute du code C pur à votre fichier XS. Les fichiers XS sont structurés de telle sorte que le code C pur doit
viennent avant les spécifications XS. Cela vous permet de spécifier un tel code C.

pp_boundscheck
PDL vérifie normalement les limites de vos accès avant de les faire. Tu peux tourner ça
activé ou désactivé au moment de l'exécution en définissant MyPackage::set_boundscheck. Cette fonction vous permet
pour supprimer cette flexibilité d'exécution et jamais faire une vérification des limites. Il renvoie également le
état actuel de la vérification des limites s'il est appelé sans aucun argument.

REMARQUE : je n'ai rien trouvé sur la vérification des limites dans d'autres documents. Cette
doit être abordée.

Génération Perl Code
De nombreuses fonctions importées lors de l'utilisation de PDL::PP permettent de modifier le contenu du
fichier .pm généré. En plus de pp_def et pp_done, le rôle de ces fonctions est
principalement pour ajouter du code à diverses parties de votre fichier .pm généré.

pp_addpm
Ajoute du code Perl au fichier .pm généré. PDL::PP garde en fait la trace de trois
différentes sections du code généré : le haut, le milieu et le bas. Vous pouvez ajouter
Code Perl à la section du milieu en utilisant la forme à un argument, où l'argument est le
Code Perl que vous souhaitez fournir. Dans la forme à deux arguments, le premier argument est un
hachage anonyme avec une seule clé qui spécifie où mettre le deuxième argument,
qui est la chaîne que vous souhaitez ajouter au fichier .pm. Le hachage est l'un de ceux-ci
trois:

{At => 'Top'}
{At => 'Milieu'}
{At => 'Bot'}

Par exemple :

pp_addpm({At => 'Bot'}, <

=head1 Quelques documentations

Je sais que je tape ceci au milieu de mon fichier, mais ça ira à
le fond.

=couper

POD

Attention : Si, au milieu de votre fichier .pd, vous mettez une documentation destinée au
bas de votre pod, vous allez complètement confondre CPAN. En revanche, si dans le
milieu de votre fichier .pd, vous ajoutez du code Perl destiné au bas ou au haut de votre
.pm, vous n'avez qu'à vous confondre. :-)

pp_beginwrap
Ajoute l'encapsulation du bloc BEGIN. Certaines déclarations peuvent être encapsulées dans des blocs BEGIN, bien que
le comportement par défaut est de ne pas avoir un tel emballage.

pp_addbegin
Définit le code à ajouter en haut de votre fichier .pm, même au-dessus du code que vous spécifiez
avec "pp_addpm({At => 'Top'}, ...)". Contrairement à pp_addpm, l'appel écrase tout
était là avant. En règle générale, vous ne devriez probablement pas l'utiliser.

Suivi Gamme Nombres
Lorsque vous obtenez des erreurs de compilation, que ce soit à partir de votre code de type C ou de votre code Perl, cela peut aider
pour ramener ces erreurs aux numéros de ligne dans le fichier source où l'erreur
est produite.

pp_line_numbers
Prend un numéro de ligne et une chaîne de code (généralement longue). Le numéro de ligne doit
indiquer la ligne de début de la citation. C'est généralement le "__LINE__" de Perl
littéral, sauf si vous utilisez heredocs, auquel cas c'est "__LINE__ + 1". le
la chaîne renvoyée contient des directives #line intercalées pour aider le compilateur à signaler les erreurs
sur la bonne ligne.

Modification le Symbole lampe de table et Exportations Comportement
PDL::PP exporte généralement toutes les fonctions générées à l'aide de pp_def et les installe généralement
dans la table des symboles PDL. Cependant, vous pouvez modifier ce comportement avec ces fonctions.

pp_bless
Définit le package (table de symboles) auquel le code XS est ajouté. La valeur par défaut est PDL,
ce qui est généralement ce que vous voulez. Si vous utilisez la bénédiction par défaut et que vous créez un
fonction myfunc, vous pouvez effectuer les opérations suivantes :

$piddle->myfunc( );
PDL::myfunc($piddle, );

D'un autre côté, si vous bénissez vos fonctions dans un autre package, vous ne pouvez pas invoquer
en tant que méthodes PDL, et doit les appeler en tant que :

MyPackage::myfunc($piddle, );

Bien sûr, vous pouvez toujours utiliser la touche PMFunc pour ajouter votre fonction au symbole PDL
table, mais pourquoi faire ça ?

pp_add_isa
S'ajoute à la liste des modules à partir desquels votre module hérite. La liste par défaut est

qw(PDL::Exportateur DynaLoader)

pp_core_importlist
En haut de votre fichier .pm généré se trouve une ligne qui ressemble à ceci :

utiliser PDL::Core ;

Vous pouvez modifier cela en spécifiant une chaîne à pp_core_importlist. Par example,

pp_core_importlist('::Blarg');

aura pour résultat

utiliser PDL::Core::Blarg;

Vous pouvez l'utiliser, par exemple, pour ajouter une liste de symboles à importer depuis PDL::Core. Pour
Exemple:

pp_core_importlist(" ':Interne'");

conduira à la déclaration d'utilisation suivante :

utiliser PDL::Core ':Interne';

pp_setversion
Définit la version de votre module. La version doit être cohérente entre le .xs et le .pm
et est utilisé pour s'assurer que les bibliothèques de votre Perl ne souffrent pas de la version
fausser.

pp_add_exported
Ajoute à la liste d'exportation les noms que vous lui donnez. Fonctions créées à l'aide de pp_def
sont automatiquement ajoutés à la liste. Cette fonction est utile si vous définissez un Perl
fonctions utilisant pp_addpm ou pp_addxs que vous souhaitez également exporter.

pp_export_nothing
Cela réinitialise la liste des symboles exportés à rien. C'est probablement mieux appelé
"pp_export_clear", puisque vous pouvez ajouter des symboles exportés après avoir appelé
"pp_export_nothing". Lorsqu'il est appelé juste avant d'appeler pp_done, cela garantit que votre
module n'exporte rien, par exemple, si vous voulez seulement que les programmeurs utilisent votre
fonctionne comme des méthodes.

Utilisez PDL::PPp en ligne en utilisant les services onworks.net


Serveurs et postes de travail gratuits

Télécharger des applications Windows et Linux

  • 1
    gestionnaire de fichiers de paquets
    gestionnaire de fichiers de paquets
    Ceci est le gestionnaire de fichiers du pack Total War
    projet, à partir de la version 1.7. UNE
    courte introduction à Warscape
    modding : ...
    Télécharger le packfilemanager
  • 2
    IPerf2
    IPerf2
    Un outil de trafic réseau pour mesurer
    Performances TCP et UDP avec métriques
    autour du débit et de la latence. Les
    les objectifs comprennent le maintien d'une activité
    morue iperf...
    Télécharger IPerf2
  • 3
    fre:ac - convertisseur audio gratuit
    fre:ac - convertisseur audio gratuit
    fre:ac est un convertisseur audio gratuit et un CD
    ripper pour différents formats et encodeurs.
    Il dispose de MP3, MP4/M4A, WMA, Ogg
    Formats Vorbis, FLAC, AAC et Bonk
    Support, ...
    Télécharger fre:ac - convertisseur audio gratuit
  • 4
    matplotlib
    matplotlib
    Matplotlib est une bibliothèque complète
    pour créer des images statiques, animées et
    visualisations interactives en Python.
    Matplotlib rend les choses simples faciles et
    chose difficile...
    Télécharger Matplotlib
  • 5
    Botman
    Botman
    Écrivez votre logique de chatbot une fois et
    connectez-le à l'un des
    services de messagerie, y compris Amazon
    Alexa, Facebook Messenger, Slack,
    Télégramme ou même yo...
    Télécharger Botman
  • 6
    Joplin
    Joplin
    Joplin est un logiciel libre et open source
    application de prise de notes et de tâches qui
    peut gérer un grand nombre de notes dans
    Format Markdown, organisez-les en
    cahiers et...
    Télécharger Joplin
  • Plus "

Commandes Linux

Ad