Preprint pessoal · não revisado por pares
Ezequias Rocha: de listas de algoritmos a inferência de vínculos sociais
1Laboratório de Sistemas de Informação (LSI), Universidade Federal de Campina Grande
2Bacharel em Ciência da Computação pela UFCG; mestrando
no GitHub desde out/2018 · 50 repositórios públicos · 138 seguidores
Resumo
Este documento descreve o trabalho técnico de um analista de sistemas e pesquisador do LSI/UFCG a partir do que está publicado nos seus repositórios. O resultado central é a replicação, em PyTorch, de um modelo não supervisionado que infere amizades a partir de trajetórias de check-in, com embeddings de 128 dimensões por aspecto e projeções no estilo TransH [1], [2]. Em paralelo, relatamos uma correção de digitação em teclados ABNT num projeto de ditado por voz [3], uma API FastAPI com lint e cobertura acoplados aos testes [5], três aplicações full stack em web e mobile e duas trilhas de ensino de algoritmos que vão de busca binária ao algoritmo de Mo. Medimos cerca de 1.110 commits autorais em 22 repositórios próprios entre 2019 e 2026.
Palavras-chave: inferência de vínculos sociais; embeddings de grafos de conhecimento; TransH; PyTorch; FastAPI; programação competitiva; Neovim.
1Introdução
Ezequias Rocha é analista de sistemas e pesquisador no Laboratório de Sistemas de Informação da UFCG, em Campina Grande, Paraíba. Formou-se bacharel em Ciência da Computação na mesma universidade e hoje faz mestrado. Também integra a organização EssentIA no GitHub, dedicada a agentes de IA, cujos repositórios são privados e por isso ficam fora deste texto.
A versão anterior deste documento era uma página com um nome e uma piada.Hospedada em ezequias.vercel.app. Esta é a v2, e a mudança de escopo é proposital. A versão 2 faz o contrário: tudo o que segue foi verificado clonando os repositórios públicos e lendo o código. Não há percentuais de domínio, datas de emprego ou empresas que não estejam nos próprios commits.
As contribuições descritas são quatro:
- uma replicação completa de um modelo de inferência de vínculos sociais não supervisionado, com ~2.400 linhas de Python em oito módulos (§2.1);
- uma correção em software livre que torna o ditado por voz utilizável com layout ABNT no Linux (§2.2);
- projetos de backend e full stack com testes automatizados desde 2020 (§2.3 a §2.5);
- material didático de algoritmos, com listas semanais e vídeos de resolução (§4).
A Tabela 1 resume as ferramentas que aparecem nesses trabalhos, agrupadas por área. A ordem dentro de cada linha não indica preferência.
| Área | Ferramentas |
|---|---|
| IA e dados | Python, PyTorch, scikit-learn, Pandas, NumPy, Jupyter, embeddings de grafos (TransH, TransR, TransD), Whisper e faster-whisper |
| Backend | FastAPI, Pydantic, Node.js, Express, rotas de API do Next.js, Knex, Mongoose, Socket.io |
| Front e mobile | TypeScript, React, React Native, Expo, Next.js, Leaflet, Vue |
| Bancos | PostgreSQL, SQLite, MongoDB, MySQL e SQL relacional |
| Qualidade e infra | pytest, Jest, Supertest, Ruff, Prettier, Poetry, Docker, Docker Compose, CUDA, Vercel, Git |
| Ambiente | Linux (Pop!_OS), Neovim em Lua, tmux, Wayland e X11 |
2Trabalhos
2.1Inferência não supervisionada de vínculos sociais
Problema.Dado apenas o histórico de check-ins de usuários do Foursquare em Nova York, decidir quais pares de pessoas são amigas, sem nenhum rótulo de amizade no treino. O repositório [2] replica o modelo ANES, proposto por Byun, Choi e Kim na Information Sciences em 2023 [1]. A ideia é que dois amigos deixam rastros parecidos em vários aspectos ao mesmo tempo: os mesmos lugares, em horários parecidos, em categorias de lugar parecidas, em regiões próximas.
Representação.Cada check-in vira uma tripla aspecto-orientada, como num grafo de conhecimento. Usuário, POI, tempo, categoria e geografia recebem tabelas de embedding separadas, todas com 128 dimensões.O código traz cinco variantes de modelo: ANES, ANES_GEO, ANES_GEO_YELP, ANES_GEO_Others e LBGC_v4. Em vez de comparar embeddings direto, o modelo projeta usuário e entidade num hiperplano específico de cada aspecto, à maneira do TransH, e mede a translação ali. A Figura 1 mostra o caminho completo; passe o cursor, toque ou navegue com Tab pelas partes.
arraste para os lados para ver a figura inteira
model.py (776 linhas) [2]. Os retângulos listrados representam vetores de ℝ¹²⁸ em escala reduzida. A geometria do hiperplano segue a Equação (1).Projeção.Seja 𝐰ᵣ o vetor normal unitário do hiperplano associado ao aspecto r. A projeção de um embedding 𝐡 remove dele a componente na direção de 𝐰ᵣ:
e a plausibilidade de uma tripla (h, r, t) é a distância L1 entre as projeções depois da translação 𝐝ᵣ,O treino da replicação usa norma L1, taxa de aprendizado 10⁻⁴ e 1000 iterações.
O arquivo loss.py combina três termos: uma margin loss que separa triplas observadas de triplas negativas, uma orthogonal loss que mantém o vetor de relação coerente com o hiperplano e uma norm loss que limita a norma dos embeddings. Na formulação clássica do TransH, o termo ortogonal tem a forma
que só penaliza quando o cosseno entre 𝐰ᵣ e 𝐝ᵣ passa de ε. O módulo projection.py também traz as variantes TransR e TransD, que trocam o hiperplano por uma matriz de projeção por relação e por vetores de projeção dinâmicos, respectivamente.
Tempo.O aspecto temporal não usa o timestamp cru. A hora local de cada check-in, corrigida pelo offset de fuso em minutos que vem no próprio dado, é mapeada para um de 168 slots semanais, um por combinação de dia da semana e hora. Assim, “terça às 19h” vira o mesmo token em qualquer semana do conjunto. A Figura 1(b) mostra a grade.
Amostragem negativa.Treinar com margem exige pares negativos, e sortear negativos de forma uniforme ignora a distribuição real de popularidade dos lugares. A replicação constrói a função de distribuição acumulada e sorteia com busca binária sobre ela, o que custa O(log n) por amostra em vez de O(n).Em Python isso costuma ser bisect sobre a lista acumulada; o ganho aparece porque o sorteio roda a cada lote, milhares de vezes por época. O Algoritmo 1 descreve o esquema.
- entrada: pesos w₁ … wₙ dos candidatos
- C[i] ← w₁ + … + wᵢ // uma vez, O(n)
- x ← Uniforme(0, C[n])
- retorne o menor i com C[i] ≥ x // busca binária, O(log n)
Protocolo.O pré-processamento gera recortes NYC_20, NYC_40, NYC_60, NYC_80 e NYC_100, cada um com pares verdadeiros e falsos separados em treino, validação e teste. O espaço aprendido é inspecionado com t-SNE. O código está dividido conforme a Tabela 2.
| Módulo | Responsabilidade |
|---|---|
preprocessing.py | check-ins, slots de tempo, recortes NYC_20 a NYC_100 |
ANES.py | laço de treino |
model.py | embeddings por aspecto e as cinco variantes (776 linhas) |
data.py | carregamento e lotes |
loss.py | margem, ortogonal, norma |
projection.py | TransH, TransR, TransD |
graphutils.py | utilidades de grafo |
utils.py | funções auxiliares |
2.2turbo-whisper: o apóstrofo que virava til
O turbo-whisper é um ditado por voz para desktop no estilo do SuperWhisper: atalho global, waveform na tela, transcrição com o Whisper da OpenAI em 99 idiomas e interface em PyQt6. Em setembro de 2026, Ezequias fez um fork do projeto original [4] e enviou três commits [3].
O primeiro corrige um bug que só aparece para quem usa teclado brasileiro. O texto transcrito era digitado na janela ativa via evdev, que injeta scancodes crus pensando num teclado US-QWERTY. O scancode que no layout americano produz ' cai, no ABNT, na tecla do til. Resultado: todo apóstrofo ditado aparecia como ~.O evdev fala com o kernel em nível de tecla física, abaixo do layout. Quem traduz tecla em caractere é o servidor gráfico, por isso o mesmo código físico vira outro símbolo quando o layout muda. A correção inverte a ordem de preferência: primeiro ferramentas que digitam caracteres respeitando o layout ativo, e só depois o evdev.
1def _type_linux(self, text: str) -> bool:
2 # Prefer xdotool (X11) / wtype (Wayland): both honor the active keyboard
3 # layout and handle Unicode. The evdev fallback sends raw US-QWERTY
4 # scancodes, so non-US layouts mistype punctuation (e.g. ABNT turns ' into ~).
5 is_wayland = bool(os.environ.get("WAYLAND_DISPLAY")) or (
6 os.environ.get("XDG_SESSION_TYPE", "").lower() == "wayland"
7 )
8 if is_wayland and shutil.which("wtype"):
9 subprocess.run(["wtype", "--", text], check=True, timeout=30)
10 if shutil.which("xdotool"):
11 delay_ms = max(1, int(self._typing_delay * 1000))
12 subprocess.run(["xdotool", "type", "--clearmodifiers",
13 "--delay", str(delay_ms), "--", text], check=True, timeout=30)
14 if self._evdev_available and self._uinput:
15 return self._type_evdev(text)
16 # ... depois PyAutoGUI e, por último, área de transferência
typer.py após o commit fix: prefer xdotool/wtype over evdev for auto-typing. Trecho resumido: no original, cada tentativa fica num try que retorna True no sucesso e imprime o erro antes de cair para a próxima.Dois detalhes da listagem merecem nota. A detecção de Wayland olha duas variáveis, porque nem toda sessão exporta XDG_SESSION_TYPE de forma confiável. E o xdotool roda com --clearmodifiers,--clearmodifiers solta temporariamente teclas como Ctrl e Shift que ainda estejam pressionadas pelo atalho de gravação, evitando que o texto vire uma sequência de comandos. com o atraso entre teclas vindo da configuração typing_delay_ms já existente no projeto.
O segundo commit, feat: language selection, headless recording, clearer offline error, acrescenta 143 linhas em api.py, config.py e main.py: escolha de idioma, gravação sem interface e uma mensagem de erro que diz claramente quando o servidor de transcrição está fora do ar. O terceiro documenta a instalação auto-hospedada no Pop!_OS: um servidor faster-whisper em Docker com CUDA (--gpus all, modelo Systran/faster-whisper-small), porta exposta só em 127.0.0.1, cache do HuggingFace montado como volume para não baixar o modelo a cada subida, e áudio via PipeWire e PortAudio.
2.3fast_zero: qualidade amarrada ao comando de teste
Uma API REST de usuários em FastAPI [5], pequena de propósito, onde o interesse está na engenharia ao redor. Os schemas em Pydantic v2 separam papéis: UserSchema para entrada, UserPublic para resposta, UserDB para o registro e UserList para coleções. O e-mail é validado por EmailStr, as rotas respondem com HTTPStatus explícito e o caso de usuário inexistente devolve 404.
O projeto usa Python 3.14 e Poetry. O Ruff roda com as regras I, F, E, W, PL (as checagens do pylint) e PT (estilo pytest), em modo preview. O taskipy encadeia tudo: pre_test = lint impede que um teste rode sobre código fora do padrão e post_test = coverage html gera o relatório de cobertura do pytest-cov ao final.O TestClient do FastAPI fica numa fixture do pytest, então cada teste recebe um cliente pronto sem subir servidor.
2.4clone-tabnews
Um clone do TabNews em Next.js 13 com PostgreSQL [6], publicado na Vercel [7]. O banco de desenvolvimento sobe via Docker Compose a partir de infra/compose.yaml, a aplicação fala com ele pelo driver pg e o endpoint /api/v1/status tem teste de integração em Jest, que bate no banco de verdade em vez de num mock. Prettier, .editorconfig e .nvmrc fixam formatação e versão do Node para qualquer máquina.
2.5Três aplicações em três plataformas
Em 2020, três projetos repetiram a mesma forma (API, web e app mobile) com problemas diferentes. O Ecoleta [8] é um marketplace de pontos de coleta de resíduos por geolocalização; o DevRadar [9] encontra desenvolvedores próximos e avisa em tempo real; o be-the-hero [10] é o que tem a API coberta por testes. A Tabela 3 compara as decisões técnicas.
| Ecoleta [8] | DevRadar [9] | be-the-hero [10] | |
|---|---|---|---|
| API | Express + Knex, migrations e seeds | Express + Mongoose | Express + Knex |
| Banco | SQLite | MongoDB, consultas geoespaciais | SQLite |
| Destaque | validação Celebrate/Joi; upload com Multer; mapas Leaflet; drag-and-drop | Socket.io avisa devs próximos; API do GitHub via axios | validação Celebrate; testes com Jest + Supertest, cross-env |
| Web | React + TypeScript, react-router | React | React |
| Mobile | Expo, react-native-maps, expo-location, mail-composer | Expo, mapas, WebView, socket.io-client | React Native / Expo |
| Commits | 124 | 123 | 122 |
No DevRadar, a busca por proximidade fica no banco, com consultas geoespaciais do MongoDB via Mongoose, e o Socket.io avisa em tempo real os devs próximos. No Ecoleta, a mesma imagem atravessa duas camadas: react-dropzone no navegador e Multer na API, que valida o corpo da requisição com Celebrate antes de gravar pelo Knex.
3Métodos e ambiente
O trabalho acontece em Linux, no Pop!_OS, com Neovim configurado em Lua [15] e tmux [16]. A configuração do editor usa LSP para diagnóstico e navegação, Telescope para busca, Treesitter para sintaxe, Harpoon para alternar entre poucos arquivos marcados,Harpoon troca a busca por arquivo por atalhos fixos para os três ou quatro arquivos da tarefa atual. Undotree mostra o histórico de desfazer como árvore, não como linha. Fugitive para Git, Undotree, Trouble para listas de diagnóstico, Zen Mode, um plugin de refatoração e o cloak, que esconde valores de arquivos .env enquanto a tela está sendo compartilhada.
É o mesmo ambiente das notas de auto-hospedagem do §2.2: Pop!_OS, Docker com CUDA e teclado ABNT, onde o bug do apóstrofo aparece no uso diário.
4Ensino de algoritmos
Desde 2020, Ezequias monta trilhas semanais de Aprendizado de Algoritmos com listas no vJudge e grava vídeos resolvendo as questões para os alunos [11], [12].
Trilha iniciante.Ad hoc, dois ponteiros, soma acumulada, busca binária, estruturas de dados (fila, heap, pilha, set e mapa), teoria dos números com MDC, MMC e crivo, aritmética modular e exponenciação binária.
Trilha avançada.Três técnicas para consultas em intervalos, que respondem a perguntas diferentes, como resume a Tabela 4. A Segment Tree responde consulta e atualização pontual em O(log n). A Lazy Propagation adia atualizações de intervalo inteiro nos nós internos e só as empurra para baixo quando um filho é visitado. O algoritmo de Mo resolve consultas offline: ordena as consultas por bloco de tamanho √n e move dois ponteiros, adicionando e removendo um elemento por vez.Mo serve quando a resposta não é decomponível (contar elementos distintos num intervalo, por exemplo), situação em que a Segment Tree não combina bem os filhos.
| Técnica | Atualização | Consulta | Modo |
|---|---|---|---|
| Segment Tree | O(log n) pontual | O(log n) | online |
| + Lazy Propagation | O(log n) em intervalo | O(log n) | online |
| Decomposição √n | O(1) ou O(√n) | O(√n) | online |
| Algoritmo de Mo | não se aplica | O((n + q)√n) no total | offline |
ATAL.Na disciplina de Análise e Técnicas de Algoritmos da UFCG, as soluções de Codeforces ficaram organizadas por paradigma [13]: força bruta, backtracking, guloso, divisão e conquista, programação dinâmica e grafos com BFS e DFS. Organizar por paradigma, e não por número de questão, faz do repositório um índice de técnicas.
Inteligência Artificial.Entre 2022 e 2023, os quizzes da disciplina de IA da UFCG ficaram em notebooks Jupyter [14], o que explica boa parte do volume de Jupyter na Figura 3.
5Resultados quantitativos
As medidas abaixo vêm de 22 repositórios próprios clonados e analisados, sem contar forks. A Figura 2 mostra os commits do autor por ano, desenhados na mesma escala; o total é de aproximadamente 1.110.Os 3 commits de 2026 são os do turbo-whisper (§2.2). A contagem só enxerga repositórios públicos próprios; os da EssentIA são privados e ficam de fora.
A Figura 3 mede volume de código por linguagem, em bytes. É uma medida de quanto texto foi escrito em cada linguagem, não de proficiência.Notebooks Jupyter são JSON com saídas embutidas, então os bytes superestimam o código ali. CSS e HTML vêm sobretudo dos projetos web de 2019 e 2020. O peso de JavaScript reflete os anos de estudo web e os projetos de 2020; Python é menor em bytes mas concentra o trabalho de pesquisa.
6Histórico
Como num histórico de versões, cada ano registra o que entrou.
- 2018
- Conta no GitHub, em outubro.
- 2019
- Começa os repositórios de estudo de longo prazo: Web-Estudos [17] e Python-Estudos [18].
- 2020
- Java na UFCG; Semanas Omnistack (DevRadar, be-the-hero) e NLW (Ecoleta); extensão que acelera áudios do WhatsApp Web; começa a ensinar algoritmos.
- 2021
- ATAL: soluções organizadas por paradigma.
- 2022–23
- IA na UFCG em notebooks; ambiente migra para Neovim em Lua; clone-tabnews começa em 2023.
- 2024
- Replicação do ANES em PyTorch (pesquisa); configuração de tmux.
- 2025
- fast_zero em FastAPI; nova turma de algoritmos.
- 2026
- Contribuição open source no turbo-whisper, com a correção do ABNT.
Estudos de longo prazo.O Web-Estudos tem 844 commits entre 2019 e 2025, 479 deles do autor. Vai de JavaScript do zero (map, filter, reduce, estilo imperativo contra declarativo) a AJAX com XHR, fetch, axios e jQuery, depois Express, Gulp, Webpack, Vue e React, e termina em SQL relacional com joins e agregação e em MongoDB com $lookup. O Python-Estudos, com 105 commits do autor, cobre acesso a banco com consultas parametrizadas, incluindo um exercício chamado “selecionar sem SQL injection”, CRUD e paginação com LIMIT/OFFSET.
Completam o arquivo: ibdmd, com datasets de BI cruzando lojas, gerentes e vendas; os primeiros projetos em Java na UFCG, como o coisa (Controle Institucional da Situação Acadêmica), uma agenda de contatos e um controle de alunos; o audio-speed-controller; e os exercícios bin2dec, casa-criativa e doe, este último da MaratonaDev.
7Conclusão
O fio que liga as seções é o mesmo nos dois extremos do histórico: ler a fundo antes de construir. Nas listas de algoritmos, isso significa saber por que Mo precisa ser offline. Na pesquisa, significa reimplementar um paper inteiro, com suas três perdas e sua amostragem pela CDF, em vez de chamar uma biblioteca. Em software livre, significa descer até o scancode para entender por que um apóstrofo vira til.
Disponibilidade de código.Todos os repositórios citados são públicos em github.com/ezequiasOR. Os repositórios da EssentIA são privados e não foram usados aqui.
Agradecimentos
Aos alunos das trilhas de Aprendizado de Algoritmos, para quem as listas e os vídeos foram feitos. Ao LSI/UFCG. E aos mantenedores do turbo-whisper, por deixarem o código aberto o bastante para alguém com teclado ABNT consertar.
Referências
- [1]J. Byun, S. Choi, S. Kim. Aspect-oriented unsupervised social link inference on user trajectory data. Information Sciences, vol. 626, 2023. doi:10.1016/j.ins.2023.01.022
- [2]E. Rocha. replication-ANES: replicação em PyTorch de [1], 2024. github.com/ezequiasOR/replication-ANES
- [3]E. Rocha. turbo-whisper (fork): correção ABNT, seleção de idioma, notas de auto-hospedagem, 2026. github.com/ezequiasOR/turbo-whisper
- [4]knowall-ai. turbo-whisper, projeto original. github.com/knowall-ai/turbo-whisper
- [5]E. Rocha. fast_zero: API em FastAPI com Ruff, pytest e taskipy, 2025. github.com/ezequiasOR/fast_zero
- [6]E. Rocha. clone-tabnews: Next.js e PostgreSQL em Docker, 2023–24. github.com/ezequiasOR/clone-tabnews
- [7]clone-tabnews, demonstração publicada na Vercel. clone-tabnews-brown.vercel.app
- [8]E. Rocha. Ecoleta: API, web e mobile em TypeScript, 2020. github.com/ezequiasOR/Ecoleta
- [9]E. Rocha. DevRadar: geolocalização e WebSocket, 2020. github.com/ezequiasOR/DevRadar
- [10]E. Rocha. be-the-hero: API testada com Jest e Supertest, 2020. github.com/ezequiasOR/be-the-hero
- [11]E. Rocha. aa-iniciante: trilha iniciante de Aprendizado de Algoritmos. github.com/ezequiasOR/aa-iniciante
- [12]E. Rocha. aa: trilha avançada, Segment Tree, Lazy Propagation, Mo. github.com/ezequiasOR/aa
- [13]E. Rocha. atal-ufcg: soluções por paradigma. github.com/ezequiasOR/atal-ufcg
- [14]E. Rocha. ia-ufcg: quizzes de Inteligência Artificial em Jupyter, 2022–23. github.com/ezequiasOR/ia-ufcg
- [15]E. Rocha. nvim: configuração do Neovim em Lua. github.com/ezequiasOR/nvim
- [16]E. Rocha. tmux: configuração do tmux. github.com/ezequiasOR/tmux
- [17]E. Rocha. Web-Estudos, 2019–2025. github.com/ezequiasOR/Web-Estudos
- [18]E. Rocha. Python-Estudos. github.com/ezequiasOR/Python-Estudos
Correspondência
Correspondência sobre este trabalho pode ser enviada por qualquer um dos canais abaixo.