Thursday, August 21, 2025

ARMv7-A/9 Translation for Adi Protocol Suite! :-S*

 


 // Conceptual ARM Operand Set Translation
// This Operand codeset is a conceptual example and is not intended to be runnable on its own.
// It assumes a standard ARMv7-A architecture with VFPv4 (Vector Floating-Point) extensions, common for chipsets like the MT8196.

// C++ Function for Reference:
/*
std::vector<double> pack_eigenvalue_data(const std::vector<double>& eigenvalues) {
    std::vector<double> packed_data(eigenvalues.size());
    for (size_t i = 0; i < eigenvalues.size(); ++i) {
        double val = eigenvalues[i];
        if (std::abs(val) >= 1.0) {
            packed_data[i] = calculate_arcsecant(val);
        } else {
            packed_data[i] = val;
        }
    }
    return packed_data;
}
*/

// --- ARM Operand Script ---

.global pack_eigenvalue_data
.type pack_eigenvalue_data, %function

// The function signature in ARM (following a common ABI):
// r0: Pointer to the input vector `eigenvalues` (const std::vector<double>&)
// r1: Size of the input vector
// r2: Pointer to the output vector `packed_data`

pack_eigenvalue_data:
    // Standard function prologue: push link register (lr) and frame pointer (fp)
    push {r4, r5, r6, lr}

    // Set up local variables/pointers
    mov r4, r0             // r4 = pointer to eigenvalues (input)
    mov r5, r2             // r5 = pointer to packed_data (output)
    mov r6, #0             // r6 = loop counter `i`

loop_start:
    cmp r6, r1             // Compare loop counter `i` with vector size
    bge loop_end           // Branch if greater than or equal to (end of loop)

    // Calculate memory address for the current `val` in the input vector
    // LDRD loads a double-precision floating-point value (8 bytes)
    // ldrd d0, [r4, r6, lsl #3] (Equivalent to: load d0, [r4 + r6*8])
    // The `lsl #3` scales the index `r6` by 8 to get the byte offset for a double.
    ldr d0, [r4, r6, lsl #3] // Load `val` into floating-point register d0

    // Compare abs(val) with 1.0
    // VABS.F64 d1, d0       // d1 = abs(val)
    vabs.f64 d1, d0
    // VCMPE.F64 d1, d1     // The C++ `std::abs` function is translated here
    vcmp.f64 d1, #1.0      // Compare d1 with 1.0
    vmrs APSR_nzcv, fpscr  // Move floating-point status flags to ARM status register

    // Branch based on the comparison result
    bge .abs_greater_equal_1 // Branch if abs(val) >= 1.0

    // `else` block: `packed_data[i] = val;`
    // VSTR.F64 d0, [r5, r6, lsl #3] // Store the original value to the output vector
    strd d0, [r5, r6, lsl #3]
    b .loop_continue

.abs_greater_equal_1:
    // `if` block: `packed_data[i] = calculate_arcsecant(val);`
    // We would call a separate function here.
    // In a real scenario, this would be a function call that takes a double
    // in d0 and returns the result in d0.
    // bl calculate_arcsecant_func
    
    // For this conceptual example, let's just simulate a store
    // This is where you would introduce a breakpoint for `break functionality` research
    // to observe the input to the `calculate_arcsecant` function.
    
    // VSTR.F64 d0, [r5, r6, lsl #3] // Store the calculated value to the output vector
    strd d0, [r5, r6, lsl #3]


.loop_continue:
    // Increment the loop counter
    add r6, r6, #1
    b loop_start           // Jump back to the start of the loop

loop_end:
    // Function epilogue: pop registers and return
    pop {r4, r5, r6, pc}

 

 //C++ translation for ARMv7-A

// Adi-Protocol_ARMv7A.c 

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <memory>
#include <cmath>
#include <numeric> // For std::accumulate
#include <algorithm>
#include <stdexcept>
#include <thread>
#include <mutex>

// For JSON handling (requires nlohmann/json library)
#include "json.hpp"
using json = nlohmann::json;

// --- Mock Socket and Network Utilities for Conceptual Example ---
// Note: A real implementation would use a library like Boost.Asio or implement sockets manually.
// This is a simplified model to demonstrate the protocol logic.

class MockSocket {
public:
    std::string buffer;
    void sendall(const std::string& data) {
        // Simulate sending
    }
    std::string recv(size_t size) {
        // Simulate receiving
        return "mock data"; // Return some dummy data for the example
    }
};

std::string _recvall(MockSocket& sock, size_t n) {
    std::string data;
    while (data.size() < n) {
        data += sock.recv(n - data.size());
    }
    return data;
}

// Helper to convert std::vector<double> to a mock binary string.
std::string _pack_data(const std::vector<double>& data) {
    std::string binary_data(data.size() * sizeof(double), '\0');
    std::memcpy(&binary_data[0], data.data(), binary_data.size());
    return binary_data;
}

// Helper to convert a mock binary string to std::vector<double>.
std::vector<double> _unpack_data(const std::string& binary_data) {
    std::vector<double> data(binary_data.size() / sizeof(double));
    std::memcpy(data.data(), binary_data.data(), binary_data.size());
    return data;
}

// --- Common Constants (Matches Python protocol) ---
const int OPERATION_INTERPOLATE = 0;
const int OPERATION_DIFFERENTIATE = 1;
const int OPERATION_CALCULATE_GRADIENT_1D = 2;
const int OPERATION_HYPERBOLIC_INTERCEPT_HANDLER = 3;
const int OPERATION_INTEGRATE = 4;
const int OPERATION_INTEGRATE_ND = 5;
const int OPERATION_WORKFLOW = 6; // NEW: For relational compositions

// --- Helper Functions ---
double calculate_arcsecant(double val) {
    if (std::abs(val) < 1.0) {
        return NAN;
    }
    return std::acos(1.0 / val);
}

std::vector<double> pack_eigenvalue_data(const std::vector<double>& eigenvalues) {
    std::vector<double> packed_data(eigenvalues.size());
    for (size_t i = 0; i < eigenvalues.size(); ++i) {
        double val = eigenvalues[i];
        if (std::abs(val) >= 1.0) {
            packed_data[i] = calculate_arcsecant(val);
        } else {
            packed_data[i] = val;
        }
    }
    return packed_data;
}

// --- FPU Operations (from Python adi_server.py) ---
std::vector<double> hyperbolic_parabolic_interpolation(
    const std::map<std::string, std::vector<double>>& data_dict,
    const std::vector<double>& x_interp) {
    
    // ... (rest of the function, no changes needed for this refit)
    std::vector<std::vector<double>> all_fx_data;
    std::vector<std::vector<double>> all_fy_data;

    for (const auto& pair : data_dict) {
        if (pair.first.find("fx") == 0) {
            all_fx_data.push_back(pair.second);
        } else if (pair.first.find("fy") == 0) {
            all_fy_data.push_back(pair.second);
        }
    }

    if (all_fx_data.size() != all_fy_data.size() || x_interp.empty()) {
        throw std::invalid_argument("Invalid data for interpolation.");
    }

    std::vector<double> all_interp_y;
    for (size_t i = 0; i < all_fx_data.size(); ++i) {
        const auto& fx = all_fx_data[i];
        const auto& fy = all_fy_data[i];

        if (fx.size() != fy.size() || fx.size() < 3) {
            throw std::invalid_argument("X and Y data must have equal length and at least three points.");
        }

        for (double x : x_interp) {
            std::vector<std::pair<double, double>> points(fx.size());
            for (size_t j = 0; j < fx.size(); ++j) {
                points[j] = {std::abs(fx[j] - x), fx[j]};
            }
            std::sort(points.begin(), points.end());

            double x1 = points[0].second;
            double x2 = points[1].second;
            double x3 = points[2].second;
            
            auto find_y = [&](double search_x) {
                for(size_t k = 0; k < fx.size(); ++k) {
                    if (fx[k] == search_x) return fy[k];
                }
                return 0.0;
            };

            double y1 = find_y(x1);
            double y2 = find_y(x2);
            double y3 = find_y(x3);

            double L1 = ((x - x2) * (x - x3)) / ((x1 - x2) * (x1 - x3));
            double L2 = ((x - x1) * (x - x3)) / ((x2 - x1) * (x2 - x3));
            double L3 = ((x - x1) * (x - x2)) / ((x3 - x1) * (x3 - x2));
            double interp_y = L1 * y1 + L2 * y2 + L3 * y3;
            all_interp_y.push_back(interp_y);
        }
    }
    return all_interp_y;
}

std::vector<double> calculate_gradient_1d(const std::vector<double>& data) {
    if (data.size() < 2) {
        throw std::invalid_argument("Data must have at least two points to calculate a gradient.");
    }
    std::vector<double> gradient;
    for (size_t i = 0; i < data.size() - 1; ++i) {
        gradient.push_back(data[i+1] - data[i]);
    }
    return gradient;
}

std::vector<double> handle_eigenvalue_reference_op(const std::vector<double>& packed_data) {
    double sum = std::accumulate(packed_data.begin(), packed_data.end(), 0.0);
    double mean_value = sum / packed_data.size();
    
    std::cout << "Server received 'eigenvalue packed radices' data." << std::endl;
    std::cout << "Calculated mean medium: " << mean_value << std::endl;

    std::vector<double> result;
    for (int i = 0; i < 5; ++i) {
        result.push_back(mean_value * (i + 1));
    }
    return result;
}

// --- NEW: Workflow Handler from adi-ndim.py ---
std::vector<double> handle_workflow(const json& workflow) {
    std::map<std::string, std::vector<double>> data_store;
    std::vector<double> final_result;

    for (const auto& step : workflow) {
        std::string operation = step["operation_type"];
        std::vector<double> input_data_vec;

        // Determine input data source (direct or reference)
        if (step["input_data"]["type"] == "direct") {
            // Unpack direct input data
            if (operation == "INTERPOLATE") {
                const auto& fx_data_list = step["input_data"]["fx_data"];
                const auto& fy_data_list = step["input_data"]["fy_data"];
                const auto& fz_data_list = step["input_data"]["fz_data"];
                
                std::map<std::string, std::vector<double>> interpolation_data;
                for (size_t i = 0; i < fx_data_list.size(); ++i) {
                    interpolation_data["fx" + std::to_string(i)] = fx_data_list[i].get<std::vector<double>>();
                    interpolation_data["fy" + std::to_string(i)] = fy_data_list[i].get<std::vector<double>>();
                    // Note: fz_data would be handled here too if needed
                }
                std::vector<double> x_interp = step["parameters"]["x_interp_points"].get<std::vector<double>>();
                input_data_vec = hyperbolic_parabolic_interpolation(interpolation_data, x_interp);

            } else {
                throw std::runtime_error("Direct input is only supported for INTERPOLATE operation in this mock.");
            }
        } else if (step["input_data"]["type"] == "reference") {
            std::string source_id = step["input_data"]["source_id"];
            if (data_store.find(source_id) != data_store.end()) {
                input_data_vec = data_store[source_id];
            } else {
                throw std::runtime_error("Referenced data not found in store: " + source_id);
            }
        }

        // Execute the operation
        if (operation == "INTERPOLATE") {
            // Result is already in input_data_vec from the direct path above
            // Now, store it for future steps
            if (step.count("output_id")) {
                data_store[step["output_id"]] = input_data_vec;
            } else {
                final_result = input_data_vec;
            }
        } else if (operation == "CALCULATE_GRADIENT_1D") {
            std::vector<double> result = calculate_gradient_1d(input_data_vec);
            if (step.count("output_id")) {
                data_store[step["output_id"]] = result;
            } else {
                final_result = result;
            }
        } else {
            throw std::runtime_error("Unsupported operation type in workflow: " + operation);
        }
    }
    return final_result;
}

// A simplified function to handle client requests.
std::string handle_request(const json& header, const std::string& binary_payload) {
    if (header["operation"] == OPERATION_WORKFLOW) {
        try {
            // Mock unpacking of the binary payload into a vector
            json workflow = json::parse(binary_payload);
            std::vector<double> result = handle_workflow(workflow);

            json response_header;
            response_header["status"] = "success";
            response_header["result"] = result;
            return response_header.dump();
        } catch (const std::exception& e) {
            json error_header;
            error_header["status"] = "error";
            error_header["message"] = e.what();
            return error_header.dump();
        }
    }
    // ... (rest of the handle_request function, no changes needed)
    return "unsupported operation";
}

// --- Main Server Functionality ---
void start_server() {
    std::cout << "Server listening..." << std::endl;
    MockSocket client_socket;
    
    // Simulate a client request with the new workflow
    std::cout << "Simulating a client request with a workflow..." << std::endl;
    
    json workflow_mock = json::parse(R"(
        [
            {
                "operation_type": "INTERPOLATE",
                "input_data": {
                    "type": "direct", 
                    "fx_data": [[1.0, 2.0, 3.0, 4.0, 5.0]],
                    "fy_data": [[10.0, 12.0, 15.0, 19.0, 25.0]],
                    "fz_data": [[20.0, 21.0, 23.0, 26.0, 30.0]]
                },
                "parameters": {
                    "x_interp_points": [1.5, 2.5, 3.5, 4.5]
                },
                "output_id": "interpolated_data"
            },
            {
                "operation_type": "CALCULATE_GRADIENT_1D",
                "input_data": {
                    "type": "reference",
                    "source_id": "interpolated_data"
                }
            }
        ]
    )");
    std::string workflow_payload = workflow_mock.dump();

    json request_header;
    request_header["operation"] = OPERATION_WORKFLOW;
    std::string response = handle_request(request_header, workflow_payload);
    std::cout << "Server response: " << response << std::endl;
}

// --- Main Client Functionality ---
void start_client() {
    std::cout << "Client started." << std::endl;
    std::vector<double> eigenvalues = {2.5, 10.0, 100.0, 0.5, -0.75, 500.0, -2.5, -100.0};
    auto packed_data = pack_eigenvalue_data(eigenvalues);

    std::cout << "Original eigenvalues: ";
    for (double val : eigenvalues) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    std::cout << "Packed data (arcsecant and linear): ";
    for (double val : packed_data) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::thread server_thread(start_server);
    std::thread client_thread(start_client);

    server_thread.join();
    client_thread.join();

    return 0;
}



// --- ARM Operand Set for ARMv9 utilizing SVE ---

.global pack_eigenvalue_data
.type pack_eigenvalue_data, %function

// The function signature in ARM (following a common ABI):
// x0: Pointer to the input vector `eigenvalues`
// x1: Size of the input vector
// x2: Pointer to the output vector `packed_data`

pack_eigenvalue_data:
    // Standard function prologue: save used registers
    stp x29, x30, [sp, #-16]! // Save frame pointer (x29) and link register (x30)
    mov x29, sp               // Set up new frame pointer
    
    // Set up local variables/pointers
    mov x4, x0                // x4 = pointer to eigenvalues (input)
    mov x5, x2                // x5 = pointer to packed_data (output)
    mov x6, #0                // x6 = loop counter `i`

    // --- SVE Vectorized Loop ---
    // SVE uses a loop predicate to handle different vector lengths
    // and process data in chunks.
    
    // Set up a vector of 1.0s for comparison.
    mov d0, #1.0
    fmov z0.d, d0             // Broadcast 1.0 to all elements of vector register z0

sve_loop_start:
    // Determine the number of elements to process in this iteration.
    whilelt p0.d, x6, x1     // p0.d is a predicate (boolean mask) for double elements.
                             // `whilelt` sets the predicate for elements where x6 < x1.
    
    // If no elements remain, break the loop.
    b.none sve_loop_end      // Branch if none of the predicate lanes are true.
    
    // Load a vector of double-precision floating-point values from memory.
    // The predicate `p0` ensures we don't load past the end of the array.
    ld1d z1.d, p0/z, [x4, x6, lsl #3] // Load a vector of doubles from `eigenvalues`
                                        // The lsl #3 scales the index x6 by 8 for double-byte offsets.

    // Compare abs(val) with 1.0
    // First, compute the absolute value for each element.
    fabs z2.d, z1.d           // z2 = fabs(z1)
    
    // Predicated comparison: generate a boolean predicate (mask) where abs(val) >= 1.0.
    fcmge p1.d, p0/z, z2.d, z0.d // Compare z2 with z0, result is in predicate p1.d

    // Calculate arcsecant for elements where the predicate is true.
    // The `p1/m` indicates a merging predication.
    fdiv z3.d, p1/m, z0.d, z1.d  // z3 = 1.0 / z1 (only for active lanes in p1)
    frecps z3.d, z3.d, z3.d      // Reciprocal estimate (often part of a sequence for full precision)
    frecpe z3.d, z3.d, z3.d
    // A more realistic scenario would call a vectorized `calculate_arcsecant` function.
    // This is a conceptual example. For an accurate arccos, we would use a library function
    // or a hardware instruction if available.
    // For this example, let's assume we have a vectorized arcsecant function.
    // fsub z4.d, z3.d, z1.d // Placeholder for complex vectorized function

    // Select between `arcsecant` and the original value based on the predicate.
    sel z1.d, p1.d, z1.d, z3.d // Select `z3` if `p1` is true, otherwise `z1`.

    // Store the results back to memory.
    st1d z1.d, p0/z, [x5, x6, lsl #3] // Store the result vector to `packed_data`

    // Increment the loop counter by the number of elements processed.
    incd x6, all, x6         // Increment loop counter by SVE vector length
    
    b sve_loop_start         // Jump back to the start of the loop

sve_loop_end:
    // Function epilogue: restore registers and return
    ldp x29, x30, [sp], #16  // Restore frame pointer and link register
    ret                      // Return from function


// ARMv9 Implementation of Adi Protocol (N-Dimensional and Eigenvalue Packing Included! :-S)

// Adi-Protocol_ARMv9.c 

 

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <memory>
#include <cmath>
#include <numeric> // For std::accumulate
#include <algorithm>
#include <stdexcept>
#include <thread>
#include <mutex>

// For JSON handling (requires nlohmann/json library)
#include "json.hpp"
using json = nlohmann::json;

// --- Mock Socket and Network Utilities for Conceptual Example ---
// Note: A real implementation would use a library like Boost.Asio or implement sockets manually.
// This is a simplified model to demonstrate the protocol logic.

class MockSocket {
public:
    std::string buffer;
    void sendall(const std::string& data) {
        // Simulate sending
    }
    std::string recv(size_t size) {
        // Simulate receiving
        return "mock data"; // Return some dummy data for the example
    }
};

std::string _recvall(MockSocket& sock, size_t n) {
    std::string data;
    while (data.size() < n) {
        data += sock.recv(n - data.size());
    }
    return data;
}

// Helper to convert std::vector<double> to a mock binary string.
std::string _pack_data(const std::vector<double>& data) {
    std::string binary_data(data.size() * sizeof(double), '\0');
    std::memcpy(&binary_data[0], data.data(), binary_data.size());
    return binary_data;
}

// Helper to convert a mock binary string to std::vector<double>.
std::vector<double> _unpack_data(const std::string& binary_data) {
    std::vector<double> data(binary_data.size() / sizeof(double));
    std::memcpy(data.data(), binary_data.data(), binary_data.size());
    return data;
}

// --- Common Constants (Matches Python protocol) ---
const int OPERATION_INTERPOLATE = 0;
const int OPERATION_DIFFERENTIATE = 1;
const int OPERATION_CALCULATE_GRADIENT_1D = 2;
const int OPERATION_HYPERBOLIC_INTERCEPT_HANDLER = 3;
const int OPERATION_INTEGRATE = 4;
const int OPERATION_INTEGRATE_ND = 5;
const int OPERATION_WORKFLOW = 6; // NEW: For relational compositions

// --- Helper Functions ---
double calculate_arcsecant(double val) {
    if (std::abs(val) < 1.0) {
        return NAN;
    }
    return std::acos(1.0 / val);
}

std::vector<double> pack_eigenvalue_data(const std::vector<double>& eigenvalues) {
    std::vector<double> packed_data(eigenvalues.size());
    for (size_t i = 0; i < eigenvalues.size(); ++i) {
        double val = eigenvalues[i];
        if (std::abs(val) >= 1.0) {
            packed_data[i] = calculate_arcsecant(val);
        } else {
            packed_data[i] = val;
        }
    }
    return packed_data;
}

// --- FPU Operations (from Python adi_server.py) ---
std::vector<double> hyperbolic_parabolic_interpolation(
    const std::map<std::string, std::vector<double>>& data_dict,
    const std::vector<double>& x_interp) {
    
    // ... (rest of the function, no changes needed for this refit)
    std::vector<std::vector<double>> all_fx_data;
    std::vector<std::vector<double>> all_fy_data;

    for (const auto& pair : data_dict) {
        if (pair.first.find("fx") == 0) {
            all_fx_data.push_back(pair.second);
        } else if (pair.first.find("fy") == 0) {
            all_fy_data.push_back(pair.second);
        }
    }

    if (all_fx_data.size() != all_fy_data.size() || x_interp.empty()) {
        throw std::invalid_argument("Invalid data for interpolation.");
    }

    std::vector<double> all_interp_y;
    for (size_t i = 0; i < all_fx_data.size(); ++i) {
        const auto& fx = all_fx_data[i];
        const auto& fy = all_fy_data[i];

        if (fx.size() != fy.size() || fx.size() < 3) {
            throw std::invalid_argument("X and Y data must have equal length and at least three points.");
        }

        for (double x : x_interp) {
            std::vector<std::pair<double, double>> points(fx.size());
            for (size_t j = 0; j < fx.size(); ++j) {
                points[j] = {std::abs(fx[j] - x), fx[j]};
            }
            std::sort(points.begin(), points.end());

            double x1 = points[0].second;
            double x2 = points[1].second;
            double x3 = points[2].second;
            
            auto find_y = [&](double search_x) {
                for(size_t k = 0; k < fx.size(); ++k) {
                    if (fx[k] == search_x) return fy[k];
                }
                return 0.0;
            };

            double y1 = find_y(x1);
            double y2 = find_y(x2);
            double y3 = find_y(x3);

            double L1 = ((x - x2) * (x - x3)) / ((x1 - x2) * (x1 - x3));
            double L2 = ((x - x1) * (x - x3)) / ((x2 - x1) * (x2 - x3));
            double L3 = ((x - x1) * (x - x2)) / ((x3 - x1) * (x3 - x2));
            double interp_y = L1 * y1 + L2 * y2 + L3 * y3;
            all_interp_y.push_back(interp_y);
        }
    }
    return all_interp_y;
}

std::vector<double> calculate_gradient_1d(const std::vector<double>& data) {
    if (data.size() < 2) {
        throw std::invalid_argument("Data must have at least two points to calculate a gradient.");
    }
    std::vector<double> gradient;
    for (size_t i = 0; i < data.size() - 1; ++i) {
        gradient.push_back(data[i+1] - data[i]);
    }
    return gradient;
}

std::vector<double> handle_eigenvalue_reference_op(const std::vector<double>& packed_data) {
    double sum = std::accumulate(packed_data.begin(), packed_data.end(), 0.0);
    double mean_value = sum / packed_data.size();
    
    std::cout << "Server received 'eigenvalue packed radices' data." << std::endl;
    std::cout << "Calculated mean medium: " << mean_value << std::endl;

    std::vector<double> result;
    for (int i = 0; i < 5; ++i) {
        result.push_back(mean_value * (i + 1));
    }
    return result;
}

// --- NEW: Workflow Handler from adi-ndim.py ---
std::vector<double> handle_workflow(const json& workflow) {
    std::map<std::string, std::vector<double>> data_store;
    std::vector<double> final_result;

    for (const auto& step : workflow) {
        std::string operation = step["operation_type"];
        std::vector<double> input_data_vec;

        // Determine input data source (direct or reference)
        if (step["input_data"]["type"] == "direct") {
            // Unpack direct input data
            if (operation == "INTERPOLATE") {
                const auto& fx_data_list = step["input_data"]["fx_data"];
                const auto& fy_data_list = step["input_data"]["fy_data"];
                const auto& fz_data_list = step["input_data"]["fz_data"];
                
                std::map<std::string, std::vector<double>> interpolation_data;
                for (size_t i = 0; i < fx_data_list.size(); ++i) {
                    interpolation_data["fx" + std::to_string(i)] = fx_data_list[i].get<std::vector<double>>();
                    interpolation_data["fy" + std::to_string(i)] = fy_data_list[i].get<std::vector<double>>();
                    // Note: fz_data would be handled here too if needed
                }
                std::vector<double> x_interp = step["parameters"]["x_interp_points"].get<std::vector<double>>();
                input_data_vec = hyperbolic_parabolic_interpolation(interpolation_data, x_interp);

            } else {
                throw std::runtime_error("Direct input is only supported for INTERPOLATE operation in this mock.");
            }
        } else if (step["input_data"]["type"] == "reference") {
            std::string source_id = step["input_data"]["source_id"];
            if (data_store.find(source_id) != data_store.end()) {
                input_data_vec = data_store[source_id];
            } else {
                throw std::runtime_error("Referenced data not found in store: " + source_id);
            }
        }

        // Execute the operation
        if (operation == "INTERPOLATE") {
            // Result is already in input_data_vec from the direct path above
            // Now, store it for future steps
            if (step.count("output_id")) {
                data_store[step["output_id"]] = input_data_vec;
            } else {
                final_result = input_data_vec;
            }
        } else if (operation == "CALCULATE_GRADIENT_1D") {
            std::vector<double> result = calculate_gradient_1d(input_data_vec);
            if (step.count("output_id")) {
                data_store[step["output_id"]] = result;
            } else {
                final_result = result;
            }
        } else {
            throw std::runtime_error("Unsupported operation type in workflow: " + operation);
        }
    }
    return final_result;
}

// A simplified function to handle client requests.
std::string handle_request(const json& header, const std::string& binary_payload) {
    if (header["operation"] == OPERATION_WORKFLOW) {
        try {
            // Mock unpacking of the binary payload into a vector
            json workflow = json::parse(binary_payload);
            std::vector<double> result = handle_workflow(workflow);

            json response_header;
            response_header["status"] = "success";
            response_header["result"] = result;
            return response_header.dump();
        } catch (const std::exception& e) {
            json error_header;
            error_header["status"] = "error";
            error_header["message"] = e.what();
            return error_header.dump();
        }
    }
    // ... (rest of the handle_request function, no changes needed)
    return "unsupported operation";
}

// --- Main Server Functionality ---
void start_server() {
    std::cout << "Server listening..." << std::endl;
    MockSocket client_socket;
    
    // Simulate a client request with the new workflow
    std::cout << "Simulating a client request with a workflow..." << std::endl;
    
    json workflow_mock = json::parse(R"(
        [
            {
                "operation_type": "INTERPOLATE",
                "input_data": {
                    "type": "direct", 
                    "fx_data": [[1.0, 2.0, 3.0, 4.0, 5.0]],
                    "fy_data": [[10.0, 12.0, 15.0, 19.0, 25.0]],
                    "fz_data": [[20.0, 21.0, 23.0, 26.0, 30.0]]
                },
                "parameters": {
                    "x_interp_points": [1.5, 2.5, 3.5, 4.5]
                },
                "output_id": "interpolated_data"
            },
            {
                "operation_type": "CALCULATE_GRADIENT_1D",
                "input_data": {
                    "type": "reference",
                    "source_id": "interpolated_data"
                }
            }
        ]
    )");
    std::string workflow_payload = workflow_mock.dump();

    json request_header;
    request_header["operation"] = OPERATION_WORKFLOW;
    std::string response = handle_request(request_header, workflow_payload);
    std::cout << "Server response: " << response << std::endl;
}

// --- Main Client Functionality ---
void start_client() {
    std::cout << "Client started." << std::endl;
    std::vector<double> eigenvalues = {2.5, 10.0, 100.0, 0.5, -0.75, 500.0, -2.5, -100.0};
    auto packed_data = pack_eigenvalue_data(eigenvalues);

    std::cout << "Original eigenvalues: ";
    for (double val : eigenvalues) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    std::cout << "Packed data (arcsecant and linear): ";
    for (double val : packed_data) {
        std::cout << val << " ";
    }
    std::cout << std::endl;
}

int main() {
    std::thread server_thread(start_server);
    std::thread client_thread(start_client);

    server_thread.join();
    client_thread.join();

    return 0;
}
 

No comments: