char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
7a16a6ce3
char/aliceai-t5-moe
1#include "llama-grammar.h" 2 3#include "llama-impl.h" 4#include "llama-vocab.h" 5#include "llama-sampler.h" 6 7#include <cmath> 8#include <algorithm> 9#include <cstdint> 10#include <set> 11#include <stdexcept> 12 13#define MAX_REPETITION_THRESHOLD 2000 14// 15// helpers 16// 17 18// NOTE: assumes valid utf8 (but checks for overrun) 19static std::pair < uint32_t ,const char *> decode_utf8 (const char * src ) { 20static const int lookup []= {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,2 ,2 ,3 ,4 }; 21uint8_t first_byte = static_cast < uint8_t > (* src ); 22uint8_t highbits = first_byte >>4 ; 23int len = lookup [highbits ]; 24uint8_t mask = (1 << (8 - len ))- 1 ; 25uint32_t value = first_byte & mask ; 26const char * end = src + len ;// may overrun! 27const char * pos = src + 1 ; 28for ( ;pos < end && * pos ;pos ++ ) { 29value = (value <<6 )+ (static_cast < uint8_t > (* pos )& 0x3F ); 30 } 31return std::make_pair (value ,pos ); 32} 33 34static std::pair < std::vector < uint32_t > ,llama_partial_utf8 > decode_utf8 ( 35const std::string & src , 36llama_partial_utf8 partial_start ) { 37static const int lookup []= {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,2 ,2 ,3 ,4 }; 38const char * pos = src .c_str (); 39 std::vector < uint32_t > code_points ; 40 41// common english strings have the same number of codepoints and bytes. `+ 1` for the terminating 0. 42code_points .reserve (src .size ()+ 1 ); 43uint32_t value = partial_start .value ; 44int n_remain = partial_start .n_remain ; 45 46// continue previous decode, if applicable 47while (* pos != 0 && n_remain > 0 ) { 48uint8_t next_byte = static_cast < uint8_t > (* pos ); 49if ((next_byte >>6 )!= 2 ) { 50// invalid sequence, abort 51code_points .push_back (0 ); 52return std::make_pair (std::move (code_points ),llama_partial_utf8 {0 ,-1 }); 53 } 54value = (value <<6 )+ (next_byte & 0x3F ); 55++ pos ; 56-- n_remain ; 57 } 58 59if (partial_start .n_remain > 0 && n_remain == 0 ) { 60code_points .push_back (value ); 61 } 62 63// decode any subsequent utf-8 sequences, which may end in an incomplete one 64while (* pos != 0 ) { 65uint8_t first_byte = static_cast < uint8_t > (* pos ); 66uint8_t highbits = first_byte >>4 ; 67n_remain = lookup [highbits ]- 1 ; 68 69if (n_remain < 0 ) { 70// invalid sequence, abort 71code_points .clear (); 72code_points .push_back (0 ); 73return std::make_pair (std::move (code_points ),llama_partial_utf8 {0 ,n_remain }); 74 } 75 76uint8_t mask = (1 << (7 - n_remain ))- 1 ; 77value = first_byte & mask ; 78 79++ pos ; 80while (* pos != 0 && n_remain > 0 ) { 81value = (value <<6 )+ (static_cast < uint8_t > (* pos )& 0x3F ); 82++ pos ; 83-- n_remain ; 84 } 85if (n_remain == 0 ) { 86code_points .push_back (value ); 87 } 88 } 89code_points .push_back (0 ); 90 91return std::make_pair (std::move (code_points ),llama_partial_utf8 {value ,n_remain }); 92} 93 94static bool is_digit_char (char c ) { 95return '0' <=c && c <='9' ; 96} 97 98static bool is_word_char (char c ) { 99return ('a' <=c && c <='z' )|| ('A' <=c && c <='Z' )|| c == '-' || is_digit_char (c ); 100} 101 102static std::pair < uint32_t ,const char *> parse_hex (const char * src ,int size ) { 103const char * pos = src ; 104const char * end = src + size ; 105uint32_t value = 0 ; 106for ( ;pos < end && * pos ;pos ++ ) { 107value <<=4 ; 108char c = * pos ; 109if ('a' <=c && c <='f' ) { 110value += c - 'a' + 10 ; 111 }else if ('A' <=c && c <='F' ) { 112value += c - 'A' + 10 ; 113 }else if ('0' <=c && c <='9' ) { 114value += c - '0' ; 115 }else { 116break ; 117 } 118 } 119if (pos != end ) { 120throw std::runtime_error ("expecting " + std::to_string (size )+ " hex chars at " + src ); 121 } 122return std::make_pair (value ,pos ); 123} 124 125static const char * parse_space (const char * src ,bool newline_ok ) { 126const char * pos = src ; 127while (* pos == ' ' || * pos == '\t' || * pos == '#' || 128 (newline_ok && (* pos == '\r' || * pos == '\n' ))) { 129if (* pos == '#' ) { 130while (* pos && * pos != '\r' && * pos != '\n' ) { 131pos ++ ; 132 } 133 }else { 134pos ++ ; 135 } 136 } 137return pos ; 138} 139 140static const char * parse_name (const char * src ) { 141const char * pos = src ; 142while (is_word_char (* pos )) { 143pos ++ ; 144 } 145if (pos == src ) { 146throw std::runtime_error (std::string ("expecting name at " )+ src ); 147 } 148return pos ; 149} 150 151static const char * parse_int (const char * src ) { 152const char * pos = src ; 153while (is_digit_char (* pos )) { 154pos ++ ; 155 } 156if (pos == src ) { 157throw std::runtime_error (std::string ("expecting integer at " )+ src ); 158 } 159return pos ; 160} 161 162static std::pair < uint32_t ,const char *> parse_char (const char * src ) { 163if (* src == '\\' ) { 164switch (src [1 ]) { 165case 'x' :return parse_hex (src + 2 ,2 ); 166case 'u' :return parse_hex (src + 2 ,4 ); 167case 'U' :return parse_hex (src + 2 ,8 ); 168case 't' :return std::make_pair ('\t' ,src + 2 ); 169case 'r' :return std::make_pair ('\r' ,src + 2 ); 170case 'n' :return std::make_pair ('\n' ,src + 2 ); 171case '\\' : 172case '"' : 173case '[' : 174case ']' : 175case '-' : 176return std::make_pair (src [1 ],src + 2 ); 177default : 178throw std::runtime_error (std::string ("unknown escape at " )+ src ); 179 } 180 }else if (* src ) { 181return decode_utf8 (src ); 182 } 183throw std::runtime_error ("unexpected end of input" ); 184} 185 186static std::pair < uint32_t ,const char *> parse_token (const llama_vocab * vocab ,const char * src ) { 187const char * pos = src ; 188if (* pos != '<' ) { 189throw std::runtime_error (std::string ("expecting '<' at " )+ pos ); 190 } 191pos ++ ; 192 193// Parse <[id]> 194if (* pos == '[' ) { 195pos ++ ; 196const char * int_end = parse_int (pos ); 197uint32_t token_id = std::stoul (std::string (pos ,int_end - pos )); 198pos = int_end ; 199if (* pos != ']' ) { 200throw std::runtime_error (std::string ("expecting ']' at " )+ pos ); 201 } 202pos ++ ; 203if (* pos != '>' ) { 204throw std::runtime_error (std::string ("expecting '>' at " )+ pos ); 205 } 206pos ++ ; 207return std::make_pair (token_id ,pos ); 208 } 209 210if (vocab == nullptr ) { 211throw std::runtime_error (std::string ("no vocab to parse token at " )+ src ); 212 } 213 214// Parse <token> and tokenize to obtain the token id 215while (* pos != 0 && * pos != '>' ) { 216pos ++ ; 217 } 218if (* pos != '>' ) { 219throw std::runtime_error (std::string ("expecting '>' at " )+ pos ); 220 } 221pos ++ ; 222 223llama_token tokens [2 ]; 224int32_t n_tokens = vocab -> tokenize (src ,static_cast < int32_t > (pos - src ),tokens ,2 , false, true); 225if (n_tokens != 1 ) { 226// must tokenize to exactly 1 token 227throw std::runtime_error ("invalid token '" + std::string (src ,pos - src )+ "'" ); 228 } 229return std::make_pair (tokens [0 ],pos ); 230} 231 232static void print_grammar_char (FILE * file ,uint32_t c ) { 233if (0x20 <=c && c <=0x7f ) { 234fprintf (file ,"%c" ,static_cast < char > (c )); 235 }else { 236// cop out of encoding UTF-8 237fprintf (file ,"<U+%04X>" ,c ); 238 } 239} 240 241static bool is_char_element (llama_grammar_element elem ) { 242switch (elem .type ) { 243case LLAMA_GRETYPE_CHAR :return true; 244case LLAMA_GRETYPE_CHAR_NOT :return true; 245case LLAMA_GRETYPE_CHAR_ALT :return true; 246case LLAMA_GRETYPE_CHAR_RNG_UPPER :return true; 247case LLAMA_GRETYPE_CHAR_ANY :return true; 248default :return false; 249 } 250} 251 252static void print_rule_binary (FILE * file ,const llama_grammar_rule & rule ) { 253for (auto elem :rule ) { 254switch (elem .type ) { 255case LLAMA_GRETYPE_END :fprintf (file ,"END" );break ; 256case LLAMA_GRETYPE_ALT :fprintf (file ,"ALT" );break ; 257case LLAMA_GRETYPE_RULE_REF :fprintf (file ,"RULE_REF" );break ; 258case LLAMA_GRETYPE_CHAR :fprintf (file ,"CHAR" );break ; 259case LLAMA_GRETYPE_CHAR_NOT :fprintf (file ,"CHAR_NOT" );break ; 260case LLAMA_GRETYPE_CHAR_RNG_UPPER :fprintf (file ,"CHAR_RNG_UPPER" );break ; 261case LLAMA_GRETYPE_CHAR_ALT :fprintf (file ,"CHAR_ALT" );break ; 262case LLAMA_GRETYPE_CHAR_ANY :fprintf (file ,"CHAR_ANY" );break ; 263case LLAMA_GRETYPE_TOKEN :fprintf (file ,"TOKEN" );break ; 264case LLAMA_GRETYPE_TOKEN_NOT :fprintf (file ,"TOKEN_NOT" );break ; 265 } 266switch (elem .type ) { 267case LLAMA_GRETYPE_END : 268case LLAMA_GRETYPE_ALT : 269case LLAMA_GRETYPE_RULE_REF : 270fprintf (file ,"(%u) " ,elem .value ); 271break ; 272case LLAMA_GRETYPE_CHAR : 273case LLAMA_GRETYPE_CHAR_NOT : 274case LLAMA_GRETYPE_CHAR_RNG_UPPER : 275case LLAMA_GRETYPE_CHAR_ALT : 276case LLAMA_GRETYPE_CHAR_ANY : 277fprintf (file ,"(\"" ); 278print_grammar_char (file ,elem .value ); 279fprintf (file ,"\") " ); 280break ; 281case LLAMA_GRETYPE_TOKEN : 282fprintf (file ,"<[" ); 283fprintf (file ,"%u" ,elem .value ); 284fprintf (file ,"]> " ); 285break ; 286case LLAMA_GRETYPE_TOKEN_NOT : 287fprintf (file ,"!" ); 288fprintf (file ,"<[" ); 289fprintf (file ,"%u" ,elem .value ); 290fprintf (file ,"]> " ); 291break ; 292 } 293 } 294fprintf (file ,"\n" ); 295} 296 297static void print_rule ( 298FILE * file , 299uint32_t rule_id , 300const llama_grammar_rule & rule , 301const std::map < uint32_t , std::string > & symbol_id_names ) { 302if (rule .empty ()|| rule .back ().type != LLAMA_GRETYPE_END ) { 303throw std::runtime_error ( 304"malformed rule, does not end with LLAMA_GRETYPE_END: " + std::to_string (rule_id )); 305 } 306fprintf (file ,"%s ::= " ,symbol_id_names .at (rule_id ).c_str ()); 307for (size_t i = 0 ,end = rule .size ()- 1 ;i < end ;i ++ ) { 308llama_grammar_element elem = rule [i ]; 309switch (elem .type ) { 310case LLAMA_GRETYPE_END : 311throw std::runtime_error ( 312"unexpected end of rule: " + std::to_string (rule_id )+ "," + 313 std::to_string (i )); 314case LLAMA_GRETYPE_ALT : 315fprintf (file ,"| " ); 316break ; 317case LLAMA_GRETYPE_RULE_REF : 318fprintf (file ,"%s " ,symbol_id_names .at (elem .value ).c_str ()); 319break ; 320case LLAMA_GRETYPE_CHAR : 321fprintf (file ,"[" ); 322print_grammar_char (file ,elem .value ); 323break ; 324case LLAMA_GRETYPE_CHAR_NOT : 325fprintf (file ,"[^" ); 326print_grammar_char (file ,elem .value ); 327break ; 328case LLAMA_GRETYPE_CHAR_RNG_UPPER : 329if (i == 0 || !is_char_element (rule [i - 1 ])) { 330throw std::runtime_error ( 331"LLAMA_GRETYPE_CHAR_RNG_UPPER without preceding char: " + 332 std::to_string (rule_id )+ "," + std::to_string (i )); 333 } 334fprintf (file ,"-" ); 335print_grammar_char (file ,elem .value ); 336break ; 337case LLAMA_GRETYPE_CHAR_ALT : 338if (i == 0 || !is_char_element (rule [i - 1 ])) { 339throw std::runtime_error ( 340"LLAMA_GRETYPE_CHAR_ALT without preceding char: " + 341 std::to_string (rule_id )+ "," + std::to_string (i )); 342 } 343print_grammar_char (file ,elem .value ); 344break ; 345case LLAMA_GRETYPE_CHAR_ANY : 346fprintf (file ,"." ); 347break ; 348case LLAMA_GRETYPE_TOKEN : 349fprintf (file ,"<[" ); 350fprintf (file ,"%u" ,elem .value ); 351fprintf (file ,"]> " ); 352break ; 353case LLAMA_GRETYPE_TOKEN_NOT : 354fprintf (file ,"!" ); 355fprintf (file ,"<[" ); 356fprintf (file ,"%u" ,elem .value ); 357fprintf (file ,"]> " ); 358break ; 359 } 360if (is_char_element (elem )) { 361switch (rule [i + 1 ].type ) { 362case LLAMA_GRETYPE_CHAR_ALT : 363case LLAMA_GRETYPE_CHAR_RNG_UPPER : 364case LLAMA_GRETYPE_CHAR_ANY : 365break ; 366default : 367fprintf (file ,"] " ); 368 } 369 } 370 } 371fprintf (file ,"\n" ); 372} 373 374// 375// Regex utilities 376// 377 378size_t llama_grammar_trigger_pattern::find (const std::string & input )const { 379auto find_start_pos = [](const std::smatch & match ) { 380// get from the first matched capturing group to the end of the string 381size_t start = std::string::npos ; 382for (auto i = 1u ;i < match .size ();i ++ ) { 383if (match .length (i )> 0 ) { 384start = match .position (i ); 385break ; 386 } 387 } 388if (start == std::string::npos ) { 389start = match .position (0 ); 390 } 391return start ; 392 }; 393 394if (!pattern .empty ()&& pattern .front ()== '^' && pattern .back ()== '$' ) { 395// match against the entire input 396 std::smatch match ; 397if (std::regex_match (input ,match ,regex )) { 398return find_start_pos (match ); 399 } 400 } 401 402// search anywhere 403 std::smatch match ; 404if (std::regex_search (input ,match ,regex )) { 405return find_start_pos (match ); 406 } 407 408return std::string::npos ; 409} 410 411 412// 413// implementation 414// 415 416uint32_t llama_grammar_parser::get_symbol_id (const char * src ,size_t len ) { 417uint32_t next_id = static_cast < uint32_t > (symbol_ids .size ()); 418auto result = symbol_ids .emplace (std::string (src ,len ),next_id ); 419return result .first -> second ; 420} 421 422uint32_t llama_grammar_parser::generate_symbol_id (const std::string & base_name ) { 423uint32_t next_id = static_cast < uint32_t > (symbol_ids .size ()); 424symbol_ids [base_name + '_' + std::to_string (next_id )]= next_id ; 425return next_id ; 426} 427 428void llama_grammar_parser::add_rule (uint32_t rule_id ,const llama_grammar_rule & rule ) { 429if (rules .size () <=rule_id ) { 430rules .resize (rule_id + 1 ); 431 } 432rules [rule_id ]= rule ; 433} 434 435const char * llama_grammar_parser::parse_alternates ( 436const char * src , 437const std::string & rule_name , 438uint32_t rule_id , 439bool is_nested ) { 440llama_grammar_rule rule ; 441const char * pos = parse_sequence (src ,rule_name ,rule ,is_nested ); 442while (* pos == '|' ) { 443rule .push_back ({LLAMA_GRETYPE_ALT ,0 }); 444pos = parse_space (pos + 1 , true); 445pos = parse_sequence (pos ,rule_name ,rule ,is_nested ); 446 } 447rule .push_back ({LLAMA_GRETYPE_END ,0 }); 448add_rule (rule_id ,rule ); 449return pos ; 450} 451 452const char * llama_grammar_parser::parse_sequence ( 453const char * src , 454const std::string & rule_name , 455llama_grammar_rule & rule , 456bool is_nested ) { 457size_t last_sym_start = rule .size (); 458const char * pos = src ; 459uint64_t n_prev_rules = 1 ; 460 461// use UINT64_MAX as the empty value because we aligned to the proper uint64_t type so -1 can't be used 462// (though it's technically the same as -1 now) 463auto handle_repetitions = [& ](uint64_t min_times ,uint64_t max_times ) { 464bool no_max = max_times == UINT64_MAX ; 465if (last_sym_start == rule .size ()) { 466throw std::runtime_error (std::string ("expecting preceding item to */+/?/{ at " )+ pos ); 467 } 468 469// apply transformation to previous symbol (last_sym_start to end) according to 470// the following rewrite rules: 471// S{m,n} --> S S S (m times) S'(n-m) 472// S'(x) ::= S S'(x-1) | 473// (... n-m definitions of these S' rules ...) 474// S'(1) ::= S | 475// S{m,} --> S S S (m times) S' 476// S' ::= S S' | 477// S* --> S{0,} 478// --> S' ::= S S' | 479// S+ --> S{1,} 480// --> S S' 481// S' ::= S S' | 482// S? --> S{0,1} 483// --> S' 484// S' ::= S | 485 486llama_grammar_rule prev_rule (rule .begin ()+ last_sym_start ,rule .end ()); 487// Calculate the total number of rules that will be generated by this repetition 488uint64_t total_rules = 1 ;// Start with 1 for the original rule 489if (!no_max && max_times > 0 ) { 490total_rules = max_times ; 491 }else if (min_times > 0 ) { 492total_rules = min_times ; 493 } 494 495if (n_prev_rules * total_rules > MAX_REPETITION_THRESHOLD ) { 496throw std::runtime_error ("number of rules that are going to be repeated multiplied by the new repetition exceeds sane defaults, please reduce the number of repetitions or rule complexity" ); 497 } 498 499if (min_times == 0 ) { 500rule .resize (last_sym_start ); 501 }else { 502// Repeat the previous elements (min_times - 1) times 503for (uint64_t i = 1 ;i < min_times ;i ++ ) { 504rule .insert (rule .end (),prev_rule .begin (),prev_rule .end ()); 505 } 506 } 507 508uint32_t last_rec_rule_id = 0 ; 509auto n_opt = no_max ?1 :max_times - min_times ; 510 511llama_grammar_rule rec_rule (prev_rule ); 512for (uint64_t i = 0 ;i < n_opt ;i ++ ) { 513rec_rule .resize (prev_rule .size ()); 514uint32_t rec_rule_id = generate_symbol_id (rule_name ); 515if (i > 0 || no_max ) { 516rec_rule .push_back ({LLAMA_GRETYPE_RULE_REF ,no_max ?rec_rule_id :last_rec_rule_id }); 517 } 518rec_rule .push_back ({LLAMA_GRETYPE_ALT ,0 }); 519rec_rule .push_back ({LLAMA_GRETYPE_END ,0 }); 520add_rule (rec_rule_id ,rec_rule ); 521last_rec_rule_id = rec_rule_id ; 522 } 523if (n_opt > 0 ) { 524rule .push_back ({LLAMA_GRETYPE_RULE_REF ,last_rec_rule_id }); 525 } 526n_prev_rules *=total_rules ; 527GGML_ASSERT (n_prev_rules >=1 ); 528 }; 529 530while (* pos ) { 531if (* pos == '"' ) {// literal string 532pos ++ ; 533last_sym_start = rule .size (); 534n_prev_rules = 1 ; 535while (* pos != '"' ) { 536if (!* pos ) { 537throw std::runtime_error ("unexpected end of input" ); 538 } 539auto char_pair = parse_char (pos ); 540pos = char_pair .second ; 541rule .push_back ({LLAMA_GRETYPE_CHAR ,char_pair .first }); 542 } 543pos = parse_space (pos + 1 ,is_nested ); 544 }else if (* pos == '[' ) {// char range(s) 545pos ++ ; 546enum llama_gretype start_type = LLAMA_GRETYPE_CHAR ; 547if (* pos == '^' ) { 548pos ++ ; 549start_type = LLAMA_GRETYPE_CHAR_NOT ; 550 } 551last_sym_start = rule .size (); 552n_prev_rules = 1 ; 553while (* pos != ']' ) { 554if (!* pos ) { 555throw std::runtime_error ("unexpected end of input" ); 556 } 557auto char_pair = parse_char (pos ); 558pos = char_pair .second ; 559enum llama_gretype type = last_sym_start < rule .size () 560 ?LLAMA_GRETYPE_CHAR_ALT 561 :start_type ; 562 563rule .push_back ({type ,char_pair .first }); 564if (pos [0 ]== '-' && pos [1 ]!= ']' ) { 565if (!pos [1 ]) { 566throw std::runtime_error ("unexpected end of input" ); 567 } 568auto endchar_pair = parse_char (pos + 1 ); 569pos = endchar_pair .second ; 570rule .push_back ({LLAMA_GRETYPE_CHAR_RNG_UPPER ,endchar_pair .first }); 571 } 572 } 573pos = parse_space (pos + 1 ,is_nested ); 574 }else if (* pos == '<' || * pos == '!' ) {// token 575auto type = LLAMA_GRETYPE_TOKEN ; 576if (* pos == '!' ) {// token inverse 577type = LLAMA_GRETYPE_TOKEN_NOT ; 578pos ++ ; 579 } 580auto token_pair = parse_token (vocab ,pos ); 581const char * token_end = token_pair .second ; 582last_sym_start = rule .size (); 583n_prev_rules = 1 ; 584rule .push_back ({type ,token_pair .first }); 585pos = parse_space (token_end ,is_nested ); 586 }else if (is_word_char (* pos )) {// rule reference 587const char * name_end = parse_name (pos ); 588uint32_t ref_rule_id = get_symbol_id (pos ,name_end - pos ); 589pos = parse_space (name_end ,is_nested ); 590last_sym_start = rule .size (); 591n_prev_rules = 1 ; 592rule .push_back ({LLAMA_GRETYPE_RULE_REF ,ref_rule_id }); 593 }else if (* pos == '(' ) {// grouping 594// parse nested alternates into synthesized rule 595pos = parse_space (pos + 1 , true); 596uint32_t n_rules_before = symbol_ids .size (); 597uint32_t sub_rule_id = generate_symbol_id (rule_name ); 598pos = parse_alternates (pos ,rule_name ,sub_rule_id , true); 599n_prev_rules = std::max (1u , (uint32_t )symbol_ids .size ()- n_rules_before ); 600last_sym_start = rule .size (); 601// output reference to synthesized rule 602rule .push_back ({LLAMA_GRETYPE_RULE_REF ,sub_rule_id }); 603if (* pos != ')' ) { 604throw std::runtime_error (std::string ("expecting ')' at " )+ pos ); 605 } 606pos = parse_space (pos + 1 ,is_nested ); 607 }else if (* pos == '.' ) {// any char 608last_sym_start = rule .size (); 609n_prev_rules = 1 ; 610rule .push_back ({LLAMA_GRETYPE_CHAR_ANY ,0 }); 611pos = parse_space (pos + 1 ,is_nested ); 612 }else if (* pos == '*' ) { 613pos = parse_space (pos + 1 ,is_nested ); 614handle_repetitions (0 ,-1 ); 615 }else if (* pos == '+' ) { 616pos = parse_space (pos + 1 ,is_nested ); 617handle_repetitions (1 ,-1 ); 618 }else if (* pos == '?' ) { 619pos = parse_space (pos + 1 ,is_nested ); 620handle_repetitions (0 ,1 ); 621 }else if (* pos == '{' ) { 622pos = parse_space (pos + 1 ,is_nested ); 623 624if (!is_digit_char (* pos )) { 625throw std::runtime_error (std::string ("expecting an int at " )+ pos ); 626 } 627const char * int_end = parse_int (pos ); 628uint64_t min_times = std::stoull (std::string (pos ,int_end - pos )); 629pos = parse_space (int_end ,is_nested ); 630 631uint64_t max_times = UINT64_MAX ;// default: no max limit 632 633if (* pos == '}' ) { 634max_times = min_times ; 635pos = parse_space (pos + 1 ,is_nested ); 636 }else if (* pos == ',' ) { 637pos = parse_space (pos + 1 ,is_nested ); 638 639if (is_digit_char (* pos )) { 640const char * int_end = parse_int (pos ); 641max_times = std::stoull (std::string (pos ,int_end - pos )); 642pos = parse_space (int_end ,is_nested ); 643 } 644 645if (* pos != '}' ) { 646throw std::runtime_error (std::string ("expecting '}' at " )+ pos ); 647 } 648pos = parse_space (pos + 1 ,is_nested ); 649 }else { 650throw std::runtime_error (std::string ("expecting ',' at " )+ pos ); 651 } 652if (min_times > MAX_REPETITION_THRESHOLD ) { 653throw std::runtime_error (std::string ("number of repetitions exceeds sane defaults, please reduce the number of repetitions" )); 654 } 655if (max_times != UINT64_MAX && max_times > MAX_REPETITION_THRESHOLD ) { 656max_times = UINT64_MAX ; 657 } 658handle_repetitions (min_times ,max_times ); 659 }else { 660break ; 661 } 662 } 663return pos ; 664} 665 666const char * llama_grammar_parser::parse_rule (const char * src ) { 667const char * name_end = parse_name (src ); 668const char * pos = parse_space (name_end , false); 669size_t name_len = name_end - src ; 670uint32_t rule_id = get_symbol_id (src ,name_len ); 671const std::string name (src ,name_len ); 672 673if (!(pos [0 ]== ':' && pos [1 ]== ':' && pos [2 ]== '=' )) { 674throw std::runtime_error (std::string ("expecting ::= at " )+ pos ); 675 } 676pos = parse_space (pos + 3 , true); 677 678pos = parse_alternates (pos ,name ,rule_id , false); 679 680if (* pos == '\r' ) { 681pos += pos [1 ]== '\n' ?2 :1 ; 682 }else if (* pos == '\n' ) { 683pos ++ ; 684 }else if (* pos ) { 685throw std::runtime_error (std::string ("expecting newline or end at " )+ pos ); 686 } 687return parse_space (pos , true); 688} 689 690bool llama_grammar_parser::parse (const char * src ) { 691try { 692const char * pos = parse_space (src , true); 693while (* pos ) { 694pos = parse_rule (pos ); 695 } 696// Validate the state to ensure that all rules are defined 697for (const auto & rule :rules ) { 698if (rule .empty ()) { 699throw std::runtime_error ("Undefined rule" ); 700 } 701for (const auto & elem :rule ) { 702if (elem .type == LLAMA_GRETYPE_RULE_REF ) { 703// Ensure that the rule at that location exists 704if (elem .value >=rules .size ()|| rules [elem .value ].empty ()) { 705// Get the name of the rule that is missing 706for (const auto & kv :symbol_ids ) { 707if (kv .second == elem .value ) { 708throw std::runtime_error ("Undefined rule identifier '" + kv .first + "'" ); 709 } 710 } 711 } 712 } 713 } 714 } 715 }catch (const std::exception & err ) { 716fprintf (stderr ,"%s: error parsing grammar: %s\n\n%s\n" ,__func__ ,err .what (),src ); 717rules .clear (); 718return false; 719 } 720 721return true; 722} 723 724void llama_grammar_parser::FILE * file ) { 725try { 726 std::map < uint32_t , std::string > symbol_id_names ; 727for (const auto & kv :symbol_ids ) { 728symbol_id_names [kv .second ]= kv .first ; 729 } 730for (size_t i = 0 ,end = rules .size ();i < end ;i ++ ) { 731// fprintf(file, "%zu: ", i); 732// print_rule_binary(file, rules[i]); 733print_rule (file ,uint32_t (i ),rules [i ],symbol_id_names ); 734// fprintf(file, "\n"); 735 } 736 }catch (const std::exception & err ) { 737fprintf (stderr ,"\n%s: error printing grammar: %s\n" ,__func__ ,err .what ()); 738 } 739} 740 741llama_grammar_stack llama_grammar_parser::c_rules ()const { 742llama_grammar_stack ret ; 743ret .reserve (rules .size ()); 744for (const auto & rule :rules ) { 745ret .push_back (rule .data ()); 746 } 747return ret ; 748} 749 750// returns true iff pos points to the end of one of the definitions of a rule 751static bool llama_grammar_is_end_of_sequence (const llama_grammar_element * pos ) { 752switch (pos -> type ) { 753case LLAMA_GRETYPE_END :return true;// NOLINT 754case LLAMA_GRETYPE_ALT :return true;// NOLINT 755default :return false; 756 } 757} 758 759// returns true iff chr satisfies the char range at pos (regular or inverse range) 760// asserts that pos is pointing to a char range element 761static std::pair < bool ,const llama_grammar_element *> llama_grammar_match_char ( 762const llama_grammar_element * pos , 763const uint32_t chr ) { 764bool found = false; 765bool is_positive_char = pos -> type == LLAMA_GRETYPE_CHAR || pos -> type == LLAMA_GRETYPE_CHAR_ANY ; 766 767GGML_ASSERT (is_positive_char || pos -> type == LLAMA_GRETYPE_CHAR_NOT );// NOLINT 768 769do { 770if (pos [1 ].type == LLAMA_GRETYPE_CHAR_RNG_UPPER ) { 771// inclusive range, e.g. [a-z] 772found = found || (pos -> value <=chr && chr <=pos [1 ].value ); 773pos += 2 ; 774 }else if (pos -> type == LLAMA_GRETYPE_CHAR_ANY ) { 775// Any character matches "." 776found = true; 777pos += 1 ; 778 }else { 779// exact char match, e.g. [a] or "a" 780found = found || pos -> value == chr ; 781pos += 1 ; 782 } 783 }while (pos -> type == LLAMA_GRETYPE_CHAR_ALT ); 784 785return std::make_pair (found == is_positive_char ,pos ); 786} 787 788// returns true iff some continuation of the given partial UTF-8 sequence could satisfy the char 789// range at pos (regular or inverse range) 790// asserts that pos is pointing to a char range element 791static bool llama_grammar_match_partial_char ( 792const llama_grammar_element * pos , 793const llama_partial_utf8 partial_utf8 ) { 794bool is_positive_char = pos -> type == LLAMA_GRETYPE_CHAR || pos -> type == LLAMA_GRETYPE_CHAR_ANY ; 795GGML_ASSERT (is_positive_char || pos -> type == LLAMA_GRETYPE_CHAR_NOT ); 796 797uint32_t partial_value = partial_utf8 .value ; 798int n_remain = partial_utf8 .n_remain ; 799 800// invalid sequence or 7-bit char split across 2 bytes (overlong) 801if (n_remain < 0 || (n_remain == 1 && partial_value < 2 )) { 802return false; 803 } 804 805// range of possible code points this partial UTF-8 sequence could complete to 806uint32_t low = partial_value << (n_remain * 6 ); 807uint32_t high = low | ((1 << (n_remain * 6 ))- 1 ); 808 809if (low == 0 ) { 810if (n_remain == 2 ) { 811low = 1 <<11 ; 812 }else if (n_remain == 3 ) { 813low = 1 <<16 ; 814 } 815 } 816 817do { 818if (pos [1 ].type == LLAMA_GRETYPE_CHAR_RNG_UPPER ) { 819// inclusive range, e.g. [a-z] 820if (pos -> value <=high && low <=pos [1 ].value ) { 821return is_positive_char ; 822 } 823pos += 2 ; 824 }else if (pos -> type == LLAMA_GRETYPE_CHAR_ANY ) { 825// Any character matches "." 826return true; 827 }else { 828// exact char match, e.g. [a] or "a" 829if (low <=pos -> value && pos -> value <=high ) { 830return is_positive_char ; 831 } 832pos += 1 ; 833 } 834 }while (pos -> type == LLAMA_GRETYPE_CHAR_ALT ); 835 836return !is_positive_char ; 837} 838 839// returns true iff token matches the rule at pos (regular or inverse) 840// asserts that pos is pointing to a token element 841static bool llama_grammar_match_token ( 842const llama_grammar_element * pos , 843const llama_token token ) { 844GGML_ASSERT (pos -> type == LLAMA_GRETYPE_TOKEN || pos -> type == LLAMA_GRETYPE_TOKEN_NOT ); 845if (pos -> type == LLAMA_GRETYPE_TOKEN ) { 846return pos -> value == static_cast < uint32_t > (token ); 847 } 848if (pos -> type == LLAMA_GRETYPE_TOKEN_NOT ) { 849return pos -> value != static_cast < uint32_t > (token ); 850 } 851return false; 852} 853 854// transforms a grammar pushdown stack into N possible stacks, all ending 855// at a character range (terminal element) 856static void llama_grammar_advance_stack ( 857const llama_grammar_rules & rules , 858const llama_grammar_stack & stack , 859llama_grammar_stacks & new_stacks ) { 860 std::vector < llama_grammar_stack > todo ; 861todo .push_back (stack ); 862 863auto stack_cmp = [](const llama_grammar_stack & a ,const llama_grammar_stack & b ) { 864return std::lexicographical_compare (a .begin (),a .end (),b .begin (),b .end (), 865 [](const llama_grammar_element * pa ,const llama_grammar_element * pb ) { 866return pa < pb ;// Compare pointer addresses 867 } 868 ); 869 }; 870 871 std::set < llama_grammar_stack , decltype(stack_cmp )> seen (stack_cmp ); 872 873while (!todo .empty ()) { 874llama_grammar_stack curr_stack_candidate = std::move (todo .back ()); 875todo .pop_back (); 876 877auto [curr_stack_it ,inserted ]= seen .insert (std::move (curr_stack_candidate )); 878if (!inserted ) { 879continue ; 880 } 881const llama_grammar_stack & curr_stack = * curr_stack_it ; 882 883if (curr_stack .empty ()) { 884if (std::find (new_stacks .begin (),new_stacks .end (),curr_stack )== new_stacks .end ()) { 885new_stacks .emplace_back (curr_stack ); 886 } 887continue ; 888 } 889 890const llama_grammar_element * pos = curr_stack .back (); 891 892switch (pos -> type ) { 893case LLAMA_GRETYPE_RULE_REF : { 894const size_t rule_id = static_cast < size_t > (pos -> value ); 895const llama_grammar_element * subpos = rules [rule_id ].data (); 896do { 897// init new stack without the top (pos) 898llama_grammar_stack next_stack (curr_stack .begin (),curr_stack .end ()- 1 ); 899if (!llama_grammar_is_end_of_sequence (pos + 1 )) { 900// if this rule ref is followed by another element, add that to stack 901next_stack .push_back (pos + 1 ); 902 } 903if (!llama_grammar_is_end_of_sequence (subpos )) { 904// if alternate is nonempty, add to stack 905next_stack .push_back (subpos ); 906 } 907todo .push_back (std::move (next_stack )); 908while (!llama_grammar_is_end_of_sequence (subpos )) { 909// scan to end of alternate def 910subpos ++ ; 911 } 912if (subpos -> type == LLAMA_GRETYPE_ALT ) { 913// there's another alternate def of this rule to process 914subpos ++ ; 915 }else { 916break ; 917 } 918 }while (true); 919break ; 920 } 921case LLAMA_GRETYPE_CHAR : 922case LLAMA_GRETYPE_CHAR_NOT : 923case LLAMA_GRETYPE_CHAR_ANY : 924case LLAMA_GRETYPE_TOKEN : 925case LLAMA_GRETYPE_TOKEN_NOT : 926if (std::find (new_stacks .begin (),new_stacks .end (),curr_stack )== new_stacks .end ()) { 927// only add the stack if it's not a duplicate of one we already have 928new_stacks .emplace_back (curr_stack ); 929 } 930break ; 931default : 932// end of alternate (LLAMA_GRETYPE_END, LLAMA_GRETYPE_ALT) or middle of char range 933// (LLAMA_GRETYPE_CHAR_ALT, LLAMA_GRETYPE_CHAR_RNG_UPPER); stack should never be left on 934// those 935GGML_ABORT ("fatal error" ); 936 } 937 } 938} 939 940static llama_grammar_candidates llama_grammar_reject_candidates ( 941const llama_grammar_rules & rules , 942const llama_grammar_stacks & stacks , 943const llama_grammar_candidates & candidates ) { 944GGML_ASSERT (!stacks .empty ());// REVIEW 945 946if (candidates .empty ()) { 947return {}; 948 } 949 950auto rejects = llama_grammar_reject_candidates_for_stack (rules ,stacks .front (),candidates ); 951 952for (size_t i = 1 ,size = stacks .size ();i < size ;++ i ) { 953rejects = llama_grammar_reject_candidates_for_stack (rules ,stacks [i ],rejects ); 954 } 955 956return rejects ; 957} 958 959static bool llama_grammar_detect_left_recursion ( 960const llama_grammar_rules & rules , 961size_t rule_index , 962 std::vector < bool > * rules_visited , 963 std::vector < bool > * rules_in_progress , 964 std::vector < bool > * rules_may_be_empty ) { 965if ((* rules_in_progress )[rule_index ]) { 966return true; 967 } 968 969 (* rules_in_progress )[rule_index ]= true; 970 971const llama_grammar_rule & rule = rules [rule_index ]; 972 973// First check if the rule might produce the empty string. This could be done combined with the second 974// step but it's more readable as two steps. 975bool at_rule_start = true; 976for (size_t i = 0 ;i < rule .size ();i ++ ) { 977if (llama_grammar_is_end_of_sequence (& rule [i ])) { 978if (at_rule_start ) { 979 (* rules_may_be_empty )[rule_index ]= true; 980break ; 981 } 982at_rule_start = true; 983 }else { 984at_rule_start = false; 985 } 986 } 987 988// Second, recurse into leftmost nonterminals (or next-leftmost as long as the previous nonterminal may 989// be empty) 990bool recurse_into_nonterminal = true; 991for (size_t i = 0 ;i < rule .size ();i ++ ) { 992if (rule [i ].type == LLAMA_GRETYPE_RULE_REF && recurse_into_nonterminal ) { 993if (llama_grammar_detect_left_recursion (rules , (size_t )rule [i ].value ,rules_visited ,rules_in_progress ,rules_may_be_empty )) { 994return true; 995 } 996if (!((* rules_may_be_empty )[(size_t )rule [i ].value ])) { 997recurse_into_nonterminal = false; 998 } 999 }else if (llama_grammar_is_end_of_sequence (& rule [i ])) { 1000recurse_into_nonterminal = true; 1001 }else { 1002recurse_into_nonterminal = false; 1003 } 1004 } 1005 1006 (* rules_in_progress )[rule_index ]= false; 1007 (* rules_visited )[rule_index ]= true; 1008 1009return false; 1010} 1011 1012const llama_grammar_rules & llama_grammar_get_rules (const struct llama_grammar * grammar ) { 1013return grammar -> rules ; 1014} 1015 1016llama_grammar_stacks & llama_grammar_get_stacks (struct llama_grammar * grammar ) { 1017return grammar -> stacks ; 1018} 1019 1020static void llama_grammar_accept_chr ( 1021struct llama_grammar & grammar , 1022const llama_grammar_stack & stack , 1023uint32_t chr , 1024llama_grammar_stacks & new_stacks ) { 1025if (stack .empty ()) { 1026return ; 1027 } 1028 1029const llama_grammar_element * pos = stack .back (); 1030 1031// ignore if this turns into a token 1032if (pos -> type == LLAMA_GRETYPE_TOKEN || pos -> type == LLAMA_GRETYPE_TOKEN_NOT ) { 1033return ; 1034 } 1035 1036auto match = llama_grammar_match_char (pos ,chr ); 1037if (match .first ) { 1038llama_grammar_stack new_stack (stack .begin (),stack .end ()- 1 ); 1039if (!llama_grammar_is_end_of_sequence (match .second )) { 1040new_stack .push_back (match .second ); 1041 } 1042llama_grammar_advance_stack (grammar .rules ,new_stack ,new_stacks ); 1043 } 1044} 1045 1046void llama_grammar_accept (struct llama_grammar * grammar ,uint32_t chr ) { 1047llama_grammar_stacks stacks_new ; 1048stacks_new .reserve (grammar -> stacks .size ()); 1049 1050for (const auto & stack :grammar -> stacks ) { 1051llama_grammar_accept_chr (* grammar ,stack ,chr ,stacks_new ); 1052 } 1053 1054grammar -> stacks = std::move (stacks_new ); 1055} 1056 1057llama_grammar_candidates llama_grammar_reject_candidates_for_stack ( 1058const llama_grammar_rules & rules , 1059const llama_grammar_stack & stack , 1060const llama_grammar_candidates & candidates ) { 1061 1062llama_grammar_candidates rejects ; 1063rejects .reserve (candidates .size ()); 1064 1065if (stack .empty ()) { 1066for (const auto & tok :candidates ) { 1067if (* tok .code_points != 0 || tok .partial_utf8 .n_remain != 0 ) { 1068rejects .push_back (tok ); 1069 } 1070 } 1071return rejects ; 1072 } 1073 1074const llama_grammar_element * stack_pos = stack .back (); 1075 1076// if the top of the stack is a token rule, then we only need to check the token id 1077if (stack_pos -> type == LLAMA_GRETYPE_TOKEN || stack_pos -> type == LLAMA_GRETYPE_TOKEN_NOT ) { 1078for (const auto & tok :candidates ) { 1079if (* tok .code_points == 0 ) { 1080// reached the end of a token consumed by char rules, reject iff it ended 1081// in a partial response 1082if (tok .partial_utf8 .n_remain != 0 ) { 1083rejects .push_back (tok ); 1084 } 1085 }else if (!llama_grammar_match_token (stack_pos ,tok .id )) { 1086rejects .push_back (tok ); 1087 } 1088 } 1089return rejects ; 1090 } 1091 1092llama_grammar_candidates next_candidates ; 1093next_candidates .reserve (candidates .size ()); 1094 1095for (const auto & tok :candidates ) { 1096if (* tok .code_points == 0 ) { 1097// reached end of full codepoints in token, reject iff it ended in a partial sequence 1098// that cannot satisfy this position in grammar 1099if (tok .partial_utf8 .n_remain != 0 && 1100 !llama_grammar_match_partial_char (stack_pos ,tok .partial_utf8 )) { 1101rejects .push_back (tok ); 1102 } 1103 }else if (llama_grammar_match_char (stack_pos ,* tok .code_points ).first ) { 1104next_candidates .push_back ({tok .index ,tok .code_points + 1 ,tok .partial_utf8 ,tok .id }); 1105 }else { 1106rejects .push_back (tok ); 1107 } 1108 } 1109 1110const auto * stack_pos_after = llama_grammar_match_char (stack_pos ,0 ).second ; 1111 1112// update top of stack to next element, if any 1113llama_grammar_stack stack_after (stack .begin (),stack .end ()- 1 ); 1114if (!llama_grammar_is_end_of_sequence (stack_pos_after )) { 1115stack_after .push_back (stack_pos_after ); 1116 } 1117llama_grammar_stacks next_stacks ; 1118llama_grammar_advance_stack (rules ,stack_after ,next_stacks ); 1119 1120auto next_rejects = llama_grammar_reject_candidates (rules ,next_stacks ,next_candidates ); 1121for (const auto & tok :next_rejects ) { 1122rejects .push_back ({tok .index ,tok .code_points - 1 ,tok .partial_utf8 ,tok .id }); 1123 } 1124 1125return rejects ; 1126} 1127 1128//////////////////// 1129 1130struct llama_grammar * llama_grammar_init_impl ( 1131const struct llama_vocab * vocab , 1132const llama_grammar_element ** rules , 1133size_t n_rules , 1134size_t start_rule_index ) { 1135const llama_grammar_element * pos ; 1136 1137// copy rule definitions into vectors 1138llama_grammar_rules vec_rules (n_rules ); 1139for (size_t i = 0 ;i < n_rules ;i ++ ) { 1140for (pos = rules [i ];pos -> type != LLAMA_GRETYPE_END ;pos ++ ) { 1141vec_rules [i ].push_back (* pos ); 1142 } 1143vec_rules [i ].push_back ({LLAMA_GRETYPE_END ,0 }); 1144 } 1145 1146// Validate that all rule references point to valid rules 1147for (size_t i = 0 ;i < n_rules ;i ++ ) { 1148for (const auto & elem :vec_rules [i ]) { 1149if (elem .type == LLAMA_GRETYPE_RULE_REF ) { 1150if (elem .value >=n_rules || vec_rules [elem .value ].empty ()) { 1151LLAMA_LOG_ERROR ("invalid grammar: rule %zu references undefined rule %u\n" ,i ,elem .value ); 1152return nullptr ; 1153 } 1154 } 1155 } 1156 } 1157 1158// Check for left recursion 1159 std::vector < bool > rules_visited (n_rules ); 1160 std::vector < bool > rules_in_progress (n_rules ); 1161 std::vector < bool > rules_may_be_empty (n_rules ); 1162for (size_t i = 0 ;i < n_rules ;i ++ ) { 1163if (rules_visited [i ]) { 1164continue ; 1165 } 1166if (llama_grammar_detect_left_recursion (vec_rules ,i ,& rules_visited ,& rules_in_progress ,& rules_may_be_empty )) { 1167LLAMA_LOG_ERROR ("unsupported grammar, left recursion detected for nonterminal at index %zu" ,i ); 1168return nullptr ; 1169 } 1170 } 1171 1172// loop over alternates of start rule to build initial stacks 1173llama_grammar_stacks stacks ; 1174pos = vec_rules [start_rule_index ].data (); 1175do { 1176llama_grammar_stack stack ; 1177if (!llama_grammar_is_end_of_sequence (pos )) { 1178// if alternate is nonempty, add to stack 1179stack .push_back (pos ); 1180 } 1181llama_grammar_advance_stack (vec_rules ,stack ,stacks ); 1182while (!llama_grammar_is_end_of_sequence (pos )) { 1183// scan to end of alternate def 1184pos ++ ; 1185 } 1186if (pos -> type == LLAMA_GRETYPE_ALT ) { 1187// there's another alternate def of this rule to process 1188pos ++ ; 1189 }else { 1190break ; 1191 } 1192 }while (true); 1193 1194// Important: vec_rules has to be moved here, not copied, because stacks contains 1195// pointers to elements of vec_rules. If vec_rules were copied into llama_grammar 1196// then the pointers would be invalidated when the local vec_rules goes out of scope. 1197return new llama_grammar { 1198vocab , 1199 std::move (vec_rules ), 1200 std::move (stacks ), 1201/* .partial_utf8 = */ {}, 1202/* .lazy = */ false, 1203/* .awaiting_trigger = */ false, 1204/* .trigger_buffer = */ "" , 1205/* .trigger_buffer_positions = */ {}, 1206/* .trigger_tokens = */ {}, 1207/* .trigger_patterns = */ {}, 1208 }; 1209} 1210 1211struct llama_grammar * llama_grammar_init_impl ( 1212const struct llama_vocab * vocab , 1213const char * grammar_str , 1214const char * grammar_root , 1215bool lazy , 1216const char ** trigger_patterns , 1217size_t num_trigger_patterns , 1218const llama_token * trigger_tokens , 1219size_t num_trigger_tokens ) { 1220llama_grammar_parser parser (vocab ); 1221 1222// if there is a grammar, parse it 1223// rules will be empty (default) if there are parse errors 1224if (!parser .parse (grammar_str )|| parser .rules .empty ()) { 1225LLAMA_LOG_ERROR ("failed to parse grammar\n" ); 1226return nullptr ; 1227 } 1228 1229// Ensure that the grammar contains the start symbol 1230if (parser .symbol_ids .find (grammar_root )== parser .symbol_ids .end ()) { 1231LLAMA_LOG_ERROR ("grammar does not contain a '%s' symbol\n" ,grammar_root ); 1232return nullptr ; 1233 } 1234 1235 std::vector < const llama_grammar_element *> grammar_rules (parser .c_rules ()); 1236 1237const size_t n_rules = grammar_rules .size (); 1238const size_t start_rule_index = parser .symbol_ids .at (grammar_root ); 1239 1240const llama_grammar_element * pos ; 1241 1242// copy rule definitions into vectors 1243llama_grammar_rules vec_rules (n_rules ); 1244for (size_t i = 0 ;i < n_rules ;i ++ ) { 1245for (pos = grammar_rules [i ];pos -> type != LLAMA_GRETYPE_END ;pos ++ ) { 1246vec_rules [i ].push_back (* pos ); 1247 } 1248vec_rules [i ].push_back ({LLAMA_GRETYPE_END ,0 }); 1249 } 1250 1251// Check for left recursion 1252 std::vector < bool > rules_visited (n_rules ); 1253 std::vector < bool > rules_in_progress (n_rules ); 1254 std::vector < bool > rules_may_be_empty (n_rules ); 1255for (size_t i = 0 ;i < n_rules ;i ++ ) { 1256if (rules_visited [i ]) { 1257continue ; 1258 } 1259if (llama_grammar_detect_left_recursion (vec_rules ,i ,& rules_visited ,& rules_in_progress ,& rules_may_be_empty )) { 1260LLAMA_LOG_ERROR ("unsupported grammar, left recursion detected for nonterminal at index %zu\n" ,i ); 1261return nullptr ; 1262 } 1263 } 1264 1265// loop over alternates of start rule to build initial stacks 1266llama_grammar_stacks stacks ; 1267pos = vec_rules [start_rule_index ].data (); 1268do { 1269llama_grammar_stack stack ; 1270if (!llama_grammar_is_end_of_sequence (pos )) { 1271// if alternate is nonempty, add to stack 1272stack .push_back (pos ); 1273 } 1274llama_grammar_advance_stack (vec_rules ,stack ,stacks ); 1275while (!llama_grammar_is_end_of_sequence (pos )) { 1276// scan to end of alternate def 1277pos ++ ; 1278 } 1279if (pos -> type == LLAMA_GRETYPE_ALT ) { 1280// there's another alternate def of this rule to process 1281pos ++ ; 1282 }else { 1283break ; 1284 } 1285 }while (true); 1286 1287 std::vector < llama_token > vec_trigger_tokens ; 1288 std::vector < llama_grammar_trigger_pattern > vec_trigger_patterns ; 1289for (size_t i = 0 ;i < num_trigger_tokens ;i ++ ) { 1290GGML_ASSERT (trigger_tokens != nullptr ); 1291vec_trigger_tokens .push_back (trigger_tokens [i ]); 1292 } 1293for (size_t i = 0 ;i < num_trigger_patterns ;i ++ ) { 1294GGML_ASSERT (trigger_patterns != nullptr ); 1295auto & trigger = vec_trigger_patterns .emplace_back (); 1296trigger .pattern = trigger_patterns [i ]; 1297trigger .regex = std::regex (trigger .pattern ); 1298 } 1299 1300// Important: vec_rules has to be moved here, not copied, because stacks contains 1301// pointers to elements of vec_rules. If vec_rules were copied into llama_grammar 1302// then the pointers would be invalidated when the local vec_rules goes out of scope. 1303return new llama_grammar { 1304vocab , 1305 std::move (vec_rules ), 1306 std::move (stacks ), 1307/* .partial_utf8 = */ {}, 1308/* .lazy = */ lazy , 1309/* .awaiting_trigger = */ lazy , 1310/* .trigger_buffer = */ "" , 1311/* .trigger_buffer_positions = */ {}, 1312 std::move (vec_trigger_tokens ), 1313 std::move (vec_trigger_patterns ), 1314 }; 1315} 1316 1317void llama_grammar_free_impl (struct llama_grammar * grammar ) { 1318if (grammar == nullptr ) { 1319return ; 1320 } 1321 1322delete grammar ; 1323} 1324 1325struct llama_grammar * llama_grammar_clone_impl (const struct llama_grammar & grammar ) { 1326auto * result = new llama_grammar { 1327grammar .vocab , 1328grammar .rules , 1329grammar .stacks , 1330grammar .partial_utf8 , 1331grammar .lazy , 1332grammar .awaiting_trigger , 1333grammar .trigger_buffer , 1334grammar .trigger_buffer_positions , 1335grammar .trigger_tokens , 1336grammar .trigger_patterns , 1337 }; 1338 1339// redirect elements in stacks to point to new rules 1340for (size_t is = 0 ;is < result -> stacks .size ();is ++ ) { 1341for (size_t ie = 0 ;ie < result -> stacks [is ].size ();ie ++ ) { 1342for (size_t ir0 = 0 ;ir0 < grammar .rules .size ();ir0 ++ ) { 1343for (size_t ir1 = 0 ;ir1 < grammar .rules [ir0 ].size ();ir1 ++ ) { 1344if (grammar .stacks [is ][ie ]== & grammar .rules [ir0 ][ir1 ]) { 1345result -> stacks [is ][ie ]= & result -> rules [ir0 ][ir1 ]; 1346 } 1347 } 1348 } 1349 } 1350 } 1351 1352return result ; 1353} 1354 1355void llama_grammar_apply_impl (const struct llama_grammar & grammar ,llama_token_data_array * cur_p ) { 1356GGML_ASSERT (grammar .vocab != nullptr ); 1357 1358if (grammar .awaiting_trigger ) { 1359return ; 1360 } 1361 1362bool allow_eog = false; 1363for (const auto & stack :grammar .stacks ) { 1364if (stack .empty ()) { 1365allow_eog = true; 1366break ; 1367 } 1368 } 1369 1370 std::vector < std::pair < std::vector < uint32_t > ,llama_partial_utf8 >> candidates_decoded ; 1371candidates_decoded .reserve (cur_p -> size ); 1372 1373llama_grammar_candidates candidates_grammar ; 1374candidates_grammar .reserve (cur_p -> size ); 1375 1376for (size_t i = 0 ;i < cur_p -> size ;++ i ) { 1377const llama_token id = cur_p -> data [i ].id ; 1378const std::string & piece = grammar .vocab -> token_to_piece (id ); 1379 1380if (grammar .vocab -> is_eog (id )) { 1381if (!allow_eog ) { 1382cur_p -> data [i ].logit = - INFINITY ; 1383 } 1384 }else if (piece .empty ()|| piece [0 ]== 0 ) { 1385cur_p -> data [i ].logit = - INFINITY ; 1386 }else { 1387candidates_decoded .push_back (decode_utf8 (piece ,grammar .partial_utf8 )); 1388candidates_grammar .push_back ({i ,candidates_decoded .back ().first .data (),candidates_decoded .back ().second ,id }); 1389 } 1390 } 1391 1392const auto rejects = llama_grammar_reject_candidates (grammar .rules ,grammar .stacks ,candidates_grammar ); 1393for (const auto & reject :rejects ) { 1394cur_p -> data [reject .index ].logit = - INFINITY ; 1395 } 1396} 1397 1398void llama_grammar_accept_impl (struct llama_grammar & grammar ,llama_token token ) { 1399GGML_ASSERT (grammar .vocab != nullptr ); 1400 1401const auto & piece = grammar .vocab -> token_to_piece (token ); 1402 1403if (grammar .awaiting_trigger ) { 1404if (std::find (grammar .trigger_tokens .begin (),grammar .trigger_tokens .end (),token )!= grammar .trigger_tokens .end ()) { 1405grammar .awaiting_trigger = false; 1406grammar .trigger_buffer .clear (); 1407llama_grammar_accept_token (grammar ,token ,piece ); 1408LLAMA_LOG_DEBUG ("Grammar triggered on token %u (`%s`)" ,token ,piece .c_str ()); 1409return ; 1410 }else { 1411auto position = std::make_pair (grammar .trigger_buffer .size (),grammar .trigger_buffer .size ()+ piece .size ()); 1412grammar .trigger_buffer_positions .push_back (std::make_pair (token ,position )); 1413grammar .trigger_buffer += piece ; 1414 1415for (const auto & trigger_pattern :grammar .trigger_patterns ) { 1416auto start = trigger_pattern .find (grammar .trigger_buffer ); 1417if (start != std::string::npos ) { 1418grammar .awaiting_trigger = false; 1419 1420// replay tokens that overlap with [start, end) 1421for (const auto & [tok ,tok_pos ] :grammar .trigger_buffer_positions ) { 1422auto [tok_start ,tok_end ]= tok_pos ; 1423if (tok_end <=start ) { 1424continue ; 1425 } 1426 1427size_t piece_start = (tok_start < start ) ?start :tok_start ;// allow for partial token pieces 1428size_t piece_len = tok_end - piece_start ; 1429auto tok_piece = grammar .trigger_buffer .substr (piece_start ,piece_len ); 1430llama_grammar_accept_token (grammar ,tok ,tok_piece ); 1431 } 1432 1433auto constrained_str = grammar .trigger_buffer .substr (start ); 1434grammar .trigger_buffer .clear (); 1435grammar .trigger_buffer_positions .clear (); 1436LLAMA_LOG_DEBUG ("Grammar triggered on regex: '%s'\n" ,constrained_str .c_str ()); 1437return ; 1438 } 1439 } 1440LLAMA_LOG_DEBUG ("Grammar still awaiting trigger after token %d (`%s`)\n" ,token ,piece .c_str ()); 1441return ; 1442 } 1443 } 1444 1445if (grammar .vocab -> is_eog (token )) { 1446for (const auto & stack :grammar .stacks ) { 1447if (stack .empty ()) { 1448return ; 1449 } 1450 } 1451GGML_ABORT ("fatal error" ); 1452 } 1453 1454llama_grammar_accept_token (grammar ,token ,piece ); 1455} 1456 1457void llama_grammar_accept_str (struct llama_grammar & grammar ,const std::string & piece ) { 1458// Note terminating 0 in decoded string 1459const auto decoded = decode_utf8 (piece ,grammar .partial_utf8 ); 1460const auto & code_points = decoded .first ; 1461 1462for (auto it = code_points .begin (),end = code_points .end ()- 1 ;it != end ;++ it ) { 1463llama_grammar_accept (& grammar ,* it ); 1464 } 1465 1466grammar .partial_utf8 = decoded .second ; 1467if (grammar .stacks .empty ()) { 1468throw std::runtime_error ("Unexpected empty grammar stack after accepting piece: " + piece ); 1469 } 1470} 1471 1472void llama_grammar_accept_token (struct llama_grammar & grammar ,llama_token token ,const std::string & piece ) { 1473// Note terminating 0 in decoded string 1474const auto decoded = decode_utf8 (piece ,grammar .partial_utf8 ); 1475const auto & code_points = decoded .first ; 1476 1477llama_grammar_stacks stacks_new ; 1478stacks_new .reserve (grammar .stacks .size ()); 1479 1480for (const auto & stack :grammar .stacks ) { 1481if (stack .empty ()) { 1482continue ; 1483 } 1484 1485const llama_grammar_element * pos = stack .back (); 1486 1487if (pos -> type == LLAMA_GRETYPE_TOKEN || pos -> type == LLAMA_GRETYPE_TOKEN_NOT ) { 1488if (llama_grammar_match_token (pos ,token )) { 1489llama_grammar_stack new_stack (stack .begin (),stack .end ()- 1 ); 1490if (!llama_grammar_is_end_of_sequence (pos + 1 )) { 1491new_stack .push_back (pos + 1 ); 1492 } 1493llama_grammar_advance_stack (grammar .rules ,new_stack ,stacks_new ); 1494 } 1495 }else { 1496llama_grammar_stacks current_stacks = {stack }; 1497 1498for (auto it = code_points .begin (),end = code_points .end ()- 1 ;it != end ;++ it ) { 1499llama_grammar_stacks next_stacks ; 1500 1501for (const auto & cur_stack :current_stacks ) { 1502llama_grammar_accept_chr (grammar ,cur_stack ,* it ,next_stacks ); 1503 } 1504 1505current_stacks = std::move (next_stacks ); 1506if (current_stacks .empty ()) { 1507break ; 1508 } 1509 } 1510 1511for (auto & surviving_stack :current_stacks ) { 1512if (std::find (stacks_new .begin (),stacks_new .end (),surviving_stack )== stacks_new .end ()) { 1513stacks_new .emplace_back (surviving_stack ); 1514 } 1515 } 1516 } 1517 } 1518 1519grammar .stacks = std::move (stacks_new ); 1520grammar .partial_utf8 = decoded .second ; 1521 1522if (grammar .stacks .empty ()) { 1523throw std::runtime_error ("Unexpected empty grammar stack after accepting piece: " + piece + " (" + std::to_string (token )+ ")" ); 1524 } 1525} 1526