@@ -69,29 +69,48 @@ def print_coord(coord):
6969 return coord
7070
7171
72- def get_print (m : Model , anonymously : bool = True ):
72+ def get_printers (m : Model , io_api : str , anonymously : bool = True ):
7373 if anonymously :
74+ if io_api == "lp" :
75+ def print_variable_anonymous (var ):
76+ return f"x{ var } "
7477
75- def print_variable_anonymous ( var ):
76- return f"x { var } "
78+ def print_constraint_anonymous ( cons ):
79+ return f"c { cons } "
7780
78- def print_constraint_anonymous (cons ):
79- return f"c{ cons } "
81+ elif io_api == "lp-polars" :
82+ def print_variable_anonymous (series ):
83+ return pl .lit (" x" ).alias ("x" ), series .cast (pl .String )
84+
85+ def print_constraint_anonymous (series ):
86+ return pl .lit ("c" ).alias ("c" ), series .cast (pl .String )
87+ else :
88+ return None
8089
8190 return print_variable_anonymous , print_constraint_anonymous
8291 else :
83-
84- def print_variable (var ):
92+ def print_variable_lp (var ):
8593 name , coord = m .variables .get_label_position (var )
8694 name = clean_name (name )
87- return f"{ name } { print_coord (coord )} "
95+ return f"{ name } { print_coord (coord )} # { var } "
8896
89- def print_constraint (cons ):
97+ def print_constraint_lp (cons ):
9098 name , coord = m .constraints .get_label_position (cons )
9199 name = clean_name (name )
92- return f"{ name } { print_coord (coord )} "
100+ return f"{ name } { print_coord (coord )} #{ cons } "
101+
102+ def print_variable_polars (series ):
103+ return pl .lit (" " ), series .map_elements (print_variable_lp , return_dtype = pl .String )
93104
94- return print_variable , print_constraint
105+ def print_constraint_polars (series ):
106+ return pl .lit (None ), series .map_elements (print_constraint_lp , return_dtype = pl .String )
107+
108+ if io_api == "lp" :
109+ return print_variable_lp , print_constraint_lp
110+ elif io_api == "lp-polars" :
111+ return print_variable_polars , print_constraint_polars
112+ else :
113+ return None
95114
96115
97116def objective_write_linear_terms (
@@ -392,12 +411,10 @@ def to_lp_file(
392411 integer_label : str ,
393412 slice_size : int = 10_000_000 ,
394413 progress : bool = True ,
395- anonymously : bool = True ,
414+ printers = None ,
396415) -> None :
397416 batch_size = 5000
398417
399- printers = get_print (m , anonymously )
400-
401418 with open (fn , mode = "w" ) as f :
402419 start = time .time ()
403420
@@ -443,27 +460,25 @@ def to_lp_file(
443460 logger .info (f" Writing time: { round (time .time ()- start , 2 )} s" )
444461
445462
446- def objective_write_linear_terms_polars (f , df ):
463+ def objective_write_linear_terms_polars (f , df , print_variable ):
447464 cols = [
448465 pl .when (pl .col ("coeffs" ) >= 0 ).then (pl .lit ("+" )).otherwise (pl .lit ("" )),
449466 pl .col ("coeffs" ).cast (pl .String ),
450- pl .lit (" x" ),
451- pl .col ("vars" ).cast (pl .String ),
467+ * print_variable (pl .col ("vars" )),
452468 ]
453469 df = df .select (pl .concat_str (cols , ignore_nulls = True ))
454470 df .write_csv (
455471 f , separator = " " , null_value = "" , quote_style = "never" , include_header = False
456472 )
457473
458474
459- def objective_write_quadratic_terms_polars (f , df ):
475+ def objective_write_quadratic_terms_polars (f , df , print_variable ):
460476 cols = [
461477 pl .when (pl .col ("coeffs" ) >= 0 ).then (pl .lit ("+" )).otherwise (pl .lit ("" )),
462478 pl .col ("coeffs" ).mul (2 ).cast (pl .String ),
463- pl .lit (" x" ),
464- pl .col ("vars1" ).cast (pl .String ),
465- pl .lit (" * x" ),
466- pl .col ("vars2" ).cast (pl .String ),
479+ * print_variable (pl .col ("vars1" )),
480+ pl .lit (" *" ),
481+ * print_variable (pl .col ("vars2" )),
467482 ]
468483 f .write (b"+ [\n " )
469484 df = df .select (pl .concat_str (cols , ignore_nulls = True ))
@@ -473,7 +488,7 @@ def objective_write_quadratic_terms_polars(f, df):
473488 f .write (b"] / 2\n " )
474489
475490
476- def objective_to_file_polars (m , f , progress = False ):
491+ def objective_to_file_polars (m , f , progress = False , printers = None ):
477492 """
478493 Write out the objective of a model to a lp file.
479494 """
@@ -484,8 +499,10 @@ def objective_to_file_polars(m, f, progress=False):
484499 f .write (f"{ sense } \n \n obj:\n \n " .encode ())
485500 df = m .objective .to_polars ()
486501
502+ print_variable , _ = printers
503+
487504 if m .is_linear :
488- objective_write_linear_terms_polars (f , df )
505+ objective_write_linear_terms_polars (f , df , print_variable )
489506
490507 elif m .is_quadratic :
491508 lins = df .filter (pl .col ("vars1" ).eq (- 1 ) | pl .col ("vars2" ).eq (- 1 ))
@@ -495,20 +512,22 @@ def objective_to_file_polars(m, f, progress=False):
495512 .otherwise (pl .col ("vars1" ))
496513 .alias ("vars" )
497514 )
498- objective_write_linear_terms_polars (f , lins )
515+ objective_write_linear_terms_polars (f , lins , print_variable )
499516
500517 quads = df .filter (pl .col ("vars1" ).ne (- 1 ) & pl .col ("vars2" ).ne (- 1 ))
501- objective_write_quadratic_terms_polars (f , quads )
518+ objective_write_quadratic_terms_polars (f , quads , print_variable )
502519
503520
504- def bounds_to_file_polars (m , f , progress = False , slice_size = 2_000_000 ):
521+ def bounds_to_file_polars (m , f , progress = False , slice_size = 2_000_000 , printers = None ):
505522 """
506523 Write out variables of a model to a lp file.
507524 """
508525 names = list (m .variables .continuous ) + list (m .variables .integers )
509526 if not len (list (names )):
510527 return
511528
529+ print_variable , _ = printers
530+
512531 f .write (b"\n \n bounds\n \n " )
513532 if progress :
514533 names = tqdm (
@@ -525,8 +544,8 @@ def bounds_to_file_polars(m, f, progress=False, slice_size=2_000_000):
525544 columns = [
526545 pl .when (pl .col ("lower" ) >= 0 ).then (pl .lit ("+" )).otherwise (pl .lit ("" )),
527546 pl .col ("lower" ).cast (pl .String ),
528- pl .lit (" <= x " ),
529- pl .col ("labels" ). cast ( pl . String ),
547+ pl .lit (" <= " ),
548+ * print_variable ( pl .col ("labels" )),
530549 pl .lit (" <= " ),
531550 pl .when (pl .col ("upper" ) >= 0 ).then (pl .lit ("+" )).otherwise (pl .lit ("" )),
532551 pl .col ("upper" ).cast (pl .String ),
@@ -539,14 +558,16 @@ def bounds_to_file_polars(m, f, progress=False, slice_size=2_000_000):
539558 formatted .write_csv (f , ** kwargs )
540559
541560
542- def binaries_to_file_polars (m , f , progress = False , slice_size = 2_000_000 ):
561+ def binaries_to_file_polars (m , f , progress = False , slice_size = 2_000_000 , printers = None ):
543562 """
544563 Write out binaries of a model to a lp file.
545564 """
546565 names = m .variables .binaries
547566 if not len (list (names )):
548567 return
549568
569+ print_variable , _ = printers
570+
550571 f .write (b"\n \n binary\n \n " )
551572 if progress :
552573 names = tqdm (
@@ -561,8 +582,7 @@ def binaries_to_file_polars(m, f, progress=False, slice_size=2_000_000):
561582 df = var_slice .to_polars ()
562583
563584 columns = [
564- pl .lit ("x" ),
565- pl .col ("labels" ).cast (pl .String ),
585+ * print_variable (pl .col ("labels" )),
566586 ]
567587
568588 kwargs = dict (
@@ -573,7 +593,7 @@ def binaries_to_file_polars(m, f, progress=False, slice_size=2_000_000):
573593
574594
575595def integers_to_file_polars (
576- m , f , progress = False , integer_label = "general" , slice_size = 2_000_000
596+ m , f , progress = False , integer_label = "general" , slice_size = 2_000_000 , printers = None
577597):
578598 """
579599 Write out integers of a model to a lp file.
@@ -582,6 +602,8 @@ def integers_to_file_polars(
582602 if not len (list (names )):
583603 return
584604
605+ print_variable , _ = printers
606+
585607 f .write (f"\n \n { integer_label } \n \n " .encode ())
586608 if progress :
587609 names = tqdm (
@@ -596,8 +618,7 @@ def integers_to_file_polars(
596618 df = var_slice .to_polars ()
597619
598620 columns = [
599- pl .lit ("x" ),
600- pl .col ("labels" ).cast (pl .String ),
621+ * print_variable (pl .col ("labels" )),
601622 ]
602623
603624 kwargs = dict (
@@ -607,10 +628,12 @@ def integers_to_file_polars(
607628 formatted .write_csv (f , ** kwargs )
608629
609630
610- def constraints_to_file_polars (m , f , progress = False , lazy = False , slice_size = 2_000_000 ):
631+ def constraints_to_file_polars (m , f , progress = False , lazy = False , slice_size = 2_000_000 , printers = None ):
611632 if not len (m .constraints ):
612633 return
613634
635+ print_variable , print_constraint = printers
636+
614637 f .write (b"\n \n s.t.\n \n " )
615638 names = m .constraints
616639 if progress :
@@ -636,14 +659,16 @@ def constraints_to_file_polars(m, f, progress=False, lazy=False, slice_size=2_00
636659 .alias ("labels" )
637660 )
638661
662+ row_labels = print_constraint (pl .col ("labels" ))
663+ col_labels = print_variable (pl .col ("vars" ))
639664 columns = [
640- pl .when (pl .col ("labels" ).is_not_null ()).then (pl . lit ( "c" )). alias ( "c" ),
641- pl .col ("labels" ).cast ( pl . String ),
665+ pl .when (pl .col ("labels" ).is_not_null ()).then (row_labels [ 0 ] ),
666+ pl .when ( pl . col ("labels" ).is_not_null ()). then ( row_labels [ 1 ] ),
642667 pl .when (pl .col ("labels" ).is_not_null ()).then (pl .lit (":\n " )).alias (":" ),
643668 pl .when (pl .col ("coeffs" ) >= 0 ).then (pl .lit ("+" )),
644669 pl .col ("coeffs" ).cast (pl .String ),
645- pl .when (pl .col ("vars" ).is_not_null ()).then (pl . lit ( " x" )). alias ( "x" ),
646- pl .col ("vars" ).cast ( pl . String ),
670+ pl .when (pl .col ("vars" ).is_not_null ()).then (col_labels [ 0 ] ),
671+ pl .when ( pl . col ("vars" ).is_not_null ()). then ( col_labels [ 1 ] ),
647672 "sign" ,
648673 pl .lit (" " ),
649674 pl .col ("rhs" ).cast (pl .String ),
@@ -662,21 +687,27 @@ def constraints_to_file_polars(m, f, progress=False, lazy=False, slice_size=2_00
662687
663688
664689def to_lp_file_polars (
665- m , fn , integer_label = "general" , slice_size = 2_000_000 , progress : bool = True
690+ m ,
691+ fn ,
692+ integer_label = "general" ,
693+ slice_size = 2_000_000 ,
694+ progress : bool = True ,
695+ printers = None ,
666696):
667697 with open (fn , mode = "wb" ) as f :
668698 start = time .time ()
669699
670- objective_to_file_polars (m , f , progress = progress )
671- constraints_to_file_polars (m , f = f , progress = progress , slice_size = slice_size )
672- bounds_to_file_polars (m , f = f , progress = progress , slice_size = slice_size )
673- binaries_to_file_polars (m , f = f , progress = progress , slice_size = slice_size )
700+ objective_to_file_polars (m , f , progress = progress , printers = printers )
701+ constraints_to_file_polars (m , f = f , progress = progress , slice_size = slice_size , printers = printers )
702+ bounds_to_file_polars (m , f = f , progress = progress , slice_size = slice_size , printers = printers )
703+ binaries_to_file_polars (m , f = f , progress = progress , slice_size = slice_size , printers = printers )
674704 integers_to_file_polars (
675705 m ,
676706 integer_label = integer_label ,
677707 f = f ,
678708 progress = progress ,
679709 slice_size = slice_size ,
710+ printers = printers ,
680711 )
681712 f .write (b"end\n " )
682713
@@ -690,6 +721,7 @@ def to_file(
690721 integer_label : str = "general" ,
691722 slice_size : int = 2_000_000 ,
692723 progress : bool | None = None ,
724+ with_names : bool = True ,
693725) -> Path :
694726 """
695727 Write out a model to a lp or mps file.
@@ -707,20 +739,15 @@ def to_file(
707739 if progress is None :
708740 progress = m ._xCounter > 10_000
709741
742+ printers = get_printers (m , io_api , anonymously = not with_names )
743+ if with_names and io_api not in ["lp" , "lp-polars" ]:
744+ logger .warning ("Debug names are only supported for LP files." )
745+
710746 if io_api == "lp" :
711- to_lp_file (m , fn , integer_label , slice_size = slice_size , progress = progress )
712- elif io_api == "lp-debug" :
713- to_lp_file (
714- m ,
715- fn ,
716- integer_label ,
717- slice_size = slice_size ,
718- progress = progress ,
719- anonymously = False ,
720- )
747+ to_lp_file (m , fn , integer_label , slice_size = slice_size , progress = progress , printers = printers )
721748 elif io_api == "lp-polars" :
722749 to_lp_file_polars (
723- m , fn , integer_label , slice_size = slice_size , progress = progress
750+ m , fn , integer_label , slice_size = slice_size , progress = progress , printers = printers
724751 )
725752
726753 elif io_api == "mps" :
@@ -735,7 +762,7 @@ def to_file(
735762 h .writeModel (str (fn ))
736763 else :
737764 raise ValueError (
738- f"Invalid io_api '{ io_api } '. Choose from 'lp', 'lp-debug', 'lp- polars' or 'mps'."
765+ f"Invalid io_api '{ io_api } '. Choose from 'lp', 'lp-polars' or 'mps'."
739766 )
740767
741768 return fn
0 commit comments