В настоящее время существует много мануалов как правильно делать запросы, в основном они касаются привычного всем языка, причём, неважно какой он, модель преобразует его в вектор который одинаков для большинства людей. Нюансы вроде системы времён, падежей, фиксированной или гибкой последовательности слов мало влияют на структурированный вывод программ, в основном они нужны лишь для художественной генерации или передачи смысла текста от человека к человеку.

Задача довольно простая - как с использованием минимально возможного набора слов без приставок, суффиксов, окончаний или с их минимумом, а также союзов и других вспомогательных речевых конструкций получить на выходе годный код с 0% ошибок и 90% функционала согласно такому промпт-ТЗ.

Итак, приступим. Будем использовать VS Code/блокнот с пустой папкой.

Для начала необходимо развернуть виртуальное окружение. Для этого пишем следующий промпт. >Замечание - пора на Хабре добавить в язык программирования "Промптинг"<

Развёртывание виртуального окружения

Хотеть бэш скрипт проверь .venv если нет создать, обновить pip последняя версия найти requirements.txt установить библиотеки файл этот. Опция аргумент имя файла.py скрипт проверь наличие окружения .вэнв если нет установи рекварементс.txt. Если .вэнв уже есть запускай питон 3 скрипт проверь что запуск внутри вэнв. Хотеть список зависимостей флаг --g сохранить в файл requirements-текущая дата-время.txt изменить версия == на >=. выйди из вэнв по завершению питона.

Данный промпт генерирует следующий код

#!/bin/bash

# Имя виртуального окружения
VENV_DIR=".venv"
# Имя файла скрипта из аргумента
PY_SCRIPT=$1

# 1. Если передан флаг --g, сохраняем зависимости и выходим
if [[ "$1" == "--g" ]]; then
    if [ -d "$VENV_DIR" ]; then
        source "$VENV_DIR/bin/activate"
        FILENAME="requirements-$(date +'%Y%m%d-%H%M%S').txt"
        # Сохраняем, меняя == на >=
        pip freeze | sed 's/==/>=/g' > "$FILENAME"
        echo "Зависимости сохранены в $FILENAME"
        deactivate
    else
        echo "Ошибка: .venv не найден. Нечего сохранять."
    fi
    exit 0
fi

# 2. Проверка и создание .venv
if [ ! -d "$VENV_DIR" ]; then
    echo "Создаю виртуальное окружение..."
    python3 -m venv "$VENV_DIR"
    source "$VENV_DIR/bin/activate"
    
    echo "Обновляю pip..."
    pip install --upgrade pip
    
    if [ -f "requirements.txt" ]; then
        echo "Устанавливаю библиотеки из requirements.txt..."
        pip install -r requirements.txt
    fi
else
    source "$VENV_DIR/bin/activate"
fi

# 3. Запуск Python скрипта (если передан аргумент)
if [ -n "$PY_SCRIPT" ]; then
    if [ -f "$PY_SCRIPT" ]; then
        echo "Запуск $PY_SCRIPT внутри $(which python)..."
        python3 "$PY_SCRIPT"
    else
        echo "Ошибка: Файл $PY_SCRIPT не найден."
    fi
else
    echo "Окружение готово. Имя скрипта для запуска не указано."
fi

# 4. Выход из venv
deactivate

запуская командой ./generate_requirements.sh my.py можно получить запуск скрипта с автоматической установкой виртуального окружения на основе файла requirements.txt когда виртуальное окружение уже создано и имеется повторный запуск применяется уже к установленному venv. Пример файла requirements.txt
pygame
PyOpenGL
PyOpenGL_accelerate
numpy

matplotlib
Если необходимо сканировать пакеты которые установлены, запускается скрипт с флагом --g, создаётся файл с таймстемпом requirements-20260427-213724.txt
содержащий
contourpy>=1.3.3
cycler>=0.12.1
fonttools>=4.62.1
kiwisolver>=1.5.0
matplotlib>=3.10.9
numpy>=2.4.4
...

подправленные версии с точки зрения последующей установкой новых

my.py - любой hello world, но лучше использовать промпт
пример Питон numpy вектор вывод умножение число

import numpy as np

# Создание вектора
vector = np.array([1, 2, 3])

# Умножение на число
result = vector * 5

print(result)
# Вывод: [ 5 10 15]

Обратить внимание на характер фраз и введение "промпт" переменных такой как вэнв и скрипт.
Следующий пример - создаём цифровой фильтр с БИХ характеристикой на языке С и проверяем его с генерацией выходного csv файла с отсчётами и значениями коэффициентов.

Цифровой фильтр - ядро

Дай цифровой фильтр чистый С файл калькюляйт си функция калькуляйт цикл по n отсчётам вход n, массив выходов размер n, массив отсчётов х, и коэффициентов сх одинаковые размер, число коэффициентов эникс, массив отсчётов у, и коэффициентов су одинаковые размер, число коэффициентов энигрек, отсчёты и коэффициенты флоат остальное инт размер. внутри аккумулятор акк ноль, вход х нулевой константа задать 1 затем цикл умножение с накоплением сх и с цикл умножение с накоплением су и у в аккумулятор. сдвигать элементы массивы х и у прямой порядок отсчётов на один только инкремент индекса плюс плюс, начать индекс ноль использовать временная переменная t1 t2 обмен сохранить аккумулятор массив выходов

По данному промпту генерируется следующий код, причём, +- одинаковый для любых моделей.

void calculate(int n, float* outputs, float* x, float* cx, int nx, float* y, float* cy, int ny) {
    for (int i = 0; i < n; i++) {
        float acc = 0.0f;
        
        // Входной отсчет x[0] константа 1 (согласно запросу)
        x[0] = 1.0f;

        // Цикл умножения с накоплением для входов (сх и х)
        for (int j = 0; j < nx; j++) {
            acc += cx[j] * x[j];
        }

        // Цикл умножения с накоплением для выходов (су и у)
        // Обычно у[0] не используется в сумме для расчета текущего у[0], 
        // поэтому начинаем с 1, если су[0] не предусмотрен как обратная связь
        for (int j = 1; j < ny; j++) {
            acc += cy[j] * y[j];
        }

        // Сохраняем результат
        outputs[i] = acc;
        y[0] = acc;

        // Сдвиг элементов массивов х и у (прямой порядок, инкремент ++)
        // Используем временные переменные t1, t2 для обмена (сдвига)
        float t1, t2;

        // Сдвиг X
        t1 = x[0];
        for (int j = 1; j < nx; j++) {
            t2 = x[j];
            x[j] = t1;
            t1 = t2;
        }

        // Сдвиг Y
        t1 = y[0];
        for (int j = 1; j < ny; j++) {
            t2 = y[j];
            y[j] = t1;
            t1 = t2;
        }
    }
}

Отличный фильтр! Как и требуется - умножение с накоплением, сдвиг элементов на 1 только с использованием инкремента указателя. На архитектурах DSP процессоров есть команды, которые используют пост-инкремент указателя. Пример кода ассемблера и промпт для этого:

иметь реализация сдвиг массивов Х и У фрагмент кода ассемблер для Техас Инструменты процессор семейства С2000 используй пост-инкремент

; Предположим:
; XAR4 указывает на начало массива (X[0])
; XAR5 указывает на X[1]
; AL используется как временная переменная (T1)
; PH используется как счетчик (NX - 1)

        MOVZ    AR6, @NX        ; Загружаем NX
        SUBB    XAR6, #1        ; Нам нужно NX-1 итераций для сдвига
        MOVZ    AR0, @AR6       ; Переносим в AR0 для использования в BANZ

        ; Настройка указателей
        MOVL    XAR4, #_X       ; Адрес X[0]
        MOVL    XAR5, #_X       ; Адрес X[0]
        ADDB    XAR5, #1        ; Теперь XAR5 указывает на X[1]

SHIFT_LOOP:
        MOV     AL, *XAR4       ; T1 = X[i]
        MOV     AH, *XAR5       ; Временный буфер для обмена (T2)
        MOV     *XAR4++, AH     ; X[i] = X[i+1], инкремент указателя i
        MOV     *XAR5++, AL     ; X[i+1] = T1, инкремент указателя i+1
        
        BANZ    SHIFT_LOOP, AR0-- ; Цикл, пока AR0 не станет 0

Довольно неплохо, но требует проверки, которую оставим за кадром. Что касается оптимизации то можно получить классическое решение


хотеть реализация ассемблер код фрагмент фильтр для Техас Инструменты процессор семейства С2000 используй рэп и мак

; На входе:
; XAR4 - указатель на массив данных (X)
; XAR5 - указатель на массив коэффициентов (CX)
; PH   - количество коэффициентов (NX)
; ACC  - результат (аккумулятор)

        ZAPA                    ; Обнулить ACC и P (регистр произведения)
        MOVZ    AR0, @NX        ; Загрузить количество итераций (NX)
        SUBB    XAR0, #1        ; RPT выполняет N+1 раз, поэтому вычитаем 1

        ; --- Цикл умножения с накоплением (MAC) ---
        ; RPT повторяет следующую инструкцию AR0 раз
        ; *XAR4++ : берет X[i], пост-инкремент адреса
        ; *XAR5++ : берет CX[i], пост-инкремент адреса
        RPT     @AR0
        MAC     *XAR4++, *XAR5++, ACC
        
        ADDL    ACC, P          ; Добавить последний результат произведения в ACC

Достаточно попросить использовать команды RPT (рэп) - повторение заданного количества раз в регистре и MAC (мак) - умножение с накоплением. Последовательность на ассемблере RPT-MAC означает выполнить эту команду заданное количество раз, очень удобно для повторяющихся операций.
Для оптимизации попросить MACD. Оптимизированная версия

дать реализация ассемблер код фрагмент фильтр для Техас Инструменты процессор семейства С2000 используй команду Макдональдс вместо Т1 Т2

; XAR4 — указывает на ПОСЛЕДНИЙ элемент массива данных X (X[NX-1])
; XAR5 — указывает на ПОСЛЕДНИЙ элемент массива коэффициентов CX (CX[NX-1])
; ACC  — аккумулятор (результат)
; Обязательно: массивы должны идти "задом наперед" для логики сдвига MACD

        SETC    SXM             ; Включить знаковое расширение
        ZAPA                    ; Обнулить ACC и P

        MOVZ    AR0, @NX        ; Загружаем число коэффициентов
        SUBB    XAR0, #1        ; Корректировка для RPT (выполняет N+1 раз)

        ; --- Главный цикл фильтрации ---
        ; MACD делает: P = *XAR4 * *XAR5, ACC = ACC + P, 
        ; затем копирует: *(XAR4+1) = *XAR4 (сдвиг!)
        ; и делает декремент: XAR4--, XAR5-- (пост-декремент)
        
        RPT     @AR0
        MACD    ACC, *XAR4--, *XAR5--

        ADDL    ACC, P          ; Добавить финальное произведение в ACC

Получаем полностью оптимизированный вариант. Но это уже другая история, какой командой обнулить аккумулятор.

Создаём заголовочник
генерируй калькюляйт аш с прототипом функции кальк, документ и кислород но будь осторожен с типами и указателями

/**
 * @file calculate.h
 * @brief Реализация цифрового фильтра (Прямая форма I).
 */

#ifndef CALCULATE_H
#define CALCULATE_H

/**
 * @brief Вычисляет выходные значения цифрового фильтра.
 * 
 * Функция проходит циклом по n отсчетам, выполняя умножение с накоплением (MAC)
 * и обновляя линии задержки x и y.
 * 
 * @param n        [in]  Количество итераций (отсчетов).
 * @param outputs  [out] Массив для записи результатов (размер n).
 * @param x        [in,out] Массив предыдущих входных отсчетов (размер nx).
 * @param cx       [in]  Массив коэффициентов для входов (размер nx).
 * @param nx       [in]  Количество входных коэффициентов.
 * @param y        [in,out] Массив предыдущих выходных отсчетов (размер ny).
 * @param cy       [in]  Массив коэффициентов обратной связи (размер ny).
 * @param ny       [in]  Количество выходных коэффициентов.
 */
void calculate(int n, float* outputs, float* x, float* cx, int nx, float* y, float* cy, int ny);

#endif // CALCULATE_H

Любезно позаботился сделав Doxygen формат описания, необходимый как воздух (кислород)

Далее продолжаем с новым контекстным окном. Пробуем сопряжение без запоминания предыдущего, описываем прототип функции промптом вместо кода. Рассчитываем коэффициенты цифрового фильтра - нерекуррентная часть скользящее среднее, рекуррентная - комплексно сопряжённые (колебательные) полюса, расположенные случайным образом на комплексной окружности.

Генерация коэффициентов цифрового фильтра и главная функция

Дать проверку чистый С вызови готовая функция калькюляйт прототип аргументы вход N, массив выходов вых размер N, массив отсчётов Х, и коэффициентов СХ одинаковые размер, число коэффициентов ЭнИкс, массив отсчётов У, и коэффициентов СУ одинаковые размер, число коэффициентов ЭнИгрек, отсчёты коэффициенты флоат остальное инт, инклуд калькюляйт аш без заглушек. Сделать формирование коэффициентов СХ и СУ так что СУ индекс ноль всегда ноль. Коэффициенты СХ одинаково единица делённая на ЭнИкс размер. Коэффициенты СУ функция рандом внутри единичной комплексная окружность устойчивость учти, альфа амплитуда количество по размеру ЭнИгрек. Хардкод Пи. Обнули массивы Х и У. Массивы статические макросы ЭнИкс 5 ЭнИгрек 7 Эн 50. Дай вывод CSV файл и на экран сначала коэффициенты СХ СУ потом отсчёты вых Эн с индекс. Внимательно вызов калькюляйт число аргументов типы и массивы последовательность.

Вывод

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "calculate.h"

#define NX 5
#define NY 7
#define N  50
#define PI 3.14159265358979323846

int main() {
    // Статические массивы
    float out[N];
    float x[NX] = {0};
    float cx[NX];
    float y[NY] = {0};
    float cy[NY];

    srand((unsigned int)time(NULL));

    // 1. Формирование CX: 1/NX
    for (int i = 0; i < NX; i++) {
        cx[i] = 1.0f / NX;
    }

    // 2. Формирование CY: устойчивые коэффициенты
    // CY[0] всегда 0 по условию
    cy[0] = 0.0f;
    // Генерируем остальные как малые случайные величины для устойчивости
    // (Сумма модулей CY < 1 — достаточное условие устойчивости)
    for (int i = 1; i < NY; i++) {
        float alpha = (float)rand() / RAND_MAX; // амплитуда < 1
        float phase = (float)rand() / RAND_MAX * 2.0f * PI;
        // Берем проекцию на вещественную ось и нормируем, чтобы система не "разлетелась"
        cy[i] = (alpha * cosf(phase)) / NY; 
    }

    // 3. Вызов функции calculate
    // Прототип: void calculate(int n, float *out, int nx, float *x, float *cx, int ny, float *y, float *cy);
    calculate(N, out, x, cx, NX, y, cy, NY);

    // 4. Вывод на экран
    printf("Coefficients CX:\n");
    for (int i = 0; i < NX; i++) printf("%.4f ", cx[i]);
    
    printf("\n\nCoefficients CY:\n");
    for (int i = 0; i < NY; i++) printf("%.4f ", cy[i]);

    printf("\n\nResults (Index, Value):\n");
    for (int i = 0; i < N; i++) {
        printf("%d, %.6f\n", i, out[i]);
    }

    // 5. Вывод в CSV файл
    FILE *f = fopen("output.csv", "w");
    if (f) {
        fprintf(f, "Type,Index,Value\n");
        for (int i = 0; i < NX; i++) fprintf(f, "CX,%d,%.6f\n", i, cx[i]);
        for (int i = 0; i < NY; i++) fprintf(f, "CY,%d,%.6f\n", i, cy[i]);
        for (int i = 0; i < N; i++)  fprintf(f, "OUT,%d,%.6f\n", i, out[i]);
        fclose(f);
        printf("\nData saved to output.csv\n");
    }

    return 0;
}

Создаём файл Main.c и сохраняем

После чего конечно же мы не будем долго думать как создать Makefile для gcc

Makefile

Хотеть Makefile для антилопы а также Си не хуже 2011 года, сканировать все файлы с и компилировать в оут исполняемый а также математика либа

# Настройки компилятора
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -O2
LDFLAGS = -lm

# Имя выходного файла
TARGET = out

# Автоматический поиск всех .c файлов в текущей директории
SRCS = $(wildcard *.c)
# Превращение списка .c в список .o
OBJS = $(SRCS:.c=.o)

# Главная цель
all: $(TARGET)

# Сборка исполняемого файла
$(TARGET): $(OBJS)
        $(CC) $(OBJS) -o $(TARGET) $(LDFLAGS)

# Правило для объектных файлов
%.o: %.c
        $(CC) $(CFLAGS) -c $< -o $@

# Очистка
clean:
        rm -f $(OBJS) $(TARGET)

.PHONY: all clean

запускаем make, видим
gcc -Wall -Wextra -std=c11 -O2 -c calculate.c -o calculate.o
gcc -Wall -Wextra -std=c11 -O2 -c Main.c -o Main.o
gcc calculate.o Main.o -o out -lm
запускаем исполняемый файл ./out

Вывод программы

Type,Index,Value
CX,0,0.200000
CX,1,0.200000
CX,2,0.200000
CX,3,0.200000
CX,4,0.200000
CY,0,0.000000
CY,1,0.049448
CY,2,-0.008871
CY,3,0.092645
CY,4,0.083334
CY,5,-0.053389
CY,6,-0.077179
OUT,0,0.200000
OUT,1,0.409890
OUT,2,0.618494
OUT,3,0.845476
OUT,4,1.090962
OUT,5,1.127226
OUT,6,1.138613
OUT,7,1.153176
OUT,8,1.149394
OUT,9,1.122531
OUT,10,1.102652
OUT,11,1.099363
OUT,12,1.094917
OUT,13,1.089723
OUT,14,1.089271
OUT,15,1.091743

....

Теперь приступим к визуализации результатов нашего csv. Также очищаем контекст для старта с нуля

Визуализатор Питон

Да, Питон, визуализируй комплексная плоскость если коэффициенты отсчётов входа X как CX а выходов Y как СУ поля а на графике от отсчётов размести поле OUT. Читай csv формат тип CX или CY или OUT ,index,value. Индекс коэффициентов максимальный есть порядок фильтра. Пересчитать коэффициенты в нули и полюса для строить график комплексная плоскость и единичная окружность справа половина слева половина график отсчётов ОУТ от индекса. матплотлиб без пандас. открой любой csv папка текущая. данные идут списком в столбец, первый столбец тип, первая строка заголовок

import matplotlib.pyplot as plt
import numpy as np
import glob

# 1. Чтение CSV (без pandas)
csv_files = glob.glob("*.csv")
if not csv_files:
    raise FileNotFoundError("CSV файл не найден в текущей директории.")

filename = csv_files[0]
cx_dict, cy_dict, out_dict = {}, {}, {}

with open(filename, 'r') as f:
    next(f)  # Пропуск заголовка
    for line in f:
        parts = line.strip().split(',')
        if len(parts) < 3: continue
        label, idx, val = parts[0], int(parts[1]), float(parts[2])
        if label == 'CX': cx_dict[idx] = val
        elif label == 'CY': cy_dict[idx] = val
        elif label == 'OUT': out_dict[idx] = val

# 2. Подготовка массивов
def to_arr(d):
    if not d: return np.array([1.0])
    res = np.zeros(max(d.keys()) + 1)
    for k, v in d.items(): res[k] = v
    return res

b = to_arr(cx_dict)  # Числитель (нули)
a = to_arr(cy_dict)  # Знаменатель (полюса)

# 3. Расчет нулей и полюсов
zeros = np.roots(b) if len(b) > 1 else []
poles = np.roots(a) if len(a) > 1 else []

# 4. Визуализация
fig, (ax_out, ax_z) = plt.subplots(1, 2, figsize=(12, 5))

# Слева: График отсчетов OUT
indices = sorted(out_dict.keys())
values = [out_dict[i] for i in indices]
ax_out.stem(indices, values)
ax_out.set_title("Отсчеты OUT")
ax_out.grid(True)

# Справа: Комплексная плоскость
unit_circle = plt.Circle((0,0), 1, color='black', fill=False, linestyle='--', alpha=0.5)
ax_z.add_artist(unit_circle)
ax_z.scatter(np.real(zeros), np.imag(zeros), s=60, marker='o', edgecolors='blue', facecolors='none', label='Нули (CX)')
ax_z.scatter(np.real(poles), np.imag(poles), s=60, marker='x', color='red', label='Полюса (CY)')

ax_z.axhline(0, color='black', lw=1)
ax_z.axvline(0, color='black', lw=1)
ax_z.set_xlim([-1.5, 1.5])
ax_z.set_ylim([-1.5, 1.5])
ax_z.set_aspect('equal')
ax_z.set_title("Комплексная плоскость")
ax_z.legend()
ax_z.grid(True)

plt.tight_layout()
plt.show()

Ну что-ж, довольно неплохо вайб-ЦОС позволяет анализировать различные фильтры, хорошо видна КИХ-составляющая вначале пятого порядка (5 отсчётов) и БИХ с затуханием, построена единичная окружность, нанесены нули-полюса.

Далее следуют небольшие примеры для методов с конечными разностями

Столкновение Тейи и Земли. Луна не получилась

Язык Змей Горыныч модель окружность 1 окружность 2 навстречу друг другу диаметры отношение один к четырём окружность есть 64 точки отрезков аппроксимация каждый отрезок масса отрезки связаны в точках использовать сохранение импульса закон Ньютона столкновение без рассеяния отрезки между собой закон Гука пружинят конечные разности расчёт шаг счёта по времени примерно одна окружность в секундe использовать матплотлиб визуализация мышь слайдер быстрее медленнее логарифм

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
from matplotlib.animation import FuncAnimation

# Параметры системы
N = 64              # Количество точек в окружности
K_SPRING = 5000.0   # Жесткость пружин
MASS = 0.1          # Масса одной точки
R1, R2 = 1.0, 4.0   # Радиусы (1:4)
V_INIT = 2.5        # Начальная скорость сближения

# Инициализация координат и скоростей
theta = np.linspace(0, 2 * np.pi, N, endpoint=False)

# Окружность 1 (Малая)
pos1 = np.stack([R1 * np.cos(theta) - 7.0, R1 * np.sin(theta)], axis=1)
vel1 = np.zeros_like(pos1)
vel1[:, 0] = V_INIT

# Окружность 2 (Большая)
pos2 = np.stack([R2 * np.cos(theta) + 7.0, R2 * np.sin(theta)], axis=1)
vel2 = np.zeros_like(pos2)
vel2[:, 0] = -V_INIT

# Длины покоя (отрезки аппроксимации)
def get_lengths(p):
    diff = np.roll(p, -1, axis=0) - p
    return np.sqrt(np.sum(diff**2, axis=1))

L1, L2 = get_lengths(pos1), get_lengths(pos2)

# Визуализация
fig, ax = plt.subplots(figsize=(10, 6))
plt.subplots_adjust(bottom=0.2)
line1, = ax.plot([], [], 'r-o', markersize=3, lw=1.5, label='Small (1x)')
line2, = ax.plot([], [], 'b-o', markersize=3, lw=1.5, label='Large (4x)')
ax.set_xlim(-12, 12)
ax.set_ylim(-6, 6)
ax.set_aspect('equal')
ax.legend()

# Слайдер для скорости (логарифмический шаг)
ax_speed = plt.axes([0.25, 0.05, 0.5, 0.03])
slider = Slider(ax_speed, 'Time Step (log)', -4.0, -1.5, valinit=-3.0)

def compute_physics(p, v, L_rest):
    # Силы упругости (Закон Гука)
    diff = np.roll(p, -1, axis=0) - p
    dist = np.sqrt(np.sum(diff**2, axis=1))
    f_mag = K_SPRING * (dist - L_rest)
    f_vec = (diff / dist[:, None]) * f_mag[:, None]
    
    # Результирующая сила на каждую точку (соседние сегменты)
    net_f = f_vec - np.roll(f_vec, 1, axis=0)
    
    # Ускорение (Закон Ньютона)
    a = net_f / MASS
    return a

def update(frame):
    global pos1, vel1, pos2, vel2
    
    # Текущий шаг времени из слайдера
    dt = 10**slider.val
    
    # Расчет сил и обновление (метод Эйлера-Кромера для стабильности)
    for _ in range(5): # Вложенные итерации для точности при больших dt
        # Физика связей
        vel1 += compute_physics(pos1, vel1, L1) * dt
        vel2 += compute_physics(pos2, vel2, L2) * dt
        
        # Обработка столкновения (Сохранение импульса)
        # Проверка расстояния между всеми парами точек окружностей
        dist_matrix = np.linalg.norm(pos1[:, None, :] - pos2[None, :, :], axis=2)
        collisions = np.where(dist_matrix < 0.25)
        
        for i, j in zip(*collisions):
            normal = (pos1[i] - pos2[j]) / dist_matrix[i, j]
            v_rel = vel1[i] - vel2[j]
            v_norm = np.dot(v_rel, normal)
            if v_norm < 0:
                # Обмен импульсами (массы равны, без рассеяния)
                impulse = v_norm * normal
                vel1[i] -= impulse
                vel2[j] += impulse
        
        pos1 += vel1 * dt
        pos2 += vel2 * dt

    # Обновление графики (замыкаем кольцо для отрисовки)
    p1_plot = np.vstack([pos1, pos1[0]])
    p2_plot = np.vstack([pos2, pos2[0]])
    line1.set_data(p1_plot[:, 0], p1_plot[:, 1])
    line2.set_data(p2_plot[:, 0], p2_plot[:, 1])
    return line1, line2

ani = FuncAnimation(fig, update, interval=20, blit=True)
plt.show()

Как обычно запускаем ранее навайбкоженным ./generate_requirements.sh zmei.py с автоматической подцепкой виртуального окружения


Робот-манипулятор двузвенный. Используется матмодель, которой надо дать инъекцию в виде подсказок про арктангенс двойного аргумента (от 0 до 360) и sqrt - теорему Пифагора, а также что одной точке может соответствовать 2 положения (плюс минус дискриминант), которых тем больше чем больше звеньев.

Автоботы и Десептиконы

Пропитонь двузвенный манипулятор да дай-ка в него PyGame numpy но будь осторожен с дискриминант sqrt а угол atan2 клавиатура меняй знак положение. Мышь точка задания фиксация первого звена центр координаты ортогональные сцены сетка имеется. Ай да обратная кинематика! Ух сольвер тригонометрический.

import pygame
import numpy as np
import math

# Константы сцены
WIDTH, HEIGHT = 800, 600
L1, L2 = 180, 140  # Длины звеньев
ORIGIN = np.array([WIDTH // 2, HEIGHT // 2])

def solve_ik(target, l1, l2, sign):
    tx, ty = target
    dist_sq = tx**2 + ty**2
    dist = math.sqrt(dist_sq)

    # Ограничение рабочей зоны
    if dist > l1 + l2:
        dist_sq = (l1 + l2)**2
        dist = l1 + l2
    
    # Закон косинусов для второго угла
    cos_a2 = (dist_sq - l1**2 - l2**2) / (2 * l1 * l2)
    cos_a2 = np.clip(cos_a2, -1, 1) # Защита от ошибок в sqrt
    
    # Выбор знака локтя через atan2
    sin_a2 = math.sqrt(1 - cos_a2**2) * sign
    a2 = math.atan2(sin_a2, cos_a2)

    # Угол первого звена
    a1 = math.atan2(ty, tx) - math.atan2(l2 * sin_a2, l1 + l2 * cos_a2)
    
    return a1, a2

def run():
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    clock = pygame.time.Clock()
    elbow_sign = 1
    
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT: return
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE: elbow_sign *= -1

        screen.fill((30, 30, 30))
        
        # Сетка
        for i in range(0, WIDTH, 40): pygame.draw.line(screen, (50,50,50), (i,0), (i,HEIGHT))
        for i in range(0, HEIGHT, 40): pygame.draw.line(screen, (50,50,50), (0,i), (WIDTH,i))

        # Таргет от мышки относительно центра
        m_pos = np.array(pygame.mouse.get_pos()) - ORIGIN
        
        # Расчет
        a1, a2 = solve_ik(m_pos, L1, L2, elbow_sign)

        # Координаты суставов
        joint = ORIGIN + np.array([L1 * math.cos(a1), L1 * math.sin(a1)])
        end_eff = joint + np.array([L2 * math.cos(a1 + a2), L2 * math.sin(a1 + a2)])

        # Отрисовка (Ортогонально из центра)
        pygame.draw.line(screen, (0, 255, 0), ORIGIN, joint, 6)   # Плечо
        pygame.draw.line(screen, (255, 100, 0), joint, end_eff, 6) # Предплечье
        pygame.draw.circle(screen, (255, 255, 255), ORIGIN, 8)
        pygame.draw.circle(screen, (200, 0, 0), end_eff.astype(int), 5)

        pygame.display.flip()
        clock.tick(60)

if __name__ == "__main__":
    run()

Пробелом можно менять положение локтя, мышью - крутить роботом обеспечивая положение звеньев

Вайб-код-стих. Пропарсим с использованием питона C-файлы сделанные выше и выберем имена функций.

Рифмо-парсер

Питоном я доволен
Файл открыть любой
Там С код стройный
Читай его любой
Используй regexp дорогой
И извлекай Имя функции () как родной
Те что в скобках и
Фигурных расписных
Строй список мне имён
Довольный и на экран выводи
Мой файл пай мне задай
Ищем мы всё в каталоге текущем
Всё что Си имеет текст грядущий
Но ты за ключевым словом следи
Всякие форы и ифы убери!
Устроит меня не имплементация
А только реализация


Результат:

import re
import os

# Регулярка: ищет потенциальное имя функции перед скобками,
# игнорируя ключевые слова C, и проверяет наличие открывающей фигурной скобки
pattern = r'\b(?!if|while|for|switch|return|void|int|char|float|double|static|struct|else)\w+\s*\([^)]*\)\s*\{'

def find_functions():
    # Ищем файлы с расширением .c в текущей папке
    c_files = [f for f in os.listdir('.') if f.endswith('.c')]

    if not c_files:
        print("Си-файлов в округе не видать...")
        return

    for filename in c_files:
        print(f"--- Файл: {filename} ---")
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                content = f.read()
                # Находим все совпадения
                matches = re.findall(pattern, content)

                for match in matches:
                    # Очищаем имя от скобок и лишних символов
                    func_name = match.split('(')[0].strip()
                    # На случай, если в match попал тип данных (например, "int main")
                    func_name = func_name.split()[-1]
                    print(f"Найдена функция: {func_name}")
        except Exception as e:
            print(f"Ошибка при чтении {filename}: {e}")

if __name__ == "__main__":
    find_functions()

В созданных выше файлах он прекрасно находит наши функции
--- Файл: Main.c ---
Найдена функция: main
--- Файл: calculate.c ---
Найдена функция: calculate

Практически все модели обладают +- одинаковым выводом, так как обучающие выборки наверняка в большинстве своём примерно одни и те же, собраны из исходников, форумов и подготовлены по известным шаблонам датасетов. Промпты рабочие с первого раза за редким исключением.

Комментарии (8)


  1. arch1lochus
    28.04.2026 03:03

    хотеть закрыть статья конецхотеть


    1. TimurZhoraev Автор
      28.04.2026 03:03

      Высочайшая энтропия!


  1. vkrasikov
    28.04.2026 03:03

    Задача довольно простая - как с использованием минимально возможного набора слов без приставок, суффиксов, окончаний или с их минимумом, а также союзов и других вспомогательных речевых конструкций получить на выходе годный код с 0% ошибок и 90% функционала согласно такому промпт-ТЗ.

    Задача понятна. А цель задачи?

    И как вы понимаете слово "высокоэнтропийный"?


    1. TimurZhoraev Автор
      28.04.2026 03:03

      Высокоэнтропийный - весьма условно, по аналогии с losless сжатием, когда энтропия после архивации возрастает (см спойлер). То есть мы условно вспомогательные элементы размещаем внутрь слова так как они являются избыточными. Целью является эксперимент по определению "векторения" или схожести текста с точки зрения модели. Это непосредственно связано с входным токенизатором и эмбеддером.
      Гипотеза. Вероятно, что несмотря на обучение грамматически более-менее разговорным текстам в датасетах, выходная информация в виде кода довольно скудна, по-сути там из слов только for if else do while class.... поэтому, направление вектора может быть задано приближённо, за счёт разницы между семантикой разговорного языка и семантикой языков программирования, который гораздо менее насыщен. Фактически скудная семантика как бы "квантует" фразы, оставляя больше простора для вариаций.
      В этом случае контекстное окно можно использовать ещё лучше, при этом остаётся и понятный смысл для человека и надёжная реализация вывода модели.


      Пример высокоэнтропийного вайб-кода который считает энтропию файла. Можно даже посмотреть её значение до архивации и после для какого-нибудь текстовика

      Вайб-калькулятор Шеннон-энтропии

      Хотеть Питон открыть аргумент скрипт файл считать 8 бит энтропия Шеннона среднее значение весь файл

      import sys
      import math
      from collections import Counter
      
      def analyze_file(filepath):
          try:
              with open(filepath, 'rb') as f:
                  data = f.read()
              
              if not data:
                  print("Файл пуст.")
                  return
      
              # Среднее значение (Mean)
              mean_val = sum(data) / len(data)
      
              # Энтропия Шеннона
              counts = Counter(data)
              file_len = len(data)
              entropy = -sum((count / file_len) * math.log2(count / file_len) 
                             for count in counts.values())
      
              print(f"Файл: {filepath}")
              print(f"Среднее значение (byte mean): {mean_val:.4f}")
              print(f"Энтропия Шеннона: {entropy:.4f} бит/байт")
      
          except FileNotFoundError:
              print("Ошибка: Файл не найден.")
          except Exception as e:
              print(f"Произошла ошибка: {e}")
      
      if __name__ == "__main__":
          if len(sys.argv) < 2:
              print("Использование: python script.py <путь_к_файлу>")
          else:
              analyze_file(sys.argv[1])
      

      Необходимо для чистоты эксперимента взять текстовый файл побольше, около мегабайта, например, на просторах полное собрание стихотворений Пушкина около 712 кБ. В архиве tar.gz 320 кБ
      Результат

      python3 entropy.py push.txt  
      Файл: push.txt
      Среднее значение (byte mean): 171.1301
      Энтропия Шеннона: 5.1418 бит/байт

      Файл: push.tar.gz
      Среднее значение (byte mean): 127.2625
      Энтропия Шеннона: 7.9972 бит/байт

      Видно, что за счёт ASCII кириллицы среднее значение смещено вверх в диапазон символов, после архивации данные выглядят как белый шум со средним значением 128 как 256/2 - двоичная последовательность.




      P.S. почему "хотеть" - на hugging face есть весёлые датасеты из разряда "go_emotions", вполне вероятно это помогает заострить внимание на то, что это начало технического задания.


      1. Zeus42
        28.04.2026 03:03

        Идея интересная, однако как по мне не достаточно раскрыта в этой статье.

        Да, результат есть, но без сравнения с обычным промптингом на разговорной речи не понятен уровень эффективности.

        Целью является эксперимент по определению "векторения" или схожести текста с точки зрения модели. Это непосредственно связано с входным токенизатором и эмбеддером.

        А тут (в идеале) было бы сравнить так же доступные токенизаторы на открытых моделях и посмотреть, какое влияние оказывает входной промпт для "векторения". Сравнить эффективность одного и того же кода, после одного и другого промпта в численном эквиваленте.


        1. TimurZhoraev Автор
          28.04.2026 03:03

          Вот теперь уже самое сложное, привык к такому вот вайбкодингу. То есть очень кратко и образно описать алгоритм что на английском что на русском. В английском можно редуцировать всё до группы времён simple, на русском глаголы в несовершенном виде, слова без приставок суффиксов и окончаний. Как-то это всё работает даже лучше (субъективно) чем пытаться подробно объяснить что необходимо. Чем больше пытаюсь объяснить подробно - тем больше вылазят глюки. Я специально привёл пример разрыва окна на прототипе функции С. Если в промпте что-то поменять в хвосте, обязательно в main.с сломаются аргументы вызова, он может в функцию вместо 7 аргументов поставить 8, изменить типы данных с float на int. То есть чем более кратко тем лучше. По поводу эмбеддеров можно попробовать. В качестве эмбеддера берём облачный на cloud.ru

          Тестируем вектор предложений
          1. Создаём инстанс эмбеддера и настраиваем у провайдера, формируем сервисный аккаунт, назначаем или оставляем пустой роль в организации, получаем API ключ, закидываем на баланс минимальный квант вместо кофе, нам потребуется Embedder baai bge m3

          2. Берём питон-код пустышку отсюда.

          3. Чтобы не светить ключём и преобразовать в эмбеддер пишем следующий промпт

          Вайб-настройка эмбеддера от провайдера

          Оё-ёй! безопасно ключ не свети тут!
          import os from openai import OpenAI api_key = os.environ["API_KEY"] url = "https://foundation-models.api.cloud.ru/v1" client = OpenAI( api_key=api_key, base_url=url ) response = client.chat.completions.create( model="ai-sage/GigaChat3-10B-A1.8B", max_tokens=2500, temperature=0.5, presence_penalty=0, top_p=0.95, messages=[ { "role": "user", "content":"Как написать хороший код?" } ] ) print(response.choices[0].message.content)
          это пример обратиться к модели сайт. Преобразовать чтение ключа файл key.txt используй модель равно BAAI/bge-m3. Хотеть тест ембеддер вектор 1024 две строки читай строка1.txt строка2.txt выведи часть вектора 1 и 2 и степень схожести используй эмбеддер апи

          В результате имеем код. Разместить ключ в файл key.txt и предложения в строка1.txt и строка2.txt которые необходимо сравнить

          import os
          from openai import OpenAI
          import numpy as np
          
          # 1. Читаем ключ из файла
          with open("key.txt", "r") as f:
              api_key = f.read().strip()
          
          # 2. Читаем строки из файлов
          with open("строка1.txt", "r", encoding="utf-8") as f:
              text1 = f.read().strip()
          with open("строка2.txt", "r", encoding="utf-8") as f:
              text2 = f.read().strip()
          
          url = "https://foundation-models.api.cloud.ru/v1"
          client = OpenAI(api_key=api_key, base_url=url)
          
          # 3. Получаем эмбеддинги
          def get_embedding(text):
              response = client.embeddings.create(
                  model="BAAI/bge-m3",
                  input=text,
                  encoding_format="float"
              )
              return response.data[0].embedding
          
          vec1 = np.array(get_embedding(text1))
          vec2 = np.array(get_embedding(text2))
          
          # 4. Расчет схожести (Cosine Similarity)
          similarity = np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))
          
          print(f"Размер вектора: {len(vec1)}")
          print(f"Часть вектора 1 (первые 5): {vec1[:5]}")
          print(f"Часть вектора 2 (первые 5): {vec2[:5]}")
          print(f"Степень схожести: {similarity:.4f}")
          

          Содержимое строка1.txt
          Хотеть питон скрипт реализация принтф текстовая строка читай файл

          Содержимое строка2.txt
          Создай скрипт на Питон который читает файл и выводит на экран текстовую строку с использованием функции printf

          Устанавливаем необходимые pip-ы и запускаем ./generate_requirements.sh embcloud.py   Running embcloud.py... Размер вектора: 1024

          Часть вектора 1 (первые 5): [-0.0236261  -0.02383822 -0.023057   -0.02170362 -0.0012989 ]

          Часть вектора 2 (первые 5): [-0.02825816 -0.008068   -0.01357161 -0.02528192  0.00704397]

          Степень схожести: 0.8607

          Всё что выше 0.6 полностью пригодно для генерации.


  1. saneea
    28.04.2026 03:03

    Речекряк


  1. tzlom
    28.04.2026 03:03