Lugh

 view release on metacpan or  search on metacpan

lib/Lugh.xs  view on Meta::CPAN

int
backend_device_count()
CODE:
    /* Return count of available devices */
    RETVAL = (int)ggml_backend_dev_count();
OUTPUT:
    RETVAL

void
available_backends()
PPCODE:
{
    size_t i, count;
    /* Always include "auto" option */
    count = ggml_backend_reg_count();
    EXTEND(SP, count + 1);
    
    /* List all registered backends by name */
    for (i = 0; i < count; i++) {
        ggml_backend_reg_t reg = ggml_backend_reg_get(i);
        const char *name = ggml_backend_reg_name(reg);

lib/Lugh.xs  view on Meta::CPAN

    RETVAL

void
forward(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int i, j;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Parse named parameters: forward(tokens => \@t, lora => $l, ...) */
    parse_forward_options(aTHX_ &opts, &ST(0), 1, items);

    if (!opts.tokens && !opts.all_tokens) {
        croak("forward() requires tokens => \\@tokens");
    }
    

lib/Lugh.xs  view on Meta::CPAN


void
forward_simple(self, tokens_ref)
    SV *self
    SV *tokens_ref
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int j;
PPCODE:
    if (!SvROK(tokens_ref) || SvTYPE(SvRV(tokens_ref)) != SVt_PVAV) {
        croak("forward_simple() requires an array reference");
    }
    
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);
    opts.tokens = parse_tokens_av(aTHX_ (AV*)SvRV(tokens_ref), &opts.n_tokens);
    
    if (!do_forward_unified(aTHX_ hv, &opts, &result)) {
        char *err = result.error ? result.error : "Forward pass failed";

lib/Lugh.xs  view on Meta::CPAN

    free_forward_result(&result);

void
forward_cache(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int j;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Detect positional: forward_cache($cache, \@tokens, ...) */
    if (items >= 3 && sv_isobject(ST(1)) && SvROK(ST(2)) && SvTYPE(SvRV(ST(2))) == SVt_PVAV) {
        opts.cache = get_lugh_kvcache(aTHX_ ST(1));
        opts.tokens = parse_tokens_av(aTHX_ (AV*)SvRV(ST(2)), &opts.n_tokens);
        /* Parse remaining as named params */
        parse_forward_options(aTHX_ &opts, &ST(0), 3, items);
    } else {

lib/Lugh.xs  view on Meta::CPAN


void
forward_pool(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int j;
    SV **svp;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Detect positional: forward_pool($pool, \@tokens, ...) */
    if (items >= 3 && sv_isobject(ST(1)) && SvROK(ST(2)) && SvTYPE(SvRV(ST(2))) == SVt_PVAV) {
        SV *pool_sv = ST(1);
        if (SvROK(pool_sv) && SvTYPE(SvRV(pool_sv)) == SVt_PVHV) {
            HV *pool_hv = (HV*)SvRV(pool_sv);
            svp = hv_fetch(pool_hv, "_pool_id", 8, 0);
            if (svp && *svp) opts.pool = get_mempool_by_id(SvIV(*svp));

lib/Lugh.xs  view on Meta::CPAN

    free_forward_result(&result);

void
forward_batch(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int i, j;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Detect positional: forward_batch(\@sequences, ...) */
    if (items >= 2 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
        if (!parse_sequences_av(aTHX_ (AV*)SvRV(ST(1)), &opts.all_tokens, &opts.seq_lengths, &opts.n_sequences)) {
            croak("Invalid sequences format");
        }
        /* Parse remaining as named params */
        parse_forward_options(aTHX_ &opts, &ST(0), 2, items);

lib/Lugh.xs  view on Meta::CPAN


void
forward_cache_pool(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int j;
    SV **svp;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Detect positional: forward_cache_pool($cache, $pool, \@tokens, ...) */
    if (items >= 4 && sv_isobject(ST(1)) && sv_isobject(ST(2)) &&
        SvROK(ST(3)) && SvTYPE(SvRV(ST(3))) == SVt_PVAV) {
        opts.cache = get_lugh_kvcache(aTHX_ ST(1));
        SV *pool_sv = ST(2);
        if (SvROK(pool_sv) && SvTYPE(SvRV(pool_sv)) == SVt_PVHV) {
            HV *pool_hv = (HV*)SvRV(pool_sv);

lib/Lugh.xs  view on Meta::CPAN


void
forward_batch_pool(self, ...)
    SV *self
PREINIT:
    HV *hv;
    LughForwardOpts opts;
    LughForwardResult result;
    int i, j;
    SV **svp;
PPCODE:
    hv = (HV*)SvRV(self);
    Zero(&opts, 1, LughForwardOpts);

    /* Detect positional: forward_batch_pool($pool, \@sequences, ...) */
    if (items >= 3 && sv_isobject(ST(1)) && SvROK(ST(2)) && SvTYPE(SvRV(ST(2))) == SVt_PVAV) {
        SV *pool_sv = ST(1);
        if (SvROK(pool_sv) && SvTYPE(SvRV(pool_sv)) == SVt_PVHV) {
            HV *pool_hv = (HV*)SvRV(pool_sv);
            svp = hv_fetch(pool_hv, "_pool_id", 8, 0);
            if (svp && *svp) opts.pool = get_mempool_by_id(SvIV(*svp));

lib/Lugh.xs  view on Meta::CPAN

    int max_tokens = 128;
    float temperature = 0.8f;
    float top_p = 0.95f;
    int top_k = 40;
    int eos_token = 2;
    int greedy = 0;
    SV *callback = NULL;
    int i;
    int n_result;
    SV **orig_sp;
PPCODE:
    orig_sp = SP;  /* Save original stack pointer */
    
    /* Get model */
    hv = (HV*)SvRV(self);
    svp = hv_fetch(hv, "_model", 6, 0);
    if (!svp || !*svp) croak("No model in inference object");
    model = get_lugh_model(aTHX_ *svp);
    if (!model) croak("Invalid model");
    
    /* Parse input tokens */

lib/Lugh.xs  view on Meta::CPAN

    SV **svp;
    HV *token_to_id;
    AV *id_to_token;
    const char *str;
    STRLEN len;
    AV *tokens;
    int add_bos = 1;
    int bos_id, eos_id, unk_id;
    size_t pos;
    int i;
PPCODE:
    hv = (HV*)SvRV(self);
    
    svp = hv_fetch(hv, "_token_to_id", 12, 0);
    if (!svp || !SvROK(*svp)) croak("Tokenizer not initialized");
    token_to_id = (HV*)SvRV(*svp);
    
    svp = hv_fetch(hv, "_id_to_token", 12, 0);
    if (!svp || !SvROK(*svp)) croak("Tokenizer not initialized");
    id_to_token = (AV*)SvRV(*svp);
    

lib/Lugh.xs  view on Meta::CPAN

    for (i = 0; i < n_elements; i++) {
        ggml_set_f32_1d(tensor, i, SvNV(ST(i + 1)));
    }

void
get_f32(self)
    SV *self
PREINIT:
    struct ggml_tensor *tensor;
    int64_t i, n_elements;
PPCODE:
    tensor = INT2PTR(struct ggml_tensor *, SvIV(SvRV(self)));
    n_elements = ggml_nelements(tensor);
    
    EXTEND(SP, n_elements);
    for (i = 0; i < n_elements; i++) {
        mPUSHn(ggml_get_f32_1d(tensor, i));
    }

int64_t
nelements(self)

lib/Lugh.xs  view on Meta::CPAN

    RETVAL = ggml_n_dims(tensor);
OUTPUT:
    RETVAL

void
shape(self)
    SV *self
PREINIT:
    struct ggml_tensor *tensor;
    int i, n_dims;
PPCODE:
    tensor = INT2PTR(struct ggml_tensor *, SvIV(SvRV(self)));
    n_dims = ggml_n_dims(tensor);
    
    EXTEND(SP, n_dims);
    for (i = 0; i < n_dims; i++) {
        mPUSHi(tensor->ne[i]);
    }

int
type(self)

lib/Lugh.xs  view on Meta::CPAN

OUTPUT:
    RETVAL

void
tensor_info(self, name)
    SV *self
    const char *name
PREINIT:
    LughModel *lm;
    struct ggml_tensor *t;
PPCODE:
    lm = get_lugh_model(aTHX_ self);
    t = ggml_get_tensor(lm->ctx, name);
    if (t) {
        /* Return: type, n_dims, ne[0], ne[1], ne[2], ne[3] */
        EXTEND(SP, 6);
        mPUSHi(t->type);
        mPUSHi(ggml_n_dims(t));
        mPUSHi(t->ne[0]);
        mPUSHi(t->ne[1]);
        mPUSHi(t->ne[2]);
        mPUSHi(t->ne[3]);
    }

void
tensor_names(self)
    SV *self
PREINIT:
    LughModel *lm;
    int64_t i;
PPCODE:
    lm = get_lugh_model(aTHX_ self);
    EXTEND(SP, lm->n_tensors);
    for (i = 0; i < lm->n_tensors; i++) {
        mPUSHs(newSVpv(gguf_get_tensor_name(lm->gguf, i), 0));
    }

void
kv_keys(self)
    SV *self
PREINIT:
    LughModel *lm;
    int64_t i;
PPCODE:
    lm = get_lugh_model(aTHX_ self);
    EXTEND(SP, lm->n_kv);
    for (i = 0; i < lm->n_kv; i++) {
        mPUSHs(newSVpv(gguf_get_key(lm->gguf, i), 0));
    }

SV *
get_kv(self, key)
    SV *self
    const char *key

lib/Lugh.xs  view on Meta::CPAN

OUTPUT:
    RETVAL

void
weight_names(self)
    SV *self
PREINIT:
    LughLoRAAdapter *lora;
    MAGIC *mg;
    int i;
PPCODE:
    if (!SvROK(self)) croak("Not a reference");
    mg = mg_findext(SvRV(self), PERL_MAGIC_ext, &lugh_lora_vtbl);
    if (!mg) croak("Invalid LoRA object");
    lora = get_lora_by_id((int)(IV)mg->mg_ptr);
    if (!lora) croak("LoRA adapter not found");
    
    EXTEND(SP, lora->n_weights);
    for (i = 0; i < lora->n_weights; i++) {
        mPUSHp(lora->weights[i].name, strlen(lora->weights[i].name));
    }

lib/Lugh.xs  view on Meta::CPAN


void
trainable_parameters(self)
    SV *self
PREINIT:
    LughLoRAAdapter *lora;
    LughTensor *lt;
    MAGIC *mg;
    int i, count = 0;
    HV *result_hv;
PPCODE:
    if (!SvROK(self)) croak("Not a reference");
    mg = mg_findext(SvRV(self), PERL_MAGIC_ext, &lugh_lora_vtbl);
    if (!mg) croak("Invalid LoRA object");
    lora = get_lora_by_id((int)(IV)mg->mg_ptr);
    if (!lora) croak("LoRA adapter not found");
    
    if (!lora->trainable) {
        croak("trainable_parameters() only available for trainable LoRA adapters (created with create())");
    }
    

lib/Lugh.xs  view on Meta::CPAN

    SV *self
    SV *input_tokens_ref
    int n_draft
PREINIT:
    HV *hv;
    SV **svp;
    LughSpeculative *spec;
    AV *input_av, *draft_av;
    int i, n_input;
    int *input_tokens;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Speculative object");
    hv = (HV*)SvRV(self);
    
    svp = hv_fetch(hv, "_spec_id", 8, 0);
    if (!svp) croak("Invalid Lugh::Speculative object");
    spec = get_speculative_by_id(SvIV(*svp));
    if (!spec) croak("Speculative decoder has been destroyed");
    
    if (!SvROK(input_tokens_ref) || SvTYPE(SvRV(input_tokens_ref)) != SVt_PVAV)

lib/Lugh.xs  view on Meta::CPAN

    SV *self
    SV *input_tokens_ref
    SV *draft_tokens_ref
PREINIT:
    HV *hv;
    SV **svp;
    LughSpeculative *spec;
    AV *input_av, *draft_av_in, *accepted_av;
    int i, n_input, n_draft;
    int *input_tokens, *draft_tokens;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Speculative object");
    hv = (HV*)SvRV(self);
    
    svp = hv_fetch(hv, "_spec_id", 8, 0);
    if (!svp) croak("Invalid Lugh::Speculative object");
    spec = get_speculative_by_id(SvIV(*svp));
    if (!spec) croak("Speculative decoder has been destroyed");
    
    if (!SvROK(input_tokens_ref) || SvTYPE(SvRV(input_tokens_ref)) != SVt_PVAV)

lib/Lugh.xs  view on Meta::CPAN

step(self, input_tokens_ref)
    SV *self
    SV *input_tokens_ref
PREINIT:
    HV *hv;
    SV **svp;
    LughSpeculative *spec;
    AV *input_av, *accepted_av;
    int *input_tokens;
    int n_input, i;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Speculative object");
    hv = (HV*)SvRV(self);
    
    svp = hv_fetch(hv, "_spec_id", 8, 0);
    if (!svp) croak("Invalid Lugh::Speculative object");
    spec = get_speculative_by_id(SvIV(*svp));
    if (!spec) croak("Speculative decoder has been destroyed");
    
    if (!SvROK(input_tokens_ref) || SvTYPE(SvRV(input_tokens_ref)) != SVt_PVAV)

lib/Lugh.xs  view on Meta::CPAN

    SV *input_tokens_ref
    int max_tokens
PREINIT:
    HV *hv;
    SV **svp;
    LughSpeculative *spec;
    AV *input_av, *output_av, *accepted_av;
    int *current_tokens;
    int n_current, n_generated;
    int i;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Speculative object");
    hv = (HV*)SvRV(self);
    
    svp = hv_fetch(hv, "_spec_id", 8, 0);
    if (!svp) croak("Invalid Lugh::Speculative object");
    spec = get_speculative_by_id(SvIV(*svp));
    if (!spec) croak("Speculative decoder has been destroyed");
    
    if (!SvROK(input_tokens_ref) || SvTYPE(SvRV(input_tokens_ref)) != SVt_PVAV)

lib/Lugh.xs  view on Meta::CPAN

    }

void
get_data(self)
    SV *self
PREINIT:
    HV *hv;
    SV **svp;
    LughTensor *lt;
    int64_t i, n_elements;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Autograd::Tensor object");
    hv = (HV*)SvRV(self);
    svp = hv_fetch(hv, "_tensor_id", 10, 0);
    if (!svp) croak("Invalid tensor object");
    lt = get_tensor_by_id(SvIV(*svp));
    if (!lt) croak("Tensor has been freed");
    
    n_elements = ggml_nelements(lt->tensor);
    EXTEND(SP, n_elements);

lib/Lugh.xs  view on Meta::CPAN

    RETVAL

void
shape(self)
    SV *self
PREINIT:
    HV *hv;
    SV **svp;
    LughTensor *lt;
    int i, n_dims;
PPCODE:
    if (!SvROK(self) || SvTYPE(SvRV(self)) != SVt_PVHV)
        croak("Invalid Lugh::Autograd::Tensor object");
    hv = (HV*)SvRV(self);
    svp = hv_fetch(hv, "_tensor_id", 10, 0);
    if (!svp) croak("Invalid tensor object");
    lt = get_tensor_by_id(SvIV(*svp));
    if (!lt) croak("Tensor has been freed");
    
    n_dims = ggml_n_dims(lt->tensor);
    EXTEND(SP, n_dims);

lib/Lugh.xs  view on Meta::CPAN

void
batch_data(class, data_av, ...)
    SV* class
    AV* data_av
PREINIT:
    STRLEN batch_size = 32;
    int shuffle = 0;
    STRLEN data_len, i, j;
    STRLEN *indices = NULL;
    AV *result_av;
PPCODE:
    PERL_UNUSED_VAR(class);
    
    /* Parse optional args - items includes class and data_av, so remaining must be even */
    if (items > 2) {
        if ((items - 2) % 2 != 0) croak("Expected key-value pairs after data");
        for (i = 2; i < (STRLEN)items; i += 2) {
            const char *key = SvPV_nolen(ST(i));
            SV *val = ST(i + 1);
            if (strEQ(key, "batch_size")) {
                batch_size = SvIV(val);

lib/Lugh.xs  view on Meta::CPAN

tokenize_batch(class, tokenizer, texts_av, ...)
    SV* class
    SV* tokenizer
    AV* texts_av
PREINIT:
    STRLEN max_length = 512;
    STRLEN i, n_texts;
    AV *all_input_ids;
    AV *all_targets;
    AV *result;
PPCODE:
    PERL_UNUSED_VAR(class);
    
    if (!tokenizer || !SvOK(tokenizer)) {
        croak("tokenizer required");
    }
    
    /* Parse optional args */
    if (items > 3) {
        for (i = 3; i < (STRLEN)items; i += 2) {
            const char *key = SvPV_nolen(ST(i));

lib/Lugh.xs  view on Meta::CPAN

    /* Return (\@all_input_ids, \@all_targets) */
    EXTEND(SP, 2);
    PUSHs(sv_2mortal(newRV_noinc((SV*)all_input_ids)));
    PUSHs(sv_2mortal(newRV_noinc((SV*)all_targets)));

void
zero_grad(class, ...)
    SV* class
PREINIT:
    STRLEN i;
PPCODE:
    PERL_UNUSED_VAR(class);
    
    for (i = 1; i < (STRLEN)items; i++) {
        SV *tensor_sv = ST(i);
        if (!SvOK(tensor_sv)) continue;
        
        dSP;
        ENTER;
        SAVETMPS;
        

lib/Lugh.xs  view on Meta::CPAN

void
clip_grad_norm(class, max_norm, ...)
    SV* class
    float max_norm
PREINIT:
    float total_norm = 0.0f;
    float clip_coef;
    STRLEN i;
    AV* tensors_av = NULL;
    AV* all_grads = NULL;
PPCODE:
    PERL_UNUSED_VAR(class);
    
    if (max_norm <= 0) {
        croak("max_norm must be positive");
    }
    
    /* Collect all gradient data */
    all_grads = newAV();
    
    for (i = 2; i < (STRLEN)items; i++) {

lib/Lugh.xs  view on Meta::CPAN

    /* Return total norm (before clipping) */
    EXTEND(SP, 1);
    mPUSHn(total_norm);

void
clip_grad_value(class, max_value, ...)
    SV* class
    float max_value
PREINIT:
    STRLEN i;
PPCODE:
    PERL_UNUSED_VAR(class);
    
    if (max_value <= 0) {
        croak("max_value must be positive");
    }
    
    for (i = 2; i < (STRLEN)items; i++) {
        SV *tensor_sv = ST(i);
        if (!SvOK(tensor_sv)) continue;
        if (!SvROK(tensor_sv) || SvTYPE(SvRV(tensor_sv)) != SVt_PVHV) continue;

lib/Lugh/Prompt.xs  view on Meta::CPAN

        }
        
        RETVAL = newSVpv(buf.data, buf.len);
        strbuf_free(&buf);
    OUTPUT:
        RETVAL

# Return list of available format names
void
available_formats(...)
    PPCODE:
        int i;
        for (i = 0; FORMATS[i].name != NULL; i++) {
            mXPUSHs(newSVpv(FORMATS[i].name, 0));
        }

# Get format name for architecture
SV*
format_for_architecture(...)
    CODE:
        const char* arch_str = NULL;

lib/Lugh/Quant.xs  view on Meta::CPAN

type_count()
CODE:
    RETVAL = GGML_TYPE_COUNT;
OUTPUT:
    RETVAL

void
all_types()
PREINIT:
    int i;
PPCODE:
    EXTEND(SP, GGML_TYPE_COUNT);
    for (i = 0; i < GGML_TYPE_COUNT; i++) {
        const char *name = ggml_type_name((enum ggml_type)i);
        if (name && strlen(name) > 0) {
            mPUSHi(i);
        }
    }

void
all_quantized_types()
PREINIT:
    int i;
PPCODE:
    for (i = 0; i < GGML_TYPE_COUNT; i++) {
        if (ggml_is_quantized((enum ggml_type)i)) {
            XPUSHs(sv_2mortal(newSViv(i)));
        }
    }

int
type_from_name(name)
    const char *name
CODE:



( run in 0.770 second using v1.01-cache-2.11-cpan-5511b514fd6 )