Обновить
2
-0.2
Жораев Тимур Юлдашевич@TimurZhoraev

Доцент института МПСУ им. Л. Н. Преснухина

Отправить сообщение

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

Именно! Так зачем теперь нужно дополнять ценные гигаватт-часы на дополнительные новомодные триллионы токенов, когда банальный С вытягивает 100% проблем. Да, человеку неудобно, а кто сказал что там что-то нужно читать и знать когда есть 100500 различных парсеров, тестов, санитайзеров, которые генерируются или обвязка для которых налету llm-кой. Вплоть до питона, который анализирует С, делает заголовки и код С, заготавливает метрику, отправляет в LLM, делает автоматом рефакторинг, с файлами -конфигами больше уже нет необходимости возиться, да и версия кода не есть версия текста программы по большому счёту. Это про комментарии и их хранилище с нагенерённой документацией и summary от LLM.

Позвонить в сервис, попросить чтобы дали задание написать мануал для LLM с годной векторной базой данных. Старые мануалы скорее переживают суровый закат, всевозможные языки разметок чтобы быть покрасивее, все эти md, man, hlp, да ещё и не векторные и не структурированные рисунки. Машинно-ориентированный мануал это фактически генератор знаний по запросу. Линейные книги и html-ки это уже прошлый век.

Проблема скорее в формализации качества. Новая фишка должна либо быть более понятной, более безопасной, уменьшить время на её обучение, на разработку, величину кода, его эффективность. Все языки как раз состязались именно чтобы быть приятными человеку, машине всё равно что там написано. Когда же пришла LLM это соревнование потеряло смысл и проще взять совершенно базовые вещи языков высокого уровня которые становятся просто ассемблером для LLM. И чем лаконичнее язык в плане грамматики и синтаксиса тем лучше. В конечном итоге это С (с диалектами CUDA, шейдеры, OpenCL, OpenMP...), Питон, Бэйсик, Фортран, ЛИСП, Verilog ну и ещё что-то из разряда Maxima, Maple, Mathematica. Оркестрируя этим делом можно составить приложение любой сложности.

Чем больше синтаксического сахара - тем больше можно получить случайной соли.

Поэтому и хорош С, что его можно попарсить всем чем угодно и вытащить сам алгоритм - отследить все вызовы malloc-free и где они вызываются и в каком порядке, промптом можно даже попросить сделать смартпойнтер или глобальный стек для отладки, вывод которого скормить той же модели для анализа если там вдруг двойной фри на указатель или указатель без фри. Если этот довесок невозможен ввиду того что это одноплатный процессор на логике 555й серии - можно попросить создать на питоне виртуальную машину с вызовами и моделью поведения, как на верилоге.

так нужно генерировать неправильный код на очень хорошей платформе, который будет генерировать правильный код на плохой. Иными словами кто мешает сгенерировать питон который будет следить за дефайнами, стимулусами, тестбенчами и прочими do-файлами со времён tcl tk, и иже с ними имеющие кодовую базу в тератокены. То есть он будет делать C-вставки в проект, включая парсинг самих C-файлов проекта тем же cparcer. В этом и заключается сила простых языков с точки зрения промптинга и анализа что для них есть превосходные инструменты для обратных связей - вытаскивать структуры, определения, функции итд и встраивать то что необходимо, включая тесты. Изолированная единица с параметром - и настраивай как угодно, остальные имеют те же питон модели поведения, не обязательно всё возлагать на один язык. Достаточно промоделировать и использовать сгенерированный код. В ту же копилку и DMA с режимами работы, потокобезопасные очереди, всевозможные контроллеры прерываний с приоритетами итд

Для решения проблемы с динамической памятью можно использовать штатный санитайзер gcc или просить модель сделать smart pointer даже на простом С. Вообще говоря этот язык переживёт с LLM второе рождение, так как все новомодные фишки которые появились за последнее десятилетие в языках и призванные синтаксисом улучшить читабельность для человека уйдут на второй план, так как контроль за надёжностью и управлением памяти как раз может взять на себя модель, мало того, сугубо компилируемые языки разрослись до уровня интерпретаторов, для нововведений нет кодовой базы для глубокого обучения. Более того, стиль написания скриптов будет примерно такой, как новый язык. Известно, что в моделях есть "температура", а значит, и "энтропия" (cross-entropy). Поэтому промпт-ТЗ должно предельно иметь её высокое значение относительно алгоритма без лишней составляющей. Пример для простого С, используемого как ассемблер для промпта. Сделаем цифровой фильтр с динамической памятью.


Практикум вайб-курса цифровой обработки сигналов в одном Хабр-комментарии. Промптим код без демонов Максвелла с хорошей энтропией:

Язык С мэйн иметь флоат два массива cx и x длина nx два массива cy и y длина ny объединить одна структура глобальная поля структура сделать маллок область видимости выход фри. Инициализация x и y ноль. Мэйн внутри цикл отсчёты внутри аккумулятор ноль первый элемент x равно константа цикл по элемент массив cx и x умножение с накоплением цикл по элемент массив cy и y аккумулятор минус умножение с накоплением. Сохранить аккумулятор первый элемент массив y. Сдвинуть элемент массив x и массив y один позиция вправо, инкремент индекса только использовать временная переменная тэ1 тэ2 обмен.

Код-скелет
#include <stdio.h>
#include <stdlib.h>

// Константы для примера
#define NX 3
#define NY 3
#define STEPS 10
#define CONST_VAL 1.0f

// --- Глобальная структура ---
typedef struct {
    float *cx;
    float *x;
    int nx;
    
    float *cy;
    float *y;
    int ny;
} FilterData;

FilterData g_data; // Глобальный экземпляр

int main() {
    // --- Выделение памяти (malloc) ---
    g_data.nx = NX;
    g_data.ny = NY;
    
    g_data.cx = (float*)malloc(g_data.nx * sizeof(float));
    g_data.x  = (float*)malloc(g_data.nx * sizeof(float));
    
    g_data.cy = (float*)malloc(g_data.ny * sizeof(float));
    g_data.y  = (float*)malloc(g_data.ny * sizeof(float));

    // --- Инициализация ---
    // Коэффициенты (для примера)
    for(int i = 0; i < g_data.nx; i++) { g_data.cx[i] = 0.5f; g_data.x[i] = 0.0f; }
    for(int i = 0; i < g_data.ny; i++) { g_data.cy[i] = 0.2f; g_data.y[i] = 0.0f; }

    printf("Starting processing loop...\n");

    // --- Основной цикл (Отсчеты) ---
    for (int t = 0; t < STEPS; t++) {
        float acc = 0.0f;
        
        // Первый элемент x равен константе
        g_data.x[0] = CONST_VAL;

        // Цикл по cx и x: умножение с накоплением
        for (int i = 0; i < g_data.nx; i++) {
            acc += g_data.cx[i] * g_data.x[i];
        }

        // Цикл по cy и y: аккумулятор минус умножение с накоплением
        // (Обычно пропускают y[0] в обратной связи, но делаем строго по описанию)
        for (int i = 0; i < g_data.ny; i++) {
            acc -= g_data.cy[i] * g_data.y[i];
        }

        // Сохранить аккумулятор в первый элемент y
        g_data.y[0] = acc;

        printf("Step %d: Result Y[0] = %.4f\n", t, g_data.y[0]);

        // --- Сдвиг элементов вправо с использованием временных переменных ---
        // Сдвиг x
        float te1 = g_data.x[0];
        for (int i = 1; i < g_data.nx; i++) {
            float te2 = g_data.x[i];
            g_data.x[i] = te1;
            te1 = te2;
        }

        // Сдвиг y
        te1 = g_data.y[0];
        for (int i = 1; i < g_data.ny; i++) {
            float te2 = g_data.y[i];
            g_data.y[i] = te1;
            te1 = te2;
        }
    }

    // --- Освобождение памяти (free) ---
    free(g_data.cx);
    free(g_data.x);
    free(g_data.cy);
    free(g_data.y);

    return 0;
}

Хотеть коэффициент cx массив как единица делить количество. Нужно первый коэффициент cy равно ноль. Ещё два коэффициент cy посчитать полюс устойчивость единичная окружность комплексная плоскость хорошо остальные ноль.

Догадайся что это IIR
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define NX 5
#define NY 5
#define STEPS 15
#define CONST_VAL 1.0f

typedef struct {
    float *cx;
    float *x;
    int nx;
    
    float *cy;
    float *y;
    int ny;
} FilterData;

FilterData g_data;

int main() {
    // --- Выделение памяти ---
    g_data.nx = NX;
    g_data.ny = NY;
    g_data.cx = (float*)malloc(g_data.nx * sizeof(float));
    g_data.x  = (float*)malloc(g_data.nx * sizeof(float));
    g_data.cy = (float*)malloc(g_data.ny * sizeof(float));
    g_data.y  = (float*)malloc(g_data.ny * sizeof(float));

    // --- Инициализация массивов ---
    for(int i = 0; i < g_data.nx; i++) {
        g_data.cx[i] = 1.0f / (float)g_data.nx; // Коэффициент 1/N
        g_data.x[i] = 0.0f;
    }

    // Инициализация cy нулями
    for(int i = 0; i < g_data.ny; i++) {
        g_data.cy[i] = 0.0f;
        g_data.y[i] = 0.0f;
    }

    // Расчет коэффициентов cy для устойчивых полюсов
    float r = 0.9f;         // Радиус (внутри единичной окружности)
    float theta = 0.5f;     // Угол (фаза)
    
    g_data.cy[0] = 0.0f;    // Первый коэффициент ноль по условию
    if (g_data.ny > 2) {
        g_data.cy[1] = -2.0f * r * cosf(theta); 
        g_data.cy[2] = r * r;
    }

    printf("cx[0] = %.4f, cy[1] = %.4f, cy[2] = %.4f\n", g_data.cx[0], g_data.cy[1], g_data.cy[2]);
    printf("--------------------------------------\n");

    // --- Основной цикл ---
    for (int t = 0; t < STEPS; t++) {
        float acc = 0.0f;
        
        g_data.x[0] = CONST_VAL;

        // Умножение с накоплением для x
        for (int i = 0; i < g_data.nx; i++) {
            acc += g_data.cx[i] * g_data.x[i];
        }

        // Вычитание умножения с накоплением для y
        for (int i = 0; i < g_data.ny; i++) {
            acc -= g_data.cy[i] * g_data.y[i];
        }

        g_data.y[0] = acc;

        printf("Step %d: y[0] = %.4f\n", t, g_data.y[0]);

        // --- Сдвиг x ---
        float te1 = g_data.x[0];
        for (int i = 1; i < g_data.nx; i++) {
            float te2 = g_data.x[i];
            g_data.x[i] = te1;
            te1 = te2;
        }

        // --- Сдвиг y ---
        te1 = g_data.y[0];
        for (int i = 1; i < g_data.ny; i++) {
            float te2 = g_data.y[i];
            g_data.y[i] = te1;
            te1 = te2;
        }
    }

    // --- Очистка ---
    free(g_data.cx);
    free(g_data.x);
    free(g_data.cy);
    free(g_data.y);

    return 0;
}

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

ввод-вывод
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define NX 5
#define NY 5
#define STEPS 20

typedef struct {
    float *cx, *x, *cy, *y;
    int nx, ny;
} FilterData;

FilterData g_data;

int main() {
    g_data.nx = NX; g_data.ny = NY;
    g_data.cx = (float*)malloc(NX * sizeof(float));
    g_data.x  = (float*)calloc(NX, sizeof(float)); // Инициализация 0
    g_data.cy = (float*)malloc(NY * sizeof(float));
    g_data.y  = (float*)calloc(NY, sizeof(float)); // Инициализация 0

    // Настройка коэффициентов
    for(int i = 0; i < NX; i++) g_data.cx[i] = 1.0f / NX;
    for(int i = 0; i < NY; i++) g_data.cy[i] = 0.0f;
    
    float r = 0.95f;      // Полюс внутри окружности
    float theta = 0.4f;   // Угол
    g_data.cy[1] = -2.0f * r * cosf(theta); 
    g_data.cy[2] = r * r;

    FILE *f = fopen("experiment.txt", "w");
    if (!f) return 1;

    printf("Импульсная характеристика:\n");
    printf("T\tInput\tOutput\n");
    printf("--------------------------\n");
    fprintf(f, "Step,Input,Output\n"); // Заголовок CSV

    for (int t = 0; t < STEPS; t++) {
        // Импульс: 1.0 только в t=0, иначе 0.0
        float current_input = (t == 0) ? 1.0f : 0.0f;
        g_data.x[0] = current_input;

        float acc = 0.0f;
        for (int i = 0; i < NX; i++) acc += g_data.cx[i] * g_data.x[i];
        for (int i = 0; i < NY; i++) acc -= g_data.cy[i] * g_data.y[i];

        g_data.y[0] = acc;

        // Вывод: дисплей (табуляция) и файл (CSV)
        printf("%d\t%.2f\t%.4f\n", t, current_input, acc);
        fprintf(f, "%d,%.2f,%.4f\n", t, current_input, acc);

        // Сдвиг x
        float te1 = g_data.x[0];
        for (int i = 1; i < NX; i++) {
            float te2 = g_data.x[i];
            g_data.x[i] = te1;
            te1 = te2;
        }
        // Сдвиг y
        te1 = g_data.y[0];
        for (int i = 1; i < NY; i++) {
            float te2 = g_data.y[i];
            g_data.y[i] = te1;
            te1 = te2;
        }
    }

    fclose(f);
    free(g_data.cx); free(g_data.x); 
    free(g_data.cy); free(g_data.y);
    return 0;
}

Ой плохо проверка после маллок массив что индекс цикл не высоко его размер сделать до 20. Но вводи сканф размер массив x,y и cx,cy клавиатура если энтер и энтер то по умолчанию.

Тест границы массива
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define MAX_SIZE 20
#define DEFAULT_NX 5
#define DEFAULT_NY 5
#define STEPS 20

typedef struct {
    float *cx, *x, *cy, *y;
    int nx, ny;
} FilterData;

FilterData g_data;

// Функция для безопасного ввода размера
int get_size(const char *name, int def_val) {
    char buffer[100];
    printf("Введите размер %s (по умолчанию %d, макс %d): ", name, def_val, MAX_SIZE);
    if (fgets(buffer, sizeof(buffer), stdin) == NULL || buffer[0] == '\n') {
        return def_val;
    }
    int val = atoi(buffer);
    if (val <= 0) return def_val;
    if (val > MAX_SIZE) return MAX_SIZE;
    return val;
}

int main() {
    // Ввод размеров с клавиатуры
    g_data.nx = get_size("X/CX", DEFAULT_NX);
    g_data.ny = get_size("Y/CY", DEFAULT_NY);

    // --- Выделение памяти с проверкой ---
    g_data.cx = (float*)malloc(g_data.nx * sizeof(float));
    g_data.x  = (float*)calloc(g_data.nx, sizeof(float));
    g_data.cy = (float*)malloc(g_data.ny * sizeof(float));
    g_data.y  = (float*)calloc(g_data.ny, sizeof(float));

    if (!g_data.cx || !g_data.x || !g_data.cy || !g_data.y) {
        printf("Ошибка: не удалось выделить память!\n");
        return 1;
    }

    // --- Инициализация коэффициентов ---
    for(int i = 0; i < g_data.nx; i++) g_data.cx[i] = 1.0f / (float)g_data.nx;
    for(int i = 0; i < g_data.ny; i++) g_data.cy[i] = 0.0f;
    
    // Полюса для устойчивости
    float r = 0.95f; 
    float theta = 0.4f;
    if (g_data.ny > 2) {
        g_data.cy[1] = -2.0f * r * cosf(theta); 
        g_data.cy[2] = r * r;
    }

    // --- Работа с файлом и вывод ---
    FILE *f = fopen("experiment.txt", "w");
    if (!f) {
        printf("Ошибка открытия файла!\n");
        return 1;
    }

    printf("\nИмпульсная характеристика (NX=%d, NY=%d):\n", g_data.nx, g_data.ny);
    printf("T\tInput\tOutput\n");
    printf("--------------------------\n");
    fprintf(f, "Step,Input,Output\n");

    for (int t = 0; t < STEPS; t++) {
        float current_input = (t == 0) ? 1.0f : 0.0f;
        g_data.x[0] = current_input;

        float acc = 0.0f;
        // Циклы теперь ограничены введенными размерами
        for (int i = 0; i < g_data.nx; i++) acc += g_data.cx[i] * g_data.x[i];
        for (int i = 1; i < g_data.ny; i++) acc -= g_data.cy[i] * g_data.y[i];

        g_data.y[0] = acc;

        printf("%d\t%.2f\t%.4f\n", t, current_input, acc);
        fprintf(f, "%d,%.2f,%.4f\n", t, current_input, acc);

        // Сдвиг x через временные переменные
        float te1 = g_data.x[0];
        for (int i = 1; i < g_data.nx; i++) {
            float te2 = g_data.x[i];
            g_data.x[i] = te1;
            te1 = te2;
        }
        // Сдвиг y через временные переменные
        te1 = g_data.y[0];
        for (int i = 1; i < g_data.ny; i++) {
            float te2 = g_data.y[i];
            g_data.y[i] = te1;
            te1 = te2;
        }
    }

    // --- Завершение ---
    fclose(f);
    free(g_data.cx); free(g_data.x);
    free(g_data.cy); free(g_data.y);
    printf("\nДанные сохранены в experiment.txt. Память очищена.\n");

    return 0;
}

Хотеть ГНУ мэйкфайл компиляция что мой С стандарт проверка не хуже C11 мой архитектура есть 64 бита и процессор x86 а не АРМ иначе ошибка. Называю mymain си мой файл я

Антилопа мэйкфайл
# Имя исходного файла и исполняемого файла
TARGET = mymain
SRC = mymain.c

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

# Определение архитектуры и разрядности
ARCH = $(shell uname -m)
BITS = $(shell getconf LONG_BIT)

# Проверка условий: x86_64 и 64 бита
all: check_arch $(TARGET)

check_arch:
	@echo "Проверка системных требований..."
	@if [ "$(ARCH)" != "x86_64" ]; then \
		echo "Ошибка: Архитектура $(ARCH) не поддерживается. Нужен x86_64 (не ARM)."; \
		exit 1; \
	fi
	@if [ "$(BITS)" != "64" ]; then \
		echo "Ошибка: Требуется 64-битная система."; \
		exit 1; \
	fi
	@echo "Система подходит: $(ARCH) $(BITS)-bit. Стандарт C11."

$(TARGET): $(SRC)
	$(CC) $(CFLAGS) $(SRC) -o $(TARGET)

clean:
	rm -f $(TARGET) experiment.txt

run: all
	./$(TARGET)

Хотеть бэш скрипт питон автомат загрузка матплотлиб вэнв виртуальное окружение зависимости хорошо а ежели вэнв есть то продолжить активировать вэнв и запустить скрипт питон называю я graph а если скрипт нет выйти сообщить создайте скрипт.

Бэш питон вэнв автомат
#!/bin/bash

# 1. Проверка наличия Python-скрипта
if [ ! -f "graph.py" ]; then
    echo "Ошибка: Файл graph.py не найден! Пожалуйста, создайте скрипт."
    exit 1
fi

# 2. Проверка и создание venv
VENV_DIR="venv"

if [ ! -d "$VENV_DIR" ]; then
    echo "Виртуальное окружение не найдено. Создаю..."
    python3 -m venv $VENV_DIR
    source $VENV_DIR/bin/activate
    echo "Установка зависимостей (matplotlib)..."
    pip install --upgrade pip
    pip install matplotlib
else
    echo "Активация существующего окружения..."
    source $VENV_DIR/bin/activate
fi

# 3. Запуск Python-скрипта
echo "Запуск визуализации..."
python3 graph.py

# Деактивация после выхода
deactivate

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

Питон язык строить CSV
import matplotlib.pyplot as plt
import csv
import os

def draw_graph():
    filename = "experiment.txt"
    
    # Проверка файла
    if not os.path.exists(filename):
        print(f"Ошибка: Создайте сначала {filename} (запустите C программу)")
        return

    steps = []
    values = []

    # Чтение данных без использования сторонних пакетов (только стандартный csv)
    try:
        with open(filename, "r", encoding="utf-8") as f:
            reader = csv.reader(f)
            next(reader)  # Пропускаем заголовок (Step, Input, Output)
            for row in reader:
                if len(row) >= 3:
                    steps.append(int(row[0]))   # Время / Номер отсчета
                    values.append(float(row[2])) # Значение (Output)
    except Exception as e:
        print(f"Ошибка чтения CSV: {e}")
        return

    # --- Настройка визуализации (Красиво) ---
    plt.figure(figsize=(11, 6))
    
    # Рисуем линии и точки одновременно
    # 'o-' означает точки и сплошную линию
    # color='#2c3e50' - темно-синий/графитовый цвет
    plt.plot(steps, values, 'o-', color='#e74c3c', linewidth=1.5, 
             markersize=5, markerfacecolor='#2980b9', markeredgecolor='white',
             label='Импульсный отклик')

    # Оформление осей и заголовка
    plt.title("Импульсная характеристика системы", fontsize=14, pad=15)
    plt.xlabel("Номер отсчета (n)", fontsize=11)
    plt.ylabel("Амплитуда сигнала (y)", fontsize=11)

    # Сетка
    plt.grid(True, linestyle='--', alpha=0.7)
    
    # Линии осей для наглядности (проходят через 0)
    plt.axhline(0, color='black', linewidth=0.8, alpha=0.5)
    plt.axvline(0, color='black', linewidth=0.8, alpha=0.5)

    plt.legend()
    
    # Сохранение и отображение
    print("Сохранение графика в impulse_response.png...")
    plt.savefig("impulse_response.png", dpi=200)
    plt.show()

if __name__ == "__main__":
    draw_graph()
Результат

Это импульсная характеристика или переходная на функцию Хевисайда - уже вопрос для билета

Один из главных моментов - не существует релятивистской динамики абсолютно твёрдого тела, так как возмущение в нём передаётся мгновенно а не со скоростью света, являющейся предельной. Поэтому рассматриваются только материальные точки или их облака (см. тензор Риччи) Если точка неподвижна - тензор Эйнштейна равен нулю, тензор Риччи обращается в ноль (рядом нет энергии), остаётся скаляр Риччи и метрический тензор, для точки - это решение в виде метрики Шварцшильда, представляющей собой расстояние в пространстве-времени (скалярный интервал), квадрат вектора - скаляр, он то и показывает величину того самого искривления, более верно - величина близости к точеченой массе. Ещё более весомый постулат - это дивергенция тензора Эйнштейна равна нулю, это означает, что нет источников и приёмников энергии и момента, то есть можно приравнять энергию к геометрии с коэффициентом. То есть дивергенция геометрии должна быть нулевой, что означает, что гравитация локально не способна порождать или поглощать энергию (!), закон сохранения энергии-момента. Грубо говоря четырёхмерная плёнка, охватывающая точку в пространстве-времени имеет нулевую общую входящую и выходящую энергию (геометрию) - это про ковариантную дивергенцию (там же инвариантность к диффеоморфизму) .

Постскриптум. Про эту самую матрицу. Берём
C = Matrix( [ [1/R1,0,0,0,0,0,0,0], [0,1/R2,0,0,0,0,0,0], [0,0,1/R3,0,0,0,0,0], [0,0,0,1/R4,0,0,0,0], [0,0,0,0,s*C1,0,0,0], [0,0,0,0,0,s*C2,0,0], [0,0,0,0,0,0,s*C3,0], [0,0,0,0,0,0,0,s*C4] ] )

Ответ на промпт "what is it"

А это оказывается

This matrix represents a diagonal constitutive matrix (often labeled 

 or 

) typically used in Modified Nodal Analysis (MNA) or State-Space Modeling for an electrical circuit.

It maps the relationships between voltages and currents for individual passive components in a system with 8 distinct elements.

1. Breakdown of the Elements

The matrix is structured into two distinct blocks, representing different types of electrical components:

  • The Conductance Block (Rows 1–4):
    The terms 

     (conductance, 

    ) represent four resistors. In the frequency domain (s-domain), the relationship is governed by Ohm's Law: 

    .

  • The Susceptance Block (Rows 5–8):
    The terms 

     represent four capacitors. In the Laplace domain, the admittance of a capacitor is defined as:

    This accounts for the frequency-dependent nature of capacitors, where 

     is the complex frequency variable (

    ).

2. Physical Meaning

In a system of equations like 

, this matrix serves as the "link" between the across-variables (voltages) and the through-variables (currents) for each component:

Component IndexParameterTypeExpression1–4

Resistors

5–8

Capacitors

3. Context of Use

You will most likely find this matrix in:

  • Automated Circuit Simulators: Like the backend of SPICE, where the software builds a large matrix to solve for branch currents.

  • Control Theory: Defining the passive part of a state-space representation.

  • Graph Theory / Network Topology: It represents the edge weights (admittances) of the circuit graph before they are projected onto the nodes via an incidence matrix (

    ).

Would you like me to show you how to multiply this by an incidence matrix to find the nodal admittance matrix (

)?

... курс ТОЭ. Ну разве что отсутствует вектор источников тока/ЭДС. Называется сделай свой SPICE налету. Там же и вайбкод извлечения структуры электросхемы из нетлиста какого-нибудь KiCAD/OrCAD, вайбкод обратного преобразования Лапласа да что угодно. Вопрос - зачем уже заморачиваться всем этим вручную, особенно для тривиальных или рутинных элементов.

Мало того, как бы это парадоксально не звучало но описать код действительно можно мотивационным методом, экспрессией, эмоциями, чувсвтами, настоящим вайбом. Вполне допускаю что лет через 5 можно будет соорудить на какой-нибудь Ардуине или ESP-шке с акселерометром и гироскопом пояс, браслет и для создания софта для дерева составить танец. Например, побегать в лесу, покидать снежки, объяснить модели что хочу сделать обход ветвей и печать узлов, привязав к ветвям какие-нибудь цветные ленточки синей изолентой. Зафотать это, отправить на распознавание, модель увидит что мне нужно. Если алгоритм параллельный - наберу хворост, если быстрый - оставлю много-много следов на снегу и пульс под 140. Рекурсия - это покружиться вокруг, стек - прыжки в длину. Кеш - лепить снежки на кору, хеширование - нарезание веточек секатором, постучать по пню - вызвать деструктор.

Речь о том чтобы грузить LLM генерацией того что позволит обработать эти данные. Программы которые пишут программы. Рассмотрим маленько шире задачу - имеются данные, выглядящие для человека как случайный набор. Вопрос - являются ли они деревом?
Берём из примера и генерируем промпт" [0], [1], [1, 0], [1, 1], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 1, 3], [1, 2], [1, 2, 0] is it a tree?" причём для формирования этих данных любезно попросил модель сделать в CSV то что в квадратных скобках.

Ответ

Yes, the sequence provided is a tree. It represents a tree structure using a hierarchical numbering system (similar to Dewey Decimal or legal numbering) where each list of numbers identifies a specific node's position and path from the root. 

Tree Structure Visualization

In this system, the first number represents the top-level branches, the second number represents children of those branches, and so on. 

  • Root (Implicit/Level 0)

    • 0 (First top-level node)

    • 1 (Second top-level node)

      • 1, 0 (First child of node 1)

      • 1, 1 (Second child of node 1)

        • 1, 1, 0 (First child of node 1, 1)

        • 1, 1, 1 (Second child of node 1, 1)

        • 1, 1, 2 (Third child of node 1, 1)

        • 1, 1, 3 (Fourth child of node 1, 1)

      • 1, 2 (Third child of node 1)

        • 1, 2, 0 (First child of node 1, 2)

Key Characteristics

  • Hierarchy: Each additional digit represents a new level of depth in the tree.

  • Parent-Child Relationship: A node like [1, 1] is the parent of all nodes starting with 1, 1, ... (e.g., [1, 1, 0]).

  • Ordered Tree: Because the nodes are numbered (0, 1, 2...), it represents an ordered tree where the sequence of siblings matters.

  • Non-Binary: This specific tree is not binary; for example, node [1, 1] has four children (012, and 3), whereas a binary tree is limited to two. 

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

Сюда смотри, человек! Можешь ли параллель даже если смысл хороший ты взгляд первый сказать написано здесь в тут есть имеется быть место, позволяет результат хороший если быть таким!
<-Есть модели которые в принципе могут быть заточены и на это (Dual Inference, Tail Refinement). Даже прочитав такой текст, для человека вызывает некоторые эмоции, соответствующие общему восприятию ну как в Буратино "А роза упала на лапу Азора". Поэтому вайбкодинг это действительно вайб, вы должны описать свои чувства примерно как в предложении выше. Работающие примеры с деревом на Питоне я уже привёл. А благодаря разнообразию творчества человека на этот промпт рифмоплёт сгенерит

Пусть слог разбит, и фраза — как в тумане,
И первый взгляд не видит берегов,
Но если смысл в благом живет желанье —
Он выше правил и сильнее слов.

Сквозь путаницу ломаных пророчеств,
Где «быть» и «место» в пляске круговой,
Хороший результат родиться хочет —
Из мысли чистой, а не из прямой.


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

Код неявно использует стек, который хотелось бы чтобы был управляемый вместо рекурсии, например, чтобы не возиться потом с его упором в плинтус на микроконтроллере. Помимо всего прочего необходимо чтобы node не имел гонки данных если захочу сделать параллельный код. Цикл for должен гарантировать последовательный обход элементов и замьютить дерево чтобы в этот момент кто-то не добавил элементы, и не зависать на обращении, если захочу добавить таймаут и перегрузить оператор обращения. Вот это всё собственно и позволяет автоматизировать рутину а не использовать ресурсы компилятора, которые разжирели уже почти до интерпретируемых языков. А это и есть 99% работы, когда всплывают мелочи но значимые во всём проекте и их гораздо больше чем рук и мозгов.
Нейросеть вбирает не пустой контекст сразу и целиком после токенизации-векторизации, там нет никаких if-else, наоборот от них стараются избавиться так как параллельная "комбинационная" числодробилка гораздо эффективнее чем "последовательностные" алгоритмы которым нужно предыдущее состояние, ветвление - это всегда проблемы особенно на математических ядрах, условное умножение с накоплением с параллельным чтением из памяти на DSP занимает такт, call/jmp по 3-4 такта.
Вы так и не заметили в пункте 5 "дебаг" - что результат обхода дерева, то есть само дерево из пункта 4 в виде вывода printf и описываемое идентификаторами узлов-ветвей, было скормлено LLM для анализа и она подтвердила что выходные данные соответствуют алгоритму (обратная задача).
Что же касается примера - он генерируется по промпту "nary Post-order Traversal Python " подставить на любой вкус.

python

def dfs(node):
    for child in node.children:
        dfs(child)
    print(node.val)

JavaScript

const dfs = n => {
  n.children.map(dfs)
  console.log(n.val)
}

Ruby

def dfs(n)
  n.children.each { dfs(_1) }
  p n.val
end

Swift

func dfs(_ n: Node) {
  n.children.forEach(dfs)
  print(n.val)
}

Go

func dfs(n *Node) {
	for _, c := range n.children { dfs(c) }
	print(n.val)
}

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

Главная проблема в том что 99% знаний - это кем-то разработанные мануалы, фреймворки, флажки, что куда и как без каких-либо решений фундаментальных проблем на уровне сложности алгоритмов. То есть они просто копают ТЗ до функционала согласно тем ограничениям, которые дают библиотеки, включая глюки-баги самих библиотек особенно при масштабируемости, если прилетает апдейт итд. В этом случае действительно лучше забыть и не смотреть, это всё равно образно говоря опции командной строки. А вот миддл или синьор - знает как организовать подход к синтезу кода на основании представлений о том что нужно сделать с использованием промптов и может "по диагонали" проверить код, включая даже тест самих библиотек и самого кода. Речь о том, что от знаний с использованием ИИ отваливается искусственная шелуха и остаётся только кристалл структуры алгоритмов и данных, безотносительно каким инструментом они формируются для вычислителя, хоть машинные коды в hex-блокноте. Поэтому задача миддла - это оркестрация джунов, которые промптами кодят ИИ-хелперы. Он принимает результат, просит сделать всевозможные обёртки и даже кодогенераторы, включая промпт, генерирующий промпт.

В примере ниже (в другом сообщении в этой ветке) я решил составить алгоритм обхода дерева с использованием промптов в минимальной форме. Обратите внимание на минимализм описания того что необходимо. Что касается АСД - оно практически везде граф, но скелетная структура именно такова с точки зрения компилятора который затем её превращает в intermediate представления сводя n-арные операции к тернарным или бинарным (подготовка к ассемблеру). Нейросеть вбирает в себя всё сразу, и решает наподобие квантовых вычислений. Поэтому "сведение" к нулю это аналог некоторой суперпозиции в квантовых вычислениях когда обрабатываются в параллель все идентификаторы дерева. Если нейросеть не может его обойти - она может предложить сделать кодогенерацию по его обходу а также по анализу дерева, если окажется что оно +-отсортировано, то предложит метод log (n), частично n, плохо n^2 итд. То есть для неё больше нет методов конкретной реализации а есть задание на параметры алгоритма.
Пример промпта: Скажи алгоритм дерево обход логарифм н обход линейно время процессор объём память если сортированное дерево то как или эн в квадрате сложность экспонента и как узел оптимально обход сортировка поиск. - идеальная формулировка запроса, предельно чётко и понятно.
Ответ:

Вычислительная сложность и объём ОЗУ ЭВМ

Привет! Давай разберемся в этих терминах и алгоритмах. Похоже, ты хочешь структурировать знания о том, как время выполнения и память зависят от структуры дерева. Ниже приведен разбор основных операций, их сложностей и логики работы. 1. Обход дерева (Traversals) Обход — это посещение каждого узла ровно один раз. Временная сложность: . Мы обязаны зайти в каждый из узлов, поэтому быстрее, чем за линейное время, это сделать невозможно. Затраты памяти: В худшем случае , где — высота дерева. В сбалансированном дереве это . В «вырожденном» (похожем на список) это . 2. Поиск в сортированном дереве (BST) Если дерево является бинарным деревом поиска (BST), то данные в нем упорядочены: левый потомок меньше родителя, правый — больше. Оптимальный поиск: . Это работает как бинарный поиск: на каждом шаге мы отбрасываем половину веток. Худший случай ( ): Если дерево не сбалансировано (все узлы выстроены в одну линию), поиск превращается в линейный. Сортировка: Чтобы получить отсортированный список из BST, используется In-order traversal (лево-корень-право). Это занимает . 3. Сложности: когда бывает или экспонента? : Обычно возникает при неэффективной работе с деревом. Например, если вы строите дерево из уже отсортированного массива, просто вставляя элементы по очереди без балансировки, а затем выполняете поиск для каждого элемента. Экспонента ( ): В обычных деревьях встречается редко. Она характерна для задач полного перебора (например, поиск всех возможных подмножеств или путей в сложном графе), либо при наивной рекурсии (как в числах Фибоначчи без кэширования). Сводная таблица сложностей Операция Сбалансированное (AVL/Red-Black) Несбалансированное Поиск Вставка Обход (все узлы) Память (стек) Как сделать обход оптимальным? Если ты хочешь сэкономить память и избежать или даже в стеке, существует Алгоритм Морриса. Алгоритм Морриса позволяет обходить дерево за по времени и по дополнительной памяти, используя временные ссылки (threads) в пустых дочерних указателях. Что именно ты планируешь реализовать? Если хочешь, я могу написать пример кода на Python или C++ для балансировки дерева или реализации алгоритма Морриса для экономии памяти.

То есть фундаментальные справочники уже там имеются, и Кнутом там всё полировано.

Так сейчас необходимо просто сформулировать задачу. Промпты:


1. Язык Питон дерево узел класс массив элемент дочерний узел от 0 до 4 дочерний каждый узел поле случайно число от 0 до 255 глубина дерево 4 дочерних разместить дерево переменная Tree

1
import random

class TreeNode:
    def __init__(self, depth):
        # Поле со случайным числом от 0 до 255
        self.value = random.randint(0, 255)
        self.children = []
        
        # Если глубина еще не достигла предела, создаем дочерние узлы
        if depth < 4:
            # Количество дочерних узлов от 0 до 4 (как в условии)
            num_children = random.randint(0, 4)
            for _ in range(num_children):
                self.children.append(TreeNode(depth + 1))

# Создаем дерево и сохраняем корень в переменную Tree
Tree = TreeNode(1)

2. Начало Tree взять узел печать "узел" поле валуэ и координаты узел номер дочерний перейти дочерний узел если дочерний нет возврат на элемент предыдущий печать "ветвь" пока не все узел использовать стек узел пройден

2
# Используем ранее созданную переменную Tree

def traverse_with_stack(root):
    # Стек хранит кортеж: (текущий_узел, индекс_следующего_ребенка, координаты_пути)
    # Координаты — это список номеров дочерних элементов, например [1, 3, 0]
    stack = [(root, 0, [])]
    
    # Печатаем корневой узел
    print(f"узел: value={root.value}, координаты=[]")

    while stack:
        node, child_idx, coords = stack[-1]

        # Если у узла есть еще не посещенные дети
        if child_idx < len(node.children):
            # Обновляем индекс ребенка в текущем элементе стека
            stack[-1] = (node, child_idx + 1, coords)
            
            # Берем следующего ребенка
            child = node.children[child_idx]
            new_coords = coords + [child_idx]
            
            # Печатаем информацию о входе в узел
            print(f"узел: value={child.value}, координаты={new_coords}")
            
            # Кладем ребенка в стек для обработки его детей
            stack.append((child, 0, new_coords))
        else:
            # Если детей больше нет (или они закончились), выходим из узла
            stack.pop()
            if stack: # Если это не корень, печатаем возврат
                print("ветвь")

# Запуск обхода
traverse_with_stack(Tree)

3. Сделать мэйн и дать весь полнота скрипт для дерево принтф

3
import random

class TreeNode:
    """Класс узла дерева."""
    def __init__(self, depth):
        # Поле со случайным числом от 0 до 255
        self.value = random.randint(0, 255)
        self.children = []
        
        # Ограничение глубины до 4 уровней
        if depth < 4:
            # От 0 до 4 дочерних узлов
            num_children = random.randint(0, 4)
            for _ in range(num_children):
                self.children.append(TreeNode(depth + 1))

def traverse_tree_with_stack(root):
    """
    Обход дерева с использованием стека.
    Печатает 'узел', координаты и 'ветвь' при возврате.
    """
    if not root:
        print("Дерево пустое")
        return

    # Стек хранит: (текущий_узел, индекс_следующего_ребенка, координаты)
    stack = [(root, 0, [])]
    
    # Печать начального корневого узла
    print(f"узел: value={root.value}, координаты=root")

    while stack:
        current_node, child_idx, coords = stack[-1]

        # Если есть еще необработанные дочерние узлы
        if child_idx < len(current_node.children):
            # Обновляем индекс в текущем элементе стека (готовим для следующего шага)
            stack[-1] = (current_node, child_idx + 1, coords)
            
            # Берем дочерний узел
            child = current_node.children[child_idx]
            new_coords = coords + [child_idx]
            
            print(f"узел: value={child.value}, координаты={new_coords}")
            
            # Добавляем дочерний узел в стек (погружаемся глубже)
            stack.append((child, 0, new_coords))
        else:
            # Все дети обработаны, возвращаемся назад
            stack.pop()
            # Если стек не пуст, значит мы вернулись из дочернего узла в родительский
            if stack:
                print("ветвь")

def main():
    # 1. Создание дерева (корень Tree)
    # Передаем 1 как начальную глубину
    Tree = TreeNode(1)
    
    print("--- Начало обхода дерева ---")
    # 2. Запуск обхода со стеком
    traverse_tree_with_stack(Tree)
    print("--- Обход завершен ---")

if __name__ == "__main__":
    main()

4. Как онлайн запуск тест это скрипт.
Replit — Самый мощный Позволяет сохранять код и делиться ссылкой. Нажмите Create Repl. Вставьте код в файл. Нажмите Run вверху.

Результат

--- Начало обхода ---
узел: value=147, координаты=root
узел: value=130, координаты=[0]
ветвь
узел: value=79, координаты=[1]
узел: value=153, координаты=[1, 0]
ветвь
узел: value=196, координаты=[1, 1]
узел: value=127, координаты=[1, 1, 0]
ветвь
узел: value=184, координаты=[1, 1, 1]
ветвь
узел: value=0, координаты=[1, 1, 2]
ветвь
узел: value=139, координаты=[1, 1, 3]
ветвь
ветвь
узел: value=32, координаты=[1, 2]
узел: value=186, координаты=[1, 2, 0]
ветвь
ветвь
ветвь
--- Конец ---

<completed>

5. Дебаг проверить вывод программа работать всё хорошо (копируем и вставляем в модель вывод)

Ответ

Результат дебага отличный! Программа отработала строго по заданному алгоритму.

Вот краткий анализ вашего вывода, подтверждающий корректность:

  1. Глубина: Мы видим координаты максимум из 3 чисел (например, [1, 1, 3]). С учетом корня (root) — это как раз 4-й уровень вложенности. Лимит соблюден. [1]

  2. Диапазон чисел: Все значения (147, 130, 0, 184...) входят в диапазон 0–255. [1]

  3. Логика стека:

    • Когда вы видите узел: ... [1, 1], а следом узел: ... [1, 1, 0], это значит, что стек успешно «погрузился» вглубь.

    • Когда вы видите несколько ветвь подряд в конце, это значит, что стек успешно «схлопнулся», возвращаясь от листьев к корню. [1]

  4. Количество детей: У узла [1, 1] мы видим четырех детей (0, 1, 2, 3), что соответствует условию от 0 до 4.

Всё работает идеально.

Если захотите усложнить задачу — например, найти в этом дереве самый "тяжелый" путь (где сумма value максимальна) или подсчитать количество всех "листьев" (узлов без детей), — обращайтесь!

Жирным - тот самый, долгожданный, настоящий, лаконичный, чёткий, полностью и исчерпывающе с максимальной информационной ёмкостью формулирующий задачу со всеми граничными условиями и последовательностью действий, язык 21 века!

В случае саммари ИИ помогает обеспечить максимальную энтропию сообщения, которая в полной мере раскрывает синтезируемый алгоритм на исходном коде. Вот как раз сейчас всё крутится именно вокруг этого. То есть дистанция между спецификацией и реализацией на вычислителе общего назначения, который воспринимает последовательность команд в виде произвольного языка программирования. Иными словами, необходимо для себя дать ответ - а какой я должен написать промпт, какие токены использовать, чтобы они содержали максимум информации для реализации на заданном вычислителе (граничные условия). Таким образом, обязательно всегда в промпте необходимо указать какое-либо численное значение или параметр (в общем виде) характеризующий алгоритм. N элементов, используй явный стек вместо рекурсии, запиши через временные переменные T1,T2, битовое поле в структуре A являющейся частью структуры B, обрати внимание на строгую последовательность полей, это протокол, цикл в цикле, умножение с накоплением, индексация, массив или список. Поменьше слов, можно даже использовать сокращения но побольше именно скелетных форм, выражающих алгоритм, мало того можно даже не склонять слова, например "сделать алгоритм сортировка N элемент целое массив A использовать стек рекурсия нельзя метод пузырёк применить указатель сравнить элемент тип 16 бит язык Питон без библиотек" - абсолютно прозрачная и чёткая формулировка. Попробуйте вбить в любой онлайн ИИ-агент - решение идеальное.

Так разве проект нельзя свести к АСТ? В принципе любое дерево может иметь его генератор в виде программы, ну как loseless архиватор фактически создаёт микро-ВМ для упаковки и распаковки данных. Также дерево позволяет вообще обойтись без каких-либо границ в проекте, убрать файловую систему как метод структурирования и преобразовать в метод хранения и извлечения данных. АСТ - это базовая структура, там никто не запрещает иметь обратные связи, кратные ветви, замыкания и прочее. Вот это и необходимо в будущем вталкивать в контекстное окно и уже ведутся работы на этот счёт и это весьма радует. Здесь ещё интересная фича - обратная матрица в int8 в принципе может быть довольно эффективно найдена сдвигами по методу Ньютона-Рафсона, а значит, прямое и обратное распространение это примерно одно и тоже, особенно когда активация ReLU или 1/(1+2^x), гипотетически даже может будет аналоговый нейропроцессор с диодом или "транзисторной экспонентой" с обученными весами-резисторами, поэтому кстати и фигурируют эти функции с заделом на будущее хотя имеются более устойчивые но сложно вычисляемые или реализуемые. Поэтому, нейросеть с деревом делает некую "магию" с идентификаторами узлов и ветвей, фактически решая некоторую очень большую СЛАУ своим только ей известным методом, который есть результат гигаватт-часов потраченных на градиентный спуск, случайный поиск, возмущения и иные методы. И вероятностный подход это как Копенгагенская интерпретация, физически там может быть совершенно другой смысл. Функция взята просто из удобства готовых библиотек для определения кросс-энтропии из статмеха времён Больцмана. Есть ещё и гармонический метод, наименьшие квадраты, да и выбор функционала это скорее искусство нежели нечто строгое. То есть то что на выходе - это просто минимум ошибки между запросом и ответом. Задача обратной матрицы или решения СЛАУ легко превращается в задачу оптимизации, в случае оптимального решения получаем необходимые значения например y = a \cdot xпереписывается как y - a \cdot x = 0и ищем минимум (y - a \cdot x)^2. Факт в том что нейросеть предоставляет для анализа дерева универсальное решение практически не зависящее от его структуры и начальных условий, включая кодогенерацию для его обхода, а также кодогенерацию для анализа его свойств (отсортированное, частично сортированное, на основе хешей узлов итд)

Хороший метод подстроиться под модель - попросить её же усовершенствовать промпт. То есть сгенерируй промпт на основе промпта, фактически сделав некий аналог RAG, каждый промпт должен содержать частичку предыдущего. Лучше задачу скармливать агентом по частям чем целиком ТЗ с превью каждого шага.

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

1
23 ...

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Инженер электронных устройств, Научный специалист, исследователь
Старший
От 300 000 ₽
Прикладная математика
Разработка программного обеспечения
Оптимизация кода
C
Assembler
Python
Алгоритмы и структуры данных
Объектно-ориентированное проектирование
Многопоточность
Verilog HDL