/** * Synor Compute SDK - C Implementation */ #include "../include/synor_compute.h" #include #include #include #include #include #include /* ============ Internal Structures ============ */ struct synor_client { char* api_key; char* base_url; synor_processor_t default_processor; synor_precision_t default_precision; synor_priority_t default_priority; int timeout_ms; bool debug; bool closed; CURL* curl; }; typedef struct { char* data; size_t size; } response_buffer_t; /* ============ Internal Functions ============ */ static size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) { size_t realsize = size * nmemb; response_buffer_t* buf = (response_buffer_t*)userp; char* ptr = realloc(buf->data, buf->size + realsize + 1); if (!ptr) return 0; buf->data = ptr; memcpy(&(buf->data[buf->size]), contents, realsize); buf->size += realsize; buf->data[buf->size] = 0; return realsize; } static char* synor_strdup(const char* str) { if (!str) return NULL; size_t len = strlen(str) + 1; char* copy = malloc(len); if (copy) memcpy(copy, str, len); return copy; } static size_t compute_tensor_size(const int* shape, int ndim) { size_t size = 1; for (int i = 0; i < ndim; i++) { size *= shape[i]; } return size; } /* ============ Client Functions ============ */ void synor_config_default(synor_config_t* config) { config->api_key = NULL; config->base_url = "https://api.synor.io/compute/v1"; config->default_processor = SYNOR_PROCESSOR_AUTO; config->default_precision = SYNOR_PRECISION_FP32; config->default_priority = SYNOR_PRIORITY_NORMAL; config->timeout_ms = 30000; config->debug = false; } synor_client_t* synor_create(const char* api_key) { synor_config_t config; synor_config_default(&config); config.api_key = api_key; return synor_create_with_config(&config); } synor_client_t* synor_create_with_config(const synor_config_t* config) { if (!config || !config->api_key) return NULL; synor_client_t* client = calloc(1, sizeof(synor_client_t)); if (!client) return NULL; client->api_key = synor_strdup(config->api_key); client->base_url = synor_strdup(config->base_url ? config->base_url : "https://api.synor.io/compute/v1"); client->default_processor = config->default_processor; client->default_precision = config->default_precision; client->default_priority = config->default_priority; client->timeout_ms = config->timeout_ms; client->debug = config->debug; client->closed = false; curl_global_init(CURL_GLOBAL_DEFAULT); client->curl = curl_easy_init(); return client; } void synor_destroy(synor_client_t* client) { if (!client) return; client->closed = true; if (client->curl) { curl_easy_cleanup(client->curl); } curl_global_cleanup(); free(client->api_key); free(client->base_url); free(client); } /* ============ Tensor Functions ============ */ synor_tensor_t* synor_tensor_create( const int* shape, int ndim, const double* data, synor_precision_t dtype ) { synor_tensor_t* tensor = calloc(1, sizeof(synor_tensor_t)); if (!tensor) return NULL; tensor->ndim = ndim; tensor->dtype = dtype; tensor->size = compute_tensor_size(shape, ndim); tensor->shape = malloc(ndim * sizeof(int)); if (!tensor->shape) { free(tensor); return NULL; } memcpy(tensor->shape, shape, ndim * sizeof(int)); tensor->data = malloc(tensor->size * sizeof(double)); if (!tensor->data) { free(tensor->shape); free(tensor); return NULL; } if (data) { memcpy(tensor->data, data, tensor->size * sizeof(double)); } return tensor; } synor_tensor_t* synor_tensor_zeros(const int* shape, int ndim) { synor_tensor_t* tensor = synor_tensor_create(shape, ndim, NULL, SYNOR_PRECISION_FP32); if (tensor) { memset(tensor->data, 0, tensor->size * sizeof(double)); } return tensor; } synor_tensor_t* synor_tensor_ones(const int* shape, int ndim) { synor_tensor_t* tensor = synor_tensor_create(shape, ndim, NULL, SYNOR_PRECISION_FP32); if (tensor) { for (size_t i = 0; i < tensor->size; i++) { tensor->data[i] = 1.0; } } return tensor; } synor_tensor_t* synor_tensor_rand(const int* shape, int ndim) { synor_tensor_t* tensor = synor_tensor_create(shape, ndim, NULL, SYNOR_PRECISION_FP32); if (tensor) { srand((unsigned int)time(NULL)); for (size_t i = 0; i < tensor->size; i++) { tensor->data[i] = (double)rand() / RAND_MAX; } } return tensor; } synor_tensor_t* synor_tensor_randn(const int* shape, int ndim) { synor_tensor_t* tensor = synor_tensor_create(shape, ndim, NULL, SYNOR_PRECISION_FP32); if (tensor) { srand((unsigned int)time(NULL)); for (size_t i = 0; i < tensor->size; i++) { // Box-Muller transform double u1 = (double)rand() / RAND_MAX; double u2 = (double)rand() / RAND_MAX; tensor->data[i] = sqrt(-2 * log(u1)) * cos(2 * M_PI * u2); } } return tensor; } synor_tensor_t* synor_tensor_eye(int n) { int shape[] = {n, n}; synor_tensor_t* tensor = synor_tensor_zeros(shape, 2); if (tensor) { for (int i = 0; i < n; i++) { tensor->data[i * n + i] = 1.0; } } return tensor; } synor_tensor_t* synor_tensor_reshape(const synor_tensor_t* tensor, const int* new_shape, int new_ndim) { if (!tensor) return NULL; size_t new_size = compute_tensor_size(new_shape, new_ndim); if (new_size != tensor->size) return NULL; return synor_tensor_create(new_shape, new_ndim, tensor->data, tensor->dtype); } synor_tensor_t* synor_tensor_transpose(const synor_tensor_t* tensor) { if (!tensor || tensor->ndim != 2) return NULL; int rows = tensor->shape[0]; int cols = tensor->shape[1]; int new_shape[] = {cols, rows}; synor_tensor_t* result = synor_tensor_create(new_shape, 2, NULL, tensor->dtype); if (!result) return NULL; for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { result->data[j * rows + i] = tensor->data[i * cols + j]; } } return result; } double synor_tensor_mean(const synor_tensor_t* tensor) { if (!tensor || tensor->size == 0) return 0.0; double sum = 0.0; for (size_t i = 0; i < tensor->size; i++) { sum += tensor->data[i]; } return sum / tensor->size; } double synor_tensor_sum(const synor_tensor_t* tensor) { if (!tensor) return 0.0; double sum = 0.0; for (size_t i = 0; i < tensor->size; i++) { sum += tensor->data[i]; } return sum; } double synor_tensor_std(const synor_tensor_t* tensor) { if (!tensor || tensor->size == 0) return 0.0; double mean = synor_tensor_mean(tensor); double sum_sq = 0.0; for (size_t i = 0; i < tensor->size; i++) { double diff = tensor->data[i] - mean; sum_sq += diff * diff; } return sqrt(sum_sq / tensor->size); } double synor_tensor_max(const synor_tensor_t* tensor) { if (!tensor || tensor->size == 0) return 0.0; double max = tensor->data[0]; for (size_t i = 1; i < tensor->size; i++) { if (tensor->data[i] > max) max = tensor->data[i]; } return max; } double synor_tensor_min(const synor_tensor_t* tensor) { if (!tensor || tensor->size == 0) return 0.0; double min = tensor->data[0]; for (size_t i = 1; i < tensor->size; i++) { if (tensor->data[i] < min) min = tensor->data[i]; } return min; } void synor_tensor_free(synor_tensor_t* tensor) { if (!tensor) return; free(tensor->shape); free(tensor->data); free(tensor); } /* ============ Memory Management ============ */ void synor_job_result_free(synor_job_result_t* result) { if (!result) return; free(result->job_id); free(result->result_string); free(result->error); synor_tensor_free(result->result_tensor); free(result); } void synor_model_info_free(synor_model_info_t* info) { if (!info) return; free(info->id); free(info->name); free(info->description); free(info->format); free(info->license); free(info->cid); free(info); } void synor_model_info_array_free(synor_model_info_t* models, size_t count) { if (!models) return; for (size_t i = 0; i < count; i++) { free(models[i].id); free(models[i].name); free(models[i].description); free(models[i].format); free(models[i].license); free(models[i].cid); } free(models); } void synor_pricing_info_array_free(synor_pricing_info_t* pricing, size_t count) { free(pricing); } void synor_usage_stats_free(synor_usage_stats_t* stats) { free(stats); } /* ============ Utility Functions ============ */ const char* synor_error_string(synor_error_t error) { switch (error) { case SYNOR_OK: return "OK"; case SYNOR_ERROR_INVALID_ARGUMENT: return "Invalid argument"; case SYNOR_ERROR_OUT_OF_MEMORY: return "Out of memory"; case SYNOR_ERROR_NETWORK: return "Network error"; case SYNOR_ERROR_API: return "API error"; case SYNOR_ERROR_TIMEOUT: return "Timeout"; case SYNOR_ERROR_CLIENT_CLOSED: return "Client closed"; default: return "Unknown error"; } } const char* synor_processor_string(synor_processor_t processor) { switch (processor) { case SYNOR_PROCESSOR_CPU: return "cpu"; case SYNOR_PROCESSOR_GPU: return "gpu"; case SYNOR_PROCESSOR_TPU: return "tpu"; case SYNOR_PROCESSOR_NPU: return "npu"; case SYNOR_PROCESSOR_LPU: return "lpu"; case SYNOR_PROCESSOR_FPGA: return "fpga"; case SYNOR_PROCESSOR_DSP: return "dsp"; case SYNOR_PROCESSOR_WEBGPU: return "webgpu"; case SYNOR_PROCESSOR_WASM: return "wasm"; case SYNOR_PROCESSOR_AUTO: return "auto"; default: return "unknown"; } } const char* synor_precision_string(synor_precision_t precision) { switch (precision) { case SYNOR_PRECISION_FP64: return "fp64"; case SYNOR_PRECISION_FP32: return "fp32"; case SYNOR_PRECISION_FP16: return "fp16"; case SYNOR_PRECISION_BF16: return "bf16"; case SYNOR_PRECISION_INT8: return "int8"; case SYNOR_PRECISION_INT4: return "int4"; default: return "unknown"; } } const char* synor_status_string(synor_status_t status) { switch (status) { case SYNOR_STATUS_PENDING: return "pending"; case SYNOR_STATUS_QUEUED: return "queued"; case SYNOR_STATUS_RUNNING: return "running"; case SYNOR_STATUS_COMPLETED: return "completed"; case SYNOR_STATUS_FAILED: return "failed"; case SYNOR_STATUS_CANCELLED: return "cancelled"; default: return "unknown"; } } /* ============ API Functions (Stubs) ============ */ synor_job_result_t* synor_matmul( synor_client_t* client, const synor_tensor_t* a, const synor_tensor_t* b, const synor_matmul_options_t* options ) { if (!client || client->closed || !a || !b) return NULL; synor_job_result_t* result = calloc(1, sizeof(synor_job_result_t)); if (!result) return NULL; // TODO: Implement HTTP call to API result->status = SYNOR_STATUS_COMPLETED; result->job_id = synor_strdup("job-placeholder"); return result; } synor_job_result_t* synor_conv2d( synor_client_t* client, const synor_tensor_t* input, const synor_tensor_t* kernel, const synor_conv2d_options_t* options ) { if (!client || client->closed || !input || !kernel) return NULL; synor_job_result_t* result = calloc(1, sizeof(synor_job_result_t)); if (!result) return NULL; result->status = SYNOR_STATUS_COMPLETED; result->job_id = synor_strdup("job-placeholder"); return result; } synor_job_result_t* synor_attention( synor_client_t* client, const synor_tensor_t* query, const synor_tensor_t* key, const synor_tensor_t* value, const synor_attention_options_t* options ) { if (!client || client->closed || !query || !key || !value) return NULL; synor_job_result_t* result = calloc(1, sizeof(synor_job_result_t)); if (!result) return NULL; result->status = SYNOR_STATUS_COMPLETED; result->job_id = synor_strdup("job-placeholder"); return result; } synor_job_result_t* synor_inference( synor_client_t* client, const char* model, const char* prompt, const synor_inference_options_t* options ) { if (!client || client->closed || !model || !prompt) return NULL; synor_job_result_t* result = calloc(1, sizeof(synor_job_result_t)); if (!result) return NULL; result->status = SYNOR_STATUS_COMPLETED; result->job_id = synor_strdup("job-placeholder"); return result; } synor_error_t synor_inference_stream( synor_client_t* client, const char* model, const char* prompt, const synor_inference_options_t* options, synor_stream_callback_t callback, void* user_data ) { if (!client || client->closed) return SYNOR_ERROR_CLIENT_CLOSED; if (!model || !prompt || !callback) return SYNOR_ERROR_INVALID_ARGUMENT; // TODO: Implement streaming HTTP call return SYNOR_OK; } bool synor_health_check(synor_client_t* client) { if (!client || client->closed) return false; // TODO: Implement health check return true; } synor_error_t synor_list_models( synor_client_t* client, synor_model_category_t category, synor_model_info_t** models, size_t* count ) { if (!client || client->closed) return SYNOR_ERROR_CLIENT_CLOSED; if (!models || !count) return SYNOR_ERROR_INVALID_ARGUMENT; *models = NULL; *count = 0; // TODO: Implement model listing return SYNOR_OK; } synor_model_info_t* synor_get_model(synor_client_t* client, const char* model_id) { if (!client || client->closed || !model_id) return NULL; // TODO: Implement model fetching return NULL; } synor_error_t synor_search_models( synor_client_t* client, const char* query, synor_model_info_t** models, size_t* count ) { if (!client || client->closed) return SYNOR_ERROR_CLIENT_CLOSED; if (!query || !models || !count) return SYNOR_ERROR_INVALID_ARGUMENT; *models = NULL; *count = 0; // TODO: Implement model search return SYNOR_OK; } synor_error_t synor_get_pricing( synor_client_t* client, synor_pricing_info_t** pricing, size_t* count ) { if (!client || client->closed) return SYNOR_ERROR_CLIENT_CLOSED; if (!pricing || !count) return SYNOR_ERROR_INVALID_ARGUMENT; *pricing = NULL; *count = 0; // TODO: Implement pricing fetch return SYNOR_OK; } synor_usage_stats_t* synor_get_usage(synor_client_t* client) { if (!client || client->closed) return NULL; // TODO: Implement usage stats fetch return NULL; }