--- /dev/null
+//lcmのruby拡張
+#include <ruby.h>
+#include <fstream>
+#include <memory>
+//Vsop_Rubyクラス
+#include"CtoI.h"
+
+extern int CtoI_Lcm1_ub(char *, char *, int, int, int); // by ham
+
+// ruby 1.8.5以下対応
+#ifndef RSTRING_PTR
+ #define RSTRING_PTR(s) (RSTRING(s)->ptr)
+#endif
+#ifndef RARRAY_PTR
+ #define RARRAY_PTR(s) (RARRAY(s)->ptr)
+#endif
+
+
+
+
+CtoI* string2ctoi(char *str);
+CtoI* int2ctoi(int val);
+CtoI *value2ctoi(VALUE v);
+//------------------------------------------------------------------------------
+// 配列型に拡張したauto_ptr
+//------------------------------------------------------------------------------
+template<class T>
+class kgAutoPtr2 {
+ T* _ptr;
+
+public:
+ kgAutoPtr2(T* ptr=0) : _ptr(ptr) {};
+ virtual ~kgAutoPtr2(void) { if(_ptr != NULL) delete[] _ptr; }
+ T* get(void) const throw() { return _ptr; }
+ void set(T* ptr) throw() { if(_ptr!=NULL) delete[] _ptr; _ptr=ptr; }
+ void clear(void) { if(_ptr!=NULL) delete[] _ptr; _ptr=0;}
+};
+
+
+class Vsop_Ruby{
+public:
+ CtoI *cmod;
+ ~Vsop_Ruby(void){
+ if(cmod!=0) delete cmod;
+ }
+};
+void free_rmod(Vsop_Ruby* rmod){
+ if(rmod!=0){
+ delete rmod;
+ }
+}
+//初期化カウント
+int init_cnt=0;
+//ノード数
+#define DEF_ENV_NMAX 400000000
+int env_nmax=0;
+bool env_warning = false;
+
+#include "setfunc.cpp"
+
+
+#define MAX_LEN 409600
+
+extern "C"{
+ void Init_zdd_so();
+}
+#define HASH_MAX 409600
+int yylineno=1;
+static int hashcnt;
+static int Depth;
+static int* S_Var;
+static int PFflag;
+
+static int Depth_e;
+static int* S_Var_e;
+
+static int Depth_item;
+static int* S_Var_item;
+
+static int* S_Var_ary;
+
+
+static int PutNum(CtoI a, int base,ofstream &fs)
+{
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ kgAutoPtr2<char> a_ptr;
+ char *s;
+ try{
+ a_ptr.set(new char[d]);
+ s = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err;
+ if(base == 16) err = a.StrNum16(s);
+ else err = a.StrNum10(s);
+ if(err == 1) return 1;
+ fs << s<< ",";
+
+ return 0;
+}
+
+static int PF(CtoI a, int base,ofstream &fs)
+{
+ if(a.IsConst())
+ {
+ if(PFflag == 1){fs << endl;}
+ if(a.TopDigit() & 1) {fs << "-" ; a = -a; }
+
+ PFflag = 1;
+ int c1 = (a != 1);
+ if(c1 || Depth == 0)
+ {
+ if(PutNum(a, base,fs) == 1) return 1;
+ }
+ else if(!c1){
+ fs << "1,";
+ }
+ for(int i=0; i<Depth; i++)
+ {
+ if(i==0){fs << VTable.GetName(S_Var[i]);}
+ else{fs << " " << VTable.GetName(S_Var[i]);}
+ }
+ return 0;
+ }
+ int v = a.TopItem();
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var[Depth] = v;
+ Depth++;
+ if(PF(b, base,fs) == 1) return 1;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF(b, base,fs);
+}
+
+int CsvoutCtoI(CtoI a,ofstream &fs)
+{
+ if(a == CtoI_Null()) return 1;
+ if(a == 0) return 0;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ PFflag = 0;
+ int err = PF(a, 10,fs);
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return 1;
+ }
+ }
+ fs << endl;
+ return 0;
+}
+/*
+ * call-seq:
+ * zdd.csvout(fileName) -> self : CSV出力
+ *
+ * zdd : ZDD Object
+ * fileName : Ruby String
+ *
+ * === 説明
+ * zddオブジェクトの内容をfileNameで指定したファイル名にCSV形式で出力する。
+ * 項目は、重みとアイテム集合がこの順番で出力される。
+ * ただし項目名は出力されない。
+ * 空のアイテム集合はnull値として出力される。
+ * 返り値はself(自分自身)。
+ *
+ * === 例
+ * > a.show # -> a b + 2 b c + 3 d + 4
+ * > a.csvout("output.csv")
+ *
+ * $ more output.csv
+ * 1,a b
+ * 2,b c
+ * 3,d
+ * 4,
+ *
+ * === 関連
+ * hashout
+ */
+VALUE vsop_csvout(int argc, VALUE *argv, VALUE self) {
+ Vsop_Ruby* rmod;
+ VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,"10",&v);
+ char *str = RSTRING_PTR(v);
+ ofstream fs;
+ fs.open(str);
+ CsvoutCtoI(*rmod->cmod,fs);
+ fs.close();
+ return self;
+}
+
+static int PF_hash(CtoI a, int base,VALUE& hash)
+{
+ if(a.IsConst())
+ {
+ char valstr[MAX_LEN];
+ if(a.TopDigit() & 1) {strcpy(valstr,"-") ; a = -a; }
+ else{ strcpy(valstr,"");}
+
+ PFflag = 1;
+ int c1 = (a != 1);
+
+ char *valrtn;
+ kgAutoPtr2<char> a_ptr;
+ if(c1 || Depth == 0)
+ {
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ try{
+ a_ptr.set(new char[d]);
+ valrtn = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err;
+ if(base == 16) err = a.StrNum16(valrtn);
+ else err = a.StrNum10(valrtn);
+ if(err == 1)
+ {
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return 1;
+ }
+ strcat(valstr,valrtn);
+ }
+ else if(!c1){
+ strcat(valstr,"1");
+ }
+
+ char keystr[MAX_LEN];
+ *keystr = 0;
+ for(int i=0; i<Depth; i++)
+ {
+ int size = strlen(keystr)+strlen(VTable.GetName(S_Var[i]))+2;
+ if(size>MAX_LEN){
+ rb_raise(rb_eRuntimeError,"string size over flow");
+ }
+ if(i==0){
+ strcpy(keystr,VTable.GetName(S_Var[i]));
+ }
+ else{
+ strcat(keystr," ");
+ strcat(keystr,VTable.GetName(S_Var[i]));
+ }
+ }
+
+ VALUE key = rb_str_new2(keystr);
+ VALUE val = INT2NUM(atoi(valstr));
+ rb_hash_aset(hash, key, val);
+ hashcnt++;
+ if(hashcnt> HASH_MAX){return 2;}
+ return 0;
+ }
+ int v = a.TopItem();
+ printf("HPF_2 %d\n",v);
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var[Depth] = v;
+ Depth++;
+ int chk=PF_hash(b, base,hash);
+ if(chk > 0) return chk;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+
+ return PF_hash(b, base,hash);
+}
+
+
+static void num_check(char *str){
+ //数値チェック(アイテムが数値なら警告)
+ char *p=str;
+ if(*p=='-' || *p=='+' ) p++;
+ while(*p){
+ if( ( *p>='0' && *p<='9' ) || *p == '.' ){
+ fprintf(stderr,"chech %c\n",*p);
+ fprintf(stderr,"use numbers for symbol Variable\n");
+ break;
+ }
+ p++;
+ }
+}
+
+
+
+VALUE HashoutCtoI(CtoI a,int *rtn)
+{
+ hashcnt=0;
+ VALUE hash = rb_hash_new();
+ if(a == CtoI_Null()) return 1;
+ if(a == 0) return 0;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ PFflag = 0;
+ int err = PF_hash(a, 10,hash);
+ *rtn = err;
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return rb_hash_new();
+ }
+ }
+ return hash;
+}
+
+
+
+
+/*
+ * call-seq:
+ * zdd.hashout -> hash : Hash出力
+ *
+ * zdd : ZDD Object
+ * hash : Ruby Hash
+ *
+ * === 説明
+ * zddの内容をrubyのHashオブジェクトに変換し、そのオブジェクトを返す。
+ * ハッシュキーはアイテム集合、対応する値は重み。
+ *
+ * === 例
+ * > a.show
+ * a b + 2 b c + 3 d + 4
+ *
+ * > h=a.hashout
+ * > p h #
+ * {""=>4, "a b"=>1, "d"=>3, "b c"=>2}
+ *
+ * === 関連
+ * csvout
+ */
+VALUE vsop_hashout(VALUE self){
+ int rtnflg=0;
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE hash = HashoutCtoI(*rmod->cmod,&rtnflg);
+ if(rtnflg==2){
+ rb_iv_set(self,"@partly", Qtrue );
+ }
+ else{
+ rb_iv_set(self,"@partly", Qfalse);
+ }
+ return hash;
+}
+
+
+
+/////////// each用
+static int PF_array_each(CtoI a, VALUE& self)
+{
+ int sign=1;
+ if(a.IsConst())
+ {
+ char valstr[MAX_LEN];
+ if(a.TopDigit() & 1) {sign= -1 ; a = -a; }
+ CtoI rtn;
+ int c1 = (a != 1);
+ char *valrtn;
+ kgAutoPtr2<char> a_ptr;
+ if(c1 || Depth_e == 0)
+ {
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ try{
+ a_ptr.set(new char[d]);
+ valrtn = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err = a.StrNum10(valrtn);
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return 1;
+ }
+ rtn = CtoI(CtoI_atoi(valrtn));
+ }
+ else if(!c1){
+ rtn = CtoI(CtoI_atoi("1"));;
+ }
+
+ for(int i=0; i<Depth_e; i++)
+ {
+ char *str = VTable.GetName(S_Var_e[i]);
+ int ckck = VTable.GetID(str);
+ rtn =Product(rtn, CtoI(1).AffixVar( ckck));
+ }
+
+ Vsop_Ruby* rmod=new Vsop_Ruby;
+ rmod->cmod = new CtoI (rtn) ;
+ rb_yield_values(1,Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod));
+ return 0;
+ }
+
+ int v = a.TopItem();
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var_e[Depth_e] = v;
+ Depth_e++;
+ int chk=PF_array_each(b, self);
+ if(chk > 0) return chk;
+ Depth_e--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF_array_each(b,self);
+}
+
+//////////////////////////////////////////////
+void CtoI2Array_each(CtoI a,VALUE &self)
+{
+ if(a == CtoI_Null()) return ;
+ if(a == 0) return ;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth_e = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var_e = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ PF_array_each(a, self);
+ }
+}
+/*
+ * call-seq:
+ * zdd.each{|x|} -> Qtrue
+ *
+ * ZDDからアイテムセットを1つずつ読み込み,指定されたブロックを実行する.
+ *
+ * === 例
+ * > x.show
+ * 2 a + 2 b + 4 a c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > x.each{|x|
+ * > x.show
+ * > }
+ * 4 a c
+ * 2 a
+ * 2 b
+*/
+VALUE vsop_each(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI2Array_each(*rmod->cmod,self);
+ return Qtrue;
+}
+
+
+
+
+
+
+// array用
+static int PF_array(CtoI a,VALUE& array)
+{
+ if(a.IsConst())
+ {
+ char valstr[MAX_LEN];
+ if(a.TopDigit() & 1) {strcpy(valstr,"-") ; a = -a; }
+ else{ strcpy(valstr,"");}
+
+ PFflag = 1;
+ int c1 = (a != 1);
+
+ char *valrtn;
+ kgAutoPtr2<char> a_ptr;
+ if(c1 || Depth == 0)
+ {
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ try{
+ a_ptr.set(new char[d]);
+ valrtn = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err;
+ err = a.StrNum10(valrtn);
+ if(err == 1)
+ {
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return 1;
+ }
+ strcat(valstr,valrtn);
+ }
+
+ char keystr[MAX_LEN];
+ *keystr = 0;
+ for(int i=0; i<Depth; i++)
+ {
+ int size = strlen(keystr)+strlen(VTable.GetName(S_Var_ary[i]))+2;
+ if(size>MAX_LEN){
+ rb_raise(rb_eRuntimeError,"string size over flow");
+ }
+ if(i==0){
+ strcpy(keystr,VTable.GetName(S_Var_ary[i]));
+ }
+ else{
+ strcat(keystr," ");
+ strcat(keystr,VTable.GetName(S_Var_ary[i]));
+ }
+ }
+ if(*valstr&& *keystr){
+ strcat(valstr," ");
+ strcat(valstr,keystr);
+ }
+ else{strcat(valstr,keystr); }
+
+ VALUE val = rb_str_new2(valstr);
+ rb_ary_push(array,val);
+ return 0;
+ }
+ int v = a.TopItem();
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var_ary[Depth] = v;
+ Depth++;
+ int chk=PF_array(b, array);
+ if(chk > 0) return chk;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+
+ return PF_array(b, array);
+}
+
+
+VALUE CtoI2Array(CtoI a)
+{
+ VALUE array = rb_ary_new();
+ if(a == CtoI_Null()) return array;
+ if(a == 0) return array;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var_ary = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err = PF_array(a, array);
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return array;
+ }
+ }
+ return array;
+}
+/*
+ * call-seq:
+ * zdd.to_a -> Array
+ *
+ * ZDDからアイテムセット文字列の配列を返す.
+ *
+ * === 例
+ * > x.show
+ * 2 a + 2 b + 4 a c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > array = x.to_a
+ * [ "4 a c","2 a","2 b"]
+*/
+VALUE vsop_to_a(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE array = CtoI2Array(*rmod->cmod);
+
+ return array;
+}
+
+
+
+
+
+//str用
+static int PutNum_str(CtoI a, int base,VALUE &str)
+{
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ kgAutoPtr2<char> a_ptr;
+ char *s;
+ try{
+ a_ptr.set(new char[d]);
+ s = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err;
+ if(base == 16) err = a.StrNum16(s);
+ else err = a.StrNum10(s);
+ if(err == 1) return 1;
+ rb_str_cat(str,s,strlen(s));
+
+ return 0;
+}
+
+static int PF_str(CtoI a,VALUE str)
+{
+ if(a.IsConst())
+ {
+ if(PFflag == 1){rb_str_cat(str," + ",strlen(" + "));}
+ if(a.TopDigit() & 1) {rb_str_cat(str," - ",strlen(" - ")); a = -a; }
+
+ PFflag = 1;
+ int c1 = (a != 1);
+ if(c1 || Depth == 0)
+ {
+ if(PutNum_str(a, 10,str) == 1) return 1;
+ rb_str_cat(str," ",strlen(" "));
+ }
+
+ for(int i=0; i<Depth; i++)
+ {
+ char *p = VTable.GetName(S_Var[i]);
+ rb_str_cat(str,p,strlen(p));
+ if( i<Depth-1) rb_str_cat(str," ",strlen(" "));
+ }
+ return 0;
+ }
+ int v = a.TopItem();
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var[Depth] = v;
+ Depth++;
+ if(PF_str(b, str) == 1) return 1;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF_str(b,str);
+}
+
+VALUE CtoI2String(CtoI a)
+{
+ VALUE str = rb_str_new2("");
+
+ if(a == CtoI_Null()) return str;
+ if(a == 0) return str;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ PFflag = 0;
+ int err = PF_str(a, str);
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return str;
+ }
+ }
+ return str;
+}
+
+/*
+ * call-seq:
+ * zdd.to_a -> String
+ *
+ * ZDDからアイテムセット文字列を返す.
+ *
+ * === 例
+ * > x.show
+ * 2 a + 2 b + 4 a c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > array = x.to_s
+ * "4 a c + 2 a + 2 b"
+*/
+VALUE vsop_to_s(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE str = CtoI2String(*rmod->cmod);
+ return str;
+}
+
+
+
+/////////// each_item用
+static int PF_itemarray(CtoI a, VALUE& self)
+{
+ int sign=1;
+ if(a.IsConst())
+ {
+ char valstr[MAX_LEN];
+ if(a.TopDigit() & 1) {sign= -1 ; a = -a; }
+ int c1 = (a != 1);
+ VALUE weight;
+ char *valrtn;
+ kgAutoPtr2<char> a_ptr;
+ if(c1 || Depth_item == 0)
+ {
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ try{
+ a_ptr.set(new char[d]);
+ valrtn = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int err = a.StrNum10(valrtn);
+ if(err == 1){
+ rb_raise(rb_eRuntimeError,"memory over flow");
+ return 1;
+ }
+ weight = INT2NUM(atoi(valrtn));
+ }
+ else if(!c1){
+ weight = INT2NUM(1);
+ }
+
+ VALUE top=Qtrue;
+ VALUE bottom=Qfalse;
+ for(int i=0; i<Depth_item; i++){
+ char *str = VTable.GetName(S_Var_item[i]);
+ int ckck = VTable.GetID(str);
+ Vsop_Ruby* rmod=new Vsop_Ruby;
+ rmod->cmod = new CtoI (CtoI(1).AffixVar( ckck)) ;
+ if( i>0 ) top=Qfalse;
+ if( i+1==Depth_item ) bottom=Qtrue;
+ rb_yield_values(4,weight,Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod) ,top,bottom);
+ }
+ return 0;
+ }
+ int v = a.TopItem();
+ CtoI b = a.Factor1(v);
+ if(b == CtoI_Null()) return 1;
+ S_Var_item[Depth_item] = v;
+ Depth_item++;
+ int chk=PF_itemarray(b, self);
+ if(chk > 0) return chk;
+ Depth_item--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF_itemarray(b,self);
+}
+
+//////////////////////////////////////////////
+void CtoI2ItemArray(CtoI a,VALUE &self)
+{
+ VALUE ary = rb_ary_new();
+ if(a == CtoI_Null()) return;
+ if(a == 0) return;
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth_item = 0;
+ kgAutoPtr2<int> a_ptr;
+ try{
+ a_ptr.set(new int[lev]);
+ S_Var_item = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ PF_itemarray(a, self);
+ }
+}
+
+
+
+/*
+ * call-seq:
+ * zdd.each_item{|val ,item,top,botom |} -> Qtrue
+ *
+ * ZDDをアイテムセットのアイテムを1つずつ読み込み,指定されたブロックを実行する.
+ *
+ * === ブロック引数
+ * zddeach {|weight,item,top,bottom|}
+ * weight :: アイテムセットの重み
+ * item :: アイテムzdd
+ * top :: アイテムセットの最初のアイテムであればture、それ以外はfalse
+ * bottom :: アイテムセットの最後のアイテムであればture、それ以外はfalse.
+ *
+ * === 例
+ * > x.show
+ * 2 a + 2 b + 4 a c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > f.each_item{|val,x,t,b|
+ * > p val
+ * > x.show
+ * > p t
+ * > p b
+ * > p "----------"
+ * >}
+ * 4
+ * a
+ * true
+ * false
+ * "----------"
+ * 4
+ * c
+ * false
+ * true
+ * "----------"
+ * 2
+ * a
+ * true
+ * true
+ * "----------"
+ * 2
+ * b
+ * true
+ * true
+ * "----------"
+*/
+VALUE vsop_each_item(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI2ItemArray(*rmod->cmod,self);
+ return Qtrue;
+}
+
+
+//この値はBDDライブラリとかぶらないよう注意すること
+// キャッシュがおかしくなる
+static const char BC_CtoI_DELTA = 50;
+
+CtoI CtoI_Delta(CtoI a, CtoI b)
+{
+ if(a == CtoI_Null()) return a;
+ if(b == CtoI_Null()) return b;
+ if(a == 0) return 0;
+ if(b == 0) return 0;
+ if(a == 1 && b==1) return 1;
+
+
+ int atop = a.Top();
+ int btop = b.Top();
+ if(BDD_LevOfVar(atop) < BDD_LevOfVar(btop)) return CtoI_Delta(b, a);
+
+ bddword ax = a.GetZBDD().GetID();
+ bddword bx = b.GetZBDD().GetID();
+ if(atop == btop && ax < bx) return CtoI_Delta(b, a);
+
+ ZBDD z = BDD_CacheZBDD(BC_CtoI_DELTA, ax, bx);
+ if(z != -1) return CtoI(z);
+
+ CtoI a0 = a.Factor0(atop);
+ CtoI a1 = a.Factor1(atop);
+ CtoI c;
+ if(atop != btop)
+ {
+ if(a.IsBool()) c = CtoI_Union( CtoI_Delta(a0, b), CtoI_Delta(a1, b).AffixVar(atop) );
+ else c = CtoI_Delta(a0, b) + CtoI_Delta(a1, b).TimesSysVar(atop);
+ }
+ else
+ {
+ CtoI b0 = b.Factor0(atop);
+ CtoI b1 = b.Factor1(atop);
+ if(a.IsBool())
+ c = CtoI_Union( CtoI_Delta(a0, b0) + CtoI_Delta(a1, b1),
+ (CtoI_Delta(a1, b0)+ CtoI_Delta(a0, b1)).AffixVar(atop) ) ;
+ else if(atop > 1)
+ c = CtoI_Delta(a0, b0)
+ + (CtoI_Delta(a1, b0) + CtoI_Delta(a0, b1)).TimesSysVar(atop)
+ + CtoI_Delta(a1, b1).TimesSysVar(atop-1);
+ else BDDerr("CtoI_Delta(): SysVar overflow.");
+ }
+ BDD_CacheEnt(BC_CtoI_DELTA, ax, bx, c.GetZBDD().GetID());
+ return c;
+}
+
+/*
+ * call-seq:
+ * zdd1.delta(zdd2) -> ZDD Object : delta演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合αとzdd2に含まれるアイテム集合βのα ⊕βを求める。
+ * 例えば、アイテム集合abc と bcd の排他的論理和は以下の通り。
+ * abc.delta(bcd) = abc ⊕ bcd = ad
+ * 複数のアイテム集合間の演算では全組合せについて排他的論理和を求める。
+ * (abc + a).delta(bcd + b) = abc ⊕ bcd + abc ⊕ b + a ⊕ bcd + a ⊕ b
+ * = ad + ac + abcd + ab
+ * 重みについては、同じアイテム集合を複数に展開して計算すればよい。
+ * (2abc).delta(bcd) = (abc+abc).delta(bcd) = ad + ad = 2ad
+ *
+ * === 例
+ * > a=VSOP.itemset("a")
+ * > b=VSOP.itemset("b")
+ * > f=a+2*a*b+3*b
+ *
+ * # a + 2ab + 3b の各アイテム集合と引き数で指定されたアイテム集合 a との排他的論理和を求めると、
+ * # 3 a b + 2 b + 1 となる。
+ * > f.delta(a).show
+ * 3 a b + 2 b + 1
+ *
+ * # アイテム集合bとの排他的論理和を求めると a b + 2 a + 3 となる。
+ * > f.delta(b).show
+ * a b + 2 a + 3
+ *
+ * # アイテム集合 ab との排他的論理和を求めると 3 a + b + 2 となる。
+ * > f.delta(a*b).show
+ * 3 a + b + 2
+ *
+ * # 定数1は空のアイテム集合なので、それとの排他的論理和を求めると元の集合のままとなる。
+ * > f.meet(1).show
+ * 2 a b + a + 3 b
+ * > exit
+ *
+ * > a=VSOP.itemset("a")
+ * > b=VSOP.itemset("b")
+ * > c=VSOP.itemset("c")
+ * >
+ * > f=((a*b*c)+2*(a*b)+(b*c)+1)
+ * > f.show
+ * a b c + 2 a b + b c + 1
+ *
+ * > g=2*a*b + a
+ * > g.show
+ * a b + a
+ * # abc + 2ab + bc + 1 の各アイテム集合と引き数で指定された 2ab + a の各アイテム集合との排他的論理和を求めると、
+ * # 以下の通りとなる(アイテム間のスペースは省略)。
+ * # abc ⊕ 2ab = 2c
+ * # 2ab ⊕ 2ab = 4
+ * # bc ⊕ 2ab = 2ac
+ * # 1 ⊕ 2ab = 2ab
+ * # abc ⊕ a = bc
+ * # 2ab ⊕ a = 2b
+ * # bc ⊕ a = abc
+ * # 1 ⊕ a = a
+ * # 結果をまとめると a b c + 2 a b + 2 a c + a + b c + 2 b + 2 c + 4 となる。
+ * #
+ * > f.delta(g).show
+ * a b c + 2 a b + 2 a c + a + b c + 2 b + 2 c + 4
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_delta(int argc, VALUE *argv,VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,"10",&v);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_modc = value2ctoi(v);
+ CtoI *ctoi_fin;
+ *ctoi_moda = CtoI_Delta(*ctoi_moda, *ctoi_modc);
+ ctoi_fin = ctoi_moda;
+ delete ctoi_modc;
+ Vsop_Ruby *rmod_rtn = new Vsop_Ruby;
+ rmod_rtn->cmod = ctoi_fin;
+ return Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod_rtn);
+}
+
+CtoI* string2ctoi(char *str){
+ //初回呼び出し時のみBDDの初期化
+/*
+ v = rb_cv_get(self,"@@init_cnt");
+ int init_cnt_v = NUM2INT(v);
+ if(init_cnt_v==0){ BDDV_Init(256, env_nmax);}
+ init_cnt_v++;
+ rb_cv_set(self,"@@init_cnt",INT2NUM(init_cnt_v));
+*/
+
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+ int sep_cnt=0;
+ for(char *p=str;*p;p++){
+ if(*p==' '){
+ sep_cnt++;
+ }
+ }
+ sep_cnt++;
+ kgAutoPtr2<CtoI> a_ptr;
+ CtoI * ctoitmp;
+ try{
+ a_ptr.set(new CtoI[sep_cnt]);
+ ctoitmp = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ int i=0;
+ char *p,*q;
+ p=str;
+ q=str;
+ while(1){
+ if(*p==' '){//区切り文字
+ *p='\0';
+ int var = VTable.GetID(q);
+ if(var == 0){
+ if(env_warning){ num_check(q); }
+ VTable.SetB(q, power16/2);
+ var = VTable.GetID(q);
+ }
+ ctoitmp[i] = CtoI(1).AffixVar(var);
+ q=p+1;
+ i++;
+ }
+ else if(*p=='\0'){//終了時文字
+ int var = VTable.GetID(q);
+ if(var == 0){
+ if(env_warning){ num_check(q); }
+ VTable.SetB(q, power16/2);
+ var = VTable.GetID(q);
+ }
+ ctoitmp[i] = CtoI(1).AffixVar(var);
+ break;
+ }
+ p++;
+ }
+ CtoI ctmp = ctoitmp[0];
+ for(int i=1;i<sep_cnt;i++){
+ ctmp = Product(ctmp,ctoitmp[i]);
+ }
+ CtoI *rtnctoi = new CtoI(ctmp);
+ return rtnctoi;
+}
+
+//VALUEを受け取り、CtoI*を返す
+CtoI *value2ctoi(VALUE v){
+ CtoI *rtnctoi;
+ Vsop_Ruby* argrmod;
+ if(TYPE(v)==T_STRING){
+ rtnctoi=string2ctoi(RSTRING_PTR(v));
+ }
+ else if(TYPE(v)==T_FIXNUM){
+ rtnctoi=int2ctoi(FIX2INT(v));
+ }
+ else if(TYPE(v)==T_BIGNUM){
+ rtnctoi=int2ctoi(NUM2INT(v));
+ }
+ else{
+ Data_Get_Struct(v,Vsop_Ruby,argrmod);
+ rtnctoi =new CtoI(*argrmod->cmod);
+ }
+ return rtnctoi;
+}
+
+/*
+ * call-seq:
+ * 書式1) ZDD.symbol(itemName, value, to) -> Qture : シンボル変数の宣言
+ * 書式2) ZDD.symbol -> itemList : シンボル変数の一覧
+ *
+ * itemName : Ruby String
+ * value : Ruby Float
+ * to : Ruby String
+ * itemList : Ruby String
+ *
+ * === 説明
+ * 書式1)
+ * itemNameで指定した文字列のZDDアイテム名を宣言する。
+ * アイテム名として利用できる文字種に特に制限はない。また文字列長についても特に制限はない(メモリ容量制限のみ)。
+ * valueは、そのアイテムに与える値で、valueやmaxcoverなどのメソッドで利用される。詳しくは、valueメソッドを参照のこと。
+ * 省略時には0.5が設定される。
+ * toは宣言したアイテムの追加する方向を指定する(top | bottom)。
+ * 省略時にはbottomが設定される。
+ * 書式2)
+ * 引数なしでこのメソッドを呼び出すと、シンボル変数の一覧がスペース区切りの文字列として返される。
+ *
+ * === 例
+ * > ZDD.symbol("a",1.0)
+ * > ZDD.symbol("b",0.5)
+ * > ZDD.symbol("c",2.0,"top")
+ * > ZDD.symbol("d")
+ * > ZDD.symbol
+ * c a b d
+ *
+ * > (1..10).each{|i|
+ * > ZDD.symbol("s_#{i}",i)
+ * > }
+ * > puts ZDD.symbol
+ * c a b d s_1 s_2 s_3 s_4 s_5 s_6 s_7 s_8 s_9 s_10
+ *
+ * === 関連
+ * itemset, value
+ */
+VALUE vsop_symbol(int argc, VALUE *argv, VALUE self) {
+ //引数読み込み
+ VALUE rtn;
+ //初回呼び出し時のみBDDの初期化
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ if(argc>=1){
+ int val=power16/2;
+ char *to ="bottom";
+ char *str;
+ VALUE v1,v2,v3;
+ rb_scan_args(argc, argv,"12",&v1,&v2,&v3);
+ switch(argc){
+ case 3:
+ if(TYPE(v3)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ to = RSTRING_PTR(v3);
+ case 2:
+ if(TYPE(v2)==T_FLOAT){
+ val = (int)( NUM2DBL(v2)*power16);
+ }
+ else if(TYPE(v2)==T_FIXNUM){
+ val = NUM2INT(v2)*power16;
+ }
+ else if(TYPE(v2)==T_NIL){
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be FLOAT or INT or NIL)");
+ }
+ case 1:
+ if(TYPE(v1)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ str = RSTRING_PTR(v1);
+ //数値チェック(アイテムが数値なら警告)
+ if(env_warning){ num_check(str); }
+ break;
+ default:
+ rb_raise(rb_eRuntimeError,"argument type error");
+ break;
+ }
+ if(*str!='\0'){
+ int var = VTable.GetID(str);
+ if(var == 0){
+ if(!strcmp(to,"top")) { VTable.SetT(str, val);}
+ else { VTable.SetB(str, val);}
+ }
+ }
+ rtn = Qtrue;
+ }
+ else{
+ int n = VTable.Used();
+ string str ;
+ for(int i=n; i>0; i--)
+ {
+ int var = BDD_VarOfLev(i);
+ str += VTable.GetName(var);
+ str += " ";
+ }
+ rtn = rb_str_new2(str.c_str());
+ }
+ return rtn;
+}
+/*
+ * call-seq:
+ * ZDD.itemset(itemSets) -> zdd : アイテム集合のzddオブジェクトの作成
+ *
+ * itemSets : Ruby String
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * itemSetsで指定されたアイテム集合のzddオブジェクトを生成する。
+ * 複数のアイテムは半角スペースで区切る。
+ * 空文字("")が指定された場合は空のアイテム集合と扱われ、積和表現の定数項1として設定される(zdd.constant(1)と同様)。
+ * symbolメソッドで宣言されていないアイテムは現在のアイテム順の最後に追加される。
+ * またアイテムに設定される値はデフォルトの0.5となる。
+ *
+ * === 例
+ * > a=ZDD.itemset("a b")
+ * > a.show
+ * a b
+ *
+ * > b=ZDD.itemset("b")
+ * > b.show
+ * b
+ *
+ * > c=ZDD.itemset("")
+ * > c.show
+ * 1
+ *
+ * # 数字をアイテム名として利用することも可能
+ * > x0=ZDD.itemset("2")
+ * > x0.show
+ * 2
+ *
+ * # ただし、表示上重みと区別がつかなくなるので注意が必要。
+ * > (2*x0).show
+ * 2 2
+ *
+ * # こんな記号ばかりのアイテム名もOK。
+ * > x1=ZDD.itemset("!#%&'()=~|@[;:]")
+ * > x1.show
+ * !#%&'()=~|@[;:]
+ *
+ * # ただし、rubyで特殊な意味を持つ記号はエスケープする必要がある。
+ * > x2=ZDD.itemset("\\\$\"")
+ * > x2.show
+ * \$"
+ *
+ * # もちろん日本語も利用可。
+ * > x3=ZDD.itemset("りんご ばなな")
+ * > x3.show
+ * りんご ばなな
+ *
+ * === 関連
+ * symbol, constant, value
+ */
+VALUE vsop_itemset(int argc, VALUE *argv, VALUE self) {
+
+ Vsop_Ruby* rmod=new Vsop_Ruby;
+ VALUE v;
+
+ //引数読み込み
+ rb_scan_args(argc, argv,"10",&v);
+ if(TYPE(v)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+
+ char *str = RSTRING_PTR(v);
+ if (*str =='\0'){
+ rmod->cmod = int2ctoi(1);
+ }
+ else{
+ rmod->cmod = string2ctoi(str);
+ }
+
+ return Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod);
+}
+
+CtoI * int2ctoi(int val){
+ //初回呼び出し時のみBDDの初期化
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+ char wrkval[64];
+ sprintf(wrkval,"%d",val);
+ CtoI *rtnctoi = new CtoI(CtoI_atoi(wrkval));
+ return rtnctoi;
+}
+
+/*
+ * call-seq:
+ * ZDD.constant(weight) -> zdd : ZDD重みオブジェクトの生成
+ *
+ * weight : Ruby Integer
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * weightで指定した整数をZDDの重みオブジェクト(空のアイテム集合の重み)に変換する。
+ *
+ * === 例
+ * > c=ZDD.constant(10)
+ * > c.show
+ * 10
+ *
+ * > c*"a" -> 10 a # ZDD重みオブジェクトとruby文字列との演算では、ruby文字列はアイテム集合と見なされ自動でZDDオブジェクトにキャストされる。
+ * > 0*c -> 0 # ZDD重みオブジェクトとruby整数との演算では、ruby整数はZDD重みオブジェクトと見なされる。
+ * > puts c.to_i*10 # ZDD重みオブジェクトをruby整数に変換し、ruby整数として演算する。
+ * 100
+ *
+ * # 以下のように、0の重みを定義しておくと、そのオブジェクトとの演算においては、RubyStringを自動的にキャストしてくれるので便利である。
+ * > a=ZDD.constant(0)
+ * > a+="x"
+ * > a+="x z"
+ * > a+="z"
+ * > a.show
+ * x z + x + z
+ *
+ * === 関連
+ * to_i
+ */
+VALUE vsop_constant(int argc, VALUE *argv, VALUE self) {
+ Vsop_Ruby* rmod=new Vsop_Ruby;
+ VALUE v;
+
+ //引数読み込み
+ rb_scan_args(argc, argv,"10",&v);
+
+ CtoI ctoitmp;
+ //定数FIXNUM
+ if(TYPE(v)==T_FIXNUM){
+ rmod->cmod = int2ctoi(FIX2INT(v));
+ }
+ //定数BIGNUM
+ else if(TYPE(v)==T_BIGNUM){
+ rmod->cmod = int2ctoi(NUM2INT(v));
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be FIXNUM or BIGNUM)");
+ }
+ VALUE rtn = Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod);
+ return rtn;
+}
+
+/* call-seq:
+ * ZDD.lcm(transaction, type,fixnum [,order]) -> zdd : lcm over zdd(最大サポート指定可能)
+ *
+ * transaction : RubyString
+ * type : RubyString
+ * minSupport : RubyInteger
+ * order : RubyString
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * transactionで指定されたファイルから、LCM over zdd アルゴリズムを利用し頻出パターンを列挙しそのZDDオブジェクトを返す。
+ * 列挙する頻出パターンの種別はtypeで与える("F":頻出集合, "M":極大集合, "C":飽和集合)。
+ *
+ * orderファイルによりアイテムの宣言順序を制御できる。
+ * 同じtransactionデータに対して異なる最小サポートで実行すると、本メソッドにおける内部的なアイテム宣言方法 (得られる全パターンにのみ含まれるアイテムについて、頻度の高い順に宣言される)が原因して宣言順序にずれが生じる可能性がある。
+ * それを回避するために、頻度1以上の全アイテムを頻度の高い順に登録したorderファイルを用意し、本メソッドに与える。
+ * orderファイルの作成についてはlcm-ruby拡張パッケージのメソッドを利用することで得ることができる。
+ *
+ * transactionのデータ値は数字に変換しておく必要がある。
+ *
+ * <b>説明</b>
+ * ==== sring3がない場合
+ * generates frequent patterns using LCM algorithm from the FIMI format database file "string2" with minimum support = "fixnum".
+ * ===== "string1" specifies LCM parameter as:
+ * * F all patterns,
+ * * C clesed patterns,
+ * * M maximal patterns,
+ * * FQ all patterns with frequencies,
+ * * CQ clesed patterns with frequencies,
+ * * MQ maximal patterns with frequencies.
+ * ==== sring3がある場合
+ * generates frequent patterns using LCM algorithm from the FIMI format database file "string1" with minimum support = "fixnum" and variable order file "string3".
+ * ===== "string1" specifies LCM parameter as:
+ * * F all patterns,
+ * * C clesed patterns,
+ * * M maximal patterns,
+ * * FQ all patterns with frequencies,
+ * * CQ clesed patterns with frequencies,
+ * * MQ maximal patterns with frequencies.
+ *
+*/
+VALUE vsop_lcm(int argc, VALUE *argv, VALUE self){
+ VALUE rtnval;
+ if(argc==4){
+ rtnval = vsop_lcm_order(argc,argv,self);
+ }
+ else{
+ rtnval = vsop_lcm_nomal(argc,argv,self);
+ }
+ return rtnval;
+}
+
+
+
+// ------------------------------ パターン長制約を入れたlcm over zdd
+
+VALUE vsop_lcm_nomal_ub(int argc, VALUE *argv, VALUE self){
+/*
+ VALUE vz = rb_cv_get(self,"@@init_cnt");
+ int init_cnt_v = NUM2INT(vz);
+ if(init_cnt_v==0){ BDDV_Init(256, env_nmax);}
+ init_cnt_v++;
+ rb_cv_set(self,"@@init_cnt",INT2NUM(init_cnt_v));
+*/
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ VALUE v1,v2,v3,v4;
+ CtoI *ctoi_fin;
+ rb_scan_args(argc, argv,"40",&v1,&v2,&v3,&v4);
+ if(TYPE(v1)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ if(TYPE(v2)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ if(TYPE(v3)!=T_FIXNUM){
+ rb_raise(rb_eRuntimeError,"argument type error (3rd argument must be FIXNUM)");
+ }
+ if(TYPE(v4)!=T_FIXNUM){
+ rb_raise(rb_eRuntimeError,"argument type error (4th argument must be FIXNUM)");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+ int len_ub = FIX2INT(v4);
+
+ int len;
+
+ len = strlen(arg1);
+ char *str_c = new char[len+3];
+ sprintf(str_c,"\"%s\"",arg1);
+ int len_c = len+2;
+
+ len = strlen(arg2);
+ char *str_d = new char[len+3];
+ sprintf(str_d,"\"%s\"",arg2);
+ int len_d = len+2;
+
+ char *str_e = new char[64];
+ sprintf(str_e,"%d",arg3_fix);
+ str_c[len_c - 1] = 0;
+ str_d[len_d - 1] = 0;
+ int th = atoi(str_e);
+ if(strcmp(str_c+1, "F" ) == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 0, len_ub);
+ else if(strcmp(str_c+1, "C" ) == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 1, len_ub);
+ else if(strcmp(str_c+1, "M" ) == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 2, len_ub);
+ else if(strcmp(str_c+1, "FQ") == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 10, len_ub);
+ else if(strcmp(str_c+1, "CQ") == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 11, len_ub);
+ else if(strcmp(str_c+1, "MQ") == 0) CtoI_Lcm1_ub(str_d+1, 0, th, 12, len_ub); //11 -> 12 by ham
+ for(int i=VTable.Used(); i<CtoI_LcmItems(); i++)
+ {
+ int t = 1;
+ char s[32];
+ int x = CtoI_LcmPerm(i);
+ sprintf(s, "x%d", x);
+ while(VTable.GetID(s) != 0)
+ {
+ t++;
+ sprintf(s, "x%d_%d", x, t);
+ }
+ VTable.SetT(s, power16/2);
+ }
+ CtoI a = CtoI_Lcm2();
+ ctoi_fin = new CtoI(a);
+ delete[] str_c;
+ delete[] str_d;
+ delete[] str_e;
+
+ Vsop_Ruby *rmod_rtn = new Vsop_Ruby;
+ rmod_rtn->cmod = ctoi_fin;
+ return Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod_rtn);
+}
+
+
+VALUE vsop_lcm_order_ub(int argc, VALUE *argv, VALUE self){
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ VALUE v1,v2,v3,v4,v5;
+ CtoI *ctoi_fin;
+ rb_scan_args(argc, argv,"50",&v1,&v2,&v3,&v4,&v5);
+ if(TYPE(v1)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ if(TYPE(v2)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ if(TYPE(v3)!=T_FIXNUM){
+ rb_raise(rb_eRuntimeError,"argument type error (3rd argument must be FIXNUM)");
+ }
+ if(TYPE(v4)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (4th argument must be STRING)");
+ }
+ if(TYPE(v5)!=T_FIXNUM){
+ rb_raise(rb_eRuntimeError,"argument type error (5th argument must be FIXNUM)");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+ char *arg4 = RSTRING_PTR(v4);
+
+ int len_ub = FIX2INT(v5);
+
+ int len;
+
+ len = strlen(arg1);
+ char *str_c = new char[len+3];
+ sprintf(str_c,"\"%s\"",arg1);
+ int len_c = len+2;
+
+ len = strlen(arg2);
+ char *str_d = new char[len+3];
+ sprintf(str_d,"\"%s\"",arg2);
+ int len_d = len+2;
+
+ char *str_e = new char[64];
+ sprintf(str_e,"%d",arg3_fix);
+
+ len = strlen(arg4);
+ char *str_f = new char[len+3];
+ sprintf(str_f,"\"%s\"",arg4);
+ int len_f = len+2;
+
+ str_c[len_c - 1] = 0;
+ str_d[len_d - 1] = 0;
+ int th = atoi(str_e);
+ str_f[len_f - 1] = 0;
+ if(strcmp(str_c+1, "F" ) == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 0, len_ub);
+ else if(strcmp(str_c+1, "C" ) == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 1, len_ub);
+ else if(strcmp(str_c+1, "M" ) == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 2, len_ub);
+ else if(strcmp(str_c+1, "FQ") == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 10, len_ub);
+ else if(strcmp(str_c+1, "CQ") == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 11, len_ub);
+ else if(strcmp(str_c+1, "MQ") == 0) CtoI_Lcm1_ub(str_d+1, str_f+1, th, 12, len_ub);
+ for(int i=VTable.Used(); i<CtoI_LcmItems(); i++)
+ {
+ int t = 1;
+ char s[32];
+ int x = CtoI_LcmPerm(i);
+ sprintf(s, "x%d", x);
+ while(VTable.GetID(s) != 0)
+ {
+ t++;
+ sprintf(s, "x%d_%d", x, t);
+ }
+ VTable.SetT(s, power16/2);
+ }
+ CtoI a = CtoI_Lcm2();
+ ctoi_fin = new CtoI(a);
+ delete[] str_c;
+ delete[] str_d;
+ delete[] str_e;
+ delete[] str_f;
+
+
+ Vsop_Ruby *rmod_rtn = new Vsop_Ruby;
+ rmod_rtn->cmod = ctoi_fin;
+ return Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod_rtn);
+}
+
+
+
+/*
+ * call-seq:
+ * ZDD.lcm_ub() -> zdd : lcm over zdd(最大サポート指定可能)
+ *
+ * === 説明
+ *
+ * === 関連
+ * show
+ */
+VALUE vsop_lcm_ub(int argc, VALUE *argv, VALUE self){
+ VALUE rtnval;
+ if(argc==5){
+ rtnval = vsop_lcm_order_ub(argc,argv,self);
+ }
+ else{
+ rtnval = vsop_lcm_nomal_ub(argc,argv,self);
+ }
+ return rtnval;
+}
+
+// ------------------------------ パターン長制約を入れたlcm over zdd ここまで 2010/02/28
+// print関係
+
+/*
+ * call-seq:
+ * zdd.map -> self : カルノー図の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddのカルノー図を標準出力に表示する。
+ * アイテム数は6個まで表示できる。
+ *
+ * === 例
+ * > a=2*ZDD.itemset("a b")+3*ZDD.itemset("b")+4
+ * > a.show
+ * 2 a b + 3 b + 4
+ *
+ * > a.map
+ * a : b
+ * | 0 1
+ * 0 | 4 3
+ * 1 | 0 2
+ *
+ * # アイテムaが1列目のビット列に、アイテムbが1行目のビット列に対応してアイテム集合が表現されている。
+ * # セルの値は重みを表す。左上のセルはaが0、bが0、すなわち定数項が4であることが示されている。
+ *
+ * # 4アイテムでは以下の通り。
+ * > a=ZDD.itemset("a b")+2*ZDD.itemset("b c")+3*ZDD.itemset("d")+4
+ * > a.show
+ * a b + 2 b c + 3 d + 4
+ *
+ * > a.map
+ * a b : c d
+ * | 00 01 11 10
+ * 00 | 4 3 0 0
+ * 01 | 0 0 0 2
+ * 11 | 1 0 0 0
+ * 10 | 0 0 0 0
+ *
+ * === 関連
+ * rmap
+ */
+VALUE vsop_print_map(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ if(MapAll(*ctoitmp) == 1){
+ rb_raise(rb_eRuntimeError,"01Memory overflow");
+ }
+
+ bout.Unset();
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.rmap -> self : 冗長性を排除したカルノー図の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddのカルノー図を標準出力に表示する。ただし、使われていないアイテムは省いて表示される。
+ *
+ * === 例
+ * # 4つのアイテムa,b,c,dを宣言
+ * > ZDD.symbol("a")
+ * > ZDD.symbol("b")
+ * > ZDD.symbol("c")
+ * > ZDD.symbol("d")
+ * # a,b,cのみ利用したZDD
+ * > a=ZDD.itemset("a b")+2*ZDD.itemset("b c")+4
+ * > a.show
+ * a b + 2 b c + 4
+ *
+ * # mapで表示させると以下の通り。
+ * > a.map
+ * a b : c d
+ * | 00 01 11 10
+ * 00 | 4 0 0 0
+ * 01 | 0 0 0 2
+ * 11 | 1 0 0 0
+ * 10 | 0 0 0 0
+ *
+ * # rmapで表示させるとdが省かれて表示される。
+ * > a.rmap
+ * a : b c
+ * | 00 01 11 10
+ * 0 | 4 0 2 0
+ * 1 | 0 0 0 1
+ * === 関連
+ * map
+ */
+VALUE vsop_print_rmap(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ if(MapSel(*ctoitmp) == 1){
+ rb_raise(rb_eRuntimeError,"02Memory overflow");
+ }
+
+ bout.Unset();
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.hex -> self : 16進数表現積和表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * 係数を16進数で表現し積和形で標準出力に出力する。
+ *
+ * === 例
+ * > a=ZDD.itemset("a b")+11*ZDD.itemset("b c")+30*ZDD.itemset("d")+4
+ * > a.show
+ * a b + 11 b c + 30 d + 4
+ * > a.hex
+ * a b + B b c + 1E d + 4
+ *
+ * === 関連
+ * show
+ */
+VALUE vsop_print_hex(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ if(PrintCtoI_16(*ctoitmp) == 1){
+ rb_raise(rb_eRuntimeError,"03Memory overflow");
+ }
+ bout.Unset();
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.bit -> self : 重みの(-2)進数の各桁別アイテム集合の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * ZDDでは重みをマイナス2進数で表現し、各桁ごとにZDDを生成している。
+ * このメソッドにより各桁別に、そのZDDに登録されているアイテム集合を標準出力に出力できる。
+ *
+ * === 例
+ * > a=5*ZDD.itemset("a b c")+3*ZDD.itemset("a b")+2*ZDD.itemset("b c")+1*ZDD.it
+ * > a.show
+ * 5 a b c - 3 a b + 2 b c + c
+ *
+ * > a.bit
+ * 3: a b
+ * 2: a b c + a b + b c
+ * 1: b c
+ * 0: a b c + a b + c
+ *
+ * # "a b c"の重み5の(-2)進数は101となる。
+ * # 1*(-2)^2+0*(-2)^1+1*(-2)^0 = 5
+ * # よって0桁目と2桁目にアイテム集合"a b c"が表示されている。
+ * # "a b"の重み-3の(-2)進数は1101となる。
+ * # 1*(-2)^3+1*(-2)^2+0*(-2)^1+1*(-2)^0 = -3
+ * # よって0,2,3桁目にアイテム集合"a b"が表示されている。
+ */
+VALUE vsop_print_bit(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ if(PrintDigital(*ctoitmp) == 1){
+ rb_raise(rb_eRuntimeError,"04Memory overflow");
+ }
+ bout.Unset();
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.case -> self : 重み別アイテム集合の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * 重みの値別にアイテム集合を標準出力に出力する。
+ *
+ * === 例
+ * > a=5*ZDD.itemset("a b c")+3*ZDD.itemset("a b")+2*ZDD.itemset("b c")+1*ZDD.it
+ * > a.show
+ * 5 a b c - 3 a b + 2 b c + c
+ *
+ * > a.case
+ * 5: a b c
+ * 2: b c
+ * 1: c
+ * -3: a b
+ *
+ * === 関連
+ * show
+ */
+VALUE vsop_print_case(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ if(PrintCase(*ctoitmp) == 1){
+ rb_raise(rb_eRuntimeError,"05Memory overflow");
+ }
+
+ bout.Unset();
+ return self;
+}
+
+
+/*
+ * call-seq:
+ * zdd1.same?(zdd2) -> bool : 等価比較
+ * zdd1 === (zdd2) -> bool : 等価比較
+ *
+ * bool : Qtrue or Qfalse
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1とzdd2を比較し、同じならtrue、異なるならfalseを返す
+ *
+ * === 関連
+ * diff?
+ */
+ VALUE vsop_same(int argc, VALUE *argv,VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,"10",&v);
+
+ CtoI *ctoi_modc = value2ctoi(v);
+ if ( *rmod->cmod == *ctoi_modc){
+ return Qtrue;
+ }
+ else{
+ return Qfalse;
+ }
+}
+
+/*
+ * call-seq:
+ * zdd1.diff?(zdd2) -> bool : 不等価比較
+ *
+ * bool : Qtrue or Qfalse
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1とzdd2を比較し、同じならfalse、異なるならtrueを返す
+ *
+ * === 関連
+ * same? ,===
+ */
+VALUE vsop_diff(int argc, VALUE *argv,VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,"10",&v);
+
+ CtoI *ctoi_modc = value2ctoi(v);
+ if ( *rmod->cmod != *ctoi_modc){
+ return Qtrue;
+ }
+ else{
+ return Qfalse;
+ }
+}
+
+
+/*
+ * call-seq:
+ * zdd.size -> nodeSize : ZDD節点数
+ *
+ * zdd : ZDD Object
+ * nodeSize : Ruby Integer
+ *
+ * === 説明
+ * zddの節点数を返す。
+ *
+ * === 例
+ * > a=5*ZDD.ƒ("a b c")-3*ZDD.itemset("a b")+2*ZDD.itemset("b c")+1*ZDD.itemset("c")
+ * > a.show
+ * 5 a b c - 3 a b + 2 b c + c
+ *
+ * > puts a.size
+ * 10
+ *
+ * === 関連
+ * totalsize
+ */
+VALUE vsop_print_size( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ int val = rmod->cmod->Size();
+ return INT2NUM(val);
+}
+
+/*
+ * call-seq:
+ * ZDD.totalsize -> nodeSize : 処理系全体のZDD節点数
+ *
+ * nodeSize : Ruby Integer
+ *
+ * === 説明
+ * 動作中のrubyインタープリタ上で構築された全ZDDオブジェクトの節点数を返す。
+ *
+ * === 例
+ * > a=5*ZDD.itemset("a b c")-3*ZDD.itemset("a b")+2*ZDD.itemset("b c")+1*ZDD.itemset("c")
+ * > a.show
+ * 5 a b c - 3 a b + 2 b c + c
+ * > puts a.size
+ * 10
+ * > puts ZDD.totalsize
+ * 10
+ *
+ * > b=-3*ZDD.itemset("a c")
+ * > b.show
+ * - 3 a c
+ * > puts b.size
+ * 5
+ * > puts ZDD.nodesize
+ * 14
+ *
+ * === 関連
+ * size
+ */
+VALUE vsop_print_totalsize(VALUE self){
+ rb_gc();
+ BDD_GC();
+ VALUE rtn = INT2NUM(BDD_Used());
+
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.count -> numItemsets : 項数計算
+ *
+ * numItemsets : Ruby Integer
+ *
+ * === 説明
+ * zddに格納された項の数(アイテム集合の数)を返す。
+ *
+ * === 例
+ * > A=ZDD.itemset("a")
+ * > B=ZDD.itemset("b")
+ * > F=A+B+A*B
+ * > F.show
+ * a b + a + b
+ * > puts F.count
+ * 3
+ *
+ * > G=A+B+A*B+1
+ * > G.show
+ * a b + a + b + 1
+ * > puts G.count
+ * 4
+ *
+ * > c=ZDD.constant(0)
+ * > puts c.count
+ * 0
+ *
+ * > d=ZDD.constant(1)
+ * > puts d.count
+ * 1
+ */
+
+VALUE vsop_print_count( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ *ctoitmp = ctoitmp -> CountTerms();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"06Memory overflow");
+ }
+ int slen = ctoitmp->TopDigit() / 3 + 14;
+ kgAutoPtr2<char> a_ptr;
+ char *s;
+ try{
+ a_ptr.set(new char[slen]);
+ s = a_ptr.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ ctoitmp -> StrNum10(s);
+// VALUE rtn = LL2NUM(atoll(s));
+ VALUE rtn = rb_cstr_to_inum(s, 10, Qfalse);
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.density -> dens : ZDDの濃度計算
+ *
+ * dens : Ruby Float
+ *
+ * === 説明
+ * 濃度とは、登録されている全アイテムから構成可能なアイテム集合の総数に対するzddに格納されたアイテム集合の数の割合と定義される。
+ *
+ * === 例
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ *
+ * # a,b,cの3アイテムを使った全組合せ数は8通り。
+ * # 以下で、Fにはそのすべての組合せが格納されているので濃度は1.0となる。
+ * > F=(a+1)*(b+1)*(c+1)
+ * > F.show
+ * a b c + a b + a c + a + b c + b + c + 1
+ * > puts F.density
+ * 1.0
+ *
+ * # 以下で、Fには1通りの組合せ(a b)が格納されているので濃度は1/8=0.125となる。
+ * > F=a*b
+ * > F.show
+ * a b
+ * > puts F.density
+ * 0.125
+ *
+ * # 以下で、Fには3通りの組合せ(a b,a,b)が格納されているので濃度は3/8=0.375となる。
+ * > F+=a
+ * > F+=b
+ * > F.show
+ * a b + a + b
+ * > puts F.density
+ * 0.375
+ */
+
+VALUE vsop_print_density( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"07Memory overflow");
+ }
+ int d = Density(ctoitmp -> GetZBDD(), VTable.Used());
+ if(d == 0 && *ctoitmp != 0){
+ rb_raise(rb_eRuntimeError,"Bit underflow occurred");
+ }
+ VALUE rtn = rb_float_new((float)d / power30);
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.value -> cost : アイテムの値による式の評価
+ *
+ * cost : Ruby Float
+ *
+ * === 説明
+ * アイテムに設定された値(symbolメソッドを参照のこと)をzddの各アイテムに代入したときの式の値を返す(この値をコストと呼ぶ)。
+ *
+ * === 例
+ * # シンボルa, b, cに値1.0, 0.5, 1.8をそれぞれ与える。
+ * > ZDD.symbol("a",1.0)
+ * > ZDD.symbol("b",0.5)
+ * > ZDD.symbol("c",2.0)
+ *
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ *
+ * # 式は1つのシンボルaから構成されa=1.0
+ * > puts a.value
+ * a
+ * > puts f.value
+ * 1.5
+ *
+ * # 式"a b"にa=1.0,b=0.5を代入すると1.0*0.5=0.5
+ * > f*=b
+ * > f.show
+ * a b
+ * > puts f.value
+ * 0.5
+ *
+ * # 式"a b + 2 a + c + 3"にa=1.0,b=0.5,c=2.0を代入すると 1.0*0.5+2*1.0+2.0+3=7.5
+ * > f+=2*a + c + 3
+ * > f.show
+ * a b + 2 a + c + 3
+ * > puts f.value
+ * 7.5
+ *
+ * === 関連
+ * itemset,maxcover,maxcost,mincover,mincost
+ */
+
+VALUE vsop_print_value( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ if(OVF.Check()!= 0){
+ rb_raise(rb_eRuntimeError,"Bit overflow occurred");
+ }
+ VALUE rtn = rb_float_new((float)Value(*ctoitmp)/power16);
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.maxcover -> self : コスト最大のアイテム集合の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれるアイテム集合の中で、コストが最大となるアイテム集合を表示する。
+ * そのコストの値を表示するにはzdd.maxcostを用いる。
+ *
+ * === 例
+ * > ZDD.symbol("a",1.0)
+ * > ZDD.symbol("b",0.5)
+ * > ZDD.symbol("c",2.0)
+ *
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ *
+ * > f=a*b + b*c + c*a
+ * > f.show
+ * # a b のコスト=1.0+0.5=1.5
+ * # b c のコスト=0.5+2.0=2.5
+ * # c a のコスト=2.0+1.0=3.0
+ * > puts f.maxcover
+ * a c
+ * > puts f.maxcost
+ * 3.0
+ * > puts f.mincover
+ * a b
+ * > puts f.mincost
+ * 1.5
+ *
+ * === 関連
+ * symbol
+ * value
+ * maxcost
+ * mincover
+ * mincost
+ */
+VALUE vsop_print_maxcover(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ //引数読み込み
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"08Memory overflow");
+ }
+ if(*ctoitmp == 0){
+ bout << " 0";
+ }
+ else
+ {
+ ZBDD f = ctoitmp -> GetZBDD();
+ if(MaxCost(f)==0){
+ bout << " 1";
+ }
+ else
+ {
+// bout << "<Items>: ";
+ while(1)
+ {
+ int var = f.Top();
+ if(var == 0) break;
+ ZBDD f0 = f.OffSet(var);
+ ZBDD f1 = f.OnSet0(var);
+ int c1 = MaxCost(f1) + VTable.GetValue(var);
+ if(MaxCost(f0) < c1)
+ {
+ bout << VTable.GetName(var);
+ bout.Delimit();
+ f = f1;
+ }
+ else f = f0;
+ }
+ }
+ }
+ bout.Return();
+ bout.Unset();
+
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.maxcost -> cost : コスト最大のアイテム集合のコスト値を返す
+ *
+ * zdd : ZDD Object
+ * cost : Ruby Float
+ *
+ * === 説明,例
+ * maxcoverメソッドを参照のこと。
+ *
+ * === 関連
+ * symbol
+ * value
+ * maxcover
+ * mincover
+ * mincost
+ */
+VALUE vsop_print_maxcost( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"09Memory overflow");
+ }
+ VALUE rtn;
+ if(*ctoitmp == 0){
+ rtn = Qnil;
+ }
+ else
+ {
+ int c = MaxCost(ctoitmp -> GetZBDD());
+ rtn = rb_float_new((float)c/power16);
+ }
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.mincover -> self : コスト最小のアイテム集合の表示
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明,例
+ * maxcoverメソッドを参照のこと。
+ *
+ * === 関連
+ * symbol
+ * value
+ * maxcover
+ * maxcost
+ * mincost
+ */
+VALUE vsop_print_mincover(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"10Memory overflow");
+ }
+ if(*ctoitmp == 0){
+ bout << " 0";
+ }
+ else
+ {
+ ZBDD f = ctoitmp -> GetZBDD();
+ if(MinCost(f)==0){
+ bout << " 1";
+ }
+ else
+ {
+// bout << "<Items>: ";
+ while(1)
+ {
+ int var = f.Top();
+ if(var == 0) break;
+ ZBDD f0 = f.OffSet(var);
+ ZBDD f1 = f.OnSet0(var);
+ int c1 = MinCost(f1) + VTable.GetValue(var);
+ if(MinCost(f0) > c1)
+ {
+ bout << VTable.GetName(var);
+ bout.Delimit();
+ f = f1;
+ }
+ else f = f0;
+ }
+ }
+ }
+ bout.Return();
+ bout.Unset();
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.mincost -> cost : コスト最小のアイテム集合のコストを返す
+ *
+ * zdd : ZDD Object
+ * cost : Ruby Float
+ *
+ * === 説明,例
+ * maxcoverメソッドを参照のこと。
+ *
+ * === 関連
+ * symbol
+ * value
+ * maxcover
+ * maxcost
+ * mincover
+ */
+VALUE vsop_print_mincost( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ rb_raise(rb_eRuntimeError,"11Memory overflow");
+ }
+ VALUE rtn;
+ if(*ctoitmp == 0){
+ rtn = Qnil;
+ }
+ else
+ {
+ int c = MinCost(ctoitmp -> GetZBDD());
+ rtn = rb_float_new((float)c/power16);
+ }
+ return rtn;
+}
+
+/*
+ * call-seq:
+ * zdd.decomp([fileName]) -> self : 単純直交分解形式での出力
+ *
+ * zdd : ZDD Object
+ * fileName : Ruby String
+ *
+ * === 説明
+ * zddを単純直交分解(simple disjoint decomposition)形式で出力する。
+ * fileNameの指定があれば、そのファイルに出力する。
+ * 省略すれば標準出力に出力する。
+ *
+ * === 例
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ *
+ * > f1=(a*b*c)
+ * > f1.show
+ * a b c
+ * > f1.decomp
+ * AND( a b c )
+ * # a,b,cのANDということでa*b*c=a b c
+ *
+ * > f2=((a*b*c)+(a*b))
+ * > f2.show
+ * a b c + a b
+ * > f2.decomp
+ * AND( a b OR( c 1 ) )
+ * # c,1のORにて(c+1)、それとa bとのANDで(a b)*(c+1)=a b c + a b
+ *
+ * > f3=((a*b*c)+(a*b)+(b*c))
+ * > f3.show
+ * a b c + a b + b c
+ * > f3.decomp
+ * AND( [ a c ] b )
+ * # [ a c ]はaとcによる全組合せ集合、すなわち(a c + a + c)。
+ * # それとbとのANDで b*(a c + a + c) = a b c + a b + b c
+ *
+ * > f4=((a*b*c)+(a*b)+(b*c)+(c*a))
+ * > f4.show
+ * a b c + a b + a c + b c
+ * > f4.decomp
+ * [ a b c ]
+ * # [ a b c ]はa,b,cによる全組合せ集合、すなわち(a b c + a b + b c + c a)
+ */
+
+VALUE vsop_print_decomp(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE *v;
+ rb_scan_args(argc, argv,"01",&v);
+ if(argc!=0){
+ if(TYPE(v)==T_STRING){
+ char *str = RSTRING_PTR(v);
+ bout.Set(str);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (arguments must be STRING)");
+ }
+ }
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ if(PrintDecomp(*ctoitmp) == 1)
+ {
+ rb_raise(rb_eRuntimeError,"12Memory overflow");
+ }
+ bout.Unset();
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.export([fileName]) : ZDDのエキスポート
+ *
+ * zdd : ZDD Object
+ * fileName : Ruby String
+ *
+ * === 説明
+ * zddオブジェクトのZDD内部構造をテキストで出力する。
+ * fileNameを指定すれば、そのファイルに出力する。
+ * 省略すれば標準出力に出力する。
+ *
+ * === 例
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ * > f=5*a*b*c+3*a*b++2*b*c+c
+ * > f.show
+ * 5 a b c + 3 a b + 2 b c + c
+ *
+ * > f.export
+ * _i 3
+ * _o 3
+ * _n 7
+ * 4 1 F T
+ * 248 2 F 5
+ * 276 3 4 248
+ * 232 2 F 4
+ * 2 2 F T
+ * 272 3 232 2
+ * 268 3 232 248
+ * 276
+ * 272
+ * 268
+ */
+VALUE vsop_print_export(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+ FILE *fp=NULL;
+ if(argc==1){
+ VALUE v1;
+ rb_scan_args(argc, argv,"0*",&v1);
+ if(TYPE(RARRAY_PTR(v1)[0])==T_STRING){
+ char *str = RSTRING_PTR(RARRAY_PTR(v1)[0]);
+ fp = fopen(str, "w");
+ if(fp == NULL){
+ rb_raise(rb_eRuntimeError,"Can't open the file");
+ }
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ }
+ else if(argc!=0){
+ rb_raise(rb_eRuntimeError,"number of argument is 0 or 1 ");
+ }
+
+ int d = ctoitmp -> TopDigit();
+ ZBDDV v = ZBDDV();
+ for(int i=0; i<=d; i++){
+ v += ZBDDV(ctoitmp -> Digit(i).GetZBDD(), i);
+ }
+
+ if(fp){
+ v.Export(fp);
+ fclose(fp);
+ }else{
+ v.Export();
+ }
+ return self;
+}
+
+/*
+ * call-seq:
+ * zdd.show([switch] [,fileName]) : 出力及び表示用メソッド
+ *
+ * zdd : ZDD Object
+ * switch : Ruby String
+ *
+ * === 説明
+ * string1でスイッチを指定し出力形式を決定する。exportを指定した場合のみstring2を指定可能(ファイル名)
+ *
+ * switchの内容 : 機能
+ * * (スイッチ無し) : 式のカッコを展開した積和形での表示
+ * * /bit : 重みの(-2)進数の各桁別アイテム集合の表示(bitメソッドに同じ)
+ * * /hex : 整数値を 16 進数で表現する積和形表示(hexメソッドに同じ)
+ * * /map : カルノー図で表示。アイテム変数6個まで表示できる(mapメソッドに同じ)
+ * * /rmap : カルノー図で表示。冗長なアイテム変数は省いて表示(rmapメソッドに同じ)
+ * * /case : 整数値ごとに場合分けして積和形表示(caseメソッドに同じ)
+ * * /size : 計算結果のBDD節点数(および処理系全体の節点数)を表示(sizeメソッドに同じ)
+ * * /count : 式に現れる(0 以外の値を持つ)組合せの個数を表示(countメソッドに同じ)
+ * * /density : 集合の濃度(0 以外の値を持つ組合せの比率)を表示(densityメソッドに同じ)
+ * * /value : シンボル変数にすべて数値を代入したときの式の値を表示(valueメソッドに同じ)
+ * * /maxcover : 式に含まれる(0 以外の値を持つ)コスト最大の組合せを1つ表示(maxcoverメソッドに同じ)
+ * * /maxcost : コスト最大組合せのコスト値を表示(maxcostメソッドに同じ)
+ * * /mincover : 式に含まれる(0 以外の値を持つ)コスト最小の組合せを1つ表示(mincoverメソッドに同じ)
+ * * /mincost : コスト最小組合せのコスト値を表示(mincostメソッドに同じ)
+ * * /plot : BDDの形を図示する。(使用不可)
+ * * /decomp : 単純直交分解形式での出力
+ * * /export : BDDの形を図示する(否定枝不使用)。string2に指定があれば、指定されたファイルに出力(exportメソッドに同じ)
+ *
+ * === 関連
+ * bit hex map rmap case size count density value maxcover mincover mincost decomp export
+ */
+VALUE vsop_show(int argc, VALUE *argv, VALUE self){
+ VALUE rtnval;
+ if(argc == 0){
+ rtnval = vsop_print(self);
+ }
+ else if(argc == 1) {
+ VALUE v;
+ rb_scan_args(argc, argv,"10",&v);
+ if(TYPE(v)!=T_STRING){
+ rb_raise(rb_eRuntimeError,"argument type error (1st argument must be STRING)");
+ }
+ char *argtmp = RSTRING_PTR(v);
+ int len = strlen(argtmp);
+ char *str_c;
+ if(*argtmp=='/'){
+ str_c = new char[len];
+ strcpy(str_c,argtmp+1);
+ }
+ else{
+ str_c = new char[len+1];
+ strcpy(str_c,argtmp);
+ }
+ rtnval = vsop_print_arg1(self,str_c);
+
+ }
+ else if(argc == 2)
+ {
+ rtnval = vsop_print_arg2(argc,argv,self);
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"number of argument is 0 or 1 or 2");
+ }
+ return rtnval;
+}
+
+/*
+ * call-seq:
+ * ZDD.partly -> bool : 部分hash出力フラグ
+ *
+ * bool : Qtrue or Qfalse
+ *
+ * === 説明
+ * hashoutメソッドにて全データをセット出来なかった場合、このメソッドはtrueを返す。
+ *
+ * === 関連
+ * hashout
+ */
+VALUE vsop_partly(VALUE self){
+ return rb_iv_get(self,"@partly");
+}
+
+//強制変換用
+VALUE vsop_coerce(int argc, VALUE *argv, VALUE self){
+ VALUE v;
+ Vsop_Ruby* rmod=new Vsop_Ruby;
+ rb_scan_args(argc, argv,"10",&v);
+ rmod->cmod =value2ctoi(v);
+ VALUE rtn_v = Data_Wrap_Struct(rb_class_of(self),0,free_rmod,rmod);
+ return rb_ary_new3(2,rtn_v,self);
+}
+
+/*
+ * call-seq:
+ * zdd.to_i -> int : ZDDの重みをRuby整数に変換
+ *
+ * int : Ruby Integer
+ *
+ * === 説明
+ * ZDD重みオブジェクト(空のアイテム集合の重み)をruby整数に変換する。重みオブジェクトでないZDDオブジェクトに適用した場合はnilを返す。
+ *
+ * === 例
+ * > c=ZDD.constant(10)
+ * > c.show # ZDD重みオブジェクト
+ * 10
+ * > puts c.to_i # ruby整数
+ * 10
+ * a=ZDD.itemset("a") # ZDDアイテム集合オブジェクトに対して適用するとnil
+ * a.to_i
+ * nil
+ *
+ * === 関連
+ * constant
+ */
+
+VALUE vsop_const_to_i(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+
+ if(rmod->cmod->IsConst()){
+ int val = rmod->cmod->GetInt();
+ return INT2NUM(val);
+ }else{
+ return Qnil;
+ }
+}
+
+
+void Init_zdd_so() {
+/*
+ * Document-class: ZDD
+ * = ZDDを動作させるモジュール
+ * (version: ##version##.##revision##)
+ *
+ * === 0.概要
+ * ZDD(Zero-suppressed Binary Decision Diagrams: ゼロサプレス型二分決定グラフ)を利用し、
+ * 重み付きのアイテムの組み合わせ集合をコンパクトに格納することを可能とするZDD
+ * (Valued-Sum-Of-Products calculator)をruby拡張ライブラリとして実装したもの。
+ * ZDDオブジェクトに対する演算子(`+',`-',`=='など)の多くは、ZDD演算としてオーバーロードしており、
+ * ZDDの各種機能とrubyの制御などの各種機能をシームレスに組み合わせて利用することを可能としている。
+ *
+ * 本マニュアルはRDocとしても提供されているので、コマンドライン上からも閲覧可能である。
+ * ----
+ * $ ri ZDD # ZDDモジュール全体のマニュアルの閲覧
+ * $ ri ZDD.symbol # symbolメソッドの閲覧
+ * ----
+ *
+ * 注: 本モジュールは開発途上であり、本文書の仕様は予告なしに変更することがある。
+ *
+ * 科学技術振興機構 ERATO湊離散構造系プロジェクト 関西サテライトラボ
+ *
+ * === 1.はじめよう!(チュートリアル)
+ * 以下では、4つのアイテムの全組合せ集合を列挙する方法を示す。
+ * rubyスクリプトを記述して実行してもよいし、irbで一行ずつ実行してもよい。
+ * ZDD ruby拡張ライブラリが既に正しくインストールされており、またrubyについての基本的な知識があることを前提としている。
+ *
+ * 注:本マニュアルでの例で使われている記号の意味は以下の通り。
+ * ">" : rubyのメソッド入力を表す。
+ * "$" : シェルのコマンドライン入力を表す。
+ * "#" : コメントを表す。
+ * 記号なし : 実行結果を表す。
+ *
+ * ==== 1-1. ZDD ruby拡張ライブラリのrequire
+ * vsop ruby拡張ライブラリはrubygemsを使ってパッケージングされているので、以下の通りrubygemsをrequireした後にvsopをrequireする。
+ *
+ * ----
+ * > require 'rubygems'
+ * > require 'zdd'
+ * ----
+ *
+ * ==== 1-2. 利用するアイテムの宣言
+ * 利用するアイテム名を宣言するためにZDD.symbolメソッドを利用する。一つのメソッドで一つのアイテムが宣言できる。
+ * アイテム宣言の順序は重要で、その順序がZDDの木構造における根からのレベルに対応する。宣言の順序により異なる構造のZDDが作成され、よってそのサイズに大幅に影響を与えることがある。
+ * 以下では、"a","b","c","d"という名前の4つのアイテムを宣言している。
+ *
+ * ----
+ * > ZDD.symbol("a")
+ * > ZDD.symbol("b")
+ * > ZDD.symbol("c")
+ * > ZDD.symbol("d")
+ * ----
+ *
+ * ==== 1-3. アイテムの定義
+ * symbolでは単に利用するアイテムを宣言しただけなので、次に、それらのアイテムから構成されるアイテム集合の定義、すなわちZDDオブジェクトを作成していく。
+ * 以下では、1つのアイテムから構成されるアイテム集合を作る。次のステップで、それらのアイテム集合に対して様々な演算を加えることで全組合せを列挙する。
+ *
+ * ----
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ * > d=ZDD.itemset("d")
+ * ----
+ *
+ * 最初の行は、"a"というアイテムから構成されるアイテム集合のZDDオブジェクトがruby変数aに格納される。以下同様にb,c,dの変数にもZDDオブジェクトが格納される。
+ *
+ * ==== 1-4. 演算
+ * ZDDで定義されている様々な演算を利用してアイテム集合を変換していく。
+ * 以下のような式を入力すると、4つのアイテムa,b,c,dの全組合せが列挙されることになる。
+ * 式の展開方法は、以下のケースにおいては、一般的な多項式の展開方法と同様に考えれば良い。
+ * 右辺の演算結果として構築されたZDDオブジェクトがruby変数fに代入されている。
+ * そしてZDDオブジェクトの内容を表示するshowメソッドにより表示する。
+ * showはZDDオブジェクトの内容を重み付き積和形で表示するメソッドである。
+ * 最後の項の"1"は空集合の係数である。
+ *
+ * ----
+ * > f=(a+1)*(b+1)*(c+1)*(d+1)
+ * > f.show
+ * a b c d + a b c + a b d + a b + a c d + a c + a d + a + b c d + b c +
+ * b d + b + c d + c + d + 1
+ * ----
+ *
+ * 他にも、2つほど異なる演算結果を示す。なぜこのような結果になるかは本マニュアルの"*"演算子(乗算)を参照のこと。
+ *
+ * ----
+ * > g=(a+b)*(b+c)*(c+d)*(d+a)
+ * > g.show
+ * 2 a b c d + 3 a b c + 3 a b d + 3 a c d + a c + 3 b c d + b d
+ *
+ * > h=(a+1)*(a+1)*(a+1)*(a+1)
+ * > h.show
+ * 15 a + 1
+ * ----
+ *
+ * === 2. 様々な用法
+ * 以下では、よく利用するメソッドを中心にして、vsopライブラリの様々な用法について学ぶ。
+ *
+ * ==== 2-1. symbolメソッドによる宣言なしにitemsetメソッドを使う
+ * ZDD.symbolメソッドは利用するアイテムの宣言に利用するが、これは省くことができる。省略した場合は、itemsetメソッドで定義されたアイテムの登場順にsymbolで宣言することに等しい。
+ *
+ * ----
+ * > a=ZDD.itemset("a")
+ * > b=ZDD.itemset("b")
+ * > c=ZDD.itemset("c")
+ * > ZDD.itemset # itemsetメソッドを引き数なしで呼び出すと、宣言されたアイテムがその順番で表示される。
+ * a b c
+ *
+ * > a=ZDD.itemset("a")
+ * > c=ZDD.itemset("c")
+ * > b=ZDD.itemset("b")
+ * > ZDD.itemset
+ * a c b
+ * ----
+ *
+ * ==== 2-2. アイテム集合のZDDオブジェクトを一行で生成する方法
+ * ZDD.itemsetメソッドにアイテム名をスペース区切りで列挙することでアイテム集合のZDDオブジェクトを作成することができる。
+ *
+ * ----
+ * # 3つのアイテム`a',`b',`c'で構成されるアイテム集合{a,b,c}を表すZDDオブジェクトをrubyの変数`a'にセットする。
+ * > a=ZDD.itemset("a b c")
+ * > a.show
+ * a b c
+ * ----
+ *
+ * ==== 2-3. 重みの定義
+ * 重みを表す整数値定数項(空のアイテム集合の重み)はconstantメソッドを利用する。
+ *
+ * ----
+ * > a=ZDD.itemset("a b c")
+ * > q=ZDD.constant(4) # 重み4の空のアイテム集合ZDDオブジェクトが作成されruby変数qに格納される。
+ * > (q*a).show
+ * 4 a b c
+ * ----
+ *
+ * ==== 2-4. ZDDオブジェクトに対する演算
+ * ZDDオブジェクトを一つでも引数に持つ演算子はオーバーロードされたZDD演算子となる。
+ *
+ * ----
+ * > a=ZDD.itemset("a b c") # rubyの変数`a'はZDDオブジェクト
+ * > (4*a).show # よって`*'はZDD演算子として機能し、ruby整数`4'は自動的にZDDオブジェクトに型変換される。
+ * 4 a b c # 内部的には、(ZDD.constant(4)*a).show を実行している。
+ * > (a+"a b").show # ruby文字列"a b"は自動的にZDDオブジェクトに変換される。
+ * a b c + a b # 内部的には、(a+ZDD.itemset("a b")).show を実行している。
+ * > a="a b"+"c d" #これは演算子の引数が二つともrubyのStringオブジェクトであるため、単なる文字列の結合となってしまう。
+ * ----
+ *
+ * ==== 2-5. 制御文との組合せ
+ * 制御文と組み合わせると以下のような書き方も可能である
+ *
+ * ----
+ * > z=ZDD.constant(0)
+ * > ["a","b","c"].each{|item|
+ * > z += item # `z'はZDDオブジェクトなので、それに対する`+'演算はZDD演算子となる。
+ * > }
+ * > z.show
+ * a + b + c
+ *
+ * > z=ZDD.constant(0)
+ * > (1..5).each{|i|
+ * > z += "item_#{i}"
+ * > }
+ * > z.show
+ * item_1 + item_2 + item_3 + item_4 + item_5
+ * ----
+ *
+ * === 3.環境変数
+ * 以下の環境変数を設定することでデフォルトの動作を変更することができる
+ * ZDDLimitNode
+ * 最大節点数 デフォルト値:1000000
+ * ZDDWarning
+ * 警告メッセージ出力 設定すると数値文字をアイテムに使用使用とした場合に警告メッセージが出力される
+ *
+ */
+ //環境変数取得
+ char *envStr;
+ envStr=getenv("ZDDLimitNode");
+ if(envStr!=NULL){
+ env_nmax=atoi(envStr);
+ }else{
+ env_nmax=DEF_ENV_NMAX ;
+ }
+ envStr=getenv("ZDDWarning");
+ if(envStr!=NULL){
+ env_warning=true;
+ }else{
+ env_warning=false;
+ }
+
+
+ VALUE vsop_main=rb_define_module("ZDD");
+ //モジュール変数設定
+ rb_define_module_function(vsop_main, "itemset", RUBY_METHOD_FUNC(vsop_itemset), -1);
+ rb_define_module_function(vsop_main, "constant", RUBY_METHOD_FUNC(vsop_constant), -1);
+ rb_define_module_function(vsop_main, "symbol", RUBY_METHOD_FUNC(vsop_symbol), -1);
+ rb_define_module_function(vsop_main, "each", RUBY_METHOD_FUNC(vsop_each), 0);
+ rb_define_module_function(vsop_main, "each_item", RUBY_METHOD_FUNC(vsop_each_item), 0);
+
+ rb_define_module_function(vsop_main, "show", RUBY_METHOD_FUNC(vsop_show), -1);
+ rb_define_module_function(vsop_main, "lcm", RUBY_METHOD_FUNC(vsop_lcm), -1);
+ rb_define_module_function(vsop_main, "lcm_ub", RUBY_METHOD_FUNC(vsop_lcm_ub), -1);
+ rb_define_module_function(vsop_main, "permit", RUBY_METHOD_FUNC(vsop_permit), -1);
+ rb_define_module_function(vsop_main, "permitsym", RUBY_METHOD_FUNC(vsop_permitsym), -1);
+ rb_define_module_function(vsop_main, "restrict", RUBY_METHOD_FUNC(vsop_restrict), -1);
+ rb_define_module_function(vsop_main, "freqpatC", RUBY_METHOD_FUNC(vsop_freqpatC), -1);
+ rb_define_module_function(vsop_main, "freqpatM", RUBY_METHOD_FUNC(vsop_freqpatM), -1);
+ rb_define_module_function(vsop_main, "freqpatA", RUBY_METHOD_FUNC(vsop_freqpatA), -1);
+ rb_define_module_function(vsop_main, "termsLE", RUBY_METHOD_FUNC(vsop_termsLE), -1);
+ rb_define_module_function(vsop_main, "termsLT", RUBY_METHOD_FUNC(vsop_termsLT), -1);
+ rb_define_module_function(vsop_main, "termsGE", RUBY_METHOD_FUNC(vsop_termsGE), -1);
+ rb_define_module_function(vsop_main, "termsGT", RUBY_METHOD_FUNC(vsop_termsGT), -1);
+ rb_define_module_function(vsop_main, "termsNE", RUBY_METHOD_FUNC(vsop_termsNE), -1);
+ rb_define_module_function(vsop_main, "termsEQ", RUBY_METHOD_FUNC(vsop_termsEQ), -1);
+
+ rb_define_module_function(vsop_main, "<=", RUBY_METHOD_FUNC(vsop_le), -1);
+ rb_define_module_function(vsop_main, "<", RUBY_METHOD_FUNC(vsop_lt), -1);
+ rb_define_module_function(vsop_main, ">=", RUBY_METHOD_FUNC(vsop_ge), -1);
+ rb_define_module_function(vsop_main, ">", RUBY_METHOD_FUNC(vsop_gt), -1);
+ rb_define_module_function(vsop_main, "ne?", RUBY_METHOD_FUNC(vsop_ne), -1);
+ rb_define_module_function(vsop_main, "==", RUBY_METHOD_FUNC(vsop_eq), -1);
+ rb_define_module_function(vsop_main, "iif", RUBY_METHOD_FUNC(vsop_iif), -1);
+ //rb_define_module_function(vsop_main, "meet", RUBY_METHOD_FUNC(vsop_meet), -1);
+ rb_define_module_function(vsop_main, "same?", RUBY_METHOD_FUNC(vsop_same), -1);
+ rb_define_module_function(vsop_main, "===", RUBY_METHOD_FUNC(vsop_same), -1);
+ rb_define_module_function(vsop_main, "diff?", RUBY_METHOD_FUNC(vsop_diff), -1);
+ rb_define_module_function(vsop_main, "delta", RUBY_METHOD_FUNC(vsop_delta), -1);
+
+ rb_define_module_function(vsop_main, "+", RUBY_METHOD_FUNC(vsop_plus), -1);
+ rb_define_module_function(vsop_main, "-", RUBY_METHOD_FUNC(vsop_minus), -1);
+ rb_define_module_function(vsop_main, "+@", RUBY_METHOD_FUNC(vsop_plus_op), 0);
+ rb_define_module_function(vsop_main, "-@", RUBY_METHOD_FUNC(vsop_minus_op), 0);
+ rb_define_module_function(vsop_main, "*", RUBY_METHOD_FUNC(vsop_multiply), -1);
+ rb_define_module_function(vsop_main, "/", RUBY_METHOD_FUNC(vsop_quotiment), -1);
+ rb_define_module_function(vsop_main, "%", RUBY_METHOD_FUNC(vsop_remainder), -1);
+ rb_define_module_function(vsop_main, "csvout", RUBY_METHOD_FUNC(vsop_csvout), -1);
+ rb_define_module_function(vsop_main, "import", RUBY_METHOD_FUNC(vsop_import), -1);
+ rb_define_module_function(vsop_main, "hashout", RUBY_METHOD_FUNC(vsop_hashout), 0);
+ rb_define_module_function(vsop_main, "maxval", RUBY_METHOD_FUNC(vsop_maxval), 0);
+ rb_define_module_function(vsop_main, "minval", RUBY_METHOD_FUNC(vsop_minval), 0);
+ rb_define_module_function(vsop_main, "totalval", RUBY_METHOD_FUNC(vsop_totalval), 0);
+ rb_define_module_function(vsop_main, "items", RUBY_METHOD_FUNC(vsop_items), 0);
+ rb_define_module_function(vsop_main, "symgrp", RUBY_METHOD_FUNC(vsop_symgrp), 0);
+
+ rb_define_module_function(vsop_main, "map", RUBY_METHOD_FUNC(vsop_print_map), -1);
+ rb_define_module_function(vsop_main, "rmap", RUBY_METHOD_FUNC(vsop_print_rmap), -1);
+ rb_define_module_function(vsop_main, "hex", RUBY_METHOD_FUNC(vsop_print_hex), -1);
+ rb_define_module_function(vsop_main, "bit", RUBY_METHOD_FUNC(vsop_print_bit), -1);
+ rb_define_module_function(vsop_main, "case", RUBY_METHOD_FUNC(vsop_print_case), -1);
+ rb_define_module_function(vsop_main, "size", RUBY_METHOD_FUNC(vsop_print_size), 0);
+ rb_define_module_function(vsop_main, "totalsize", RUBY_METHOD_FUNC(vsop_print_totalsize), 0);
+ rb_define_module_function(vsop_main, "count", RUBY_METHOD_FUNC(vsop_print_count), 0);
+ rb_define_module_function(vsop_main, "density", RUBY_METHOD_FUNC(vsop_print_density), 0);
+ rb_define_module_function(vsop_main, "value", RUBY_METHOD_FUNC(vsop_print_value), 0);
+ rb_define_module_function(vsop_main, "maxcover", RUBY_METHOD_FUNC(vsop_print_maxcover), -1);
+ rb_define_module_function(vsop_main, "maxcost", RUBY_METHOD_FUNC(vsop_print_maxcost), 0);
+ rb_define_module_function(vsop_main, "mincover", RUBY_METHOD_FUNC(vsop_print_mincover), -1);
+ rb_define_module_function(vsop_main, "mincost", RUBY_METHOD_FUNC(vsop_print_mincost), 0);
+ rb_define_module_function(vsop_main, "decomp", RUBY_METHOD_FUNC(vsop_print_decomp), -1);
+ rb_define_module_function(vsop_main, "export", RUBY_METHOD_FUNC(vsop_print_export), -1);
+ rb_define_module_function(vsop_main, "partly", RUBY_METHOD_FUNC(vsop_partly), 0);
+ rb_define_module_function(vsop_main, "coerce", RUBY_METHOD_FUNC(vsop_coerce), -1);
+ rb_define_module_function(vsop_main, "to_i", RUBY_METHOD_FUNC(vsop_const_to_i), 0);
+ rb_define_module_function(vsop_main, "to_a", RUBY_METHOD_FUNC(vsop_to_a), 0);
+ rb_define_module_function(vsop_main, "to_s", RUBY_METHOD_FUNC(vsop_to_s), 0);
+ rb_define_module_function(vsop_main, "inspect", RUBY_METHOD_FUNC(vsop_to_s), 0);
+
+}