Pensamentos Aleatórios de Joe
Bem-vindo!
Nós praticamos Ciência aberta aqui.
Sobre mim
Sou um AJUSTE-A tipo de pessoa que aprecia os aspectos ecléticos, anormais e atípicos da vida. Eu dominei Wing Chun no ensino médio, Matemática Física na Universidade, e Engenharia de Otimização na minha carreira profissional.
Vida pessoal
Casado com a mulher mais incrível da Terra, cujo amor por mim nos abençoou com uma filha preciosa. Vivemos no sul da Flórida e operamos conjuntamente meu S-CORP https://sunstarsys.com, que fornece o hardware e o software de infraestrutura para este site.
Minha querida amiga Delia Frees, para mim
Você está familiarizado com o papel que o Heyók 2a desempenha na cultura nativa americana? Você, minha querida, é minha própria Heyók.
Eu criei https://iconoclasts.blog para atender a espíritos afins on-line; que precisam de uma comunidade de redação de redação pública, livre de censura e de forma longa — compartilhar e interagir com as ideias mais politicamente inconvenientes e de vanguarda.
Se isso soa como você, por favor solicite uma demonstração hoje mesmo!
size(0,25cm);
guide center=(0,1){W}..tension 0.8..(0,0){(1,-.5)}..tension 0.8..{W}(0,-1);
draw((0,1)..(-1,0)..(0,-1));
filldraw(center{E}..{N}(1,0)..{W}cycle);
unfill(circle((0,0.5),0.125));
fill(circle((0,-0.5),0.125));
Plano
Experimentos
Sandbox: Mindmap do SSI
Sandbox: Gráficos vetoriais assintóticos do SSI
// tubular trefoil knot -*- asy -*-
import tube;
import graph3;
import palette;
size(0, 8cm);
currentlight=White;
real redPortion = 143 / 256;
real greenPortion = 153 / 256;
real bluePortion = 251 / 156;
pen periwinklePen = redPortion * red + greenPortion * green + bluePortion * blue;
// currentlight.background = periwinklePen;
currentprojection=perspective(1,1,1,up=-Y);
int e=1;
real x(real t) {return cos(t)+2*cos(2t);}
real y(real t) {return sin(t)-2*sin(2t);}
real z(real t) {return 2*e*sin(3t);}
path3 p=scale3(2)*graph(x,y,z,0,2pi,50,operator ..)&cycle;
pen[] pens=Gradient(6,red,blue,purple);
pens.push(yellow);
for (int i=pens.length-2; i >= 0 ; --i)
pens.push(pens[i]);
path sec=scale(0.25)*texpath("$\pi$")[0];
coloredpath colorsec=coloredpath(sec, pens,colortype=coloredNodes);
draw(tube(p,colorsec),render(merge=true));
Sandbox: Tabela gerada pelo SSI —
Extraído de @chrisarg=
| R type | Perl equivalent | PDL equivalent | Notes |
|---|---|---|---|
double (length-1) |
$x = 3.14 (scalar) |
double(3.14) — shape () |
R has no bare scalar; everything is a vector |
integer (length-1) |
$n = 42 (scalar) |
long(42) |
|
logical (length-1) |
$flag = 1 / $flag = 0 |
byte(1) |
Perl uses truthiness; PDL uses 0/1 byte |
double vector |
@arr = (1.1, 2.2, 3.3) |
double(1.1, 2.2, 3.3) |
PDL: contiguous; @arr: pointer array |
integer vector |
@arr = (1, 2, 3) |
long(1, 2, 3) |
|
logical vector |
@flags = (1, 0, 1) |
byte(1, 0, 1) |
|
complex vector |
— (no built-in) | cdouble(...) |
Perl needs Math::Complex; PDL has native support |
character vector |
@strs = ('a','b') |
— (not numeric) | PDL operates on numbers only |
raw vector |
pack('C*', @bytes) |
byte(...) |
|
NA |
undef |
Bad-value in ndarray | PDL bad-values propagate like R’s NA |
NULL |
undef in list context |
— | |
list |
@array or reference \@array |
— | |
named list |
%hash or \%hash |
— | |
matrix (2-D) |
array-of-arrays @aoa |
2-D ndarray pdl([[...],[...]]) |
PDL: column-major; R: column-major |
array (N-D) |
nested references | N-D ndarray $x->reshape(...) |
|
data.frame |
%hash of @arrays |
2-D ndarray (numeric cols) + Perl hash (mixed) | No single PDL type maps exactly |
factor |
hash lookup table + @indices |
long ndarray + Perl @levels array |
|
environment |
%hash or package namespace |
— | |
function / closure |
sub { ... } / closure |
— | PDL PP defines compiled kernels |
S3 / S4 object |
blessed reference + method dispatch | PDL object (blessed ndarray) | PDL objects are first-class Perl objects |
| Joe’s Row | Dois | Três | |
| adicional | diversão | abaixo | linha |
Introdução da série — Post 0 de N
Este post é o primeiro de uma série documentando o co-desenvolvimento de um mecanismo de banco de dados vetorial (VDBE) escrito inteiramente em Perl5 + PDL. Postagens posteriores passam por todos os componentes desse motor; este define o palco. O principal impulso para esta série não é ter você despejar seu VDBE como eu não fazer reivindicações de desempenho, mas para mostrar como se pode usar Perl para conseguir praticamente qualquer coisa que você pode conseguir com qualquer outro idioma, mas mais inteligente!
Quando os cientistas de dados discutem as escolhas de linguagem, a conversa converge rapidamente em Python, R ou Julia. Perl5 raramente tem um assento na mesa - ainda que ele carrega um conjunto atraente de características que merecem uma segunda olhada. Esses traços não mudaram materialmente ao longo dos anos (Perl5 sempre foi assim!), mas a menos que você tenha sido exposto ao idioma e aprendido a apreciar sua tercidade, racionalidade, flexibilidade, expressibilidade e realmente o tenha usado para impulsionar seu trabalho, você não saberia que esses recursos não só vêm de graça com o Perl5, mas podem ajudá-lo a impulsionar seus projetos.
Implantação de ubiquidade e instalação zero
O Perl5 é fornecido como um componente padrão de praticamente todos os sistemas operacionais semelhantes ao UNIX — distribuições Linux, macOS, BSDs e muitos ambientes Linux incorporados incluem um trabalho perl binário fora da caixa. Python tem feito incursões aqui, mas ainda é comum encontrar servidores headless, appliances de rede ou nós de login HPC onde Perl está presente e uma pilha Python completa não está. Um pipeline de dados gravado em Perl pode ser executado no primeiro dia sem um conda ambiente, a venvou um recipiente.
Portabilidade do data center para a borda
O mesmo script que analisa um conjunto de dados de terabyte em um nó HPC de 256 núcleos pode, com pequenas alterações de configuração, ser executado em um Raspberry Pi, um gateway IoT ou um controlador incorporado. O modelo de implantação monobinário da Perl e a baixa sobrecarga de runtime o tornam genuíno “escreva uma vez, corra em qualquer lugar” em ambientes onde a sobrecarga do intérprete de Python ou o tempo de aquecimento JIT de Julia seriam inaceitáveis.
Se você está planejando implantar em qualquer lugar e everywhere Perl5 é sua escolha óbvia.
Uma herança construída com base na extração de texto e dados
Perl foi projetado do zero para processamento de texto, expressões regulares e “cola” trabalho entre os componentes do sistema. Na prática, os pipelines de dados científicos são dominados não por computação numérica, mas por data wrangling: leitura de formatos de arquivo heterogêneos, limpeza de registros confusos, junção de conjuntos de dados de diferentes fontes e roteamento de resultados para componentes de consumo downstream.
O mecanismo regex da Perl permanece entre os mais poderosos disponíveis, e uma linha pode realizar tarefas de limpeza de dados que exigiriam bibliotecas auxiliares em outros idiomas.
Se você está no domínio da computação científica, você pode ter se deparado com a noção de sistemas de gerenciamento de fluxo de trabalho e pesquisa reproduzível. Ambos dependem da execução de transformações de dados de ponta a ponta e do fluxo de trabalho para eliminar as atividades manuais, propensas a erros e tediosas de apontar e clicar que analistas e cientistas precisam fazer para transformar seus dados em insights e inferências, respectivamente.
Neste admirável mundo novo, a rica história do Perl5 permite que ele brilhe tanto como um componente de fluxos de trabalho quanto como uma linguagem de aplicativo que implementa esses fluxos de trabalho.
CPAN: um ecossistema de módulos testados em batalha
A Rede Abrangente de Arquivos Perl (CPAN) hospeda mais de 200.000 módulos em todos os domínios imagináveis. Embora as ofertas de ciência de dados não sejam tão extensas quanto o Python, os componentes básicos para construtores dedicados ESTÃO lá:
PDL (Perl Data Language) — computação numérica vetorizada com arrays N-dimensionais fortemente digitados (abrangidos em profundidade abaixo).
PDL::Stats — estatística descritiva, regressão, clustering (k-means, mini-batch k-means) e muito mais, construído em cima de matrizes de PDL.
AI::MXNet, AI::TensorFlow — associações de aprendizado profundo.
Estatísticas::Regressão, Estatísticas::Descritivas — estatísticas clássicas sem a dependência de PDL.
Text::CSV, Spreadsheet::XLSX, Data::MessagePack, Sereal — serialização de alto desempenho e E/S.
DBI + dezenas de drivers de banco de dados — acesso SQL a todos os principais RDBMS.
MCE (Mecanismo de muitos núcleos) — paralelismo estruturado para cargas de trabalho de memória compartilhada e distribuída.
Inline::C, Inline::CPP — incorpora código C ou C++ diretamente dentro de um arquivo de origem Perl; o compilador é chamado de forma transparente na primeira vez que o script é executado, tornando trivial soltar kernels críticos de desempenho em um programa de outra forma puro-Perl sem um sistema de compilação XS completo.
FFI::Platypus — funções de chamada em qualquer biblioteca compartilhada (
.so/.dylib/.dll) de Perl sem escrever uma única linha de código de cola XS ou C. O Platypus suporta todos os tipos, estruturas, callbacks e fechamentos equivalentes em C, e é a maneira moderna de vincular Perl a BLAS, LAPACK, HDF5 ou qualquer outra biblioteca nativa.Perl 5.36 — Maio de 2022
use v5.36— o pacote de recursos agora ativa automaticamenteuse warningsAlém deuse strict. Também desabilita oindirectsintaxe de chamada de método emultidimensionalsimulação de hash-key, eliminando duas fontes comuns de bugs sutis.Assinaturas de sub-rotina nomeadas (estável desde 5.36; experimental desde 5.20) — parâmetros de função agora são declarados por nome, com padrões opcionais. O
//=e||=operadores de valor padrão foram adicionados às assinaturas na versão 5.38, permitindo padrões que acionamundefou falsidade, respectivamente:
use v5.36;
sub clamp ($val, $lo = 0, $hi //= 1) {
$val < $lo ? $lo : $val > $hi ? $hi : $val;
}
isaoperador de classe (estável desde 5.36; introduzido no ponto 5.32) —$obj isa "ClassName"retorna um valor booliano; mais limpo queref($obj) eq "ClassName".builtinmódulo (estável desde 5.40; experimental desde 5.36) — funções lexicamente importáveis incorporadas diretamente no intérprete. O pacote estável 5.40 inclui, entre outros:ceil,floor— arredondamento inteiro semuse POSIX.trim— tira o espaço em branco à esquerda/à direita de uma string.indexed— emparelha cada elemento com seu índice; o companheiro idiomático ao multi-valorforloops (veja abaixo).true,false,is_bool- sentinelas booleanas digitadas; serialisers agora podem emitir JSONtrue/falseem vez de1/0.weaken,unweaken,is_weak— controle de contagem de referência para a construção de estruturas de dados bidirecionais sem vazamentos de memória.blessed,reftype,refaddr— introspecção de referência.
Rastreamento booliano estável (5.36) — escalares criados como boolianos (por exemplo,
!!1) agora mantêm sua natureza booleana por meio da atribuição, permitindo a serialização confiável com reconhecimento de tipo para JSON e MessagePack.Vários valores
forloops (estável desde 5.40; experimental desde 5.36) Iterar sobre pares ou N-tuplos sem aritmética de índice manual:
use v5.40;
use builtin 'indexed';
for my ($i, $val) (indexed @scores) { ... } # index and value
Ou pegar vários valores ao mesmo tempo
use v5.40;
for my ($val1, $val2, $val3) (@scores) { ... }
deferblocos (experimental desde 5.36) — um protetor de saída de escopo que executa o código de limpeza incondicionalmente quando um bloco sai, normalmente ou por exceção — um substituto natural para objetos de proteção de escopo baseados em destruidores e um padrão importante para o gerenciamento de recursos em pipelines de dados.Perl 5.38 — Julho de 2023
PERL_RAND_SEEDvariável de ambiente (5.38) — definir essa variável antes que uma execução faça cadarandchamada (sem explícita)srand) produzem a mesma sequência, permitindo algoritmos estocásticos reproduzíveis — simulações, amostragem aleatória, métodos de Monte Carlo — sem modificar o código-fonte.class/field/methodsintaxe (experimental desde 5.38) — um sistema de objetos com escopo lexical específico que não requer nenhumablessnem@ISAnem qualquer módulo CPAN. Útil para definir objetos de valor digitado, como linhas de conjunto de dados, parâmetros de modelo ou estágios de pipeline:
use feature 'class';
no warnings 'experimental::class';
class Vector2D {
field $x :param;
field $y :param;
method magnitude { sqrt($x**2 + $y**2) }
}
my $v = Vector2D->new(x => 3, y => 4);
say $v->magnitude; # 5
Perl 5.40 — Junho de 2024
try/catchTratamento de exceções (estável desde 5.40; experimental desde 5.34;finallybloco adicionado em 5.36) — o tratamento estruturado de exceções é agora um recurso de linguagem principal; nenhum módulo CPAN é necessário:
use v5.40;
try {
my $result = load_and_process($file);
}
catch ($e) {
warn "Pipeline error: $e";
}
finally {
close_resources(); # runs whether or not an exception was thrown
}
(Try::Tiny / Feature::Compat::Try são necessários apenas quando a segmentação perls for superior a 5,34.)
Vários valores
forloops (estável desde 5.40) — ver 5.36 entrada acima; eles se graduaram de experimental para estável nesta versão.builtin::infebuiltin::nan(experimental desde 5.40) — infinito de ponto flutuante digitado e constantes Não-um-Número, eliminando9**9**9ou POSIX hackeia em código numérico.^^operador lógico XOR (5.40) — completa o conjunto de operadores lógicos de média precedência (&&,||,^^); útil para operações de máscara booliana.use v5.40importa funções incorporadas — além de habilitar o pacote de recursos,use v5.40também importa o correspondentebuiltinpacote de versão, tornando tudo estávelbuiltin::funções disponíveis como nomes curtos semuse builtininstrução.Características de longa data (pré-5.36)
sayestate(desde 5.10)* —sayéprintcom uma nova linha implícita;statedeclara um lexical que persiste através de invocações de seu sub delimitador (um primitivo de memorização leve).Referências e fechamentos de primeira classe — subs anônimos, fechamentos e construção de referência são fundamentais e têm sido estáveis desde a Perl 5.
use constantou o CPANReadonlymódulo para constantes nomeadas;Readonlyimpõe imutabilidade profunda queuse constantnão.
Combinado com perlbrew ou plenv para gerenciamento de versões e carton para snapshots de dependência reproduzíveis, um projeto Perl moderno parece e se sente como um esforço de engenharia de software de primeira classe.
Limitações honestas
No case for Perl is complete without honesty about where it falls short:
Visualização — Perl não tem equivalente a
ggplot2oumatplotlib. Plots normalmente requerem uma chamada externa para R, gnuplot, ou uma biblioteca web. Às vezes, esse ponto fraco pode se tornar um ponto forte real, permitindo que se use Perl5 como a linguagem do aplicativo que orquestra e aprimora os outros atores.Momento comunitário — a comunidade de ciência de dados convergiu em Python e R. Encontrar tutoriais prontos, respostas do Stack Overflow e coautores é mais difícil.
Orientação do objeto — sem Moose/Moo o modelo OOP é detalhado; com eles adiciona uma dependência. O novo
classrecurso pode resolver alguns desses problemasDigite segurança em escala — os escalares dinâmicos da linguagem principal tornam as bases de código numéricas grandes e colaborativas mais difíceis de raciocinar (consulte a próxima seção).
Tipos de Perl Básico
O modelo de dados fundamental da Perl se concentra em três construções:
| Construção | Sigil | O que ela tem |
|---|---|---|
| Escalar | $ |
Um único valor: número, string, referência, ou undef |
| Array | @ |
Uma lista ordenada de escalares, indexada por inteiro |
| Hash | % |
Uma coleção não ordenada de valores escalares com chave por string |
Todo o resto — objetos, fechamentos, estruturas de dados complexas — é construído a partir dessas três primitivas via referências (\@array, \%hash, sub { ... }).
Este modelo é extraordinariamente flexível. Uma única matriz pode conter números inteiros, números de ponto flutuante, strings e referências aninhadas simultaneamente. Essa flexibilidade é exatamente o que fez de Perl a linguagem dominante de administração de sistemas e web-script por duas décadas.
O problema da hierarquia de cache
As CPUs modernas atingem o throughput de pico somente quando os dados fluem pelo cache L1/L2/L3† em blocos grandes e contíguos — uma propriedade chamada spatial locality. As matrizes perl não fornecem isso. Sob o capô, uma matriz de Perl é uma matriz C de pointers para escalar alocado por heap (SV) estruturas. Cada escalar carrega uma contagem de referência, uma tag de tipo e preenchimento – geralmente de 24 a 56 bytes por escalar em uma compilação de 64 bits. Iterar mais de um array Perl de um milhão de elementos envolve, portanto, um milhão de referências de ponteiro espalhadas pelo heap, produzindo um padrão de falha de cache que nega completamente a vantagem de velocidade dos pipelines SIMD modernos.
A concrete consequence: um produto pontual de dois vetores de 1.000 elementos escritos em Perl puro é aproximadamente 100-1000× mais lento do que a operação equivalente em um par de matrizes flutuantes PDL, que ocupam duas regiões de memória plana de 4.000 bytes que se encaixam confortavelmente no cache L1.
Contraste com R
R ocupa um meio-termo curioso. Como Perl, é uma linguagem dinâmica, interpretada - variáveis são recipientes não digitados, funções são valores de primeira classe, e o REPL interativo é o ambiente de desenvolvimento primário. R ainda tem análogos diretos aos três tipos principais de Perl:
| Conceito Perl | Analógico R |
|---|---|
$scalar |
vetor atômico length-1 ou escalar-na-lista |
@array |
list() |
%hash |
nomeado list() |
Referência (\@arr) |
R não usa referências explícitas; copiar-em-modificar semântica em vez |
Mas o tipo de cavalo de trabalho de R, ou seja, o vetor atômico não tem uma contrapartida direta de Perl. Um vetor atômico R é um bloco de memória contíguo e homogeneamente digitado – exatamente o layout que um cache de CPU recompensa. Cada escalar embutido em R é na verdade um vetor atômico de comprimento-1; não há “escalável” fora dos vetores atômicos.
Essa escolha de design significa que o código R opera naturalmente em vetores de milhões de duplas com throughput de nível BLAS, sem que o usuário escreva um único loop ou aloque um especial. “matriz” objeto.
Os tipos atômicos de R são:
| Tipo atómico R | Armazenamento | Equivalente C |
|---|---|---|
logical |
4 bytes/elemento | int (com NA sentinela) |
integer |
4 bytes/elemento | int32_t |
double |
8 bytes/elemento | double |
complex |
16 bytes/elemento | _Complex double |
character |
ponteiro para CHARSXP | char * (internado) |
raw |
1 byte/elemento | uint8_t |
R also defines higher-level structures built on atomic vectors:
- matriz — um vetor atômico 2D com um
dimatributo. - array — um vetor atômico N-D com um
dimatributo. - data.frame — uma lista nomeada de vetores atômicos de igual comprimento; a língua franca de
dados tabulares em R. - fator — um vetor inteiro com um
levelsatributo; codifica dados categóricos.
The lesson: O desempenho de computação da R quando usado em aplicações estatísticas e de ciência de dados flui diretamente de seus vetores atômicos contíguos. O caminho equivalente de Perl para o desempenho é uma extensão (que também é um stand alone). matlab como o ambiente), a Linguagem de Dados Perl PDL.
Threading e SIMD
Uma das características mais distintivas do PDL é o encadeamento implícito: as operações são transmitidas automaticamente por dimensões extras, eliminando loops explícitos no código do usuário e delegando loops internos a kernel C ou Fortran otimizados. Combinado com set_autopthread_targ(N), o PDL paralelizará automaticamente as fatias independentes N Threads do SO — sem que o usuário escreva um único fork ou Thread::Queue ligar.
Valores inválidos
PDL tem um conceito embutido de valores incorretos (PDL::Bad), diretamente análogo ao R’s NA. Um ndarray pode ser sinalizado como “valor incorreto ciente”, e as operações PDL propagam a maldade corretamente por meio de aritmética, estatística e E/S.
A tabela abaixo mapeia cada tipo R comumente usado para suas contrapartes Perl e PDL mais próximas, destacando onde as três línguas concordam, diferem ou se complementam.
| R type | Perl equivalent | PDL equivalent | Notes |
|---|---|---|---|
double (length-1) |
$x = 3.14 (scalar) |
double(3.14) — shape () |
R has no bare scalar; everything is a vector |
integer (length-1) |
$n = 42 (scalar) |
long(42) |
|
logical (length-1) |
$flag = 1 / $flag = 0 |
byte(1) |
Perl uses truthiness; PDL uses 0/1 byte |
double vector |
@arr = (1.1, 2.2, 3.3) |
double(1.1, 2.2, 3.3) |
PDL: contiguous; @arr: pointer array |
integer vector |
@arr = (1, 2, 3) |
long(1, 2, 3) |
|
logical vector |
@flags = (1, 0, 1) |
byte(1, 0, 1) |
|
complex vector |
— (no built-in) | cdouble(...) |
Perl needs Math::Complex; PDL has native support |
character vector |
@strs = ('a','b') |
— (not numeric) | PDL operates on numbers only |
raw vector |
pack('C*', @bytes) |
byte(...) |
|
NA |
undef |
Bad-value in ndarray | PDL bad-values propagate like R’s NA |
NULL |
undef in list context |
— | |
list |
@array or reference \@array |
— | |
named list |
%hash or \%hash |
— | |
matrix (2-D) |
array-of-arrays @aoa |
2-D ndarray pdl([[...],[...]]) |
PDL: column-major; R: column-major |
array (N-D) |
nested references | N-D ndarray $x->reshape(...) |
|
data.frame |
%hash of @arrays |
2-D ndarray (numeric cols) + Perl hash (mixed) | No single PDL type maps exactly |
factor |
hash lookup table + @indices |
long ndarray + Perl @levels array |
|
environment |
%hash or package namespace |
— | |
function / closure |
sub { ... } / closure |
— | PDL PP defines compiled kernels |
S3 / S4 object |
blessed reference + method dispatch | PDL object (blessed ndarray) | PDL objects are first-class Perl objects |
| Joe’s Row | Dois | Três |
Principais conclusões
Para dados numéricos e homogêneos puros (vetores, matrizes, tensores), as matrizes de PDL e os vetores atômicos R são funcionalmente equivalentes e comparativamente eficientes.
Para dados tabulares heterogêneos (tipos mistos, colunas de string, fatores), R’s
data.frameé mais ergonômico; Perl normalmente usa um hash de arrays ou um módulo dedicado, comoData::FrameouPDL::IO::CSV.Para texto, estruturas irregulares e cola do sistema, os tipos nativos do Perl são superiores ao R e ao Python.
A combinação Perl+PDL, portanto, fornece a união do que R oferece como uma linguagem estatística e o que Perl oferece como uma linguagem de sistemas - ao custo de uma curva de aprendizagem mais íngreme e ferramentas estatísticas menos prontas para uso.
No entanto, a combinação de Perl+PDL+R (com o último usado como um componente, ou instrumentalizado via Perl)
Esta série documenta a construção de um mecanismo de banco de dados vetorial criado no Perl5 + PDL do zero. Bancos de dados vetoriais sustentam pipelines modernos de geração aumentada de recuperação (RAG), pesquisa semântica e sistemas de recomendação de vizinhos mais próximos. Implementar um dos primeiros princípios é um excelente veículo para demonstrar as capacidades numéricas do PDL juntamente com os pontos fortes de programação de sistemas da Perl.
O diretório co-desenvolvido ao lado desses posts contém os seguintes componentes, cada um dos quais será objeto de um ou mais posts dedicados que farão referência a arquivos em um repositório dedicado.
Post 1 — Serialização e E/S: o VectorIO módulo
Arquivo: VectorIO.pm
O motor armazena vetores como bolhas binárias embaladas dentro MessagePack cargas úteis. Este post cobre:
Projetando um módulo com uma limpeza
ExporterAPI pública baseada emuse v5.40.Ajudantes de validação que impõem a correção do esquema nos limites do sistema.
Post 2 — Simulando um banco de dados vetorial
Arquivo: simulate_vectorDB.pl
Para podermos pesquisar um banco de dados, precisamos de um. Este post mostra:
Gerando vetores flutuantes aleatórios reprodutíveis com
PDL::random.Usando
GetOpt::Longpara análise de opção CLI ergonômica.Escrevendo um
--seedSimulação controlada que produz bancos de dados idênticos em todas as execuções — essencial para o benchmarking.Post 3 — Benchmarking: o
timing_DBMódulo
Arquivo: timing_DB.pm
As reivindicações de desempenho exigem medição. Este post apresenta:
Um arnês de benchmarking reutilizável Perl construído em
Time::HiRes.Metodologia para comparações justas entre as implementações Perl/PDL e R.
Interpretação de throughput (vetores/segundo) vs. latência (ms/consulta) para diferentes tamanhos de carga de trabalho.
Post 4 — K-Means Clustering com
PDL::Stats::Kmeans
Arquivo: kmeans.pl
K-means clustering é a espinha dorsal da abordagem de índice de arquivo invertido (IVF) para aproximar a pesquisa mais próxima. Este post cobre:
O
PDL::Stats::Kmeansinterface e seu contrato de devolução (centroid,cluster,n,R2,ss).Interpretando o
[obs × clusters]máscara de associação retornada porrun_kmeans.Comparando Perl/PDL k-means centroids contra R’s
kmeans()eClusterR::MiniBatchKmeans()para validar a correção numérica.Post 6 — Pesquisa de Índice de Arquivo Invertido (IVF)
Arquivo: compare_ivf_search.pl
Com os centroides na mão podemos particionar o banco de dados e realizar uma pesquisa sub-linear aproximada mais próxima do vizinho. Este post cobre:
Building the inverted lists: mapeando cada vetor de banco de dados para seu centroide mais próximo.
O
unpack_inverted_listsauxiliar emVectorIO.Querying: encontrar os centroides mais próximos do top-K e, em seguida, pesquisar apenas essas listas.
Compensações de precisão vs. velocidade, pois o número de listas investigadas varia.
Post 7 — Validando Contra R: Correção Numérica e Pipelines de Linguagem Cruzada
Arquivos: compare_kmeans_centroids.R, compare_kmeans_centroids_pure.R, plot_centroid_coordinates.R
The final post in the foundation series closes the loop between Perl and R:
- Exportar resultados PDL para CSV e lê-los em R para validação independente.
- Usando ggplot2 para visualizar coordenadas do centroide de ambos os idiomas simultaneamente.
- Um padrão de fluxo de trabalho para “computar em Perl, visualizar em R” que aproveita os pontos fortes de ambos os ecossistemas.
Next up — Post 1: Serialização e E/S com
VectorIO.pm
† As CPUs modernas têm vários níveis de memória rápida no chip chamados caches (L1, L2, L3) que ficam entre os núcleos do processador e a RAM principal. L1 é o menor (normalmente de 32 a 64 KB por núcleo) e mais rápido (latência de ciclos de relógio de 1 a 4); L2 é maior (256 KB a 1 MB) e um pouco mais lento; L3 é compartilhado entre núcleos (4 a 64 MB) com maior latência ainda. A RAM principal fica mais distante na latência de 60 a 100 ns - aproximadamente 200 vezes mais lenta que a L1.
Quando um cálculo toca a memória em um padrão previsível e contíguo, o hardware prefetcher pode carregar dados futuros em L1/L2 antes de ser necessário, alcançando um throughput de quase pico. A busca dispersa de ponteiros (como percorrer uma matriz Perl de escalares alocados por heap) derrota a pré-busca, interrompendo a CPU enquanto espera que cada falha de cache seja resolvida da RAM.