+++ /dev/null
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-\f
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-\f
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-\f
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-\f
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-\f
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
--- /dev/null
+
+version = 1.1
+
+# 共有ライブラリの拡張子を自動設定
+ifeq ($(shell uname),Linux)
+suffix=so
+else
+ifeq ($(shell uname),Darwin)
+suffix=bundle
+else
+$(error ERROR: unknown OS: `$(shell uname)')
+endif
+endif
+
+all: library mkgem
+
+install:
+ (cd gem && gem install mining-$(version).gem)
+ (cd gem/bin && install * /usr/local/bin)
+
+clean:
+ (cd lcm/lib && ruby extconf.rb && make clean)
+ (cd zdd/lib && ruby gensrc.rb && ruby extconf.rb && make clean)
+
+
+library:
+ (cd lcm/lib && gcc -O3 -D _NO_MAIN_ -c lcm_main.c -fPIC)
+ (cd lcm/lib && ruby extconf.rb && make)
+ (cd zdd/lib && sed -f lcm-vsop.ruby.sed < SAPPOROBDD/src/BDDLCM/lcm.c > xxcc && cat xxcc lcm-vsop_add.cc > SAPPOROBDD/src/BDDLCM/lcm-vsop.cc)
+ (cd zdd/lib && ruby gensrc.rb && ruby extconf.rb && make)
+
+mkgem:
+ sed 's/##version##/$(version)/' < gem/gemspec.temp | sed 's/##lib_suffix##/$(suffix)/g' >gem/gemspec ;
+ (cd gem && mkdir -p lib && mkdir -p bin)
+ (cp lcm/lib/lcm.$(suffix) gem/lib)
+ (cp zdd/lib/zdd_so.$(suffix) gem/lib)
+ (cp zdd/lib/zdd.rb gem/lib)
+ (cp take/lib/*.rb gem/lib)
+ (cp take/bin/*.rb gem/bin)
+ (cp burst/bin/*.rb gem/bin)
+ (cd gem && gem build gemspec)
+
+docs:
+
+
--- /dev/null
+#!/usr/bin/env ruby
+# encoding:utf-8
+
+require 'fileutils'
+require 'rubygems'
+require 'mcmd'
+
+$version=1.0
+
+def help
+
+STDERR.puts <<EOF
+----------------------------
+burst.rb version #{$version}
+----------------------------
+概要) HMMによるburst検知プログラム
+特徴) 1) 分布のパラメータの変化を検知する
+ 2) 確率分布としては指数分布、ポアソン分布、正規分布、二項分布に対応
+書式) burst.rb f= dist=exp|poisson|gauss|binom [s=] [p=] i= [o=] [--help]
+
+例) burst.rb f=interval dist=exp i=burstExp.csv o=output.csv
+
+ i= : 入力ファイル名【必須】
+ o= : 出力ファイル名【オプション:defaultは標準出力】
+ d= : デバッグ情報を出力するファイル【オプション】
+ dist= : 仮定する分布名称(exp:指数関数,poisson:ポアソン分布,gauss:正規分布,binom:二項分布)【必須】
+ f= : burst検知対象となる数値項目名(i=上の項目名)【必須】
+ param= : 定常状態における分布のパラメータ。注1参照【オプション】
+ pf= : 定常状態における分布のパラメータ項目名(i=上の項目名)注1参照【オプション】
+ s= : burstスケール(詳細は注2参照)【オプション:default=2.0】
+ p= : 同一状態遷移確率(この値を高くするとbusrtしにくくなる。詳細は注3参照)【オプション:default=0.6】
+
+ n= : dist=binomの場合の試行回数【n= or nf=いずれかを指定】
+ nf= : dist=binomの場合の試行回数の項目名
+ v= : dist=gaussの場合の分散値(指定がなければf=項目のデータから推定)
+ nv= : dist=gaussの場合の分散の項目名
+ --help : ヘルプの表示
+
+ 注1) 定常状態における分布のパラメータ(母数)の与え方は以下の3通り。
+ 1) para=で指定した値とする。
+ 2) pf=で指定した項目の値を用いる。時刻に依存してパラメータが異なることが仮定できる場合のため。
+ 3) para=,pf=の指定がなければ、f=で指定した値から自動的に計算される。
+
+ 注2) 定常状態、burst状態における分布パラメータの計算方法は以下のとおり。
+ S: s=で指定した値、n:データ件数、x_i: f=でしていした項目のi行目の値
+ exp: 確率密度関数f(x)=λ*exp(-λx)、パラメータはλ(平均イベント発生回数)
+ 定常(state0)状態λ0=n/Σx_i
+ burst(state1)状態λ1=λ0*S
+ poisson: 確率関数f(x)=λ^x*exp(-λ)/x!、パラメータはλ(平均イベント発生回数)
+ 定常(state0)状態λ0=Σx_i/n
+ burst(state1)状態λ1=λ0*S
+ gauss: 確率密度関数: f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2)、パラメータはμ(平均)
+ m=Σx_i/n、v=Σ(x_i-m)^2/nとすると、
+ 下側burst(state-)状態μ- =m-sqrt(v)*S
+ 定常(state0)状態μ0 =m
+ 上側burst(state+)状態μ+ =m+sqrt(v)*S
+ binom: 確率関数: f(x)=(T choose x)p^x(1-p)^(T-x):パラメータはp(成功確率)
+ 定常(state0)状態p0=(Σx_i/n)/T (平均成功回数/試行回数)
+ burst(state1)状態p1=S/((1-p0)/p0+S)
+
+ 注3) 状態遷移確率の設定方法。
+ p: p=で指定した値
+ exp, poisson, binom:
+ prob(state0→state0)=prob(state1→state1)
+ prob(state0→state1)=prob(state1→state0)=1-p
+ gauss:
+ prob(state-1→state-1)=prob(state0→state0)=prob(state1→state1)=p
+ prob(state0→state-1)=prob(state0→state1)=prob(state2→state2)=(1-p)/2
+ prob(state-1→state0)=prob(state1→state0)=(1-p)/3*2
+ prob(state-1→state1)=prob(state1→state-1)=(1-p)/3
+
+Copyright(c) NYSOL 2012- All Rights Reserved.
+EOF
+exit
+end
+
+help() if ARGV.size <= 0
+help() if ARGV[0]=="--help"
+
+# パラメータ設定
+args=MCMD::Margs.new(ARGV,"i=,o=,d=,f=,dist=,s=,p=,pf=,n=,nf=,v=,vf=,param=","i=,o=,f=,dist=")
+
+iFile = args.file("i=","r")
+dFile = args.file("d=","w",nil)
+oFile = args.file("o=","w")
+fName = args.field("f=",iFile)
+fName = fName["names"].join(",") if fName
+pName = args.field("pf=",iFile)
+pName = pName["names"].join(",") if pName
+nName = args.field("nf=",iFile)
+nName = nName["names"].join(",") if nName
+vName = args.field("vf=",iFile)
+vName = vName["names"].join(",") if vName
+
+distType = args.str("dist=")
+unless ["exp","poisson","gauss","binom"].index(distType)
+ raise "`dist=' takes `exp',`poisson',`gauss' or `binom'"
+end
+
+burstScale = args.float("s=",2.0)
+iProb = args.float("p=",0.6)
+trial = args.float("n=")
+var = args.float("v=")
+param = args.float("param=")
+
+if distType!="binom" and (trial or nName)
+ raise "`n=' or `nf=' is a parameter for binom burst."
+end
+
+if distType!="gauss" and (var or vName)
+ raise "`v=' or `vf=' is a parameter for gauss burst."
+end
+
+if distType=="binom"
+ if trial==nil and nName==nil
+ raise "`n=' or `nf=' have to be specified in binom burst."
+ end
+ if nName!=nil and not (param or pName)
+ raise "`param=' or `pf=' have to be specified with `nf=' in binom burst."
+ end
+end
+
+if distType=="gauss"
+ if (param!=nil and var==nil) or (param==nil and var!=nil)
+ raise "`param=' and `var=' have to be specified together in gaussian burst."
+ end
+end
+
+##########################
+module MDM
+
+class DistBurst
+ attr_reader :data
+ attr_reader :burstSymbol
+
+ def initialize(name)
+ @name=name
+ @data=[]
+ @dpar=nil
+ @dpar=[] if @parFld
+ # 入力ファイルを項目別にメモリにセット
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
+ csv.each{|flds|
+ v=flds[@valFld].to_f
+ p=flds[@parFld].to_f if @parFld
+ @data << v
+ @dpar << p if @parFld
+ }
+ }
+ # burst項目の出力シンボル。
+ # 状態0と状態1をburst項目として0,1として出力。
+ # このシンボル表を変更するのであれば継承クラスで独自に定義する。
+ @burstSymbol=["0","1"]
+ end
+
+ # 初期確率
+ # 2状態の確率分布のみ対応。それ以外は継承クラスで独自に定義する。
+ def initProbLn()
+ initProbLn=[ln(1.0), ln(0.0)]
+ return initProbLn
+ end
+
+ # 遷移確率
+ # 2状態の遷移確率のみ対応。それ以外は継承クラスで独自に定義する。
+ # to
+ # 0 1
+ # from 0 transProbLn[0][0] transProbLn[0][1]
+ # 1 transProbLn[1][0] transProbLn[1][1]
+ def calTransProbLn(inertiaProb)
+ transProbLn=[]
+ transProbLn << [ln( inertiaProb), ln(1.0-inertiaProb)]
+ transProbLn << [ln(1.0-inertiaProb), ln( inertiaProb)]
+ return transProbLn
+ end
+
+ # 自然対数の計算(ln(0)=-9999.0で定義
+ def ln(prob)
+ ret=-9999.0
+ if prob>0
+ ret=Math::log(prob)
+ end
+ return ret
+ end
+
+ def logsum(from,to)
+ sum=0.0
+ (from.to_i..to.to_i).each{|x|
+ sum+=Math::log(x)
+ }
+ return sum
+ end
+
+ def show(fpw=STDERR)
+ fpw.puts "### MDM::DistBurst class"
+ fpw.puts " 入力: #{@fname}, 値項目名:#{@valFld}"
+ fpw.puts " 確率(密度)関数名:#{@name}"
+ fpw.puts " データ件数: #{@data.size}"
+ fpw.puts " @data=#{@data.join(',')}"
+ end
+end
+
+#-----------------------------------------------------------
+# 指数分布(事象発生間隔分布)
+# λ: 時間あたりの事象の平均発生回数
+# x: 事象の発生間隔
+# f(x)=λe^{-λx}
+class ExpBurst < DistBurst
+ def initialize(fname,valFld,parFld,param)
+ @fname =fname
+ @valFld =valFld
+ @parFld =parFld
+ @param =param
+ super("exp")
+
+ # パラメータのセット
+ # 定常状態平均到着数
+ @term=0.0
+ @data.each{|v| @term+=v}
+
+ unless @parFld
+ if @param!=nil
+ @lamda=param
+ else
+ @lamda=@data.size.to_f/@term
+ end
+ end
+ end
+
+ # 指数分布の確率密度関数: f(x)=λexp(-λx)
+ # log f(x) = logλ - λx
+ def probFunc(x,lamda)
+ return Math::log(lamda) - lamda*x
+ end
+
+ def stateProbLn(burstScale)
+ @burstScale=burstScale
+ stateProbLn=[]
+ (0...@data.size).each{|i|
+ x=@data[i]
+ p=nil
+ if @dpar
+ p=@dpar[i]
+ else
+ p=@lamda
+ end
+ stateProbLn << [ probFunc(x,p), probFunc(x,p*@burstScale) ]
+ }
+ return stateProbLn
+ end
+
+ def show(fpw=STDERR)
+ super(fpw)
+ fpw.puts "### MDM::ExpBurst < DistBurst class"
+ fpw.puts " @lamda: #{@lamda}, @param: #{@param}"
+ fpw.puts " @dpar: #{@dpar}"
+ fpw.puts " @term : #{@term}"
+ end
+end
+
+#-----------------------------------------------------------
+# ポアソン分布(事象発生数分布)
+# λ: 時間あたりの事象の平均発生回数
+# x: 事象の発生間隔
+# 確率関数: f(x)=λ^x*exp(-λ)/x!
+class PoissonBurst < DistBurst
+ def initialize(fname,valFld,parFld,param)
+ @fname =fname
+ @valFld =valFld
+ @parFld =parFld
+ @param =param
+ super("poisson")
+
+ # パラメータのセット
+ # 定常状態平均到着数
+ @count=0.0
+ @data.each{|v| @count+=v}
+
+ unless @parFld
+ if @param!=nil
+ @lamda=param
+ else
+ @lamda=@count/@data.size.to_f
+ end
+ end
+ end
+
+ # ポアソン分布の確率関数
+ # f(x)=λ^x/x!*exp(-λ)
+ # log f(x) = x*logλ-λ-Σ_{i=1..x}i
+ def probFunc(x,lamda)
+ if x==0 # 0!=1のため
+ return -lamda
+ else
+ return x*Math::log(lamda) - Math::log((1.0+x)*x/2.0) - lamda
+ end
+ end
+
+ def stateProbLn(burstScale)
+ @burstScale=burstScale
+ stateProbLn=[]
+ (0...@data.size).each{|i|
+ x=@data[i]
+ p=nil
+ if @dpar
+ p=@dpar[i]
+ else
+ p=@lamda
+ end
+ stateProbLn << [ probFunc(x,p), probFunc(x,p*@burstScale) ]
+ }
+ return stateProbLn
+ end
+
+ def show(fpw=STDERR)
+ super(fpw)
+ fpw.puts "### MDM::PoissonBurst < DistBurst class"
+ fpw.puts " @lamda: #{@lamda}, @param: #{@param}"
+ fpw.puts " @dpar: #{@dpar}"
+ fpw.puts " @count: #{@count}"
+ end
+end
+
+#-----------------------------------------------------------
+# 正規分布(誤差分布)
+# mean: 平均
+# var: 分散
+# 確率密度関数: f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2
+class GaussBurst < DistBurst
+ def initialize(fname,valFld,parFld,param,varFld,var)
+ @fname =fname
+ @valFld =valFld
+ @parFld =parFld
+ @param =param
+ super("gauss")
+
+ # パラメータのセット
+ # 定常状態平均値と不偏分散
+ @mean=nil
+ @var=nil
+ if @parFld
+ @var=[]
+ # 分散項目読み込み
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
+ csv.each{|flds|
+ v=flds[varFld].to_f
+ @var << v
+ }
+ }
+ else
+ if @param!=nil
+ @mean=@param
+ @var=var
+ else
+ @mean=0.0
+ @var=0.0
+ @data.each{|v| @mean+=v}
+ @mean/=@data.size.to_f
+ @data.each{|v| @var+=(v-@mean)**2}
+ @var/=(@data.size-1).to_f
+ end
+ end
+
+ # gauss分布burstでは、状態0,1,2を-1,0,1で出力
+ @burstSymbol=["-1","0","1"]
+ end
+
+ # 初期確率
+ def initProbLn()
+ initProbLn=[ln(0.0), ln(1.0), ln(0.0)]
+ return initProbLn
+ end
+
+ # 遷移確率
+ # to
+ # - 0 +
+ # - transProbLn[0][0] transProbLn[0][1] transProbLn[0][2]
+ # from 0 transProbLn[1][0] transProbLn[1][1] transProbLn[1][2]
+ # + transProbLn[2][0] transProbLn[2][1] transProbLn[2][2]
+ def calTransProbLn(inertiaProb)
+ transProbLn=[]
+ transProbLn << [ln( inertiaProb ), ln((1.0-inertiaProb)/3.0*2.0), ln((1.0-inertiaProb)/3.0)]
+ transProbLn << [ln((1.0-inertiaProb)/2.0), ln( inertiaProb ), ln((1.0-inertiaProb)/2.0)]
+ transProbLn << [ln((1.0-inertiaProb)/3.0), ln((1.0-inertiaProb)/3.0*2.0), ln( inertiaProb )]
+ return transProbLn
+ end
+
+ # 正規分布の確率密度関数
+ # f(x)= 1/√2πσ^2 exp(-(x-μ)^2/2σ^2
+ # log f(x) = log1 - (1/2)log(2πσ^2) - (x-u)^2/2σ^2
+ def probFunc(x, mu, sigma2)
+ return Math.log(1.0)-Math.log(2.0*Math::PI*sigma2)/2.0-((x-mu)**2.0)/(2.0*sigma2)
+ end
+
+ def stateProbLn(burstScale)
+ @burstScale=burstScale
+ stateProbLn=[]
+ (0...@data.size).each{|i|
+ x=@data[i]
+ p=nil
+ if @dpar
+ p=@dpar[i]
+ v=@var[i]
+ else
+ p=@mean
+ v=@var
+ end
+ stateProbLn << [ probFunc(x,p-Math.sqrt(v)*burstScale,v), probFunc(x,p,v), probFunc(x,p+Math.sqrt(v)*burstScale,v)]
+ }
+ return stateProbLn
+ end
+
+ def show(fpw=STDERR)
+ super(fpw)
+ fpw.puts "### MDM::GaussBurst < DistBurst class"
+ fpw.puts " @mean: #{@mean}, @param: #{@param}"
+ fpw.puts " @dpar: #{@dpar}"
+ fpw.puts " @var: #{@var}"
+ end
+end
+
+#-----------------------------------------------------------
+# 二項分布(成功数分布)
+# p: 成功確率
+# x: 成功回数
+# 確率関数: f(x)=nCx*p^x*(1-p)^(n-x)
+class BinomBurst < DistBurst
+ def initialize(fname,valFld,parFld,param,tryFld,trial)
+ @fname =fname
+ @valFld =valFld
+ @parFld =parFld
+ @param =param
+ super("binom")
+
+ # パラメータのセット
+ # 定常状態平均成功数
+
+ @trial=nil
+ if tryFld
+ @trial=[]
+ MCMD::Mcsvin.new("i=#{@fname}"){|csv|
+ csv.each{|flds|
+ v=flds[tryFld].to_f
+ @trial << v
+ }
+ }
+ else
+ @trial=trial.to_f
+ end
+
+ @prob =nil
+ unless @parFld
+ if @param!=nil
+ @prob=param
+ else
+ avg=0.0
+ @data.each{|v| avg+=v}
+ avg=avg/@data.size.to_f
+ @prob=avg/@trial
+ end
+ end
+ end
+
+ # 二項分布の確率関数
+ # f(x)=nCx*p^x*(1-p)^(n-x)
+ # log f(x) = Σ_{i=n..n-x+1}log(i) - Σ_{i=x..1}log(i) + x*log(p) + (n-x)*log(1-p)
+ def probFunc(x,prob,trial)
+ return logsum(trial-x+1,trial) - logsum(1,x) + x*Math::log(prob)+(trial-x)*Math::log(1-prob)
+ end
+
+ def stateProbLn(burstScale)
+ @burstScale=burstScale
+ stateProbLn=[]
+ (0...@data.size).each{|i|
+ x=@data[i]
+ p=nil
+ if @dpar
+ p=@dpar[i]
+ else
+ p=@prob
+ end
+ if @trial.class.name=="Array"
+ n=@trial[i]
+ else
+ n=@trial
+ end
+ stateProbLn << [ probFunc(x,p,n), probFunc(x,@burstScale/((1.0-p)/p+@burstScale),n) ]
+ }
+ return stateProbLn
+ end
+
+ def show(fpw=STDERR)
+ super(fpw)
+ fpw.puts "### MDM::BinomBurst < DistBurst class"
+ fpw.puts " @prob: #{@mean}, @param: #{@param}"
+ fpw.puts " @dpar: #{@dpar}"
+ fpw.puts " @trial: #{@trial}"
+ end
+end
+
+
+#########################################################
+# バーストクラス
+#########################################################
+class Burst
+
+private
+
+ def initialize(dist)
+ @time=[] # メッセージの到着時刻
+ @interval=[] # メッセージの到着間隔(指数分布burstでのみ利用)
+ @count=[] # メッセージの到着件数(ポアソン分布burstでのみ利用)
+ @dist=dist # 分布オブジェクト(PoissonBurst, ExpBurst, GaussBurst, BinomBurst)
+ @stateSize = @dist.initProbLn().size # 状態数
+ @dataSize = @dist.data.size # 状態数
+ end
+
+ # ###############################
+ # 二次元配列の確保
+ def array2dim(rowSize,colSize)
+ array=Array.new(rowSize)
+ (0...rowSize).each{|i|
+ array[i] = Array.new(colSize)
+ }
+ return array
+ end
+
+ # ###############################
+ # 全stateからtargetStateへの尤度を計算し、最大尤度と最大尤度を達成するfrom state番号を返す。
+ def getMaxLike(targetState,prevLike,trans,prob)
+ maxLike=-99999999.0
+ maxFrom=nil
+ (0...@stateSize).each{|from|
+#puts "from=#{from} prevLike[from]=#{prevLike[from]} trans[from][targetState]=#{trans[from][targetState]} prob[targetState]=#{prob[targetState]}"
+ # 時刻t-1における尤度+log(遷移確率)+log(状態確率)
+ like=prevLike[from]+trans[from][targetState]+prob[targetState]
+ if maxLike<like
+ maxLike=like
+ maxFrom=from
+ end
+ }
+#puts "maxLike=#{maxLike} maxFrom=#{maxFrom}"
+ return maxLike,maxFrom
+ end
+
+ # ###############################
+ # viterbi forwardアルゴリズム
+ # initProbLn : 初期状態確率
+ # stateProbLn: 状態確率
+ # transProbLn: 状態遷移確率
+ def viterbi_fwd(initProbLn, stateProbLn, transProbLn)
+
+ # 各stateでの最小コストtransitionの計算実行
+ like =array2dim(@dataSize+1,@stateSize)
+ from =array2dim(@dataSize ,@stateSize)
+
+ # 初期状態セット
+ (0...@stateSize).each{|state|
+ like[0][state]=initProbLn[state]
+ }
+
+ # 初期状態が0なので1から始まる
+ (1..@dataSize).each{|t|
+ (0...@stateSize).each{|state|
+ # tは1から始まるのでfromと@stateProbLnはt-1となる: likeのみ0要素を持つ
+ like[t][state],from[t-1][state] = getMaxLike( state, like[t-1], @transProbLn, @stateProbLn[t-1])
+ }
+ }
+ return like,from
+ end
+
+ def getMaxState(like)
+ maxLike=-99999999.0
+ maxState=nil
+ (0...@stateSize).each{|state|
+ if maxLike<like[state]
+ maxLike=like[state]
+ maxState=state
+ end
+ }
+ maxState
+ end
+
+ # ###############################
+ # viterbi backwordアルゴリズム
+ def viterbi_bwd(like,from)
+ state=Array.new(@dataSize)
+
+ # 最終時刻における尤度最大のstate
+ state[@dataSize-1]=getMaxState(like.last)
+ (@dataSize-1).step(1,-1){|t|
+ state[t-1]=from[t][state[t]]
+ }
+ return state
+ end
+
+public
+
+ def detect(inertiaProb,burstScale)
+ @burstScale = burstScale # burst状態のパラメータのスケールリング
+ @inertiaProb = inertiaProb # 同じ状態への遷移確率
+
+ # 初期状態ベクトル(状態数)の取得
+ @initProbLn=@dist.initProbLn()
+
+ # 状態確率行列(データ数×状態数)の取得
+ @stateProbLn=@dist.stateProbLn(@burstScale)
+
+ # 状態遷移行列(状態数×状態数)の取得
+ @transProbLn=@dist.calTransProbLn(@inertiaProb)
+
+ # viterbiアルゴリズムforward実行
+ @lLikely,@from=viterbi_fwd(@initProbLn,@stateProbLn,@transProbLn)
+
+ # viterbiアルゴリズムbackward実行
+ @state=viterbi_bwd(@lLikely,@from)
+ end
+
+ # CSVによる出力
+ # 入力データの末尾にburst項目を追加して出力
+ def output(iFile,oFile)
+ MCMD::Mcsvin.new("i=#{iFile} -array"){|iCsv|
+ File.open(oFile,"w"){|fpw|
+ fpw.puts "#{iCsv.names.join(',')},burst"
+ i=0
+ iCsv.each{|flds|
+ fpw.puts "#{flds.join(',')},#{@dist.burstSymbol[@state[i]]}"
+ i+=1
+ }
+ }
+ }
+ end
+
+ # debug出力
+ def show(fname=STDERR)
+ File.open(fname,"w"){|fpw|
+ fpw.puts "### MDM::Burst class"
+ fpw.puts " @burstScale: #{@burstScale}"
+ fpw.puts " log(初期状態確率):"
+ (0...@stateSize).each{|i|
+ fpw.puts " @initProbLn[#{i}]: #{@initProbLn[i]}"
+ }
+ fpw.puts " log(状態遷移確率): @inertiaProb: #{@inertiaProb}"
+ (0...@stateSize).each{|i|
+ (0...@stateSize).each{|j|
+ fpw.puts " @transProbLn[#{i}][#{j}]: #{@transProbLn[i][j]}"
+ @transProbLn
+ }
+ }
+
+ # 項目名表示
+ fpw.print ""
+ fpw.print " t\t"
+ fpw.print " val\t"
+ (0...@stateSize).each{|state| fpw.print "probLn#{state}\t"}
+ (0...@stateSize).each{|state| fpw.print "likeLn#{state}\t"}
+ (0...@stateSize).each{|state| fpw.print " from#{state}\t"}
+ fpw.print " state\t"
+ fpw.puts ""
+
+ # 初期尤度表示
+ (0...@stateSize+2).each{|i| fpw.print "\t"}
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.1f\t",@lLikely[0][state])}
+ fpw.puts ""
+
+ # 期別尤度表示
+ (0...@dataSize).each{|i|
+ data =@dist.data[i]
+ stateProbLN=@stateProbLn[i]
+ lLikely=@lLikely[i+1]
+ from=@from[i]
+
+ fpw.print sprintf("%4d\t",i)
+ fpw.print sprintf("%7.3f\t",data)
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.3f\t",stateProbLN[state])}
+ (0...@stateSize).each{|state| fpw.print sprintf("%7.3f\t",lLikely[state])}
+ (0...@stateSize).each{|state| fpw.print sprintf("%7d\t",from[state])}
+ fpw.print sprintf("%7s\t",@dist.burstSymbol[@state[i]])
+ fpw.print "\n"
+ }
+ }
+ end
+
+end # class end
+
+########################## Module end
+end
+
+if distType=="exp"
+ dist=MDM::ExpBurst.new(iFile, fName, pName, param)
+elsif distType=="poisson"
+ dist=MDM::PoissonBurst.new(iFile, fName, pName, param)
+elsif distType=="gauss"
+ dist=MDM::GaussBurst.new(iFile, fName, pName, param, vName, var)
+elsif distType=="binom"
+ dist=MDM::BinomBurst.new(iFile, fName, pName, param, nName, trial)
+end
+
+burst=MDM::Burst.new(dist)
+burst.detect(iProb, burstScale)
+burst.output(iFile,oFile)
+if dFile
+ File.open(dFile,"w"){|fpw|
+ dist.show(fpw)
+ burst.show(fpw)
+ }
+end
+
--- /dev/null
+
+require "rubygems"
+
+spec = Gem::Specification.new do |s|
+ s.name="mining"
+ s.version="##version##"
+ s.platform="#{Gem::Platform::local.cpu}-#{Gem::Platform::local.os}"
+ s.author="NYSOL"
+ s.email="info@nysol.jp"
+ s.homepage="http://www.nysol.jp/"
+ s.summary="tools for frequent pattern mining"
+ s.files=[
+"lib/lcm.##lib_suffix##",
+"lib/zdd_so.##lib_suffix##",
+"lib/zdd.rb",
+"lib/caep.rb",
+"lib/cls.rb",
+"lib/enumLcmEp.rb",
+"lib/enumLcmIs.rb",
+"lib/items.rb",
+"lib/taxonomy.rb",
+"lib/traDB.rb",
+]
+ s.description = <<-EOF
+ アイテム集合マイニング、シーケンスマイニングのrubyコマンドセット。
+ EOF
+end
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgArgFld.h 引数項目クラス
+// ============================================================================
+#pragma once
+#include <iostream>
+#include <string>
+#include <vector>
+#include <kgConfig.h>
+#include <kgError.h>
+#include <kgCSV.h>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+
+// コマンドライン引数クラス
+class kgArgFld
+{
+ kgCSV* _csv; // 対象CSVクラス
+ vector<kgstr_t> _name; // 項目名
+ vector<kgstr_t> _attr; // 属性
+ vector<int> _num; // name位置->CSV項目番号
+ vector<int> _flg; // csv項目番号->name位置
+
+ // _name,_attrの項目名展開&
+ // _name,_attrから_num,_flgへのデータセット(set関数で使用)
+ void _num_flg_Set(kgCSV* csv ,bool fldno,bool attrEval=true);
+
+public:
+
+ // コンストラクタ
+ kgArgFld() : _csv(0){}
+
+ // set関数
+ void set(vector< vector<kgstr_t> >& vvs, kgCSV* csv ,bool fldno, bool attrEval=true) throw(kgError);
+ void set(vector<kgstr_t>& vs, kgCSV* csv,bool fldno) throw(kgError);
+ void set(kgstr_t& s, kgCSV* csv,bool fldno) throw(kgError);
+
+ // 登録されている項目名数
+ size_t size(void) const { return _name.size();}
+ size_t attrSize(void) const { return _attr.size();}
+ size_t numSize(void) const { return _num.size(); }
+
+ //アクセッサ
+ const kgCSV* csv(void) const { return _csv; }
+ const vector<kgstr_t> getAttr(void) const { return _attr; }
+ const vector<kgstr_t> getName(void) const { return _name; }
+ const vector<int> getNum(void) const { return _num; }
+ const vector<int> getFlg(void) const { return _flg; }
+ const vector<int>* getFlg_p(void) const { return &_flg; }
+
+ const kgstr_t name(size_t num) const;
+ const kgstr_t attr(size_t num) const;
+ int num (size_t num) const;
+ int flg (size_t num) const;
+
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgArgs.h コマンドライン引数クラス
+// ============================================================================
+#pragma once
+#include <iostream>
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+#include <kgConfig.h>
+#include <kgError.h>
+
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+// コマンドライン引数クラス
+class kgArgs
+{
+ // 登録されているkeywordの情報
+ map<string,kgstr_t> keyVal_;
+
+public:
+ // 引数登録
+ void add(size_t c, const char **v) throw(kgError);
+ void add(string str) throw(kgError);
+ void add(const string& key, const kgstr_t& val) throw(kgError);
+
+ // 引数サイズ&イテレーター
+ map<string,kgstr_t>::size_type size (void) const{ return keyVal_.size(); }
+ map<string,kgstr_t>::const_iterator begin(void) const{ return keyVal_.begin(); }
+ map<string,kgstr_t>::const_iterator end (void) const{ return keyVal_.end(); }
+
+ // keywordに対応する値を返す
+ kgstr_t get(const string& keyWord, bool mandatory=false, bool nullNG=false) const throw(kgError);
+
+ // 登録された引数を,様々なデータ型に変換する関数群
+ bool toBool(const string& keyWord) const;
+ kgstr_t toString(const string& keyWord, bool mandatory=false, bool nullNG=false) const;
+ vector<kgstr_t> toStringVector(const string& keyWord, bool mandatory=false, bool nullNG=false) const;
+ set<kgstr_t> toStringSet(const string& keyWord, bool mandatory=false, bool nullNG=false) const;
+ vector< vector<kgstr_t> > toStringVecVec(const string& keyWord, const wchar_t delim, unsigned int rowSize, bool mandatory, bool nullNG=false) const;
+ vector< vector<kgstr_t> > toStringVecVec(const string& keyWord, const kgstr_t delim, unsigned int rowSize, bool mandatory, bool nullNG=false) const;
+
+ // 使用不能パラメータチェック
+ void paramcheck(const char *cstr, bool addCommonArgs=true) const;
+
+ // 全引数を一つの文字列に変換する(コマンドライン出力用)
+ string to_s(void) const;
+
+
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgCSV.h KGMODで用いられる入力CSVクラス
+// =============================================================================
+#pragma once
+#include <sys/types.h>
+#include <map>
+#include <vector>
+#include <string>
+#include <kgEnv.h>
+#include <kgError.h>
+#include <kgFldBuffer.h>
+#include <kgMethod.h>
+#include <kgConfig.h>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+// 入力バッファの構造体
+// CSVの一行がメモリの連続領域にあることを保証したファイルバッファ
+//
+// バッファの全体像
+// buf_ -----+------------+-----------+
+// | | |
+// | _dupSize | |
+// | | |
+// +------------+-----+ |
+// 0| ioSize_ | | |
+// +------------+ | bufSize_
+// 1| | | |
+// +------------+ queSize_ |
+// :| | | |
+// :| | | |
+// :| | | |
+// :| | | |
+// +------------+ | |
+// readCnt_-1 | | | |
+// +------------+-----+-----+
+// bufSize_ = _dupSize + queSize_
+// queSize_ = ioSize_ * readCount_
+// _dupSize :
+// 一行がメモリの連続領域にあることを保証するための緩衝領域。
+// curPnt_がbufの後ろのborder_を超えたら,後ろのdupSizeの領域を
+// 先頭(buf_)にコピーする.
+// CSVrec,CSVfldでは_maxRecLenに等しく,CSVkeyでは_maxRecLen*2
+// _ioSize : FP.readにて一回に読み込むサイズ
+// _reqdCnt : 何回readするか。この回数でキューの大きさが決まる。
+// _maxRecLen : 最大レコードサイズ : ユーザにより与えられる。
+// (kgConfig.h or 環境変数のKG_MaxRecLen)
+// 制約事項 :
+// 1) pipeのバッファサイズ = ioSize_ * n (nは1以上の整数)
+// 2) _maxRecLen = ioSize_ * n (nは1以上の整数)
+// 3) _dupSize <= queSize_
+//
+class kgCSV
+{
+public:
+ enum Status {
+ Begin = 1, // kgCSVkey: 二行目を読み込む前までON
+ // その他 : 最初の一行目を読み込んむ前のみBeginフラグはON
+ KeyBreak = 2, // kgCSVkeyのみ有効.キーブレーク読み込み時にON
+ End = 4, // EOFを読み込もうとした時にONとなる
+ Normal = 8 // 通常行の読み込み時にON
+ };
+protected:
+ kgEnv* env_; // 環境変数クラスへのポインタ
+ int fd_; // ファイルディスクリプト
+ bool opened_; // オープンしたかどうか
+ string fname_; // ファイル名へのポインタ(標準入力は/dev/stdin)
+
+ // バッファのアドレスやサイズ関連
+ kgAutoPtr2<char> ap_; // 入力バッファをラッピングするsmart pointer
+ char* buf_; // バッファデータ本体
+ size_t maxRecLen_; // 1行の最大長(環境変数より)
+ size_t queSize_; // 1つのqueueの大きさ(環境変数より)
+ size_t ioSize_; // 実際にreadするサイズ
+ size_t ioCnt_; // 実際にreadする回数
+ char* border_; // 次que読み込みポインタ
+ char* dupTop_; // スラック領域へコピーする先頭アドレス
+ size_t dupSize_; // スラック領域へコピーするサイズ
+ size_t bufSize_; // スラック領域へコピーするサイズ
+ char* curPnt_; // 現在の読み込みポインタ
+
+ // 項目名関連
+ bool noFldName_; // 1行目が項目名行でないフラグ
+ vector<kgstr_t> fldName_; // 項目名
+ map<kgstr_t,int> fldNum_; // 項目名->num用
+ size_t fldSize_; // 登録項目数
+ size_t fldByteSize_; // 項目行のbyteサイズ
+
+ // 実行時変数
+ int status_; // 読み込み状態
+ size_t recNo_; // 現在読み込み中の行番号
+public:
+ // コンストラクタ,デストラクタ
+ kgCSV(void) : opened_(false),recNo_(0){}
+ virtual ~kgCSV(void){close();};
+
+ // ファイル操作
+ void open(const kgstr_t& fname, kgEnv* env, bool noFldName, size_t readCnt=4) throw(kgError);
+ void clear(void);
+ virtual int read(void)=0;
+ void seekTop(void) throw(kgError);
+ void close(void) throw(kgError);
+
+ // アクセッサ
+ kgstr_t fileName(void) const { return fname_;}
+ size_t fldSize(void) const { return fldSize_; }
+ bool opened(void) const { return opened_; }
+ bool noFldName(void) const { return noFldName_; }
+ size_t recNo(void) const { return recNo_; }
+ vector<kgstr_t> fldName(void) const { return fldName_;}
+ size_t bufSize(void) const { return bufSize_;}
+
+ // ステータスの判定
+ char status() const { return status_;}
+ bool end() const { return status_ & End ;}
+ bool begin() const { return status_ & Begin;}
+ bool keybreak() const { return status_ & KeyBreak;}
+ bool isEOF(void) const { return (*curPnt_=='\0'); }
+ bool isEndOfBuf(void) const { return curPnt_ >= border_; }
+ bool isStdin(void) const { return fname_=="/dev/stdin";}
+ bool isFifo(void) const;
+
+ // 項目名関連(項目名<->項目番号)
+ kgstr_t fldName(const size_t) const throw(kgError);
+ int fldNum(const kgstr_t& str,bool rtn=false) const throw(kgError);
+
+ // データコピー(ruby mtable 専用)
+ size_t bufCpy(char* to, bool toEnd) const;
+
+protected:
+ void set_fields(size_t cpSize);
+ void readCSVfile(void) throw(kgError);
+};
+// ==============================================================================
+// 継承クラス関連
+// kgCSVrec,
+// 一行単位での読み込み
+// 一行ごとに読み込む。項目のトークン分割は行わないので高速である。
+// kgCSVfld
+// 一行項目単位の読み込み
+// 一行ごとに読み込み、項目もトークン分割される。
+// kgCSVkey
+// 二行項目単位の読み込み
+// 常にデータ行を二行キープしながら読み込む。キーブレーク処理に便利。
+// ==============================================================================
+//------------------------------------------------------------------------------
+// 行単位読み込みバッファ
+//------------------------------------------------------------------------------
+class kgCSVrec : public kgCSV
+{
+ char* _rec;
+public:
+ kgCSVrec(void){};
+ ~kgCSVrec(void){};
+
+ // 読込関連
+ void read_header(void);
+ int read(void);
+
+ // データ取得関連
+ char* getRec(void) const { return _rec;}
+ size_t recLen(void) const { return curPnt_ - _rec;}
+};
+
+//------------------------------------------------------------------------------
+// 行-項目単位読み込みバッファ
+//------------------------------------------------------------------------------
+class kgCSVfld : public kgCSV
+{
+ kgAutoPtr2<char*> _fld_ap;
+ char** _fld;
+public:
+ kgCSVfld(void){}
+ ~kgCSVfld(void){};
+
+ // 読込関連
+ void read_header(void);
+ int read(void);
+ int read_limit(void);
+
+ // データ取得関連
+ char* getVal(int no) const { return *(_fld+no);}
+ char** getFld(void) const { return _fld;}
+ size_t recLen(void) const { return curPnt_ - *_fld;}
+};
+
+//------------------------------------------------------------------------------
+// キーブレーク読み込みバッファ
+//------------------------------------------------------------------------------
+class kgCSVkey : public kgCSV {
+protected:
+ kgAutoPtr2<char*> _fld0_ap;
+ kgAutoPtr2<char*> _fld1_ap;
+ char** _fld0; // 各行各項目へのポインタ(old行 or new行)
+ char** _fld1; // 各行各項目へのポインタ(old行 or new行)
+ char** _newFld; // new行格納先へのポインタ
+ char** _oldFld; // old行格納先へのポインタ
+ vector<int> _keyNum;
+public:
+ kgCSVkey(void){}
+ ~kgCSVkey(void){};
+
+ // キーセット
+ void setKey(vector<int> keyNum){ _keyNum = keyNum; }
+
+ // 読込関連
+ void read_header(void);
+ int read(void);
+
+ // データ取得関連
+ char* getNewVal(int no) const { return *(_newFld+no);}
+ char* getOldVal(int no) const { return *(_oldFld+no);}
+ char** getNewFld(void) const { return _newFld;}
+ char** getOldFld(void) const { return _oldFld;}
+ size_t recLen(void) const { return curPnt_ - *_newFld;}
+ const vector<int>* getKey(void) const {return &_keyNum;}
+};
+
+//------------------------------------------------------------------------------
+// BLOCK読み込みバッファ付きkgCSVkey
+//------------------------------------------------------------------------------
+// 最終的にBLOCK読み込むすると
+// +------------+
+// | | kgfldBuffer -+- メモリバッファ
+// | | +- ファイルバッファ
+// +------------+
+// | | kgCSVのメモリバッファ
+// +-------------
+// で一つのBLOCKとなる
+//
+class kgCSVblk : public kgCSVkey
+{
+ kgAutoPtr1<kgFldBuffer> _fldbuf_ap;
+ kgAutoPtr2<char*> _blk_ap;
+ size_t _pageSize;
+ kgFldBuffer *_fldbuf;
+
+ char** _blkFld;
+ char* _start; //kgCSV上のバッファ開始位置
+ char* _end; //kgCSV上のバッファ終了位置
+ char* _pos; //kgCSV上のバッファ終了位置
+ size_t _blkrec; //ブロックの行数
+
+public:
+ kgCSVblk(): _fldbuf(0),_blkrec(0){ }
+ ~kgCSVblk(void){}
+
+ //バッファサイズ設定
+ void setbufsize(size_t psize);
+
+ // 読込関連
+ void read_header(void);
+ int blkset(void);
+ int blkread(void);
+ int seekBlkTop(void);
+
+ // データ取得関連
+ char* getBlkVal(int no) const { return *(_blkFld+no);}
+ char** getBlkFld(void) const { return _blkFld;}
+ size_t blkrecNo(void) const { return _blkrec;}
+};
+} //////////////////////////////////////////////////////////////// end namespace
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgCSVout.h KGMODで用いられる入力CSVクラス
+// =============================================================================
+#pragma once
+#include <iostream>
+#include <kgConfig.h>
+#include <kgError.h>
+#include <kgEnv.h>
+#include <kgCSV.h>
+#include <kgArgFld.h>
+#include <kgVal.h>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#define LIMIT_OUT 2
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+// 出力ファイルclass
+// 入力バッファの構造体
+// CSVの一行がメモリの連続領域にあることを保証したファイルバッファ
+//
+// バッファの全体像
+// _buf -----+------------+-----+-----+
+// 0| ioSize_ | | |
+// +------------+ | _bufSize
+// 1| | | |
+// +------------+ queSize_ |
+// :| | | |
+// :| | | |
+// :| | | |
+// :| | | |
+// +------------+ | |
+// ioCnt_-1 | | | |
+// +------------+-----+ |
+// | | |
+// | _dupSize | |
+// | | |
+// +------------+-----+-----+
+// _bufSize = _dupSize + _queSize
+// _queSize = ioSize_ * writeCount_
+// _dupSize :
+// 書き出し緩衝領域
+// ファイルへの実writeは常に_bufからqueSize_バイトだけ出力される。
+// 一方でkgWrite系関数ではqueSize以上をメモリに書き出す(超えた時にflushされる).
+// flush後に超過分を先頭(_buf)にコピーする.
+// 現在は_maxRecLenに等しい
+// _writeSize : FP.writeにて一回に書き込むサイズ
+// _writeCnt : 何回writeするか。この回数でキューの大きさが決まる。
+// _maxRecLen : 最大レコードサイズ : ユーザにより与えられる。
+// (kgConfig.h or 環境変数のKG_MaxRecLen)
+// 制約事項 :
+// 1) pipeのバッファサイズ = ioSize_ * n (nは1以上の整数)
+// 2) _maxRecLen = ioSize_ * n (nは1以上の整数)
+// 3) _dupSize <= _queSize
+// 4) ioSize_ = readSize_(kgCSV.hより)
+class kgCSVout
+{
+private:
+ kgEnv* env_; // 環境変数クラスへのポインタ
+ int fd_;
+ kgstr_t fname_; // ファイル名へのポインタ(標準入力はempty)
+ bool opened_; // オープンしたかどうか
+
+ kgAutoPtr2<char> _buf_ap; // 出力バッファbufをラッピングするsmart pointer
+ char* _buf; // 出力バッファ
+ size_t _maxRecLen; // レコード最大長(環境変数からセットされる)
+ size_t queSize_; // 1つのqueueの大きさ(環境変数より)
+ size_t ioSize_; // write関数で一回に書き込むサイズ
+ size_t ioCnt_; // その回数
+
+ bool _noFldName; // 1行目が項目名行でないフラグ
+ char _dblFmt[256]; // double型出力フォーマット
+
+ char* _curPnt; // 現在の書き込み位置
+ char* _border; // buf配列の境界アドレス(ここを越えるとflash)
+ char* _end; // buf配列の最終アドレス(ここを越えるとerror)
+ size_t _recNo; // 現在書き込み中の行番号
+
+ char* dupTop_; // スラック領域へコピーする先頭アドレス
+ size_t dupSize_; // スラック領域へコピーするサイズ
+ size_t bufSize_; // スラック領域へコピーするサイズ
+
+public:
+ // コンストラクタ
+ kgCSVout() : opened_(false),_recNo(0){}
+ kgCSVout(kgstr_t fileName, kgEnv *env=NULL, bool noFldName=false);
+
+ // デストラクタ
+ ~kgCSVout(){ close();}
+
+ // ファイルのオープンとクローズ
+ void open(kgstr_t fileName, kgEnv *env=NULL, bool noFldName=false, size_t cnt=4) throw(kgError);
+ void close(void) throw(kgError);
+
+ // 有効桁数セット
+ void setPrecision(int precision);
+
+ // accessor
+ bool noFldName(void) const {return _noFldName;}
+ bool isOpend(void) const {return opened_;}
+ size_t recNo(void) const {return _recNo;}
+
+ // bufferの強制出力
+ void flush();
+
+ // --------------------
+ // データ型別の出力関数群
+ // (第2引数が有るのは区切り文字出力あり true:改行、false:コンマ)
+ // --------------------
+ void writeStrNdq(const char *str, bool eol);
+ void writeStrNdq(const char *str);
+ void writeStr(const char *str, bool eol);
+ void writeStr(const char *str);
+ void writeDbl(double val, bool eol);
+ void writeDbl(double val);
+ void writeInt(int val, bool eol);
+ void writeInt(int val);
+ void writeLong(long val, bool eol);
+ void writeLong(long val);
+ void writeSizeT(size_t val, bool eol);
+ void writeSizeT(size_t val);
+ void writeBool(bool val, const bool eol);
+ void writeBool(bool val);
+ void writeDate(const boost::gregorian::date& val, const bool eol);
+ void writeDate(const boost::gregorian::date& val);
+ void writeTime(const boost::posix_time::ptime& val, const bool eol);
+ void writeTime(const boost::posix_time::ptime& val);
+ void writeVal(const kgVal& val, bool eol);
+ void writeVal(const kgVal& val);
+
+ // --------------------
+ // 一行出力
+ // --------------------
+ // csv一行を出力する(項目の解釈(DQなど)なし).
+ void writeRec(char* rec);
+ // csv一行+数値(mrandで使用)
+ void writeRec(char* rec,int val);
+
+ // --------------------
+ // 項目値の出力関数群
+ // --------------------
+ // csv項目を出力する.
+ // 使用= 汎用
+ void writeFld(size_t size, char** flds, bool eol=true);
+
+ // flgが-1の項目はfldの文字列を出力し,それ以外は対応するvalを出力
+ // 使用= sum, argv
+ void writeFld(char** fld, const vector<int>* flg, vector<kgVal>& val);
+
+ // 使用= chgstr, chgnum
+ void writeFld(char** fld, const vector<int>* flg, char** val);
+
+ //joinでアウタージョイン(-Nの場合に使用)マスタにあってトラにない場合
+ // flgが-1のものはNULL出力し、それ以外はvalから項目番号割り出しを出力
+ // 使用= join, njoin, nrjoin, rjoin
+ void writeFld(const vector<int>* flg,const vector<int>* num,char** fld , const vector<int >* addcnt);
+
+ // 使用= number, newnumber, rand
+ void writeFld(char** fld ,size_t size ,int val,bool alpha_flg);
+
+ // 使用= count,
+ void writeFld(char** fld ,size_t size ,size_t val);
+
+ // 使用= cat, cut
+ void writeFld(char** fld ,const vector<int>* cnt,bool eol=true);
+
+ // 使用= join, nrjoin, rjoin
+ void writeFld(char** fld,size_t size, char** addfld , const vector<int >* addcnt);
+
+ // 使用= chgstr, chgnum, nrjoin
+ void writeFld(char** fld,size_t size, char** addfld ,int addsize);
+
+ // 使用= setstr, sed
+ void writeFld(char** fld,size_t size, vector<string> *newFld);
+
+ // int -> アルファベット出力
+ // 使用 = kgcm
+ void writeInt2alpha(int val);
+
+ // --------------------
+ // 項目名の出力関数群
+ // --------------------
+ //同じものがないことを確認してから出力する
+ void writeFldNameCHK(vector<kgstr_t>& outfld ) throw(kgError);
+
+ // csv項目名を出力する.
+ // 使用= 汎用
+ void writeFldName(kgCSV& csv) throw(kgError);
+
+ // csv項目名を出力する. (利用mod: kgsum)
+ // ex1. CSV a,b,c : f=a:A,c : a,b,c
+ // ただし,second=tureの場合,fldに指定された項目のみattr名に変えて出力
+ // ex1. CSV a,b,c : f=a:A,c : A,b,c
+ // 使用= 汎用
+ void writeFldName(kgArgFld& fld, bool second) throw(kgError);
+
+ // csv項目+fld項目を出力.or fld項目+csv項目 (利用mod: kgjoin or mwindow)
+ // ex. CSV a,b,c fld x,y : a,b,c,x,y
+ // ただし,second=tureの場合,fldに指定された項目はattr名に変えて出力
+ // ex. CSV a,b,c fld x:X,y:Y : a,b,c,X,Y
+ // 使用= 汎用
+ void writeFldName(kgCSV& csv,kgArgFld& fld,bool second,bool back=true) throw(kgError);
+
+ // csv項目+newFldを出力
+ // 使用= rand, cal, count, number
+ void writeFldName(kgCSV& csv, kgstr_t newFld) throw(kgError);
+
+ // csv項目+newFld(vector)を出力
+ // 使用= combi, setstr
+ void writeFldName(kgCSV& csv, vector<kgstr_t> newFld) throw(kgError);
+
+ // 新規項目の項目名を出力
+ // 使用= newrand, newstr, newnumber
+ void writeFldName(kgstr_t newFld) throw(kgError);
+
+ // 新規項目の項目名(複数)を出力
+ // 使用= cat、chkcsv、fldname, sep2, cm
+ void writeFldName(vector<kgstr_t> newFld) throw(kgError);
+
+ //区切り文字出力(コンマ、改行、改行[出力行数カウント有り])
+ void writeDlm(void){ *_curPnt++ = ','; }
+ void writeEolNC(void){ *_curPnt++ = '\n'; }
+ void writeEol(void){
+ _recNo++;
+ //if(_recNo>LIMIT_OUT){
+ // throw kgError("limit line over");
+ //}
+ *_curPnt++ = '\n';
+ }
+
+};
+
+
+} //////////////////////////////////////////////////////////////// end namespace
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgCSVutils.h csvファイル(infile)関連のutils
+// ============================================================================
+#pragma once
+#include <vector>
+#include <kgConfig.h>
+#include <kgCSV.h>
+
+namespace kglib {////////////////////////////////////////////// namespace start
+
+// -----------------------------------------------------------------------------
+// c=で与えられた式の項目名(${..})を検索し,項目名を展開する.
+// exp1. c=sum(${a*}) c=sum(${aa},${ab})
+// exp2. c=sum(${1_2L}) c=sum(${1},${2},${3})
+// 返り値:展開後の式
+// -----------------------------------------------------------------------------
+kgstr_t evalCalFldName(kgstr_t& expr, kgCSV& iFile,bool fldno);
+
+// -----------------------------------------------------------------------------
+// d=で与えられたファイル名で項目名(${..})を検索し,
+// 分割した文字列を返す、項目番号をセットする
+// exp1. d=dat-${日付} 返り値文字列:dat-,\0 項目番号:1
+// exp2. d=${日付}${時間} 返り値文字列:\0,\0,\0 項目番号:1,2
+// -----------------------------------------------------------------------------
+vector<kgstr_t> evalFileFldName(kgstr_t& expr, kgCSV& iFile,vector<int>& set,bool fldno);
+
+// -----------------------------------------------------------------------------
+// 項目名->項目番号を評価する.(evalflg=true:項目名変換有,evalflg=false:項目名変換無)
+// -----------------------------------------------------------------------------
+vector<int> evalFldName(vector<kgstr_t>& name, kgCSV* csv,bool fldByNum,bool evalflg=false);
+
+// -----------------------------------------------------------------------------
+// 項目名->項目番号を評価する.(項目名変換あり)
+// 項目名変換するのは以下の2つ.
+// 1. 範囲指定 -:数値指定のみの場合
+// ex. 1-3 => 1,3
+// 2. ワイルドカード *:任意の文字列にマッチ ?:任意の一文字にマッチ
+// 3. 第二vector(attr)の第一vector(name)による置換(&をnameに置換)
+// ex. aaa:&_cm =>aaa:aaa_cm aa*:&_cm => aab:aab_cm,aac:aac_cm,...
+// -----------------------------------------------------------------------------
+vector<int> evalFldName(vector<kgstr_t>& name, vector<kgstr_t>& attr, kgCSV* csv,bool fldByNum);
+
+}////////////////////////////////////////////// namespace end
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgCalParser.h kgcal,kgselで用いる構文解析パーサークラス
+// =============================================================================
+#pragma once
+#include <boost/spirit/include/classic.hpp>
+#include <boost/spirit/include/classic_utility.hpp>
+#include <boost/spirit/include/classic_ast.hpp>
+#include <kgFunction.h>
+
+using namespace boost::spirit::classic;
+using namespace std;
+
+namespace kgmod { ////////////////////////////////////////////// start namespace
+
+struct kgCalParser : public grammar<kgCalParser>{
+public:
+ // paserタグのセット
+ // 目的:parse時に定数,項目,関数(演算子)の区別を構文木のノードに
+ // 記録しておくため.setparamにてこのIDに基づき定数は値として評価し,
+ // 項目はCSVデータにおける項目番号として評価し,そして関数・演算子は
+ // 関数クラスのインスタンス化を行う.
+ // これらの値は構文木ノード構造体(struct tree_node)のメンバーである
+ // データ値構造体(struct node_val_data)のメンバーidにセットされる
+ static const int exprID = 0; // 0固定
+ static const int constIDstr = 1;
+ static const int constIDreal = 2;
+ static const int constIDdate = 3;
+ static const int constIDtime = 4;
+ static const int constIDbool = 5;
+ static const int fieldIDstr = 6;
+ static const int fieldIDreal = 7;
+ static const int fieldIDdate = 8;
+ static const int fieldIDtime = 9;
+ static const int fieldIDbool = 10;
+ static const int pfieldIDstr = 11;
+ static const int pfieldIDreal = 12;
+ static const int pfieldIDdate = 13;
+ static const int pfieldIDtime = 14;
+ static const int pfieldIDbool = 15;
+
+ template<typename ScannerT> struct definition{
+
+ // 項目値用(文字列,整数,実数,日付,時刻,bool)
+ rule<ScannerT, parser_context<>, parser_tag<fieldIDstr > > field_str;
+ rule<ScannerT, parser_context<>, parser_tag<fieldIDreal> > field_real;
+ rule<ScannerT, parser_context<>, parser_tag<fieldIDdate> > field_date;
+ rule<ScannerT, parser_context<>, parser_tag<fieldIDtime> > field_time;
+ rule<ScannerT, parser_context<>, parser_tag<fieldIDbool> > field_bool;
+
+ // 前行項目値用(文字列,整数,実数,日付,時刻,bool)
+ rule<ScannerT, parser_context<>, parser_tag<pfieldIDstr > > pfield_str;
+ rule<ScannerT, parser_context<>, parser_tag<pfieldIDreal> > pfield_real;
+ rule<ScannerT, parser_context<>, parser_tag<pfieldIDdate> > pfield_date;
+ rule<ScannerT, parser_context<>, parser_tag<pfieldIDtime> > pfield_time;
+ rule<ScannerT, parser_context<>, parser_tag<pfieldIDbool> > pfield_bool;
+
+ // 定数値用(文字列,整数,実数,日付,時刻,bool)
+ rule<ScannerT, parser_context<>, parser_tag<constIDstr > > const_str;
+ rule<ScannerT, parser_context<>, parser_tag<constIDreal> > const_real;
+ rule<ScannerT, parser_context<>, parser_tag<constIDdate> > const_date;
+ rule<ScannerT, parser_context<>, parser_tag<constIDtime> > const_time;
+ rule<ScannerT, parser_context<>, parser_tag<constIDbool> > const_bool;
+
+ //関数・演算子用
+ rule<ScannerT, parser_context<>, parser_tag<exprID> >
+ term1,term2,term3,term4,term5,term6,term7,term8,expr,
+ function1,function2,fctr;
+
+ // 文法定義(コンストラクタ)
+ definition(const kgCalParser& self){
+
+ // -----------------------------------------------------------------------
+ // [項目の指定] $x{xxx}の部分
+ // ${項目名} : 数値, 12 12.1
+ // $s{項目名} : 文字, "abc"
+ // $d{項目名} : 日付, 20080912
+ // $t{項目名} : 時刻, 121522
+ // -----------------------------------------------------------------------
+ // 文字列項目指定
+ field_str = discard_node_d[*space_p >> str_p("$s{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 数値項目指定
+ field_real = discard_node_d[*space_p >> str_p("${")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 日付項目指定
+ field_date = discard_node_d[*space_p >> str_p("$d{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 時刻項目指定
+ field_time = discard_node_d[*space_p >> str_p("$t{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // bool項目指定
+ field_bool = discard_node_d[*space_p >> str_p("$b{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // -----------------------------------------------------------------------
+ // [前行項目の指定]
+ // #{項目名} : 数値, 12 12.1
+ // #s{項目名} : 文字, "abc"
+ // #d{項目名} : 日付, 20080912
+ // #t{項目名} : 時刻, 121522
+ // -----------------------------------------------------------------------
+ // 文字列項目指定
+ pfield_str = discard_node_d[*space_p >> str_p("#s{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') | eps_p ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 数値項目指定
+ pfield_real = discard_node_d[*space_p >> str_p("#{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') | eps_p ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 日付項目指定
+ pfield_date = discard_node_d[*space_p >> str_p("#d{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') | eps_p ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // 時刻項目指定
+ pfield_time = discard_node_d[*space_p >> str_p("#t{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') | eps_p ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // bool項目指定
+ pfield_bool = discard_node_d[*space_p >> str_p("#b{")]
+ >> lexeme_d[leaf_node_d[ *(anychar_p-'}') | eps_p ]]
+ >> discard_node_d[ch_p('}') >> *space_p];
+
+ // -----------------------------------------------------------------------
+ // [定数の指定]
+ // const_str : 文字列, "abc"
+ // const_real : 数値, 12 12.1
+ // const_date : 日付, 0d20080912
+ // const_time : 日付, 0t20080912121102
+ // const_bin : 2進数, 0b110100
+ // const_oct : 8進数, 0b7022
+ // const_hex : 16進数,0x8bff
+ // -----------------------------------------------------------------------
+ // 文字列の指定 "xxx"の部分
+ const_str = discard_node_d[*space_p >> ch_p('\"')]
+ >> lexeme_d[leaf_node_d[*(c_escape_ch_p-'\"')]]
+ >> discard_node_d[ch_p('\"') >> *space_p];
+
+ // 数値の指定
+ const_real = discard_node_d[*space_p]
+ >> leaf_node_d[real_p]
+ >> discard_node_d[*space_p];
+
+ // 日付の指定
+ const_date = discard_node_d[*space_p >> str_p("0d")]
+ >> lexeme_d[leaf_node_d[repeat_p(8)[digit_p]]]
+ >> discard_node_d[*space_p];
+
+ // 時刻の指定
+ const_time = discard_node_d[*space_p >> str_p("0t")]
+ >> lexeme_d[leaf_node_d[repeat_p(14)[digit_p] | repeat_p(6)[digit_p] ]]
+ >> discard_node_d[*space_p];
+
+ // boolの指定
+ const_bool = discard_node_d[*space_p >> str_p("0b")]
+ >> lexeme_d[leaf_node_d[ch_p('0') | ch_p('1')]]
+ >> discard_node_d[*space_p];
+
+ // -----------------------------------------------------------------------
+ // [関数の指定]
+ // function1 : 引数をとる関数, fff(x1,x2,...)
+ // function2 : 引数をとらない関数, fff()
+ // -----------------------------------------------------------------------
+ // 引数をとる関数
+ function1 = root_node_d[leaf_node_d[
+ alpha_p >> *(alpha_p|digit_p|ch_p('_'))]]
+ >> discard_node_d[ch_p('(') >> *space_p]
+ >> ( expr % discard_node_d[ch_p(',') >> *space_p])
+ >> discard_node_d[ch_p(')')];
+
+ // 引数をとらない関数
+ function2 = root_node_d[leaf_node_d[alpha_p >> *(alpha_p|digit_p)]]
+ >> discard_node_d[str_p("(") >> *space_p >> str_p(")")];
+
+ // 二項演算子の指定 (優先順位込み)
+ expr = term7 % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p("||") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("^^") >>
+ discard_node_d[*space_p]
+ ];
+
+ term7= term4 % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p("&&") >>
+ discard_node_d[*space_p]
+ ];
+
+ term4= term3 % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p("==") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("!=") >>
+ discard_node_d[*space_p]
+ ];
+
+ term3= term2 % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p(">=") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("<=") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p(">") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("<") >>
+ discard_node_d[*space_p]
+ ];
+
+ term2= term1 % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p("+") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("-") >>
+ discard_node_d[*space_p]
+ ];
+
+ term1= fctr % root_node_d[
+ discard_node_d[*space_p] >>
+ str_p("*") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("/") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("%") >>
+ discard_node_d[*space_p] |
+ discard_node_d[*space_p] >>
+ str_p("^") >>
+ discard_node_d[*space_p]
+ ];
+
+ fctr = function2 | function1 | const_date | const_time |
+ const_bool | const_real | const_str |
+ field_str | field_real | field_date | field_time | field_bool |
+ pfield_str |pfield_real |pfield_date |pfield_time |pfield_bool |
+ inner_node_d[discard_node_d[*space_p]>>'('>>discard_node_d[*space_p]>>expr>>')'>>discard_node_d[*space_p]>>discard_node_d[*space_p]];
+ }
+ rule<ScannerT, parser_context<>, parser_tag<exprID> >
+ const& start() const {return expr;}
+ };
+};
+
+} //////////////////////////////////////////////////////////////////////////////
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgConfig.h 設定ヘッダファイル
+// =============================================================================
+#pragma once
+#include <string>
+
+// ファイル名(パス込)の最大長
+#define KG_MaxFileNameLen 256
+
+// read,writeのサイズ (KG_MaxRecLenで割り切れ値にする必要あり)
+//#define KG_ioSize 4096000
+#define KG_iSize 4096000
+#define KG_oSize 4096000
+
+// 一行あたりの最大文字数 (上限:1024000)
+// KG_ioSizeの1以上の整数倍でなければならない。
+#define KG_MaxRecLen 1024000
+#define KG_LimitRecLen 10240000
+
+// 出力バッファサイズ (上限:1024000)
+// KG_ioSizeの1以上の整数倍でなければならない。
+//#define KG_OutBufSize 40960
+//#define KG_LimitOutBufSize 1024000
+
+// キー単位ごとに処理する際に使用するバッファ数
+// デフォルトでの最大バッファサイズは
+// (KG_MaxRecLen *2 + 4 * KG_ioSize) * KG_BlockCount
+#define KG_BlockCount 128
+
+// ライブラリ関数が用いるデフォルトの一時ファイル用ディレクトリ
+#define KG_TmpPath "/tmp"
+
+// Mコマンドのエラーメッセージ出力レベル
+// 0:何も表示しない
+// 1:ERRORメッセージのみ表示
+// 2:+WARNINGメッセージ表示
+// 3:+ENDメッセージ表示
+// 4:+MSGメッセージ表示
+#define KG_VerboseLevel 4
+
+// 再帰メッセージ出力フラグ
+#define KG_RecursiveMsg true
+
+// KGMODが内部で扱うデフォルトの文字列encoding
+#define KG_DEFAULT_ENC "ja_JP.UTF-8"
+
+// 別名登録
+typedef char kgchr_t;
+typedef std::string kgstr_t;
+
+// 一項目あたりの最大文字数
+#define KG_MAX_STR_LEN 100000
+
+// cal,sel時最大項目数
+#define KG_MAX_CAL_TERMS 1000
+
+// 有効桁数
+#define KG_PRECISION 10
+
+// 最大有効桁数
+#define KG_MAX_PRECISION 16
+
+//### 以下システムconfiguration
+
+// size_tの最大値
+#define KG_SIZE_MAX ((size_t)-1)
+
+// 引数最大長
+#define KG_ARGLEN_MAX 102400
+
+
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgEnv.h 環境変数クラス
+// ============================================================================
+#pragma once
+#include <iostream>
+#include <string>
+#include <kgConfig.h>
+#include <kgMethod.h>
+#include <boost/random.hpp>
+using namespace std;
+
+namespace kglib { ////////////////////////////////////////////// start namespace
+
+// kgmodが利用するグローバル変数クラス
+class kgEnv {
+ int oSize_; // readのsize
+ int iSize_; // writeのsize
+ int maxRecLen; // 一行の最大文字数
+ int outBufSize; // 出力バッファのサイズ
+ int verboseLevel; // メッセージ出力をしないフラグ(kgInitで設定)
+ kgstr_t tmpPath; // 一時ファイル用ディレクトリパス名
+ string encoding; // CSVとコンソールのエンコーディング
+ bool noFldName; // 1行目は項目名行でない
+ int _precision; // double型の出力有効桁数
+ bool _fldByNum; // 項目番号で指定する
+ bool recursiveMsg_; // 再帰的にmodのエラーメッセージを出すかどうか
+
+ bool sigact_; // シグナルトラップ起動中かどうか(true:起動中, false:なし)
+ int blockCount_; // キー単位ごとに処理する際に使用するバッファ数
+
+ kgAutoPtr1<boost::variate_generator< boost::mt19937,boost::uniform_int<> > > randStrAP_;
+
+public:
+ kgEnv(void);
+ ~kgEnv(void){}
+
+ // アクセッサ
+ size_t iSize(void) const{ return iSize_; }
+ size_t oSize(void) const{ return oSize_; }
+ int getMaxRecLen(void) const{ return maxRecLen; }
+ int getOutBufSize(void) const{ return outBufSize; }
+ int getVerboseLevel(void) const{ return verboseLevel; }
+ kgstr_t getTmpPath(void) const{ return tmpPath; }
+ string getEncoding(void) const{ return encoding; }
+ bool getNoFldName(void) const{ return noFldName; }
+ int precision(void) const{ return _precision; }
+ bool fldByNum(void) const{ return _fldByNum; }
+ bool recursiveMsg(void) const{ return recursiveMsg_; }
+ int getBlockCount(void) const{ return blockCount_; }
+ bool sigactcheck(void) const{ return sigact_; }
+
+ // 有効桁数セット
+ void precision(int p);
+
+ // シグナル状況登録
+ void sigact(bool b=true){sigact_=b;}
+
+ // 乱数文字作成
+ string randStr(size_t size);
+
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgEnv.h エラー処理クラス
+// ============================================================================
+#pragma once
+#include <vector>
+#include <string>
+#include <exception>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+class kgError : public std::exception
+{
+ // errorをcatchした関数のメッセージ
+ vector<string> message_;
+
+ public:
+ // コンストラクタ
+ kgError(){}
+ kgError(string msg);
+
+ // デストラクタ
+ ~kgError(void) throw() {}
+
+ string::size_type size(void) const { return message_.size(); }
+ string message(int no) const { return message_.at(no); }
+ vector<string> message(void ) const { return message_; }
+
+ void addMessage(string msg);
+ void addModName(string msg);
+ //クラスメソッド
+ static void fldCntErr(int fldCnt, int j);
+ static void recLenErr(size_t manlen);
+ static void recLenErr(void);
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgFldBuffer.h 項目データバッファクラス
+// ============================================================================
+#pragma once
+#include <kgMethod.h>
+#include <kgTempfile.h>
+
+namespace kglib { ////////////////////////////////////////////// start namespace
+
+// 専用バッファリングクラス
+// 一度拡張されると縮小されない
+// マックスページを超えると以降のデータはファイル書き出される
+// page
+// +----------------
+// |
+// |
+// +----------------
+// +----------------
+// |
+// |
+// +----------------
+// +----------------
+// |
+// |
+// +----------------
+class kgFldBuffer{
+ size_t max_page_; // 最大ページ数
+ size_t page_size_; // ページ自体サイズ
+ size_t limit_page_; // 確保済みページ数
+ size_t w_page_; // 書込中ページ
+ size_t r_page_; // 読込中ページ
+ size_t r_pos_; // 読込位置
+
+ vector<kgAutoPtr2<char> > page_p_; // ページ領域へポインタ
+ vector<size_t > end_pos_; // データ終了位置
+
+ kgAutoPtr2<char> fpage_p_; // ファイル読み込み領域
+ kgTempfile tempFile_; // 書き出しファイル用
+ vector<string> flist_; // 書き出しファイルリスト
+ char* pageSet(void); // 読み込みページセット
+ void fileload(int fno); // ファイル(バッファファイル)からの読み込み
+
+public:
+ //コンストラクタ
+ kgFldBuffer(size_t pmax=10,size_t size=KG_iSize ,kgEnv* env=0):
+ max_page_(pmax),page_size_(size),limit_page_(0),w_page_(0),r_page_(0),r_pos_(0),tempFile_(env){
+ page_p_.resize(max_page_);
+ end_pos_.resize(max_page_,0);
+ }
+ ~kgFldBuffer(void){};
+ // バッファへの書き込み
+ void write(char * start,size_t size);
+ // データ項目セット
+ int getFld(char ** pnt, int fldcnt);
+ // SEKKTOP
+ int seekRTop(void);
+ // 初期化
+ void reset(void);
+
+};
+}
+
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgFldHash.h 項目ハッシュ(hashavg,hashsumで使用)
+// =============================================================================
+#pragma once
+#include <vector>
+#include <kgCSV.h>
+#include <kgArgFld.h>
+#include <kgMethod.h>
+
+namespace kglib {////////////////////////////////////////////// namespace start
+
+class kgFldHashNode;
+
+class kgFldHash
+{
+ int _hashVal; // hashのバケットサイズ
+ int _cnt; // 現在登録されている値の数
+ vector<kgFldHashNode*> _node; // バッケトへのポインタ
+ kgCSVfld* _csv;
+ kgArgFld* _key;
+ kgArgFld* _fld;
+
+ unsigned int calHashVal(const char** flds);
+
+ public:
+ // コンストラクタ パラメータ省略時のバケット数は199999
+ kgFldHash(int hashVal, kgCSVfld* csv, kgArgFld* key, kgArgFld* fld);
+
+ // デストラクタ
+ ~kgFldHash(void);
+
+ // 挿入
+ kgFldHashNode* insert(const char** flds);
+ kgFldHashNode* node(int num) const { return _node.at(num); }
+
+ int recLen(void) { return _csv->recLen(); } // レコード長
+ int csvSize(void) { return _csv->fldSize(); } // データ項目数
+ char* csv(int num){ return _csv->getVal(num); } // データのnum番目項目
+
+ int key(int num) { return _key->num(num);} // k=で指定した第num番目項目番号
+ int keySize(void) { return _key->size(); } // k=で指定した項目数
+ int fldSize(void) { return _fld->size(); } // f=で指定した項目数
+
+ int hashVal(void){ return _hashVal;}
+};
+
+
+class kgFldHashNode
+{
+ kgFldHash* _hash;
+ kgAutoPtr2<char> _ap1; // _bufをラッピングするsmart pointer
+ char* _buf; // 一行まるまま登録領域
+ kgAutoPtr2<char*> _ap2; // _idxをラッピングするsmart pointer
+ char** _idx; // 登録されたデータの各項目へのポインタ
+ vector<double> _cnt; // null以外件数
+ vector<double> _sum; // 合計
+ vector<bool> _nul; // nullが一行でもあればtrue
+ kgFldHashNode* _next; // 次nodeへのリンク
+
+ public:
+ // コンストラクタ
+ kgFldHashNode(const char** flds, kgFldHash* hash);
+ virtual ~kgFldHashNode(void) {};
+
+ // keyの比較
+ bool keycmp(const char** flds);
+
+ void next(kgFldHashNode* next) {_next=next;}
+ void cnt(int num, double v) { _cnt.at(num)+=v;} // f=num番目の項目cnt up
+ void sum(int num, double v) { _sum.at(num)+=v;} // f=num番目の項目sum up
+ void nul(int num, bool v) { _nul.at(num) =v;}
+
+ // accessors(get)
+ kgFldHashNode* next(void) const {return _next;}
+ char* idx(int num) const { return *(_idx+num); }
+ double cnt(int num) const {return _cnt.at(num);} // f=num番目の件数を返す
+ double sum(int num) const {return _sum.at(num);} // f=num番目の合計を返す
+ bool nul(int num) const {return _nul.at(num);}
+};
+}////////////////////////////////////////////// namespace end
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgFunction.h 演算に使用する関数のクラス
+// ============================================================================
+#pragma once
+#include <vector>
+#include <string>
+#include <cfloat>
+#include <kgCSV.h>
+#include <kgArgFld.h>
+#include <kgVal.h>
+#include <kgMethod.h>
+#include <kgConfig.h>
+#include <boost/xpressive/xpressive.hpp>
+#include <boost/xpressive/xpressive_fwd.hpp>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/random.hpp>
+#include <boost/function.hpp>
+#include <boost/lambda/bind.hpp>
+#include <boost/lambda/construct.hpp>
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+// 関数の基底クラス
+// 派生クラスでの各種関数の役割
+// コンストラクタ:返り値の型や名前など静的に決まる変数の設定
+// initialize : 式をparseした後の定数や項目番号の設定
+// preprocess : initialize以外で必要な前処理
+class kgFunction {
+ public:
+ kgVal _result; // 返値
+ vector<kgVal*> _args; // 引数
+ kgCSVkey* _csv; // 入力ファイル
+ kgVal* _prvRsl; // 前行の計算結果
+ bool _fldno; // 項目番号指定
+
+ // 指定された引数の数をチェックするために以下の2つの変数を導入
+ vector<int>::size_type _minArgc; // 最小引数数
+ vector<int>::size_type _maxArgc; // 最大引数数
+ // エラーメッセージに利用する演算子名,関数名
+ const char* _name; // 関数名
+
+ // 実行 (定数では実装する必要なし)
+ virtual void run(void){}
+
+ // 定数,項目名の評価
+ virtual void initialize(kgstr_t&){}
+
+ // 関数毎に行う前処理不必要な関数では何もしない.
+ virtual void preprocess(void){}
+
+ virtual ~kgFunction(){}
+
+ // 引数の数のチェック
+ void chkArgc(void);
+};
+// ============================================================================
+// 定数関係クラス
+// ============================================================================
+// -------------------------------------------------------------------------
+// 文字列
+// -------------------------------------------------------------------------
+class kgFunction_const_str : public kgFunction
+{
+ string _val;
+ public:
+ kgFunction_const_str(void)
+ {_result.type('S');_name="const";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+// -------------------------------------------------------------------------
+// 数値
+// -------------------------------------------------------------------------
+class kgFunction_const_real : public kgFunction
+{
+ public:
+ kgFunction_const_real(void)
+ {_result.type('N');_name="const";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+// -------------------------------------------------------------------------
+// 日付
+// -------------------------------------------------------------------------
+class kgFunction_const_date : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_const_date(void)
+ {_result.type('D');_name="const";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+// -------------------------------------------------------------------------
+// 時刻
+// -------------------------------------------------------------------------
+class kgFunction_const_time : public kgFunction
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_const_time(void)
+ {_result.type('T');_name="const";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+// -------------------------------------------------------------------------
+// bool
+// -------------------------------------------------------------------------
+class kgFunction_const_bool : public kgFunction
+{
+ public:
+ kgFunction_const_bool(void)
+ {_result.type('B');_name="const";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+
+// ============================================================================
+// 項目関係クラス
+// ============================================================================
+// -------------------------------------------------------------------------
+// スーパークラス
+// -------------------------------------------------------------------------
+class kgFunction_field : public kgFunction
+{
+ protected:
+ kgArgFld _fld;
+ public:
+ kgFunction_field(void){_name="field";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str){ _fld.set(str,_csv,_fldno); }
+};
+// -------------------------------------------------------------------------
+// 文字列
+// -------------------------------------------------------------------------
+class kgFunction_field_str : public kgFunction_field
+{
+ public:
+ kgFunction_field_str(void){_result.type('S');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 数値
+// -------------------------------------------------------------------------
+class kgFunction_field_real : public kgFunction_field
+{
+ public:
+ kgFunction_field_real(void) {_result.type('N');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 日付
+// -------------------------------------------------------------------------
+class kgFunction_field_date : public kgFunction_field
+{
+ kgAutoPtr1<date> _ap;
+ public:
+ kgFunction_field_date(void) {_result.type('D');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 時刻
+// -------------------------------------------------------------------------
+class kgFunction_field_time : public kgFunction_field
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_field_time(void){_result.type('T');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// bool
+// -------------------------------------------------------------------------
+class kgFunction_field_bool : public kgFunction_field
+{
+ public:
+ kgFunction_field_bool(void){_result.type('B');}
+ virtual void run(void);
+};
+// ============================================================================
+// 前行項目関係クラス
+// ============================================================================
+// -------------------------------------------------------------------------
+// スーパークラス
+// -------------------------------------------------------------------------
+class kgFunction_pfield : public kgFunction
+{
+ protected:
+ kgArgFld _fld;
+ bool _rsl;
+ public:
+ kgFunction_pfield(void){_name="pfield";_minArgc=1;_maxArgc=1;}
+ virtual void initialize(kgstr_t& str);
+};
+// -------------------------------------------------------------------------
+// 文字列
+// -------------------------------------------------------------------------
+class kgFunction_pfield_str : public kgFunction_pfield
+{
+ public:
+ kgFunction_pfield_str(void){ _result.type('S');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 数値
+// -------------------------------------------------------------------------
+class kgFunction_pfield_real : public kgFunction_pfield
+{
+ public:
+ kgFunction_pfield_real(void){ _result.type('N');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 日付
+// -------------------------------------------------------------------------
+class kgFunction_pfield_date : public kgFunction_pfield
+{
+ kgAutoPtr1<date> _ap;
+ public:
+ kgFunction_pfield_date(void){ _result.type('D');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// 時刻
+// -------------------------------------------------------------------------
+class kgFunction_pfield_time : public kgFunction_pfield
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_pfield_time(void){_result.type('T');}
+ virtual void run(void);
+};
+// -------------------------------------------------------------------------
+// bool
+// -------------------------------------------------------------------------
+class kgFunction_pfield_bool : public kgFunction_pfield
+{
+ public:
+ kgFunction_pfield_bool(void){ _result.type('B');}
+ virtual void run(void);
+};
+// ============================================================================
+// 四則演算関係クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// 文字列 + 文字列 => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_add_str : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_add_str(void)
+ {_result.type('S');_name="+";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 + 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_add_real : public kgFunction
+{
+ public:
+ kgFunction_add_real(void)
+ {_result.type('N');_name="+";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 + 数値 => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_add_day : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_add_day(void)
+ {_result.type('D');_name="+";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 + 数値 => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_add_sec : public kgFunction
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_add_sec(void)
+ {_result.type('T');_name="+";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 - 文字列 => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_sub_str : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_sub_str(void)
+ {_result.type('S');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 - 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_sub_real : public kgFunction
+{
+ public:
+ kgFunction_sub_real(void)
+ {_result.type('N');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 - 日付 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_sub_date : public kgFunction
+{
+ public:
+ kgFunction_sub_date(void)
+ {_result.type('N');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 - 時刻 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_sub_time : public kgFunction
+{
+ public:
+ kgFunction_sub_time(void)
+ {_result.type('N');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 - 数値 => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_sub_day : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_sub_day(void)
+ {_result.type('D');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 - 数値 => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_sub_sec : public kgFunction
+{
+ kgAutoPtr1 <ptime> _ap;
+ public:
+ kgFunction_sub_sec(void)
+ {_result.type('T');_name="-";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 * 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_mul_real : public kgFunction
+{
+ public:
+ kgFunction_mul_real(void)
+ {_result.type('N');_name="*";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 / 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_div_real : public kgFunction
+{
+ public:
+ kgFunction_div_real(void)
+ {_result.type('N');_name="/";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 % 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_mod_real : public kgFunction
+{
+ public:
+ kgFunction_mod_real(void)
+ {_result.type('N');_name="%";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 ^ 数値 => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_pow_real : public kgFunction
+{
+ public:
+ kgFunction_pow_real(void)
+ {_result.type('N');_name="^";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// ============================================================================
+// 比較演算子関係クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// 文字列 >= 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ge_str : public kgFunction
+{
+ public:
+ kgFunction_ge_str(void)
+ {_result.type('B');_name=">=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 >= 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ge_real : public kgFunction
+{
+ public:
+ kgFunction_ge_real(void)
+ {_result.type('B');_name=">=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 >= 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ge_date : public kgFunction
+{
+ public:
+ kgFunction_ge_date(void)
+ {_result.type('B');_name=">=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 >= 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ge_time : public kgFunction
+{
+ public:
+ kgFunction_ge_time(void)
+ {_result.type('B');_name=">=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 <= 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_le_str : public kgFunction
+{
+ public:
+ kgFunction_le_str(void)
+ {_result.type('B');_name="<=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 <= 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_le_real : public kgFunction
+{
+ public:
+ kgFunction_le_real(void)
+ {_result.type('B');_name="<=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 <= 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_le_date : public kgFunction
+{
+ public:
+ kgFunction_le_date(void)
+ {_result.type('B');_name="<=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 <= 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_le_time : public kgFunction
+{
+ public:
+ kgFunction_le_time(void)
+ {_result.type('B');_name="<=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 > 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_gt_str : public kgFunction
+{
+ public:
+ kgFunction_gt_str(void)
+ {_result.type('B');_name=">";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 > 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_gt_real : public kgFunction
+{
+ public:
+ kgFunction_gt_real(void)
+ {_result.type('B');_name=">";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 > 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_gt_date : public kgFunction
+{
+ public:
+ kgFunction_gt_date(void)
+ {_result.type('B');_name=">";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 > 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_gt_time : public kgFunction
+{
+ public:
+ kgFunction_gt_time(void)
+ {_result.type('B');_name=">";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 < 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_lt_str : public kgFunction
+{
+ public:
+ kgFunction_lt_str(void)
+ {_result.type('B');_name="<";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 < 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_lt_real : public kgFunction
+{
+ public:
+ kgFunction_lt_real(void)
+ {_result.type('B');_name="<";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 < 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_lt_date : public kgFunction
+{
+ public:
+ kgFunction_lt_date(void)
+ {_result.type('B');_name="<";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 < 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_lt_time : public kgFunction
+{
+ public:
+ kgFunction_lt_time(void)
+ {_result.type('B');_name="<";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 == 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_eq_str : public kgFunction
+{
+ public:
+ kgFunction_eq_str(void)
+ {_result.type('B');_name="==";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 == 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_eq_real : public kgFunction
+{
+ public:
+ kgFunction_eq_real(void)
+ {_result.type('B');_name="==";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 == 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_eq_date : public kgFunction
+{
+ public:
+ kgFunction_eq_date(void)
+ {_result.type('B');_name="==";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 == 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_eq_time : public kgFunction
+{
+ public:
+ kgFunction_eq_time(void)
+ {_result.type('B');_name="==";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 文字列 != 文字列 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ne_str : public kgFunction
+{
+ public:
+ kgFunction_ne_str(void)
+ {_result.type('B');_name="!=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 数値 != 数値 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ne_real : public kgFunction
+{
+ public:
+ kgFunction_ne_real(void)
+ {_result.type('B');_name="!=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 日付 != 日付 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ne_date : public kgFunction
+{
+ public:
+ kgFunction_ne_date(void)
+ {_result.type('B');_name="!=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// 時刻 != 時刻 => bool
+// -----------------------------------------------------------------------------
+class kgFunction_ne_time : public kgFunction
+{
+ public:
+ kgFunction_ne_time(void)
+ {_result.type('B');_name="!=";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// ============================================================================
+// 論理演算子関数クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// bool && bool => bool
+// -----------------------------------------------------------------------------
+class kgFunction_and : public kgFunction
+{
+ public:
+ kgFunction_and(void)
+ {_result.type('B');_name="&&";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// and(bool,bool,...,bool) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_multi_and : public kgFunction
+{
+ public:
+ kgFunction_multi_and(void)
+ {_result.type('B');_name="and";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// bool || bool => bool
+// -----------------------------------------------------------------------------
+class kgFunction_or : public kgFunction
+{
+ public:
+ kgFunction_or(void)
+ {_result.type('B');_name="||";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// or(bool,bool,...,bool) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_multi_or : public kgFunction
+{
+ public:
+ kgFunction_multi_or(void)
+ {_result.type('B');_name="or";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// bool ^^ bool => bool
+// -----------------------------------------------------------------------------
+class kgFunction_xor : public kgFunction
+{
+ public:
+ kgFunction_xor(void)
+ {_result.type('B');_name="^^";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// not(bool) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_not : public kgFunction
+{
+ public:
+ kgFunction_not(void)
+ {_result.type('B');_name="not";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// if(bool,文字列,文字列) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_if_str : public kgFunction
+{
+ public:
+ kgFunction_if_str(void)
+ {_result.type('S');_name="if";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// if(bool,数値,数値) => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_if_real : public kgFunction
+{
+ public:
+ kgFunction_if_real(void)
+ {_result.type('N');_name="if";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// if(bool,日付,日付) => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_if_date : public kgFunction
+{
+ public:
+ kgFunction_if_date(void)
+ {_result.type('D');_name="if";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// if(bool,時刻,時刻) => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_if_time : public kgFunction
+{
+ public:
+ kgFunction_if_time(void)
+ {_result.type('T');_name="if";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+
+// ============================================================================
+// NULL値関連関数クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// null_s
+// -----------------------------------------------------------------------------
+class kgFunction_const_nulls : public kgFunction
+{
+ public:
+ kgFunction_const_nulls(void){
+ _result.type('S');_name="nulls";_minArgc=0;_maxArgc=0;
+ _result.null(true);_result.s(const_cast<char*>(""));
+ }
+};
+// -----------------------------------------------------------------------------
+// null_n
+// -----------------------------------------------------------------------------
+class kgFunction_const_nulln : public kgFunction
+{
+ public:
+ kgFunction_const_nulln(void){
+ _result.type('N');_name="nulln";_minArgc=0;_maxArgc=0;
+ _result.null(true);
+ }
+};
+// -----------------------------------------------------------------------------
+// null_d
+// -----------------------------------------------------------------------------
+class kgFunction_const_nulld : public kgFunction
+{
+ public:
+ kgFunction_const_nulld(void){
+ _result.type('D');_name="nulld";_minArgc=0;_maxArgc=0;
+ _result.null(true);
+ }
+};
+// -----------------------------------------------------------------------------
+// null_t
+// -----------------------------------------------------------------------------
+class kgFunction_const_nullt : public kgFunction
+{
+ public:
+ kgFunction_const_nullt(void){
+ _result.type('T');_name="nullt";_minArgc=0;_maxArgc=0;
+ _result.null(true);
+ }
+};
+// -----------------------------------------------------------------------------
+// null_b
+// -----------------------------------------------------------------------------
+class kgFunction_const_nullb : public kgFunction
+{
+ public:
+ kgFunction_const_nullb(void){
+ _result.type('B');_name="nullb";_minArgc=0;_maxArgc=0;
+ _result.null(true);
+ }
+};
+// -----------------------------------------------------------------------------
+// isnull(文字列) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_isnull_s : public kgFunction
+{
+ public:
+ kgFunction_isnull_s(void)
+ {_result.type('B');_name="isnull";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// isnull(数値) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_isnull_n : public kgFunction
+{
+ public:
+ kgFunction_isnull_n(void)
+ {_result.type('B');_name="isnull";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// isnull(日付) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_isnull_d : public kgFunction
+{
+ public:
+ kgFunction_isnull_d(void)
+ {_result.type('B');_name="isnull";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// isnull(時刻) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_isnull_t : public kgFunction
+{
+ public:
+ kgFunction_isnull_t(void)
+ {_result.type('B');_name="isnull";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// isnull(bool) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_isnull_b : public kgFunction
+{
+ public:
+ kgFunction_isnull_b(void)
+ {_result.type('B');_name="isnull";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// countnull(文字列,文字列...) => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_countnull_s : public kgFunction
+{
+ public:
+ kgFunction_countnull_s(void)
+ {_result.type('N');_name="countnull";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// countnull(数値,数値,....) => 数値
+// countnull(日付,日付,...) => 数値
+// countnull(時刻,時刻,...) => 数値
+// countnull(bool,bool,..) => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_countnull : public kgFunction
+{
+ public:
+ kgFunction_countnull(void)
+ {_result.type('N');_name="countnull";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// ============================================================================
+// 型変換関数クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// s2n(文字列) => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_s2n : public kgFunction
+{
+ public:
+ kgFunction_s2n(void)
+ {_result.type('N');_name="s2n";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// s2d(文字列) => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_s2d : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_s2d(void)
+ {_result.type('D');_name="s2d";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// s2t(文字列) => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_s2t : public kgFunction
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_s2t(void)
+ {_result.type('T');_name="s2t";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// t2d(時刻) => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_t2d : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_t2d(void)
+ {_result.type('D');_name="t2d";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// d2t(日付) => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_d2t : public kgFunction
+{
+ kgAutoPtr1<ptime> _ap;
+ public:
+ kgFunction_d2t(void)
+ {_result.type('T');_name="d2t";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+
+
+// -----------------------------------------------------------------------------
+// n2s(数値) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_n2s : public kgFunction
+{
+ char _buf[256];
+ public:
+ kgFunction_n2s(void)
+ {_result.type('S');_name="n2s";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// d2s(日付) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_d2s : public kgFunction
+{
+ char _buf[10];
+ public:
+ kgFunction_d2s(void)
+ {_result.type('S');_name="d2s";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// t2s(時刻) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_t2s : public kgFunction
+{
+ char _buf[20];
+ public:
+ kgFunction_t2s(void)
+ {_result.type('S');_name="t2s";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// b2n(bool) => 数値
+// -----------------------------------------------------------------------------
+class kgFunction_b2n : public kgFunction
+{
+ public:
+ kgFunction_b2n(void)
+ {_result.type('N');_name="b2n";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// b2s(bool) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_b2s : public kgFunction
+{
+ char _buf[2];
+ public:
+ kgFunction_b2s(void)
+ {_result.type('S');_buf[1]='\0';_name="b2s";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// n2b(数値) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_n2b : public kgFunction
+{
+ public:
+ kgFunction_n2b(void)
+ {_result.type('B');_name="n2b";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// n2b(文字列) => bool
+// -----------------------------------------------------------------------------
+class kgFunction_s2b : public kgFunction
+{
+ public:
+ kgFunction_s2b(void)
+ {_result.type('B');_name="s2b";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// format(数値,文字列[書式]) => 文字列 : 数値の書式付き変換
+// -----------------------------------------------------------------------------
+class kgFunction_format_real : public kgFunction
+{
+ char _buf[256];
+ public:
+ kgFunction_format_real(void)
+ {_result.type('S');_name="format";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// ============================================================================
+// 日付時刻関数クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// today() => 日付
+// -----------------------------------------------------------------------------
+class kgFunction_today : public kgFunction
+{
+ boost::gregorian::date _today;
+ public:
+ kgFunction_today(void)
+ {_result.type('D');_name="today";_minArgc=0;_maxArgc=0;}
+ virtual void initialize(kgstr_t& str);
+};
+// -----------------------------------------------------------------------------
+// now() => 時刻
+// -----------------------------------------------------------------------------
+class kgFunction_now : public kgFunction
+{
+ boost::posix_time::ptime _now;
+ public:
+ kgFunction_now(void)
+ {_result.type('T');_name="now";_minArgc=0;_maxArgc=0;}
+ virtual void initialize(kgstr_t& str);
+};
+
+// -----------------------------------------------------------------------------
+// time(時刻) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_time_str : public kgFunction
+{
+ char _buf[16];
+ public:
+ kgFunction_time_str(void)
+ {_result.type('S');_name="time";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// date(時刻) => 文字列
+// -----------------------------------------------------------------------------
+class kgFunction_date_str : public kgFunction
+{
+ char _buf[20];
+ public:
+ kgFunction_date_str(void)
+ {_result.type('S');_name="date";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// leapyear(日付) => bool : 閏年判定する
+// -----------------------------------------------------------------------------
+class kgFunction_leapyear_d : public kgFunction
+{
+ public:
+ kgFunction_leapyear_d(void)
+ {_result.type('B');_name="leapyear";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// leapyear(時刻) => bool : 閏年判定する
+// -----------------------------------------------------------------------------
+class kgFunction_leapyear_t : public kgFunction
+{
+ public:
+ kgFunction_leapyear_t(void)
+ {_result.type('B');_name="leapyear";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// d2julian(日付) => 数値 : ユリウス通日を求める
+// -----------------------------------------------------------------------------
+class kgFunction_d2julian : public kgFunction
+{
+ public:
+ kgFunction_d2julian(void)
+ {_result.type('N');_name="d2julian";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// t2julian(時刻) => 数値 : ユリウス通日を求める
+// -----------------------------------------------------------------------------
+class kgFunction_t2julian : public kgFunction
+{
+ public:
+ kgFunction_t2julian(void)
+ {_result.type('N');_name="t2julian";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// julian2d(数値) => 日付 : ユリウス通日から日付を求める
+// -----------------------------------------------------------------------------
+class kgFunction_julian2d : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_julian2d(void)
+ {_result.type('D');_name="julian2d";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// julian2t(数値) => 日付 : ユリウス通日から時刻を求める
+// -----------------------------------------------------------------------------
+class kgFunction_julian2t : public kgFunction
+{
+ kgAutoPtr1 <ptime> _ap;
+ public:
+ kgFunction_julian2t(void)
+ {_result.type('T');_name="julian2t";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// uxt2d(数値) => 日付 : UNIX時刻から通常日付を求める
+// -----------------------------------------------------------------------------
+class kgFunction_uxt2d : public kgFunction
+{
+ kgAutoPtr1 <date> _ap;
+ public:
+ kgFunction_uxt2d(void)
+ {_result.type('D');_name="uxt2d";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// uxt2t(時刻) => 日付 : UNIX時刻から通常日時を求める
+// -----------------------------------------------------------------------------
+class kgFunction_uxt2t : public kgFunction
+{
+ kgAutoPtr1 <ptime> _ap;
+ public:
+ kgFunction_uxt2t(void)
+ {_result.type('T');_name="uxt2t";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// d2uxt(日付) => 数値 : 通常の日付をUNIX時刻に変換する
+// -----------------------------------------------------------------------------
+class kgFunction_d2uxt : public kgFunction
+{
+ public:
+ kgFunction_d2uxt(void)
+ {_result.type('N');_name="d2uxt";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// t2uxt(時刻) => 数値 : 通常の日時をUNIX時刻に変換する
+// -----------------------------------------------------------------------------
+class kgFunction_t2uxt : public kgFunction
+{
+ public:
+ kgFunction_t2uxt(void)
+ {_result.type('N');_name="t2uxt";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// age(日付1,日付2) => 数値 : 日付1を生年月日とした時の 日付2時点での年齢
+// -----------------------------------------------------------------------------
+class kgFunction_age_d : public kgFunction
+{
+ public:
+ kgFunction_age_d(void)
+ {_result.type('N');_name="age";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// age(時刻1,時刻2) => 数値 : 時刻1を生年月日日時とした時の 時刻2時点での年齢
+// -----------------------------------------------------------------------------
+class kgFunction_age_t : public kgFunction
+{
+ public:
+ kgFunction_age_t(void)
+ {_result.type('N');_name="age";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffyear(日付1,日付2) => 数値 :
+// 日付の引き算(日付1-日付2)
+// 年数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffyear_d : public kgFunction
+{
+ public:
+ kgFunction_diffyear_d(void)
+ {_result.type('N');_name="diffyear";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffmonth(日付1,日付2) => 数値 :
+// 日付の引き算(日付1-日付2)
+// 月数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffmonth_d : public kgFunction
+{
+ public:
+ kgFunction_diffmonth_d(void)
+ {_result.type('N');_name="diffmonth";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffday(日付1,日付2) => 数値 :
+// 日付の引き算(日付1-日付2)
+// 日数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffday_d : public kgFunction
+{
+ public:
+ kgFunction_diffday_d(void)
+ {_result.type('N');_name="diffday";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffyear(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ年数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffyear_t : public kgFunction
+{
+ public:
+ kgFunction_diffyear_t(void)
+ {_result.type('N');_name="diffyear";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffmonth(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ月数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffmonth_t : public kgFunction
+{
+ public:
+ kgFunction_diffmonth_t(void)
+ {_result.type('N');_name="diffmonth";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffday(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ日数差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffday_t : public kgFunction
+{
+ public:
+ kgFunction_diffday_t(void)
+ {_result.type('N');_name="diffday";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffhour(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ時間差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffhour_t : public kgFunction
+{
+ public:
+ kgFunction_diffhour_t(void)
+ {_result.type('N');_name="diffhour";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffminute(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ分差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffminute_t : public kgFunction
+{
+ public:
+ kgFunction_diffminute_t(void)
+ {_result.type('N');_name="diffminute";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// diffsecond(時刻1,時刻2) => 数値 :
+// 時刻の引き算(時刻1-時刻2)
+// それぞれ秒差を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_diffsecond_t : public kgFunction
+{
+ public:
+ kgFunction_diffsecond_t(void)
+ {_result.type('N');_name="diffsecond";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// year(日付) => 数値 : 年抽出
+// -----------------------------------------------------------------------------
+class kgFunction_year_d : public kgFunction
+{
+ public:
+ kgFunction_year_d(void)
+ {_result.type('N');_name="year";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// year(時刻) => 数値 : 年抽出
+// -----------------------------------------------------------------------------
+class kgFunction_year_t : public kgFunction
+{
+ public:
+ kgFunction_year_t(void)
+ {_result.type('N');_name="year";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// years(日付) => 文字列 : 年抽出
+// -----------------------------------------------------------------------------
+class kgFunction_years_d : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_years_d(void)
+ {_result.type('S');_name="years";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// years(時刻) => 数値 : 年抽出
+// -----------------------------------------------------------------------------
+class kgFunction_years_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_years_t(void)
+ {_result.type('S');_name="years";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// month(日付) => 文字列 : 月抽出
+// -----------------------------------------------------------------------------
+class kgFunction_month_d : public kgFunction
+{
+ public:
+ kgFunction_month_d(void)
+ {_result.type('N');_name="month";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// month(時刻) => 数値 : 月抽出
+// -----------------------------------------------------------------------------
+class kgFunction_month_t : public kgFunction
+{
+ public:
+ kgFunction_month_t(void)
+ {_result.type('N');_name="month";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// months(日付) => 文字列 : 月抽出
+// -----------------------------------------------------------------------------
+class kgFunction_months_d : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_months_d(void)
+ {_result.type('S');_name="months";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// months(時刻) => 文字列 : 月抽出
+// -----------------------------------------------------------------------------
+class kgFunction_months_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_months_t(void)
+ {_result.type('S');_name="months";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// emonthスーパークラス => 文字列 : 月抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_emonth : public kgFunction
+{
+ protected:
+ static const char* _str[13];
+};
+// -----------------------------------------------------------------------------
+// emonth(日付) => 文字列 : 月抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_emonth_d : public kgFunction_emonth
+{
+ public:
+ kgFunction_emonth_d(void)
+ {_result.type('S');_name="emonth";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// emonth(時刻) => 文字列 : 月抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_emonth_t : public kgFunction_emonth
+{
+ public:
+ kgFunction_emonth_t(void)
+ {_result.type('S');_name="emonth";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// esmonthスーパークラス => 文字列 : 月抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esmonth : public kgFunction
+{
+ protected:
+ static const char* _str[13];
+};
+// -----------------------------------------------------------------------------
+// esmonth(日付) => 文字列 : 月抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esmonth_d : public kgFunction_esmonth
+{
+ public:
+ kgFunction_esmonth_d(void)
+ {_result.type('S');_name="esmonth";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// esmonth(時刻) => 文字列 : 月抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esmonth_t : public kgFunction_esmonth
+{
+ public:
+ kgFunction_esmonth_t(void)
+ {_result.type('S');_name="esmonth";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// day(日付) => 数値 : 日抽出
+// -----------------------------------------------------------------------------
+class kgFunction_day_d : public kgFunction
+{
+ public:
+ kgFunction_day_d(void)
+ {_result.type('N');_name="day";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// day(時刻) => 数値 : 日抽出
+// -----------------------------------------------------------------------------
+class kgFunction_day_t : public kgFunction
+{
+ public:
+ kgFunction_day_t(void)
+ {_result.type('N');_name="day";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// days(日付) => 文字列 : 日抽出
+// -----------------------------------------------------------------------------
+class kgFunction_days_d : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_days_d(void)
+ {_result.type('S');_name="days";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// days(時刻) => 文字列 : 日抽出
+// -----------------------------------------------------------------------------
+class kgFunction_days_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_days_t(void)
+ {_result.type('S');_name="days";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// week(日付) => 数値 : 週数抽出
+// -----------------------------------------------------------------------------
+class kgFunction_week_d : public kgFunction
+{
+ public:
+ kgFunction_week_d(void)
+ {_result.type('N');_name="week";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// week(時刻) => 数値 : 週数抽出
+// -----------------------------------------------------------------------------
+class kgFunction_week_t : public kgFunction
+{
+ public:
+ kgFunction_week_t(void)
+ {_result.type('N');_name="week";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// week111(日付) => 数値 : 週数抽出
+// -----------------------------------------------------------------------------
+class kgFunction_week111_d : public kgFunction
+{
+ public:
+ kgFunction_week111_d(void)
+ {_result.type('N');_name="week111";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// week(時刻) => 数値 : 週数抽出
+// -----------------------------------------------------------------------------
+class kgFunction_week111_t : public kgFunction
+{
+ public:
+ kgFunction_week111_t(void)
+ {_result.type('N');_name="week111";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+
+// -----------------------------------------------------------------------------
+// dow(日付) => 数値 : 曜日番号抽出(0:日曜)
+// -----------------------------------------------------------------------------
+class kgFunction_dow_d : public kgFunction
+{
+ public:
+ kgFunction_dow_d(void)
+ {_result.type('N');_name="dow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// dow(時刻) => 数値 : 曜日番号抽出(0:日曜)
+// -----------------------------------------------------------------------------
+class kgFunction_dow_t : public kgFunction
+{
+ public:
+ kgFunction_dow_t(void)
+ {_result.type('N');_name="dow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// edowスーパークラス => 文字列 : 曜日抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_edow : public kgFunction
+{
+ protected:
+ static const char* _str[8];
+};
+// -----------------------------------------------------------------------------
+// edow(日付) => 文字列 : 曜日抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_edow_d : public kgFunction_edow
+{
+ public:
+ kgFunction_edow_d(void)
+ {_result.type('S');_name="edow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// edow(時刻) => 文字列 : 曜日抽出(英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_edow_t : public kgFunction_edow
+{
+ public:
+ kgFunction_edow_t(void)
+ {_result.type('S');_name="edow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// esdow(日付) => スーパークラス : 曜日抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esdow : public kgFunction
+{
+ protected:
+ static const char* _str[8];
+};
+// -----------------------------------------------------------------------------
+// esdow(日付) => 文字列 : 曜日抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esdow_d : public kgFunction_esdow
+{
+ public:
+ kgFunction_esdow_d(void)
+ {_result.type('S');_name="esdow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// esdow(時刻) => 文字列 : 曜日抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_esdow_t : public kgFunction_esdow
+{
+ public:
+ kgFunction_esdow_t(void)
+ {_result.type('S');_name="esdow";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// dowj(日付) => スーパークラス : 曜日抽出(日本語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_dowj : public kgFunction
+{
+ protected:
+ static const char* _str[8];
+};
+// -----------------------------------------------------------------------------
+// esdow(日付) => 文字列 : 曜日抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_dowj_d : public kgFunction_dowj
+{
+ public:
+ kgFunction_dowj_d(void)
+ {_result.type('S');_name="esdowj";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// esdow(時刻) => 文字列 : 曜日抽出(短縮英語表記)
+// -----------------------------------------------------------------------------
+class kgFunction_dowj_t : public kgFunction_dowj
+{
+ public:
+ kgFunction_dowj_t(void)
+ {_result.type('S');_name="esdowj";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+
+// -----------------------------------------------------------------------------
+// hours(時刻) => 数値 : 時間抽出
+// -----------------------------------------------------------------------------
+class kgFunction_hour_t : public kgFunction
+{
+ public:
+ kgFunction_hour_t(void)
+ {_result.type('N');_name="hour";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// hours(時刻) => 文字列 : 時間抽出
+// -----------------------------------------------------------------------------
+class kgFunction_hours_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_hours_t(void)
+ {_result.type('S');_name="hours";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// minute(時刻) => 数値 : 分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_minute_t : public kgFunction
+{
+ public:
+ kgFunction_minute_t(void)
+ {_result.type('N');_name="minute";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// minutes(時刻) => 文字列 : 分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_minutes_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_minutes_t(void)
+ {_result.type('S');_name="minutes";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// second(時刻) => 数値 : 秒抽出
+// -----------------------------------------------------------------------------
+class kgFunction_second_t : public kgFunction
+{
+ public:
+ kgFunction_second_t(void)
+ {_result.type('N');_name="second";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// seconds(時刻) => 数値 : 秒抽出
+// -----------------------------------------------------------------------------
+class kgFunction_seconds_t : public kgFunction
+{
+ char _buf[8];
+ public:
+ kgFunction_seconds_t(void)
+ {_result.type('S');_name="seconds";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// tseconds(時刻) => 数値 : トータルの秒数計算
+// -----------------------------------------------------------------------------
+class kgFunction_tseconds_t : public kgFunction
+{
+ public:
+ kgFunction_tseconds_t(void)
+ {_result.type('N');_name="tseconds";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// ============================================================================
+// 数値関連クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// sum(数値,...,数値) => 数値 : 合計(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_sum : public kgFunction
+{
+ public:
+ kgFunction_sum(void)
+ {_result.type('N');_name="sum";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// suma(数値,...,数値) => 数値 : 合計(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_sum_N : public kgFunction
+{
+ public:
+ kgFunction_sum_N(void)
+ {_result.type('N');_name="sum";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// avg(数値,...,数値) => 数値 : 平均計算(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_avg : public kgFunction
+{
+ public:
+ kgFunction_avg(void)
+ {_result.type('N');_name="avg";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// avga(数値,...,数値) => 数値 : 平均計算(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_avg_N : public kgFunction
+{
+ public:
+ kgFunction_avg_N(void)
+ {_result.type('N');_name="avg";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// sqsum(数値,...,数値) => 数値 : 平方合計(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_sqsum : public kgFunction
+{
+ public:
+ kgFunction_sqsum(void)
+ {_result.type('N');_name="sqsum";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// sqsuma(数値,...,数値) => 数値 : 平方合計(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_sqsum_N : public kgFunction
+{
+ public:
+ kgFunction_sqsum_N(void)
+ {_result.type('N');_name="sqsum";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// factorial(数値) => 数値 : 階乗計算
+// -----------------------------------------------------------------------------
+class kgFunction_factorial : public kgFunction
+{
+ public:
+ kgFunction_factorial(void)
+ {_result.type('N');_name="factorial";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// gcd(数値,数値) => 数値 : 最大公約数計算
+// -----------------------------------------------------------------------------
+class kgFunction_gcd : public kgFunction
+{
+ public:
+ kgFunction_gcd(void)
+ {_result.type('N');_name="gcd";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// lcm(数値,数値) => 数値 : 最小公倍数計算
+// -----------------------------------------------------------------------------
+class kgFunction_lcm : public kgFunction
+{
+ public:
+ kgFunction_lcm(void)
+ {_result.type('N');_name="lcm";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// sqrt(数値) => 数値 : 平方根計算
+// -----------------------------------------------------------------------------
+class kgFunction_sqrt : public kgFunction
+{
+ public:
+ kgFunction_sqrt(void)
+ {_result.type('N');_name="sqrt";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// fract(数値) => 数値 : 小数部分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_fract : public kgFunction
+{
+ public:
+ kgFunction_fract(void)
+ {_result.type('N');_name="fract";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// int(数値) => 数値 : 整数部分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_int : public kgFunction
+{
+ public:
+ kgFunction_int(void)
+ {_result.type('N');_name="int";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// min(数値,...,数値) => 数値 : 最小値計算(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_min : public kgFunction
+{
+ public:
+ kgFunction_min(void)
+ {_result.type('N');_name="min";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// mina(数値,...,数値) => 数値 : 最小値計算(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_min_N : public kgFunction
+{
+ public:
+ kgFunction_min_N(void)
+ {_result.type('N');_name="min";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// max(数値,...,数値) => 数値 : 最大値計算(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_max : public kgFunction
+{
+ public:
+ kgFunction_max(void)
+ {_result.type('N');_name="max";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// maxa(数値,...,数値) => 数値 : 最大値計算(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_max_N : public kgFunction
+{
+ public:
+ kgFunction_max_N(void)
+ {_result.type('N');_name="max";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// abs(数値) => 数値 : 絶対値計算
+// -----------------------------------------------------------------------------
+class kgFunction_abs : public kgFunction
+{
+ public:
+ kgFunction_abs(void)
+ {_result.type('N');_name="abs";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// round(数値1,数値2) => 数値 : 四捨五入計算(数値1を数値2の値で四捨五入)
+// -----------------------------------------------------------------------------
+class kgFunction_round : public kgFunction
+{
+ public:
+ kgFunction_round(void)
+ {_result.type('N');_name="round";_minArgc=1;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// power(数値1,数値2) => 数値 : べき乗計算(数値1を数値2の値でべき乗)
+// -----------------------------------------------------------------------------
+class kgFunction_power : public kgFunction
+{
+ public:
+ kgFunction_power(void)
+ {_result.type('N');_name="power";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// floor(数値1,数値2) => 数値 : 切捨計算(数値1を数値2の値で切り捨てて0に近い値にする)
+// -----------------------------------------------------------------------------
+class kgFunction_floor : public kgFunction
+{
+ public:
+ kgFunction_floor(void)
+ {_result.type('N');_name="floor";_minArgc=1;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// ceil(数値1,数値2) => 数値 : 切上計算(数値1を数値2の値で切り上げて0に遠い値にする)
+// -----------------------------------------------------------------------------
+class kgFunction_ceil : public kgFunction
+{
+ public:
+ kgFunction_ceil(void)
+ {_result.type('N');_name="ceil";_minArgc=1;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// exp(数値) => 数値 : eを底とするべき乗計算
+// -----------------------------------------------------------------------------
+class kgFunction_exp : public kgFunction
+{
+ public:
+ kgFunction_exp(void)
+ {_result.type('N');_name="exp";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// ln(数値) => 数値 : 自然対数計算
+// -----------------------------------------------------------------------------
+class kgFunction_ln : public kgFunction
+{
+ public:
+ kgFunction_ln(void)
+ {_result.type('N');_name="ln";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// log(数値) => 数値 : 対数計算
+// -----------------------------------------------------------------------------
+class kgFunction_log : public kgFunction
+{
+ public:
+ kgFunction_log(void)
+ {_result.type('N');_name="log";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// log2(数値) => 数値 : 2を底とする対数計算
+// -----------------------------------------------------------------------------
+class kgFunction_log2 : public kgFunction
+{
+ public:
+ kgFunction_log2(void)
+ {_result.type('N');_name="log2";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// log10(数値) => 数値 : 10を底とする対数計算
+// -----------------------------------------------------------------------------
+class kgFunction_log10 : public kgFunction
+{
+ public:
+ kgFunction_log10(void)
+ {_result.type('N');_name="log10";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// product(数値,...,数値) => 数値 : 数値すべての積(NULLはskip)
+// -----------------------------------------------------------------------------
+class kgFunction_product : public kgFunction
+{
+ public:
+ kgFunction_product(void)
+ {_result.type('N');_name="product";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// product_N(数値,...,数値) => 数値 : 数値すべての積(1でもNULLが有ると結果はNULL)
+// -----------------------------------------------------------------------------
+class kgFunction_product_N : public kgFunction
+{
+ public:
+ kgFunction_product_N(void)
+ {_result.type('N');_name="producta";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// sign(数値) => 数値 : 正負符号を判定する(正:1,負:-1,0:0)
+// -----------------------------------------------------------------------------
+class kgFunction_sign : public kgFunction
+{
+ public:
+ kgFunction_sign(void)
+ {_result.type('N');_name="sign";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// dist(距離関数名,数値,...,数値[2n]) => 数値 : n次元の2点の座標間のユークリッド距離を計算
+// -----------------------------------------------------------------------------
+class kgFunction_dist : public kgFunction
+{
+ unsigned int _dim;
+ char _type;
+ public:
+ kgFunction_dist(void)
+ {_result.type('N');_name="dist";_minArgc=5;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// disth(数値,...,数値[2n]) => 数値 : n次元の2点の座標間のハミング距離を計算
+// -----------------------------------------------------------------------------
+class kgFunction_disth : public kgFunction
+{
+ unsigned int _dim;
+ public:
+ kgFunction_disth(void)
+ {_result.type('N');_name="dist";_minArgc=5;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// distgps(数値[緯度],数値[経度],数値[緯度],数値[経度]) => 数値 : 2点の緯度経度から距離を計算
+// -----------------------------------------------------------------------------
+class kgFunction_distgps : public kgFunction
+{
+ static const double Eradius_;
+ public:
+ kgFunction_distgps(void)
+ {_result.type('N');_name="distgps";_minArgc=4;_maxArgc=4;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// heron(数値,...,数値[3n]) => 数値 : n次元の3点の座標によって作られる3角形の面積を計算
+// -----------------------------------------------------------------------------
+class kgFunction_heron : public kgFunction
+{
+ unsigned int _dim;
+ public:
+ kgFunction_heron(void)
+ {_result.type('N');_name="heron";_minArgc=4;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// pi() => 数値 : PI
+// -----------------------------------------------------------------------------
+class kgFunction_pi : public kgFunction
+{
+ public:
+ kgFunction_pi(void)
+ {_result.type('N');_name="pi";_minArgc=0;_maxArgc=0;_result.r(M_PI);}
+};
+// -----------------------------------------------------------------------------
+// e() => 数値 : ネイピア数
+// -----------------------------------------------------------------------------
+class kgFunction_e : public kgFunction
+{
+ public:
+ kgFunction_e(void)
+ {_result.type('N');_name="e";_minArgc=0;_maxArgc=0;_result.r(M_E);}
+};
+// -----------------------------------------------------------------------------
+// rand(数値[最小値],数値[最大数],数値[シード]) => 数値 : 一様乱数を発生させる(整数)
+// -----------------------------------------------------------------------------
+class kgFunction_rand : public kgFunction
+{
+ kgAutoPtr1<boost::variate_generator< boost::mt19937,boost::uniform_int<> > > _api;
+ public:
+ kgFunction_rand(void)
+ {_result.type('N');_name="randi";_minArgc=2;_maxArgc=3;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// rand(数値[シード],"-real") => 数値 : 一様乱数を発生させる(実数)
+// -----------------------------------------------------------------------------
+class kgFunction_rand_real : public kgFunction
+{
+ kgAutoPtr1<boost::variate_generator< boost::mt19937,boost::uniform_real<> > > _apr;
+ public:
+ kgFunction_rand_real(void)
+ {_result.type('N');_name="rand";_minArgc=0;_maxArgc=1;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// nrand(数値[平均値],数値[標準偏差],数値[シード]) => 数値 : 正規乱数を発生させる
+// -----------------------------------------------------------------------------
+class kgFunction_nrand : public kgFunction
+{
+ kgAutoPtr1<boost::variate_generator< boost::mt19937,boost::normal_distribution<> > > _ap;
+ public:
+ kgFunction_nrand(void)
+ {_result.type('N');_name="nrand";_minArgc=2;_maxArgc=3;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// berrand(数値[?],数値[シード]) => 数値 : ベルヌーイ分布に基づいた乱数生成
+// -----------------------------------------------------------------------------
+class kgFunction_berrand : public kgFunction
+{
+ kgAutoPtr1<boost::variate_generator< boost::mt19937,boost::bernoulli_distribution<> > > _ap;
+ public:
+ kgFunction_berrand(void)
+ {_result.type('B');_name="berrand";_minArgc=1;_maxArgc=2;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// binomdist(数値[成功回数],数値[試行回数],数値[確率]) => 数値 : 二項分布の確率?
+// -----------------------------------------------------------------------------
+class kgFunction_binomdist : public kgFunction
+{
+ size_t ub_;
+ vector< vector<int> > pascal_;
+ public:
+ kgFunction_binomdist(void)
+ {_result.type('N');_name="binomdist";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// ============================================================================
+// 三角関数関連クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// acos(数値) => 数値 : アークコサインを計算
+// -----------------------------------------------------------------------------
+class kgFunction_acos : public kgFunction
+{
+ public:
+ kgFunction_acos(void)
+ {_result.type('N');_name="acos";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// asin(数値) => 数値 : アークサインを計算
+// -----------------------------------------------------------------------------
+class kgFunction_asin : public kgFunction
+{
+ public:
+ kgFunction_asin(void)
+ {_result.type('N');_name="asin";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// atan(数値) => 数値 : アークタンジェントを計算
+// -----------------------------------------------------------------------------
+class kgFunction_atan : public kgFunction
+{
+ public:
+ kgFunction_atan(void)
+ {_result.type('N');_name="atan";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// atan2(数値1,数値2) => 数値 : x,y座標(数値1,数値2)と原点を結ぶ線分とx軸とが作る角度を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_atan2 : public kgFunction
+{
+ public:
+ kgFunction_atan2(void)
+ {_result.type('N');_name="atan2";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// cos(数値) => 数値 : 数値(ラジアン)に相当するコサインを計算
+// -----------------------------------------------------------------------------
+class kgFunction_cos : public kgFunction
+{
+ public:
+ kgFunction_cos(void)
+ {_result.type('N');_name="cos";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// sin(数値) => 数値 : 数値(ラジアン)に相当するサインを計算
+// -----------------------------------------------------------------------------
+class kgFunction_sin : public kgFunction
+{
+ public:
+ kgFunction_sin(void)
+ {_result.type('N');_name="sin";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// tan(数値) => 数値 : 数値(ラジアン)に相当するタンジェントを計算
+// -----------------------------------------------------------------------------
+class kgFunction_tan : public kgFunction
+{
+ public:
+ kgFunction_tan(void)
+ {_result.type('N');_name="tan";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// degree(数値) => 数値 : 数値(ラジアン)を角度に変換する
+// -----------------------------------------------------------------------------
+class kgFunction_degree : public kgFunction
+{
+ public:
+ kgFunction_degree(void)
+ {_result.type('N');_name="degree";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// radian(数値) => 数値 : 数値(角度)をラジアンに変換する
+// -----------------------------------------------------------------------------
+class kgFunction_radian : public kgFunction
+{
+ public:
+ kgFunction_radian(void)
+ {_result.type('N');_name="radian";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// cosh(数値) => 数値 : 双曲線余弦(ハイパーボリックコサイン)を計算
+// -----------------------------------------------------------------------------
+class kgFunction_cosh : public kgFunction
+{
+ public:
+ kgFunction_cosh(void)
+ {_result.type('N');_name="cosh";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// sinh(数値) => 数値 : 双曲線正弦(ハイパーボリックサイン)を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_sinh : public kgFunction
+{
+ public:
+ kgFunction_sinh(void)
+ {_result.type('N');_name="sinh";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// tanh(数値) => 数値 : 双曲線逆正接(ハイパーボリックタンジェントの逆関数)を計算する
+// -----------------------------------------------------------------------------
+class kgFunction_tanh : public kgFunction
+{
+ public:
+ kgFunction_tanh(void)
+ {_result.type('N');_name="tanh";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// ============================================================================
+// 文字列関数クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// cat(文字列0,文字列1,...,文字列m) => 文字列 :
+// 文字列1...文字列mを文字列0(トークン)で結合する
+// -----------------------------------------------------------------------------
+class kgFunction_cat : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_cat(void)
+ {_result.type('S');_name="cat";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// length(文字列) => 数値 : 文字列の長さを計算
+// -----------------------------------------------------------------------------
+class kgFunction_length : public kgFunction
+{
+ public:
+ kgFunction_length(void)
+ {_result.type('N');_name="length";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// lengthw(文字列) => 数値 : 文字列の長さを計算(マルチバイト文字文字用)
+// -----------------------------------------------------------------------------
+class kgFunction_lengthw : public kgFunction
+{
+ public:
+ kgFunction_lengthw(void)
+ {_result.type('N');_name="lengthw";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// fixlen(文字列,数値,文字1[R|L],文字2) => 文字列 :
+// 文字列を数値分固定長に変換(文字1はR:右詰orL:左詰,文字2は詰める文字)
+// -----------------------------------------------------------------------------
+class kgFunction_fixlen : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_fixlen(void)
+ {_result.type('S');_name="fixlen";_minArgc=4;_maxArgc=4;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// fixlenw(文字列,数値,文字,文字) => 文字列 :(マルチバイト文字ベース)
+// 文字列を数値分固定長に変換(文字1はR:右詰orL:左詰,文字2は詰める文字)
+// -----------------------------------------------------------------------------
+class kgFunction_fixlenw : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_fixlenw(void)
+ {_result.type('S');_name="fixlenw";_minArgc=4;_maxArgc=4;}
+ virtual void run(void);
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// right(文字列,数値) => 文字列 : 文字列を右から数値分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_right : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_right(void)
+ {_result.type('S');_name="right";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// rightw(文字列,数値) => 文字列 : 文字列を右から数値分抽出(マルチバイト文字ベース)
+// -----------------------------------------------------------------------------
+class kgFunction_rightw : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_rightw(void)
+ {_result.type('S');_name="rightw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// left(文字列,数値) => 文字列 : 文字列を左から数値分抽出
+// -----------------------------------------------------------------------------
+class kgFunction_left : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_left(void)
+ {_result.type('S');_name="left";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// leftw(文字列,数値) => 文字列 : 文字列を左から数値分抽出(マルチバイト文字ベース)
+// -----------------------------------------------------------------------------
+class kgFunction_leftw : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_leftw(void)
+ {_result.type('S');_name="leftw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// mid(文字列,数値[開始位置],数値[抽出長]) => 文字列 :
+// 文字列を左から開始位置と抽出長を指定して抽出する
+// -----------------------------------------------------------------------------
+class kgFunction_mid : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_mid(void)
+ {_result.type('S');_name="mid";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// midw(文字列,数値[開始位置],数値[抽出長]) => 文字列 :(マルチバイト文字ベース)
+// 文字列を左から開始位置と抽出長を指定して抽出する
+// -----------------------------------------------------------------------------
+class kgFunction_midw : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_midw(void)
+ {_result.type('S');_name="midw";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// toupper(文字列) => 文字列 : 文字列をすべて大文字に変更
+// -----------------------------------------------------------------------------
+class kgFunction_toupper : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_toupper(void)
+ {_result.type('S');_name="toupper";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// tolower(文字列) => 文字列 : 文字列をすべて小文字に変更
+// -----------------------------------------------------------------------------
+class kgFunction_tolower : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_tolower(void)
+ {_result.type('S');_name="tolower";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// capitalize(文字列) => 文字列 : 文字列の先頭を大文字に変更
+// -----------------------------------------------------------------------------
+class kgFunction_capitalize : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_capitalize(void)
+ {_result.type('S');_name="capitalize";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+
+// -----------------------------------------------------------------------------
+// match(文字列0,文字列1,...,文字列n) => bool :
+// 文字列1,...,文字列nのいずれかに文字列0が存在すれば真,しなければ偽(全マッチ)
+// -----------------------------------------------------------------------------
+class kgFunction_match : public kgFunction
+{
+ public:
+ kgFunction_match(void)
+ {_result.type('B');_name="match";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// matcha(文字列0,文字列1,...,文字列n) => bool :
+// 文字列1,...,文字列nのすべてに文字列0が存在すれば真,しなければ偽(全マッチ)
+// -----------------------------------------------------------------------------
+class kgFunction_matcha : public kgFunction
+{
+ public:
+ kgFunction_matcha(void)
+ {_result.type('B');_name="matcha";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// matchs(文字列0,文字列1,...,文字列n) => bool :
+// 文字列1,...,文字列nのいずれかに文字列0が存在すれば真,しなければ偽(部分マッチ)
+// -----------------------------------------------------------------------------
+class kgFunction_matchs : public kgFunction
+{
+ public:
+ kgFunction_matchs(void)
+ {_result.type('B');_name="matchs";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// matchas(文字列0,文字列1,...,文字列n) => bool :
+// 文字列1,...,文字列nのすべてに文字列0が存在すれば真,しなければ偽(部分マッチ)
+// -----------------------------------------------------------------------------
+class kgFunction_matchas : public kgFunction
+{
+ public:
+ kgFunction_matchas(void)
+ {_result.type('B');_name="matchas";_minArgc=2;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// hasspace(文字列) => bool : 文字列に空白があれば真,なければ偽
+// -----------------------------------------------------------------------------
+class kgFunction_hasspace : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_hasspace(void)
+ {_result.type('B');_name="hasspace";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// hasspacew(文字列) => bool : 文字列に空白(全角半角空白)があれば真,なければ偽
+// -----------------------------------------------------------------------------
+class kgFunction_hasspacew : public kgFunction
+{
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_hasspacew(void)
+ {_result.type('B');_name="hasspacew";_minArgc=1;_maxArgc=1;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// strchr(文字列,文字) => 数値 : 文字列の文字がある位置を調べる
+// -----------------------------------------------------------------------------
+class kgFunction_strchr : public kgFunction
+{
+ public:
+ kgFunction_strchr(void)
+ {_result.type('N');_name="strchr";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// ============================================================================
+// 正規表現関連クラス
+// ============================================================================
+// -----------------------------------------------------------------------------
+// 正規表現スーパークラス
+// -----------------------------------------------------------------------------
+class kgFunction_regex : public kgFunction
+{
+ protected:
+ boost::xpressive::cregex _reg;
+ public:
+ virtual void preprocess(void);
+
+};
+class kgFunction_regexw : public kgFunction
+{
+ protected:
+ boost::xpressive::wsregex _reg;
+ public:
+ virtual void preprocess(void);
+};
+// -----------------------------------------------------------------------------
+// regexs(文字列,文字列[正規表現]) => bool :
+// 文字列に対して正規表現がマッチする部分文字列があれば真を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexs : public kgFunction_regex
+{
+ public:
+ kgFunction_regexs(void)
+ {_result.type('B');_name="regexs";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexsw(文字列,文字列[正規表現]) => bool : (マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチする部分文字列があれば真を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexsw : public kgFunction_regexw
+{
+ public:
+ kgFunction_regexsw(void)
+ {_result.type('B');_name="regexsw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexm(文字列,文字列[正規表現]) => bool :
+// 文字列に対して正規表現が完全にマッチすれば真を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexm : public kgFunction_regex
+{
+ public:
+ kgFunction_regexm(void)
+ {_result.type('B');_name="regexm";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexmw(文字列,文字列[正規表現]) => bool : (マルチバイト文字ベース)
+// 文字列に対して正規表現が完全にマッチすれば真を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexmw : public kgFunction_regexw
+{
+ public:
+ kgFunction_regexmw(void)
+ {_result.type('B');_name="regexmw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexrep(文字列,文字列[正規表現],文字列[置換文字列]) => 文字列 :
+// 文字列に対して正規表現がマッチする部分を置換文字列に置換する
+// -----------------------------------------------------------------------------
+class kgFunction_regexrep : public kgFunction_regex
+{
+ string _buf;
+ public:
+ kgFunction_regexrep(void)
+ {_result.type('S');_name="regexrep";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexrepw(文字列,文字列[正規表現],文字列[置換文字列]) => 文字列 : (マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチする部分を置換文字列に置換する
+// -----------------------------------------------------------------------------
+class kgFunction_regexrepw : public kgFunction_regexw
+{
+ string _buf;
+ public:
+ kgFunction_regexrepw(void)
+ {_result.type('S');_name="regexrepw";_minArgc=3;_maxArgc=3;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexlen(文字列,文字列[正規表現]) => 数値 :
+// 文字列に対して正規表現がマッチした長さを返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexlen : public kgFunction_regex
+{
+ boost::xpressive::cmatch _mat;
+ public:
+ kgFunction_regexlen(void)
+ {_result.type('N');_name="regexlen";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexlenw(文字列,文字列[正規表現]) => 数値 : (マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチした長さを返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexlenw : public kgFunction_regexw
+{
+ boost::xpressive::wsmatch _mat;
+ public:
+ kgFunction_regexlenw(void)
+ {_result.type('N');_name="regexlenw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexpos(文字列,文字列[正規表現]) => 数値 :
+// 文字列に対して正規表現がマッチした先頭位置を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexpos : public kgFunction_regex
+{
+ boost::xpressive::cmatch _mat;
+ public:
+ kgFunction_regexpos(void)
+ {_result.type('N');_name="regexpos";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexposw(文字列,文字列[正規表現]) => 数値 :(マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチした先頭位置を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexposw : public kgFunction_regexw
+{
+ boost::xpressive::wsmatch _mat;
+ public:
+ kgFunction_regexposw(void)
+ {_result.type('N');_name="regexposw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexstr(文字列,文字列[正規表現]) => 文字列 :
+// 文字列に対して正規表現がマッチする部分文字列を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexstr : public kgFunction_regex
+{
+ boost::xpressive::cmatch _mat;
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_regexstr(void)
+ {_result.type('S');_name="regexstr";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexstrw(文字列,文字列[正規表現]) => 文字列 :(マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチする部分文字列を返す
+// -----------------------------------------------------------------------------
+class kgFunction_regexstrw : public kgFunction_regexw
+{
+ boost::xpressive::wsmatch _mat;
+ string _buf;
+ public:
+ kgFunction_regexstrw(void)
+ {_result.type('S');_name="regexstrw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexpfx(文字列,文字列[正規表現]) => 文字列 :
+// 文字列に対して正規表現がマッチした部分文字列の直前までの文字列を左から出力する
+// -----------------------------------------------------------------------------
+class kgFunction_regexpfx : public kgFunction_regex
+{
+ boost::xpressive::cmatch _mat;
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_regexpfx(void)
+ {_result.type('S');_name="regexpfx";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexpfxw(文字列,文字列[正規表現]) => 文字列 :(マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチした部分文字列の直前までの文字列を左から出力する
+// -----------------------------------------------------------------------------
+class kgFunction_regexpfxw : public kgFunction_regexw
+{
+ boost::xpressive::wsmatch _mat;
+ string _buf;
+ public:
+ kgFunction_regexpfxw(void)
+ {_result.type('S');_name="regexpfxw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexsfx(文字列,文字列[正規表現]) => 文字列 :
+// 文字列に対して正規表現がマッチした部分文字列の直後から右方向に最後までの文字列を出力する
+// -----------------------------------------------------------------------------
+class kgFunction_regexsfx : public kgFunction_regex
+{
+ boost::xpressive::cmatch _mat;
+ char _buf[KG_MAX_STR_LEN];
+ public:
+ kgFunction_regexsfx(void)
+ {_result.type('S');_name="regexsfx";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// regexsfxw(文字列,文字列[正規表現]) => 文字列 :(マルチバイト文字ベース)
+// 文字列に対して正規表現がマッチした部分文字列の直後から右方向に最後までの文字列を出力する
+// -----------------------------------------------------------------------------
+class kgFunction_regexsfxw : public kgFunction_regexw
+{
+ boost::xpressive::wsmatch _mat;
+ string _buf;
+ public:
+ kgFunction_regexsfxw(void)
+ {_result.type('S');_name="regexsfxw";_minArgc=2;_maxArgc=2;}
+ virtual void run(void);
+};
+// ============================================================================
+// 行項目関連
+// ============================================================================
+// -----------------------------------------------------------------------------
+// line() => 数値 :処理行中番号の取得
+// -----------------------------------------------------------------------------
+class kgFunction_line : public kgFunction
+{
+ public:
+ kgFunction_line(void)
+ {_result.type('N');_name="line";_minArgc=0;_maxArgc=0;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// fldcnt() => 数値 :データ項目数の取得
+// -----------------------------------------------------------------------------
+class kgFunction_fldsize : public kgFunction
+{
+ public:
+ kgFunction_fldsize(void)
+ {_result.type('N');_name="fldsize";_minArgc=0;_maxArgc=0;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// top() => bool :先頭行チェック 先頭ならtrue
+// -----------------------------------------------------------------------------
+class kgFunction_top : public kgFunction
+{
+ public:
+ kgFunction_top(void)
+ {_result.type('B');_name="top";_minArgc=0;_maxArgc=0;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// bottom() => bool :最終行チェック 最終ならtrue
+// -----------------------------------------------------------------------------
+class kgFunction_bottom : public kgFunction
+{
+ public:
+ kgFunction_bottom(void)
+ {_result.type('B');_name="bottom";_minArgc=0;_maxArgc=0;}
+ virtual void run(void);
+};
+// -----------------------------------------------------------------------------
+// bottom() => bool :最終行チェック 最終ならtrue
+// -----------------------------------------------------------------------------
+class kgFunction_argsize : public kgFunction
+{
+ public:
+ kgFunction_argsize(void)
+ {_result.type('N');_name="argsize";_minArgc=1;_maxArgc=KG_MAX_CAL_TERMS;}
+ virtual void run(void);
+};
+
+// ============================================================================
+// 関数の検索map構造体
+// ============================================================================
+class kgFuncMap
+{
+ typedef map<std::string, boost::function<kgFunction* ()> > func_map_t;
+ func_map_t _func_map; //keyword - 関数対応表
+ kgAutoPtr1<kgFunction> _ap[KG_MAX_CAL_TERMS]; //関数クラスのアドレスを格納するスマートポインタ
+ int _usedCnt; // 使用関数クラス数
+
+public:
+ // コンストラクタ(インデックスの作成)
+ kgFuncMap(void);
+ // 関数表のidを検索し,関数のbindアドレスを得る
+ kgFunction* get(const string& id);
+};
+
+
+} //////////////////////////////////////////////////////////////// end namespace
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgMessage.h メッセージ関係クラス
+// =============================================================================
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <cstdio>
+#include <kgConfig.h>
+#include <kgmod.h>
+using namespace std;
+
+namespace kglib { ////////////////////////////////////////////// start namespace
+
+// メッセージ出力クラス
+class kgMsg {
+
+public:
+ enum Plevel {ERR,WAR,END,MSG};
+
+private:
+ kgEnv* env_;
+
+ // ERR: 1以上
+ // WAR: 2以上
+ // END: 3以上
+ // MSG: 4以上
+ Plevel plevel_;
+
+ // ヘッダ文字列取得
+ string header(void);
+ // 日付時間取得
+ string getTime(void);
+ // 出力要否チェック
+ bool isOn(void);
+ // 出力処理
+ void WriteMsg(string v,string t);
+
+public:
+ kgMsg(Plevel plevel, kgEnv* env){
+ plevel_=plevel;
+ env_=env;
+ }
+ ~kgMsg(void){}
+
+ //メッセージ出力
+ void output(const string& v, const string& comment="");
+ void output(const vector<string>& vv, const string& comment="");
+ void output(kglib::kgMod* kgmod, string v, const string& comment="");
+ void output(kgMod* kgmod, vector<string> vv, const string& comment="");
+
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+#pragma once
+#include <iostream>
+#include <string>
+#include <vector>
+#include <set>
+#include <map>
+#include <kgConfig.h>
+
+using namespace std;
+
+namespace kglib {////////////////////////////////////////////// namespace start
+
+vector<kgstr_t> kgFilesearch(vector<kgstr_t>& vs, bool skip=false, bool stdinFlg=false,bool glob=true);
+
+wstring toWcs(const string& mbs);
+wstring toWcs(const char* mbs);
+string toMbs(const wchar_t* wcs);
+string toMbs(const wstring& wcs);
+void evalEscape(kgstr_t& str);
+int evalDigit(kgstr_t& s, int fldSize);
+void evalAttr(vector<kgstr_t>& name, vector<kgstr_t>& attr);
+
+bool hasSingleChr(char *fld, char chr1, char chr2);
+bool hasBchr(char *fld, char chr);
+bool hasMchr(char *fld, char chr);
+void rmEol(char* rec, int recLen);
+
+size_t cntFldToken(char *str, size_t maxRecLen,bool fmtErrSkip=false);
+char* sepRecTokenNdq(char* str);
+char* sepRecToken(char *str, size_t maxRecLen);
+
+char* sepFldToken(char **pnt, size_t fldCnt, char *str);
+char* sepFldToken(char **pnt, size_t fldCnt, char *str, vector<bool> &sngDQ,vector<bool> &dqflg);
+char* sepFldToken(char **pnt, size_t fldCnt, char *str, size_t maxRecLen);
+char* sepFldTokenNdq(char **pnt, size_t fldCnt, char *str);
+
+//データの終了が\0
+vector<char*> splitToken(char* str, char delim,bool skip=false);
+vector<string> splitToken(string& str, char delim,bool skip=false);
+vector<wstring> splitToken(wstring& str, wchar_t delim);
+vector<vector <kgstr_t> > splitToken2(kgstr_t& str, kgchr_t delim1, kgchr_t delim2);
+vector<vector <kgstr_t> > splitToken2(kgstr_t& str, kgchr_t delim1, kgstr_t delim2);
+vector<vector <kgstr_t> > transVector(const vector<vector <kgstr_t> >& vvs, unsigned int rowSize);
+size_t cntToken(char* str, char delim,bool skip=false);
+
+kgstr_t toString(const int i, const string s1="", const string s2="");
+kgstr_t toString(const vector<int>& vi, int add=0, const string dlm=",", const string s1="", const string s2="");
+kgstr_t toString(const vector<kgstr_t>& vs, const string dlm=",", const string s1="", const string s2="");
+
+bool date_set(const char * str,int *y,int *d,int *m);
+bool time_set(const char * str,int *h,int *m,int *s);
+bool ptime_set(const char * str,int *yr, int *mo, int *dy, int *hr,int *mi,int *sc);
+
+bool kgDiv(double* val, char* a, char* b);
+int gcd(int a, int b);
+int lcm(int a, int b);
+size_t aToSizeT(const char * a);
+
+bool chkFldName(kgstr_t vvs);
+
+//------------------------------------------------------------------------------
+// setを備えたauto_ptr
+//------------------------------------------------------------------------------
+template<class T>
+class kgAutoPtr1
+{
+ T* _ptr;
+public:
+ kgAutoPtr1(T* ptr=0) : _ptr(ptr) {}
+ virtual ~kgAutoPtr1(void) { if(_ptr != 0) delete _ptr; _ptr=0;}
+ T* get(void) const throw() { return _ptr; }
+ void set(T* ptr) throw() { if(_ptr!=0) delete _ptr; _ptr=ptr;}
+ void clear(void) { if(_ptr!=0) delete _ptr; _ptr=0;}
+};
+
+//------------------------------------------------------------------------------
+// 配列型に拡張したauto_ptr
+//------------------------------------------------------------------------------
+template<class T>
+class kgAutoPtr2
+{
+ T* _ptr;
+public:
+ kgAutoPtr2(T* ptr=0) : _ptr(ptr) {}
+ virtual ~kgAutoPtr2(void) { if(_ptr != 0) delete[] _ptr; _ptr=0;}
+ kgAutoPtr2<T>& operator=(T* ptr){_ptr=ptr; return *this;}
+ T* get(void) const throw() { return _ptr; }
+ void set(T* ptr) throw() { if(_ptr!=0) delete[] _ptr; _ptr=ptr; }
+ void clear(void) { if(_ptr!=0) delete[] _ptr; _ptr=0;}
+};
+//------------------------------------------------------------------------------
+// vectorをsetに変換するテンプレート
+//------------------------------------------------------------------------------
+template<class T>
+set<T> vector2set(const vector<T>& v)
+{
+ set<T> s;
+ for(size_t i=0; i<v.size(); i++){
+ s.insert(v[i]);
+ }
+ return s;
+}
+
+
+
+
+
+}////////////////////////////////////////////// namespace end
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgRange.h : 範囲マッチ関するクラス
+// 再考する必要有
+// ============================================================================
+#pragma once
+#include <map>
+#include <string.h>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+// multimapで使用するソート
+class list_stsort_n {
+ public:
+ bool operator()(double t1,double t2) const {
+ return t1 < t2;
+ }
+};
+class list_stsort{
+ public:
+ bool operator()(char* t1,char* t2) const {
+ return strcmp(t1,t2) < 0 ;
+ }
+};
+class list_edsort_n{
+ public:
+ bool operator()(double t1,double t2) const {
+ return t1 > t2;
+ }
+};
+class list_edsort{
+ public:
+ bool operator()(char* t1,char* t2) const {
+ if(*t1=='\0') return true;
+ if(*t2=='\0') return false;
+ return strcmp(t1,t2) > 0 ;
+ }
+};
+
+/*マップでキーになるデータに使用*/
+union range_data{
+ double f;
+ char* s;
+};
+
+/*rangeの一覧用の構造体*/
+struct kgRangetbl{
+ range_data st; //開始部分のデータ
+ bool stEq; //イコールを含むor含まない(開始部分) true:含む false:含まない
+ range_data ed; //終了部分のデータ
+ bool edEq; //イコールを含むor含まない(終了部分) true:含む false:含まない
+ char **rec; //出力する文字列
+ int reccnt; //recの個数
+ bool writeflg;//書き込み済みフラグ
+};
+
+// コマンドライン引数クラス
+class kgRange {
+ bool _nsFlg; //ソートタイプ true:数字 flase:文字
+ bool _stEQflg; //イコールを含むor含まない(開始部分) true:含む false:含まない
+ bool _edEQflg; //イコールを含むor含まない(終了部分) true:含む false:含まない
+
+ //範囲の一覧に使用(double用、char*)
+ multimap<double,kgRangetbl*,list_stsort_n> _tbl_st_dbl;
+ multimap<char*,kgRangetbl*,list_stsort> _tbl_st_str;
+
+ //検索の結果に使用(double用、char*)
+ multimap<double,kgRangetbl*,list_edsort_n> _tbl_ed_dbl;
+ multimap<char*,kgRangetbl*,list_edsort> _tbl_ed_str;
+
+public:
+ /* コンストラクタ、デストラクタ*/
+ kgRange(){}
+ ~kgRange(){
+ if(!_nsFlg){
+ for(multimap<char*,kgRangetbl*,list_stsort>::iterator i=_tbl_st_str.begin();i!=_tbl_st_str.end();i++){
+ for(int j=0;j<(i->second)->reccnt;j++){
+ delete [] *((i->second)->rec+j);
+ }
+ delete [] (i->second)->st.s;
+ delete [] (i->second)->ed.s;
+ delete i->second;
+ }
+ }
+ else{
+ for(multimap<double,kgRangetbl*,list_stsort_n>::iterator i=_tbl_st_dbl.begin();i!=_tbl_st_dbl.end();i++){
+ for(int j=0;j<(i->second)->reccnt;j++){
+ delete [] *((i->second)->rec+j);
+ }
+ delete i->second;
+ }
+ }
+ }
+ void set(int nsflg,int steqflg,int edeqflg){
+ _nsFlg = nsflg;
+ _stEQflg = steqflg;
+ _edEQflg = edeqflg;
+ }
+
+ //一覧のセット
+ void set_table(char * st_data,char * ed_data,char **rec_data,int size);
+
+ //一覧からの検索
+ bool serch(char *str);
+
+ /*一覧、検索結果を返す*/
+ multimap<double,kgRangetbl*,list_edsort_n> get_tbl_dbl(void){ return _tbl_ed_dbl;}
+ multimap<char*,kgRangetbl*,list_edsort> get_tbl_str(void){ return _tbl_ed_str;}
+ multimap<double,kgRangetbl*,list_stsort_n> get_list_dbl(void){ return _tbl_st_dbl;}
+ multimap<char*,kgRangetbl*,list_stsort> get_list_str(void){ return _tbl_st_str;}
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgTempfile.h : 一時ファイルクラス
+// ============================================================================
+#pragma once
+#include <string>
+#include <kgEnv.h>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+class kgTempfile
+{
+ kgEnv* env_;
+ vector<string> names_;
+public:
+ kgTempfile(void) : env_(0){}
+ kgTempfile(kgEnv* env) : env_(env){}
+ ~kgTempfile(void);
+ void init(kgEnv* env){env_=env;}
+
+ // 一時ファイルを作成し、そのファイル名を返す
+ string create(bool pipe=false, string prefix="");
+ // 一時ファイル名を返す
+ string name(void);
+
+ //登録ファイル名チェック
+ bool empty(void);
+
+};
+
+}
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+#pragma once
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <string>
+#include <kgMethod.h>
+#include <kgError.h>
+#include <kgConfig.h>
+#include <boost/date_time/gregorian/gregorian.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+using namespace std;
+using namespace kglib;
+using namespace boost::gregorian;
+using namespace boost::posix_time;
+
+namespace kglib ////////////////////////////////////////////// namespace start
+{
+class kgVal
+{
+ char _type;
+ bool _null;
+
+ union {
+ double r; // type=N
+ char* s; // type=S
+ bool b; // type=B
+ date* d; // type=D
+ ptime* t; // type=T
+ } _v;
+
+public:
+
+ // コンストラクタ
+ kgVal(void) : _type('0') {}
+ kgVal(const char t) : _type(t){}
+
+ void r(double v) { _v.r=v; _null=false;}
+ void s(char* v) ;
+ void b(bool v) {_v.b=v; _null=false;}
+ void d(date* v) {_v.d=v; _null=false;}
+ void t(ptime* v) {_v.t=v; _null=false;}
+
+ double r(void) const {return _v.r;}
+ char* s(void) const {return _v.s;}
+ bool b(void) const {return _v.b;}
+ date* d(void) const {return _v.d;}
+ ptime* t(void) const {return _v.t;}
+
+ void type(char type);
+ void null(bool null) {
+ _null=null;
+ if(_null){_v.s=const_cast<char*>("");}
+ }
+ char type(void) const { return _type; }
+ bool null(void) const { return _null; }
+
+ void set(const kgVal *from){
+ this->_type=from->type();
+ switch(this->_type){
+ case 'N':
+ this->r(from->r());
+ break;
+ case 'S':
+ this->s(from->s());
+ break;
+ case 'B':
+ this->b(from->b());
+ break;
+ case 'D':
+ this->d(from->d());
+ break;
+ case 'T':
+ this->t(from->t());
+ break;
+ }
+ this->null(from->null());
+ }
+
+};
+
+// 加算で実数がセットされる
+void kgA2Fadd(char* str,kgVal& result);
+
+} //////////////////////////////////////////////////////////////// namespace end
+
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// ============================================================================
+// kgWildcard.h : ファイルカードクラス
+// ============================================================================
+#pragma once
+
+#include <string>
+#include <kgError.h>
+#include <kgConfig.h>
+
+using namespace std;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+class kgWildCard
+{
+ kgstr_t _pat; // ワイルドカードを含むパターン文字列 (ex "abc*d?a*")
+ string::size_type _patLen; // その長さ
+ bool _hasWildCard; // _patにワイルドカード記号が含まれるかどうか
+
+ // ワイルドカード記号格納配列 (ex " * ? *")
+ kgchr_t _wildc[KG_MAX_STR_LEN];
+ // 決定性有限オートマトン(FSA) 全てtrueでmatchに
+ bool _state[KG_MAX_STR_LEN];
+
+public:
+ kgWildCard(const kgstr_t& p) throw(kgError);
+ ~kgWildCard(void){}
+ bool match(const kgstr_t& txt) throw(kgError);
+ bool hasWildCard(void){ return _hasWildCard; }
+};
+
+}
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+#pragma once
+
+#include <mod_asrule/kgapriori.h>
+#include <mod_asrule/kgcaep.h>
+#include <mod_clust/kgclust.h>
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// =============================================================================
+// kgmod.h : モジュールの基本クラス
+// =============================================================================
+#pragma once
+#include <kgArgs.h>
+#include <kgEnv.h>
+#include <kgConfig.h>
+#include <csignal>
+
+using namespace kglib;
+
+namespace kglib ////////////////////////////////////////////// start namespace
+{
+class kgMod
+{
+ protected:
+ kgEnv* _env; // 環境変数
+ kgArgs _args; // 引数
+ const char* _name; // コマンド名
+ const char* _version; // バージョン
+ const char* _doc; // ヘルプドキュメント
+ const char* _title; // モジュールタイトル
+ const char* _libversion; // バージョン
+
+
+ // 以下は全コマンドに共通する引数
+ // 引数として指定されていなければkgEnvにセットされている値をセットする
+ // セットされるタイミング
+ // 1. kgEnvに#defineで定義された値に初期化される.
+ // 2. 環境変数が設定されていれば上書きする.
+ // 3. 引数として指定されていればさらに上書きする.
+ // -nfnの指定で _nfn_i=true, _nfn_o=true, _fldByNum=true
+ // -xの指定で _nfn_i=false, _nfn_o=false, _fldByNum=true
+ kgstr_t _tmpPath; // TmpPath=
+ string _encoding; // encoding
+ int _precision; // Double型の有効桁数
+ bool _nfn_i; // 1行目が項目行かどうか
+ bool _nfn_o; // 項目名を出力しない
+ bool _fldByNum; // 項目の番号指定フラグ
+ int _status; // exitステータス
+ static void signalHandler(int sigNo, siginfo_t* info, void* ctx);
+
+ public:
+ kgMod(void);
+ ~kgMod(void){}
+
+ // 初期設定
+ void init(kgArgs& args, kgEnv* env);
+ void init(size_t argc, const char* argv[], kgEnv* env);
+
+ // accessor
+ const char* name(void) const{ return _name; }
+ const char* version(void) const{ return _version; }
+ kgstr_t tmpPath(void) const{ return _tmpPath; }
+ string encoding(void) const{ return _encoding; }
+ kgEnv* env(void) const{ return _env; }
+ bool nfn_i(void) const{ return _nfn_i; }
+ bool nfn_o(void) const{ return _nfn_o; }
+ int precision(void) const{ return _precision; }
+ bool fldByNum(void) const{ return _fldByNum; }
+ int status( void ) const{ return _status; }
+ const char* title(void) const{ return _title; }
+ const char* doc(void) const{ return _doc; }
+
+ string lver(void){
+ return string("lib Version ") + _libversion;
+ }
+
+
+ kgArgs* args(void) { return &_args; }
+
+ string cmdline(void) const;
+
+ // 正常終了処理(メッセージ出力)
+ void successEnd(void);
+ void successEnd(const string& comment);
+
+ // エラー終了処理(メッセージ出力)
+ void errorEnd(kgError& err);
+ void errorEnd(void);
+ void errorEnd(kgError& err, const string& comment);
+ void errorEnd(const string& comment);
+
+ // 入力データ件数と出力データ件数
+ // 各モジュールで独自に登録する.
+ // 登録しなければ-1を返し,メッセージとして表示されない.
+ virtual size_t iRecNo(void) const {return -1;}
+ virtual size_t oRecNo(void) const {return -1;}
+
+ // ----------------------------------------------------------------
+ // 各コマンドクラスにおいて実装しなければならない純粋仮想関数
+ // ----------------------------------------------------------------
+ virtual void run(void)=0;
+
+};
+
+} //////////////////////////////////////////////////////////////// end namespace
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+// Create on 2013.04.16
+#include <string>
+
+#define KGLIBVER "0.0.0"
+#define KGLIBREVISION "461"
+#define KGLIBCODENAME "jindoji"
+
--- /dev/null
+/* ////////// LICENSE INFO ////////////////////
+
+ * Copyright (C) 2013 by NYSOL CORPORATION
+ *
+ * Unless you have received this program directly from NYSOL pursuant
+ * to the terms of a commercial license agreement with NYSOL, then
+ * this program is licensed to you under the terms of the GNU Affero General
+ * Public License (AGPL) as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF
+ * NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Please refer to the AGPL (http://www.gnu.org/licenses/agpl-3.0.txt)
+ * for more details.
+
+ ////////// LICENSE INFO ////////////////////*/
+#pragma once
+#include <kgsetversion.h>
+
+using namespace std;
+
+namespace kglib { ////////////////////////////////////////////// namespace start
+
+class kgVersion {
+ const char* name_;
+ const char* version_;
+ const char* revision_;
+
+public:
+ kgVersion(void) : name_(KGLIBCODENAME), version_(KGLIBVER), revision_(KGLIBREVISION) {}
+ void show(){
+ cout << "kgmod " << version_ << "(" << name_ << ") " << "revision " << revision() << endl;
+ }
+ string name(void){ return name_;}
+ string version(void){ return version_;}
+ string revision(void){
+ string v=revision_;
+ string::size_type s1=v.find(' ');
+ string::size_type s2=v.find(' ',s1+1);
+ string::size_type s3=v.find(' ',s2+1);
+ string substr=v.substr(s2+1,s3-s2-1);
+ return substr;
+ }
+
+};
+
+} //////////////////////////////////////////////////////////////////////////////
--- /dev/null
+/*
+ array-based simple heap (fixex size)
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _aheap_c_
+#define _aheap_c_
+
+#include"aheap.h"
+
+QSORT_TYPE (AHEAP_KEY, AHEAP_KEY)
+QSORT_TYPE (AHEAP_ID, AHEAP_ID)
+AHEAP INIT_AHEAP = {TYPE_AHEAP,NULL,0,0};
+
+/* allocate memory */
+void AHEAP_alloc (AHEAP *H, AHEAP_ID num){
+ AHEAP_ID i;
+#ifdef ERROR_CHECK
+ if ( num<0 ) error_num ("size is out of range", num, EXIT);
+#endif
+ *H = INIT_AHEAP;
+ if ( num>0 ) malloc2 (H->v, num*2, "AHEAP_alloc: H->v", EXIT);
+ H->end = num;
+ ARY_FILL (H->v, 0, num*2, AHEAP_KEYHUGE);
+ for (i=0 ; i<num-1 ; i=i*2+1);
+ H->base = i - num + 1;
+}
+
+/* termination */
+void AHEAP_end (AHEAP *H){
+ free2 (H->v);
+ *H = INIT_AHEAP;
+}
+
+/* return the index of the leaf having the minimum key among the descendants
+ of the given node i. If several leaves with the smallest key are there,
+ return the minimum index among them if f=0, maximum index if f=1, and
+ random choice if f=2 */
+/* random choice version. choose one child to go down randomly for each node,
+ thus it is not uniformly random */
+AHEAP_ID AHEAP_findmin_node (AHEAP *H, AHEAP_ID i, int f){
+ if ( H->end <= 0 ) return (-1);
+ while ( i < H->end-1 ){
+ if ( H->v[i*2+1] == H->v[i] )
+ if ( H->v[i*2+2] == H->v[i] )
+ if ( f == 2 ) i = i*2 + 1 + rand()%2;
+ else i = i*2+1+f;
+ else i = i*2+1;
+ else i = i*2+2;
+ }
+ return (AHEAP_IDX(*H, i) );
+}
+AHEAP_ID AHEAP_findmin_head (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 0) ); }
+AHEAP_ID AHEAP_findmin_tail (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 1) ); }
+AHEAP_ID AHEAP_findmin_rnd (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 2) ); }
+
+/* return the index of the leaf having smaller value than a among the
+ descendants of the given node i. If several leaves with the smallest key
+ are there, return the minimum index among them if f=0, maximum index if f=1,
+ and random choice if f=2 */
+AHEAP_ID AHEAP_findlow_node (AHEAP *H, AHEAP_KEY a, AHEAP_ID i, int f){
+ if ( H->end == 0 ) return (-1);
+ if ( H->v[0] > a ) return (-1);
+ while ( i < H->end-1 ){
+ if ( f == 2 ) {
+ if ( H->v[i*2+1] <= a )
+ if ( H->v[i*2+2] <= a ) i = i*2 + 1 + rand()%2;
+ else i = i*2+1;
+ else i = i*2+2;
+ } else if ( H->v[i*2+1] <= a ) i = i*2+1+f; else i = i*2+2-f;
+ }
+ return (AHEAP_IDX(*H, i) );
+}
+AHEAP_ID AHEAP_findlow_head (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 0) ); }
+AHEAP_ID AHEAP_findlow_tail (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 1) ); }
+AHEAP_ID AHEAP_findlow_rnd (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 2) ); }
+
+/* return the index of the leaf having smaller value than a next/previous to
+ leaf i. return -1 if such a leaf does not exist */
+AHEAP_ID AHEAP_findlow_nxt (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ if ( H->end == 0 ) return (-1);
+ for (i=AHEAP_LEAF(*H,i); i>0 ; i=(i-1)/2){
+ /* i is the child of smaller index, and the key of the sibling of i is less than a */
+ if ( i%2 == 1 && H->v[i+1] <= a ) return (AHEAP_findlow_node (H, a, i+1, 0) );
+ }
+ return (-1);
+}
+AHEAP_ID AHEAP_findlow_prv (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ if ( H->end == 0 ) return (-1);
+ for (i=AHEAP_LEAF(*H,i); i>0 ; i=(i-1)/2){
+ /* i is the child of larger index, and the key of the sibling of i is less than a */
+ if ( i%2 == 0 && H->v[i-1] <= a ) return (AHEAP_findlow_node (H, a, i-1, 1) );
+ }
+ return (-1);
+}
+
+/* change the key of node i to a /Add a to the key of node i, and update heap H */
+void AHEAP_chg (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ i = AHEAP_LEAF (*H, i);
+ H->v[i] = a;
+ AHEAP_update (H, i);
+}
+void AHEAP_add (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ i = AHEAP_LEAF (*H, i);
+ H->v[i] += a;
+ AHEAP_update (H, i);
+}
+
+/* update the ancestor of node i */
+void AHEAP_update (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID j;
+ AHEAP_KEY a = H->v[i];
+ while ( i>0 ){
+ j = i - 1 + (i%2)*2; /* j = the sibling of i */
+ i = (i-1) / 2;
+ if ( H->v[j] < a ) a = H->v[j];
+ if ( a == H->v[i] ) break;
+ H->v[i] = a;
+ }
+}
+
+/* find the leaf with the minimum key value among the leaves having index
+ smaller/larger than i, or between i and j */
+AHEAP_ID AHEAP_upper_min (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID fi=0, j = AHEAP_LEAF (*H, H->end - 1);
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == 0 ) return (AHEAP_findmin_head (H) );
+ i = AHEAP_LEAF (*H, i-1);
+ while ( i != j ){
+ if ( i%2 ){ /* if i is the child with smaller index */
+ if ( fm > H->v[i+1] ){
+ fm = H->v[i+1];
+ fi = i+1;
+ }
+ }
+ i = (i-1)/2;
+ if ( j == i ) break; /* stop if the right pointer and the left pointer are the same */
+ j = (j-1)/2;
+ }
+ while ( fi < H->end-1 ) fi = fi*2 + (H->v[fi*2+1]<=fm?1:2);
+ return ( AHEAP_IDX(*H, fi) );
+}
+AHEAP_ID AHEAP_lower_min (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID fi=0, j = AHEAP_LEAF (*H, 0);
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == H->end-1 ) return (AHEAP_findmin_head (H) );
+ i = AHEAP_LEAF (*H, i+1);
+ while ( i != j ){
+ if ( i%2 == 0 ){ /* if i is the child of larger index */
+ if ( fm > H->v[i-1] ){
+ fm = H->v[i-1];
+ fi = i-1;
+ }
+ }
+ j = (j-1)/2;
+ if ( j == i ) break; /* stop if the right pointer and the left pointer are the same */
+ i = (i-1)/2;
+ }
+ while ( fi < H->end-1 ) fi = fi*2 + (H->v[fi*2+1]<=fm?1:2);
+ return (AHEAP_IDX(*H, fi) );
+}
+
+/* find the index having the minimum among given two indices */
+AHEAP_ID AHEAP_interval_min (AHEAP *H, AHEAP_ID i, AHEAP_ID j){
+ AHEAP_ID fi=0;
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == 0 ) return (AHEAP_lower_min (H, j) );
+ if ( j == H->end-1 ) return (AHEAP_upper_min (H, i) );
+ i = AHEAP_LEAF (*H, i-1);
+ j = AHEAP_LEAF (*H, j+1);
+ while ( i != j && i != j-1 ){
+ if ( i%2 ){ /* if i is the child of smaller index */
+ if ( fm > H->v[i+1] ){
+ fm = H->v[i+1];
+ fi = i+1;
+ }
+ }
+ i = (i-1)/2;
+ if ( j == i || j == i+1 ) break; /* stop if the right pointer and the left pointer are the same */
+ if ( j%2 == 0 ){ /* if j is the child of larger index */
+ if ( fm > H->v[j-1] ){
+ fm = H->v[j-1];
+ fi = j-1;
+ }
+ }
+ j = (j-1)/2;
+ }
+ while ( fi < H->end-1 )
+ fi = fi*2 + (H->v[fi*2+1] <= fm?1:2);
+ return (AHEAP_IDX(*H, fi) );
+}
+
+/* print heap keys according to the structure of the heap */
+void AHEAP_print (AHEAP *H){
+ AHEAP_ID i, j=1;
+ while ( j<=H->end*2-1 ){
+ FLOOP (i, j-1, MIN(j, H->end)*2-1) printf (AHEAP_KEYF ",", H->v[i] );
+ printf ("\n");
+ j = j*2;
+ }
+}
+
+#endif
--- /dev/null
+/*
+ array-based simple heap (fixed size)
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* bench mark
+ PentiumIII 500MHz, Memory 256MB Linux
+ values 0-1,000,000 : set & del & get 1,000,000 times
+ 2.55sec
+
+ # rotation == 1/5 per 1 set/del
+
+ *** simple array ***
+ value 0-1,000,000 set & set & set 1,000,000 times,
+ 0.88sec
+ */
+
+#ifndef _aheap_h_
+#define _aheap_h_
+
+#include"stdlib2.h"
+
+#ifndef AHEAP_KEY
+ #ifdef AHEAP_KEY_DOUBLE
+ #define AHEAP_KEY double
+ #define AHEAP_KEYHUGE DOUBLEHUGE
+ #define AHEAP_KEYF "%f"
+ #elif defined(AHEAP_KEY_WEIGHT)
+ #define AHEAP_KEY WEIGHT
+ #define AHEAP_KEYHUGE WEIGHTHUGE
+ #define AHEAP_KEYF WEIGHTF
+ #else
+#define AHEAP_KEY int
+ #define AHEAP_KEYHUGE INTHUGE
+ #define AHEAP_KEYF "%d"
+ #endif
+#endif
+
+#ifndef AHEAP_ID
+ #define AHEAP_ID int
+ #define AHEAP_ID_END INTHUGE
+ #define AHEAP_IDF "%d"
+#endif
+
+#define AHEAP_IDX(H,i) (((i)+1-(H).base)%(H).end)
+#define AHEAP_LEAF(H,i) (((i)+(H).base)%(H).end+(H).end-1)
+#define AHEAP_H(H,i) (H).v[(((i)+(H).base)%(H).end+(H).end-1)]
+
+typedef struct {
+ unsigned char type;
+ AHEAP_KEY *v; /* array for heap key */
+ int end; /* the number of maximum elements */
+ int base; /* the constant for set 0 to the leftmost leaf */
+} AHEAP;
+
+QSORT_TYPE_HEADER (AHEAP_KEY, AHEAP_KEY)
+QSORT_TYPE_HEADER (AHEAP_ID, AHEAP_ID)
+extern AHEAP INIT_AHEAP;
+
+/* initialization. allocate memory for H and fill it by +infinity */
+void AHEAP_alloc (AHEAP *H, int num);
+void AHEAP_end (AHEAP *H);
+
+/* return the index of the leaf having the minimum key among the descendants
+ of the given node i. If several leaves with the smallest key are there,
+ return the minimum index among them if f=0, maximum index if f=1, and
+ random choice if f=2 */
+AHEAP_ID AHEAP_findmin_node (AHEAP *H, AHEAP_ID i, int f);
+AHEAP_ID AHEAP_findmin_head (AHEAP *H);
+AHEAP_ID AHEAP_findmin_tail (AHEAP *H);
+AHEAP_ID AHEAP_findmin_rnd (AHEAP *H);
+
+/* return the index of the leaf having smaller value than a among the
+ descendants of the given node i. If several leaves with the smallest key
+ are there, return the minimum index among them if f=0, maximum index if f=1,
+ and random choice if f=2 */
+AHEAP_ID AHEAP_findlow_node (AHEAP *H, AHEAP_KEY a, AHEAP_ID i, int f);
+AHEAP_ID AHEAP_findlow_head (AHEAP *H, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_tail (AHEAP *H, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_rnd (AHEAP *H, AHEAP_KEY a);
+
+/* return the index of the leaf having smaller value than a next/previous to
+ leaf i. return -1 if such a leaf does not exist */
+AHEAP_ID AHEAP_findlow_nxt (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_prv (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+
+/* change the key of node i to a /Add a to the key of node i, and update heap H */
+void AHEAP_chg (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+void AHEAP_add (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+
+/* update the ancestor of node i */
+void AHEAP_update (AHEAP *H, AHEAP_ID i);
+
+/* find the leaf with the minimum key value among the leaves having index
+ smaller/larger than i, or between i and j */
+AHEAP_ID AHEAP_upper_min (AHEAP *H, AHEAP_ID i);
+AHEAP_ID AHEAP_lower_min (AHEAP *H, AHEAP_ID i);
+AHEAP_ID AHEAP_interval_min (AHEAP *H, AHEAP_ID i, AHEAP_ID j);
+
+/* print heap keys according to the structure of the heap */
+void AHEAP_print (AHEAP *H);
+
+#endif
--- /dev/null
+/*
+ blocked memory allocation library
+ 12/Mar/2002 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _base_c_
+#define _base_c_
+
+#include"base.h"
+
+BASE INIT_BASE = {TYPE_BASE,NULL,0,0,0,0,-1,NULL};
+
+/* initialization, and allocate memory for header */
+void BASE_alloc (BASE *B, int unit, int block_siz){
+ *B = INIT_BASE;
+ B->dellist = B;
+ B->unit = unit;
+ B->block_siz = block_siz;
+ B->num = block_siz;
+ B->block_num = -1;
+ calloc2 (B->base, 20, "BASE_alloc: B->base", EXIT);
+ B->block_end = 20;
+}
+
+/* termination */
+void BASE_end (BASE *B){
+ int i;
+ FLOOP (i, 0, B->block_end) free2 (B->base[i]);
+ free2 (B->base);
+ *B = INIT_BASE;
+}
+
+/* return pointer to the cell corresponding to the given index */
+void *BASE_pnt (BASE *B, size_t i){
+ return ( B->base[i/BASE_BLOCK] + (i%BASE_BLOCK)*B->unit);
+}
+/* return index corresponding to the given pointer */
+size_t BASE_index (BASE *B, void *x){
+ size_t i;
+ FLOOP (i, 0, B->block_end+1){
+ if ( ((char*)x)>= B->base[i] && ((char*)x)<=B->base[i]+B->unit*BASE_BLOCK )
+ return ( i*BASE_BLOCK + ((size_t)(((char *)x) - B->base[i])) / B->unit);
+ }
+ return (0);
+}
+
+/* increment the current memory block pointer and (re)allcate memory if necessary */
+void *BASE_get_memory (BASE *B, int i){
+ B->num += i;
+ if ( B->num >= B->block_siz ){ /* if reach to the end of base array */
+ B->num = i; /* allocate one more base array, and increment the counter */
+ B->block_num++;
+ reallocx(B->base, B->block_end, B->block_num, NULL, "BASE:block", EXIT0);
+ if ( B->base[B->block_num] == NULL )
+ malloc2 (B->base[B->block_num], B->block_siz*B->unit, "BASE_new: base", EXIT0);
+ return (B->base[B->block_num]);
+ }
+ return (B->base[B->block_num] + (B->num-i)*B->unit);
+}
+
+
+/* allocate new cell */
+void *BASE_new (BASE *B){
+ char *x;
+
+ /* use deleted cell if it exists */
+ if ( B->dellist != ((void *)B) ){
+ x = (char *)B->dellist; /* return the deleted cell */
+ B->dellist = (void *)(*((char **)x)); /* increment the head of the list */
+ } else {
+ /* take a new cell from the base array if no deleted one exists */
+ x = (char *)BASE_get_memory (B, 1);
+ }
+ return (x);
+}
+
+/* delete one cell. (add to the deleted list) */
+void BASE_del (BASE *B, void *x){
+ *((void **)x) = B->dellist;
+ B->dellist = x;
+}
+
+#endif
+
+
--- /dev/null
+/*
+ blocked memory allocation library
+ 12/Mar/2002 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+
+#ifndef _base_h_
+#define _base_h_
+
+#include"stdlib2.h"
+
+/* structure for base array */
+#define BASE_UNIT 16
+#define BASE_BLOCK 65536
+
+typedef struct {
+ unsigned char type;
+ char **base;
+ int block_siz; // size of one block of memory
+ int block_num; // currently using block
+ int unit; // size of one unit memory
+ int num; // current position in a block
+ int block_end; // current end of the block
+ void *dellist;
+
+} BASE;
+
+extern BASE INIT_BASE;
+
+/* initialization, and allocate memory for header */
+void BASE_alloc (BASE *B, int unit, int block_siz);
+
+/* termination */
+void BASE_end (BASE *B);
+
+/* return pointer to the cell corresponding to the given index */
+void *BASE_pnt (BASE *B, size_t i);
+
+/* return index corresponding to the given pointer */
+size_t BASE_index (BASE *B, void *x);
+
+/* increment the current memory block pointer and (re)allcate memory if necessary */
+void *BASE_get_memory (BASE *B, int i);
+
+/* allocate new cell */
+void *BASE_new (BASE *B);
+
+/* delete one cell. (add to the deleted list) */
+void BASE_del (BASE *B, void *x);
+
+
+#endif
+
--- /dev/null
+require "mkmf"
+
+cp="../../include"
+
+$CFLAGS = " -Wall -I#{cp} -I/usr/local/include/boost -I./"
+$CPPFLAGS = " -Wall -I#{cp} -I/usr/local/include/boost -I./"
+$LOCAL_LIBS += " -L/usr/local/lib -lstdc++ -lmcmd1"
+$objs=["lcm_main.o","lcm.o"]
+
+create_makefile("lcm")
+
--- /dev/null
+/* itemset search input/output common routines
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* routines for itemset mining */
+
+#ifndef _itemset_c_
+#define _itemset_c_
+
+#include"itemset.h"
+#include"queue.c"
+#include"aheap.c"
+
+/* flush the write buffer, available for multi-core mode */
+void ITEMSET_flush (ITEMSET *I, FILE2 *fp){
+ if ( !(I->flag&ITEMSET_MULTI_OUTPUT) || (fp->buf-fp->buf_org) > FILE2_BUFSIZ/2 ){
+ SPIN_LOCK(I->multi_core, I->lock_output);
+ FILE2_flush (fp);
+ SPIN_UNLOCK(I->multi_core, I->lock_output);
+ }
+}
+
+/* Output information about ITEMSET structure. flag&1: print frequency constraint */
+void ITEMSET_print (ITEMSET *I, int flag){
+ if ( I->lb>0 || I->ub<INTHUGE ){
+ if ( I->lb > 0 ) print_err ("%d <= ", I->lb);
+ print_err ("itemsets ");
+ if ( I->ub < INTHUGE ) print_err (" <= %d\n", I->ub);
+ print_err ("\n");
+ }
+ if ( flag&1 ){
+ if ( I->frq_lb > -WEIGHTHUGE ) print_err (WEIGHTF" <=", I->frq_lb);
+ print_err (" frequency ");
+ if ( I->frq_ub < WEIGHTHUGE ) print_err (" <="WEIGHTF, I->frq_ub);
+ print_err ("\n");
+ }
+}
+
+/* ITEMSET initialization */
+void ITEMSET_init (ITEMSET *I){
+ I->flag = 0;
+ I->iters = I->iters2 = I->iters3 = 0;
+ I->solutions = I->solutions2 = I->max_solutions = I->outputs = I->outputs2 = 0;
+ I->topk.end = 0;
+ I->item_max = I->item_max_org = 0;
+ I->ub = I->len_ub = I->gap_ub = INTHUGE;
+ I->lb = I->len_lb = I->gap_lb = 0;
+ I->frq = I->pfrq = I->total_weight = 0;
+ I->ratio = I->prob = 0.0;
+ I->posi_ub = I->nega_ub = I->frq_ub = WEIGHTHUGE;
+ I->posi_lb = I->nega_lb = I->frq_lb = I->setrule_lb = -WEIGHTHUGE;
+ I->dir = 0;
+ I->target = INTHUGE;
+ I->prob_ub = I->ratio_ub = I->rposi_ub = 1;
+ I->prob_lb = I->ratio_lb = I->rposi_lb = 0;
+ I->itemflag = NULL;
+ I->perm = NULL;
+ I->item_frq = NULL;
+ I->sc = NULL;
+ I->X = NULL;
+ I->fp = NULL;
+ I->tpfp = NULL; // hamuro add
+ I->patID = 0; // hamuro add
+ I->topk = INIT_AHEAP;
+ I->topk_weight = 0; // hamuro add
+ I->itemset = I->add = INIT_QUEUE;
+ I->set_weight = NULL;
+ I->set_occ = NULL;
+
+ I->multi_iters = I->multi_iters2 = I->multi_iters3 = NULL;
+ I->multi_outputs = I->multi_outputs2 = NULL;
+ I->multi_solutions = I->multi_solutions2 = NULL;
+ I->multi_fp = NULL;
+ I->multi_core = 0;
+}
+
+
+/* second initialization
+ topk.end>0 => initialize heap for topk mining */
+/* all pointers will be set to 0, but not for */
+/* if topK mining, set topk.end to "K" */
+void ITEMSET_init2 (ITEMSET *I, char *fname, char *tp_fname, PERM *perm, size_t item_max, size_t item_max_org){ // hamuro add tp_fname
+ LONG i;
+ size_t siz = (I->flag&ITEMSET_USE_ORG)?item_max_org+2: item_max+2;
+ I->prob = I->ratio = 1.0;
+ I->frq = 0;
+ I->perm = perm;
+ if ( I->topk.end>0 ){
+ AHEAP_alloc (&I->topk, I->topk.end);
+ FLOOP (i, 0, I->topk.end) AHEAP_chg (&I->topk, (AHEAP_ID)i, -WEIGHTHUGE);
+ I->frq_lb = -WEIGHTHUGE;
+ } else I->topk.v = NULL;
+ QUEUE_alloc (&I->itemset, (QUEUE_ID)siz); I->itemset.end = (QUEUE_ID)siz;
+ if ( I->flag&ITEMSET_ADD ) QUEUE_alloc (&I->add, (QUEUE_ID)siz);
+ calloc2 (I->sc, siz+2, "ITEMSET_init2: sc", goto ERR);
+
+ if ( I->flag&ITEMSET_SET_RULE ){
+ calloc2 (I->set_weight, siz, "ITEMSET_init2: set_weight", goto ERR);
+ if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) )
+ calloc2 (I->set_occ, siz, "ITEMSET_init2: set_weight", goto ERR);
+ }
+ I->iters = I->iters2 = I->solutions = 0;
+ I->item_max = item_max;
+ I->item_max_org = (QUEUE_INT)item_max_org;
+ if ( fname ){ fopen2 (I->fp, fname, "w", "ITEMSET_init2", goto ERR);}
+ else I->fp = 0;
+ if ( tp_fname && !I->topk.v){ fopen2 (I->tpfp, tp_fname, "w", "ITEMSET_init2", goto ERR);} // hamuro add
+ else I->tpfp = 0; // hamuro add
+ if ( I->flag&ITEMSET_ITEMFRQ )
+ malloc2 (I->item_frq, item_max+2, "ITEMSET_init2: item_frqs", goto ERR);
+ if ( I->flag&ITEMSET_RULE ){
+ calloc2 (I->itemflag, item_max+2, "ITEMSET_init2: item_flag", goto ERR);
+ }
+ I->total_weight = 1;
+
+ calloc2 (I->multi_iters, I->multi_core+1, "ITEMSET_init2: multi_iters", goto ERR);
+ calloc2 (I->multi_iters2, I->multi_core+1, "ITEMSET_init2: multi_iters2", goto ERR);
+ calloc2 (I->multi_iters3, I->multi_core+1, "ITEMSET_init2: multi_iters3", goto ERR);
+ calloc2 (I->multi_outputs, I->multi_core+1, "ITEMSET_init2: multi_outputs", goto ERR);
+ calloc2 (I->multi_outputs2, I->multi_core+1, "ITEMSET_init2: multi_outputs2", goto ERR);
+ calloc2 (I->multi_solutions, I->multi_core+1, "ITEMSET_init2: multi_solutions", goto ERR);
+ calloc2 (I->multi_solutions2, I->multi_core+1, "ITEMSET_init2: multi_solutions2", goto ERR);
+ calloc2 (I->multi_fp, I->multi_core+1, "ITEMSET_init2: multi_fp", goto ERR);
+ calloc2 (I->multi_tpfp, I->multi_core+1, "ITEMSET_init2: multi_tpfp", goto ERR); // hamuro add
+
+ FLOOP (i, 0, MAX(I->multi_core,1))
+ FILE2_open_ (I->multi_fp[i], I->fp, "ITEMSET_init2: multi_fp[i]", goto ERR);
+ FLOOP (i, 0, MAX(I->multi_core,1)) // hamuro add
+ FILE2_open_ (I->multi_tpfp[i], I->tpfp, "ITEMSET_init2: multi_tpfp[i]", goto ERR); // hamuro add
+#ifdef MULTI_CORE
+ if ( I->multi_core > 0 ){
+ pthread_spin_init (&I->lock_counter, PTHREAD_PROCESS_PRIVATE);
+ pthread_spin_init (&I->lock_sc, PTHREAD_PROCESS_PRIVATE);
+ pthread_spin_init (&I->lock_output, PTHREAD_PROCESS_PRIVATE);
+ }
+#endif
+ return;
+ ERR:;
+ ITEMSET_end (I);
+ EXIT;
+}
+
+/* sum the counters computed by each thread */
+void ITEMSET_merge_counters (ITEMSET *I){
+ int i;
+ FLOOP (i, 0, MAX(I->multi_core,1)){
+ I->iters += I->multi_iters[i];
+ I->iters2 += I->multi_iters2[i];
+ I->iters3 += I->multi_iters3[i];
+ I->outputs += I->multi_outputs[i];
+ I->outputs2 += I->multi_outputs2[i];
+ I->solutions += I->multi_solutions[i];
+ I->solutions2 += I->multi_solutions2[i];
+ FILE2_flush ( &I->multi_fp[i]);
+ if(I->tpfp) FILE2_flush ( &I->multi_tpfp[i]); //hamuro add
+ }
+}
+
+/*******************************************************************/
+/* termination of ITEMSET */
+/*******************************************************************/
+void ITEMSET_end (ITEMSET *I){
+ int i;
+ QUEUE_end (&I->itemset);
+ QUEUE_end (&I->add);
+ AHEAP_end (&I->topk);
+ fclose2 ( I->fp);
+ fclose2 ( I->tpfp); // hamuro add
+ mfree (I->sc, I->item_frq, I->itemflag, I->perm, I->set_weight, I->set_occ);
+
+ if ( I->multi_fp )
+ FLOOP (i, 0, MAX(I->multi_core,1)) free2 (I->multi_fp[i].buf);
+ mfree (I->multi_fp, I->multi_iters, I->multi_iters2, I->multi_iters3);
+ mfree (I->multi_outputs, I->multi_outputs2, I->multi_solutions, I->multi_solutions2);
+#ifdef MULTI_CORE
+ if ( I->multi_core>0 ){
+ pthread_spin_destroy(&I->lock_counter);
+ pthread_spin_destroy(&I->lock_sc);
+ pthread_spin_destroy(&I->lock_output);
+ }
+#endif
+ ITEMSET_init (I);
+}
+
+/*******************************************************************/
+/* output at the termination of the algorithm */
+/* print #of itemsets of size k, for each k */
+/*******************************************************************/
+void ITEMSET_last_output (ITEMSET *I){
+ QUEUE_ID i;
+ unsigned long long n=0, nn=0;
+
+ ITEMSET_merge_counters (I);
+ if ( I->topk.end > 0 ){
+ i = AHEAP_findmin_head (&I->topk);
+ //fprint_WEIGHT (stdout, AHEAP_H (I->topk, i));//hamuro comment out
+ //printf ("\n");//hamuro comment out
+ I->topk_weight=AHEAP_H (I->topk, i); // hamuro add
+ return;
+ }
+ return; // hamuro add
+
+ FLOOP (i, 0, I->itemset.end+1){
+ n += I->sc[i];
+ if ( I->sc[i] != 0 ) nn = i;
+ }
+ if ( !(I->flag&SHOW_MESSAGE) ) return;
+ if ( n!=0 ){
+ printf ("%llu\n", n);
+ FLOOP (i, 0, nn+1) printf ("%llu\n", I->sc[i]);
+ }
+ print_err ("iters=%lld", I->iters);
+ if ( I->flag&ITEMSET_ITERS2 ) print_err (", iters2=%lld", I->iters2);
+ print_err ("\n");
+}
+
+/* output frequency, coverage */
+void ITEMSET_output_frequency (ITEMSET *I, int core_id){
+ FILE2 *fp = &I->multi_fp[core_id];
+ if ( I->flag&(ITEMSET_FREQ+ITEMSET_PRE_FREQ) ){
+ if ( I->flag&ITEMSET_FREQ ) FILE2_putc (fp, ','); // hamuro ' ' -> ','
+ FILE2_print_WEIGHT (fp, I->frq, 4, '\0'); // hamuro ' ' -> '\0'
+ //FILE2_putc (fp, ')'); // hamuro comment out
+ if ( I->flag&ITEMSET_PRE_FREQ ) FILE2_putc (fp, ' ');
+ }
+ if ( I->flag&ITEMSET_OUTPUT_POSINEGA ){ // output positive sum, negative sum in the occurrence
+// FILE2_putc (fp, ','); // hamuro rm
+ FILE2_print_WEIGHT (fp, I->pfrq, 4, ','); // hamuro edit
+ FILE2_print_WEIGHT (fp, I->pfrq-I->frq, 4, ',');
+ FILE2_print_WEIGHT (fp, I->pfrq/(2*I->pfrq-I->frq), 4, ',');
+ //FILE2_putc (fp, ')'); // hamuro rm
+ }
+}
+
+#ifdef _trsact_h_
+void ITEMSET_output_occ (ITEMSET *I, QUEUE *occ, int core_id, FILE2 *tpfp){ // add tpfp by hamuro
+ QUEUE_ID i;
+ QUEUE_INT *x;
+ FILE2 *fp = &I->multi_fp[core_id];
+ TRSACT *TT = (TRSACT *)(I->X);
+ VEC_ID j, ee = TT->rows_org;
+ int flag = I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT);
+
+ i=0; MQUE_FLOOP_ (*occ, x, TT->occ_unit){
+ if ( (I->flag&ITEMSET_RM_DUP_TRSACT)==0 || *x != ee ){
+ //FILE2_print_int (fp, TT->trperm? TT->trperm[*x]: *x,' '); // hamuro comment out
+ FILE2_print_int (tpfp, TT->trperm? TT->trperm[*x]: *x, 0); // hamuro add
+ FILE2_print_int (tpfp, I->patID,','); //hamuro add :: bug stop
+ FILE2_putc (tpfp, '\n'); //hamuro add
+
+ if (flag == ITEMSET_MULTI_OCC_PRINT ){
+ FLOOP (j, 1, (VEC_ID)(TT->occ_unit/sizeof(QUEUE_INT)))
+ FILE2_print_int (fp, *(x+j), ' ');
+ } else if ( flag == (ITEMSET_MULTI_OCC_PRINT+ITEMSET_TRSACT_ID) ){
+ FILE2_print_int (fp, *(x+1), ' ');
+ }
+ }
+ ee = *x;
+ if ( (++i)%256==0 ) ITEMSET_flush (I, fp);
+ FILE2_flush (tpfp); //hamuro add
+ }
+ //FILE2_putc (fp, '\n'); // hamuro comment out
+}
+#endif
+
+/* output an itemset to the output file */
+void ITEMSET_output_itemset (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID i;
+ QUEUE_INT e;
+ FILE2 *fp = &I->multi_fp[core_id];
+ FILE2 *tpfp = &I->multi_tpfp[core_id]; // hamuro add
+
+ I->multi_outputs[core_id]++;
+ if ( (I->flag&SHOW_PROGRESS ) && (I->iters%(ITEMSET_INTERVAL) == 0) )
+ print_err ("---- %lld solutions in %lld candidates\n", I->solutions, I->outputs);
+ if ( I->itemset.t < I->lb || I->itemset.t > I->ub ) return;
+ if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
+ if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;
+
+ I->multi_solutions[core_id]++;
+ if ( I->max_solutions>0 && I->solutions > I->max_solutions ){
+ ITEMSET_last_output (I);
+ ERROR_MES = "reached to maximum number of solutions";
+ EXIT;
+ }
+ if ( I->topk.v ){
+ e = AHEAP_findmin_head (&(I->topk));
+ if ( I->frq > AHEAP_H (I->topk, e) ){
+ AHEAP_chg (&(I->topk), e, I->frq);
+ e = AHEAP_findmin_head (&(I->topk));
+ I->frq_lb = AHEAP_H (I->topk, e);
+ }
+ } else if ( I->fp ){
+ if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
+ if ( (I->flag & ITEMSET_NOT_ITEMSET) == 0 ){
+#ifdef _agraph_h_
+ if ( I->flag&ITEMSET_OUTPUT_EDGE ){
+ ARY_FLOOP (I->itemset, i, e){
+ FILE2_print_int (fp, AGRAPH_INC_FROM(*((AGRAPH *)(I->X)),e,I->dir), '(' );
+ FILE2_print_int (fp, AGRAPH_INC_TO(*((AGRAPH *)(I->X)),e,I->dir), ',');
+ FILE2_putc (fp, ')');
+ if ( i<I->itemset.t-1 ) FILE2_putc (fp, ' ');
+ if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
+ }
+ goto NEXT;
+ }
+#endif
+ FILE2_print_int (fp, I->patID, '\0'); // hamuro add
+ FILE2_putc (fp, ','); // hamuro add
+ ARY_FLOOP (I->itemset, i, e){
+ FILE2_print_int (fp, I->perm? I->perm[e]: e, i==0? 0: ' ');
+ if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
+ }
+#ifdef _agraph_h_
+ NEXT:;
+#endif
+ }
+ if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency (I, core_id);
+ if ( ((I->flag & ITEMSET_NOT_ITEMSET) == 0) || (I->flag&ITEMSET_FREQ) || (I->flag&ITEMSET_PRE_FREQ) ) FILE2_putc (fp, '\n');
+
+#ifdef _trsact_h_
+ if (I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT)) ITEMSET_output_occ (I, occ, core_id, tpfp);
+#endif
+ I->patID++; // hamuro add
+ }
+ I->sc[I->itemset.t]++;
+ ITEMSET_flush (I, fp);
+}
+
+/* output itemsets with adding all combination of "add"
+ at the first call, i has to be "add->t" */
+void ITEMSET_solution_iter (ITEMSET *I, QUEUE *occ, int core_id){
+//fprintf( stderr,"?? ------v=%ld t=%d\n",(*occ).v,(*occ).t );
+ QUEUE_ID t=I->add.t;
+ if ( I->itemset.t > I->ub ) return;
+ ITEMSET_output_itemset (I, occ, core_id);
+if ( ERROR_MES ) return;
+ BLOOP (I->add.t, I->add.t, 0){
+ ARY_INS (I->itemset, I->add.v[I->add.t]);
+ ITEMSET_solution_iter (I, occ, core_id);
+if ( ERROR_MES ) return;
+ I->itemset.t--;
+ }
+ I->add.t = t;
+}
+
+void ITEMSET_solution (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID i;
+ LONG s;
+//fprintf( stderr,"## ------v=%ld t=%d\n",(*occ).v,(*occ).t );
+ if ( I->itemset.t > I->ub ) return;
+ if ( I->flag & ITEMSET_ALL ){
+ if ( I->fp || I->topk.v ) ITEMSET_solution_iter (I, occ, core_id);
+ else {
+ s=1; FLOOP (i, 0, I->add.t+1){
+ I->sc[I->itemset.t+i] += s;
+ s = s*(I->add.t-i)/(i+1);
+ }
+ }
+ } else {
+ FLOOP (i, 0, I->add.t) ARY_INS (I->itemset, I->add.v[i]);
+ ITEMSET_output_itemset (I, occ, core_id);
+ I->itemset.t -= I->add.t;
+ }
+}
+
+/*************************************************************************/
+/* ourput a rule */
+/*************************************************************************/
+void ITEMSET_output_rule (ITEMSET *I, QUEUE *occ, double p1, double p2, size_t item, int core_id){
+ FILE2 *fp = &I->multi_fp[core_id];
+ if ( fp->fp && !(I->topk.v) ){
+ FILE2_print_real (fp, p1, 4, '(');
+ FILE2_print_real (fp, p2, 4, ',');
+ FILE2_putc (fp, ')');
+ FILE2_print_int (fp, I->perm[item], ' ');
+ FILE2_puts (fp, " <= ");
+ }
+ if ( I->flag & ITEMSET_RULE ) ITEMSET_output_itemset (I, occ, core_id);
+ else ITEMSET_solution (I, occ, core_id);
+}
+/*************************************************************************/
+/* check all rules for a pair of itemset and item */
+/*************************************************************************/
+void ITEMSET_check_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, size_t item, int core_id){
+ double p = w[item]/I->frq, pp, ff;
+// printf ("[ratio] %f, p=%f, (%f/ %f), %d(%d) <= ", I->ratio_lb, p, w[item], I->frq, I->perm[item], I->itemflag[item]);
+ if ( I->itemflag[item]==1 ) return;
+ if ( w[item] <= -WEIGHTHUGE ) p = 0;
+ pp = p; ff = I->item_frq[item];
+ if ( I->flag & ITEMSET_RULE_SUPP ){ pp = w[item]; ff *= I->total_weight; }
+
+ if ( I->flag & (ITEMSET_RULE_FRQ+ITEMSET_RULE_INFRQ)){
+ if ( (I->flag & ITEMSET_RULE_FRQ) && p < I->ratio_lb ) return;
+ if ( (I->flag & ITEMSET_RULE_INFRQ) && p > I->ratio_ub ) return;
+ ITEMSET_output_rule (I, occ, pp, ff, item, core_id);
+ } else if ( I->flag & (ITEMSET_RULE_RFRQ+ITEMSET_RULE_RINFRQ) ){
+ if ( (I->flag & ITEMSET_RULE_RFRQ) && (1-p) > I->ratio_lb * (1-I->item_frq[item]) ) return;
+ if ( (I->flag & ITEMSET_RULE_RINFRQ) && p > I->ratio_ub * I->item_frq[item] ) return;
+ ITEMSET_output_rule (I, occ, pp, ff, item, core_id);
+ }
+}
+
+/*************************************************************************/
+/* check all rules for an itemset and all items */
+/*************************************************************************/
+void ITEMSET_check_all_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, QUEUE *jump, WEIGHT total, int core_id){
+ QUEUE_ID i, t;
+ QUEUE_INT e, f=0, *x;
+ WEIGHT d = I->frq/total;
+
+ // checking out of range for itemset size and (posi/nega) frequency
+ if ( I->itemset.t+I->add.t < I->lb || I->itemset.t>I->ub || (!(I->flag&ITEMSET_ALL) && I->itemset.t+I->add.t>I->ub)) return;
+ if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
+ if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;
+
+ if ( I->flag&ITEMSET_SET_RULE ){ // itemset->itemset rule for sequence mining
+ FLOOP (i, 0, I->itemset.t-1){
+ if ( I->frq/I->set_weight[i] >= I->setrule_lb && I->fp ){
+ I->sc[i]++;
+ if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
+ FLOOP (t, 0, I->itemset.t){
+ FILE2_print_int (&I->multi_fp[core_id], I->itemset.v[t], t?' ':0);
+ if ( t == i ){
+ FILE2_putc (&I->multi_fp[core_id], ' ');
+ FILE2_putc (&I->multi_fp[core_id], '=');
+ FILE2_putc (&I->multi_fp[core_id], '>');
+ }
+ }
+ if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency ( I, core_id);
+ FILE2_putc (&I->multi_fp[core_id], ' ');
+ FILE2_print_real (&I->multi_fp[core_id], I->frq/I->set_weight[i], 4, '(');
+ FILE2_putc (&I->multi_fp[core_id], ')');
+ FILE2_putc (&I->multi_fp[core_id], '\n');
+#ifdef _trsact_h_
+ if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) )
+ ITEMSET_output_occ (I, I->set_occ[i], core_id,NULL);
+#endif
+ ITEMSET_flush (I, &I->multi_fp[core_id]);
+ }
+ }
+ }
+ // constraint of relational frequency
+ if ( ((I->flag&ITEMSET_RFRQ)==0 || d >= I->prob_lb * I->prob )
+ && ((I->flag&ITEMSET_RINFRQ)==0 || d <= I->prob * I->prob_ub) ){
+ if ( I->flag&ITEMSET_RULE ){ // rule mining routines
+ if ( I->itemset.t == 0 ) return;
+ if ( I->target < I->item_max ){
+ ITEMSET_check_rule (I, w, occ, I->target, core_id); if (ERROR_MES) return;
+ } else {
+ if ( I->flag & (ITEMSET_RULE_FRQ + ITEMSET_RULE_RFRQ) ){
+ if ( I->add.t>0 ){
+// if ( I->itemflag[I->add.v[0]] ) // for POSI_EQUISUPP (occ_w[e] may not be 100%, in the case)
+ f = I->add.v[I->add.t-1]; t = I->add.t; I->add.t--;
+ FLOOP (i, 0, t){
+ e = I->add.v[i];
+ I->add.v[i] = f;
+ ITEMSET_check_rule (I, w, occ, e, core_id); if (ERROR_MES) return;
+ I->add.v[i] = e;
+ }
+ I->add.t++;
+ }
+ MQUE_FLOOP (*jump, x)
+ ITEMSET_check_rule (I, w, occ, *x, core_id); if (ERROR_MES) return;
+ } else {
+ if ( I->flag & (ITEMSET_RULE_INFRQ + ITEMSET_RULE_RINFRQ) ){
+// ARY_FLOOP ( *jump, i, e ) I->itemflag[e]--;
+ FLOOP (i, 0, I->item_max){
+ if ( I->itemflag[i] != 1 ){
+ ITEMSET_check_rule (I, w, occ, i, core_id); if (ERROR_MES) return;
+ }
+ }
+// ARY_FLOOP ( *jump, i, e ) I->itemflag[e]++;
+// }
+// ARY_FLOOP ( *jump, i, e ) ITEMSET_check_rule (I, w, occ, e);
+ }
+ }
+ }
+ } else { // usual mining (not rule mining)
+ if ( I->fp && (I->flag&(ITEMSET_RFRQ+ITEMSET_RINFRQ))){
+ FILE2_print_real (&I->multi_fp[core_id], d, 4, '[');
+ FILE2_print_real (&I->multi_fp[core_id], I->prob, 4, ',');
+ FILE2_putc (&I->multi_fp[core_id], ']');
+ }
+ ITEMSET_solution (I, occ, core_id);
+ }
+ }
+}
+
+#endif
--- /dev/null
+/* itemset search input/output common routines
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* routines for itemset mining */
+
+#ifndef _itemset_h_
+#define _itemset_h_
+
+#include"stdlib2.h"
+#include"queue.h"
+#define AHEAP_KEY_WEIGHT
+#include"aheap.h"
+
+
+typedef struct {
+ int a;
+ QUEUE itemset; // current operating itemset
+ QUEUE add; // for equisupport (hypercube decomposition)
+ int ub, lb; // upper/lower bounds for the itemset size
+ WEIGHT frq, pfrq, frq_ub, frq_lb; // upper/lower bounds for the frequency
+ WEIGHT rposi_lb, rposi_ub, posi_lb, posi_ub, nega_ub, nega_lb; // upper/lower bounds for the sum of positive/negative weights
+ WEIGHT setrule_lb; // frequency lower bound for set rule
+ double ratio, prob; // confidence and independent probability of the current pattern
+ double ratio_ub, ratio_lb, prob_ub, prob_lb; // upper/lower bounds for confidence and independent probability
+ QUEUE_INT target; // target item for rule mining
+ char *itemflag; // 1 if it is include in the pattern (and 2 if included in add)
+ WEIGHT *item_frq; // frequency of each item
+ WEIGHT total_weight; // total weight of the input database
+ int len_ub, len_lb; // upper/lower bounds for the length of the pattern
+ int gap_ub, gap_lb; // upper/lower bounds for the gaps in the pattern
+ LONG *sc; // #itemsets classified by the sizes
+ QUEUE_INT item_max, item_max_org; // (original) maximum item
+ AHEAP topk; // heap for topk mining. valid if topk->h is not NULL
+ WEIGHT topk_weight; // hamuro add
+ int flag; // flag for various functions
+ PERM *perm; // permutation array for output itemset: item => original item
+ FILE *fp; // file pointer to the output file
+ FILE *tpfp; // hamuro add file pointer to the output file for traID-patID
+ LONG patID; // hamuro add patID
+ LONG iters, iters2, iters3; //iterations
+ LONG solutions, solutions2; // number of solutions output
+ LONG outputs, outputs2; // #calls of ITEMSET_output_itemset or ITEMSET_solusion
+ LONG max_solutions; // maximum solutions to be output
+ void *X; // pointer to the original data
+ int dir; // direction flag for AGRAPH & SGRAPH
+
+ int multi_core; // number of processors
+ LONG *multi_iters, *multi_iters2, *multi_iters3; //iterations
+ LONG *multi_solutions, *multi_solutions2; // number of solutions output
+ LONG *multi_outputs, *multi_outputs2; // #calls of ITEMSET_output_itemset or ITEMSET_solusion
+ FILE2 *multi_fp; // output file2 pointer for multi-core mode
+ FILE2 *multi_tpfp; // hamuro add : output file2 pointer for multi-core mode
+ WEIGHT *set_weight; // the frequency of each prefix of current itemset
+ QUEUE **set_occ; // the occurrence of each prefix of current itemset
+
+#ifdef MULTI_CORE
+ pthread_spinlock_t lock_counter; // couneter locker for jump counter
+ pthread_spinlock_t lock_sc; // couneter locker for
+ pthread_spinlock_t lock_output; // couneter locker for output
+#endif
+} ITEMSET;
+
+/* parameters for ITEMSET.flag */
+
+#define ITEMSET_ITERS2 4 // output #iters2
+#define ITEMSET_PRE_FREQ 8 // output frequency preceding to each itemset
+#define ITEMSET_FREQ 16 // output frequency following to each itemset
+#define ITEMSET_ALL 32 // concat all combinations of "add" to each itemset
+
+#define ITEMSET_TRSACT_ID 64 // output transaction ID's in occurrences
+#define ITEMSET_OUTPUT_EDGE 128 // output itemset as edge set (refer AGRAPH)
+#define ITEMSET_IGNORE_BOUND 256 // ignore constraint for frequency
+#define ITEMSET_RM_DUP_TRSACT 512 // remove duplicated transaction ID's
+#define ITEMSET_MULTI_OCC_PRINT 1024 //print each component of occ
+ // TRSACT_ID+MULTI_OCC_PRINT means print first two components of occ
+#define ITEMSET_NOT_ITEMSET 2048 // do not print itemset to the output file
+#define ITEMSET_RULE_SUPP 4096 // output confidence and item frquency by abusolute value
+#define ITEMSET_OUTPUT_POSINEGA 8192 // output negative/positive frequencies
+#define ITEMSET_MULTI_OUTPUT 16384 // for multi-core mode
+#define ITEMSET_USE_ORG 32768 // use item_max_org to the size of use
+#define ITEMSET_ITEMFRQ 65536 // allocate item_frq
+#define ITEMSET_ADD 131072 // allocate add
+
+#define ITEMSET_RULE_FRQ 262144
+#define ITEMSET_RULE_INFRQ 524288
+#define ITEMSET_RULE_RFRQ 1048576
+#define ITEMSET_RULE_RINFRQ 2097152
+#define ITEMSET_RFRQ 4194304
+#define ITEMSET_RINFRQ 8388608
+#define ITEMSET_POSI_RATIO 16777216
+#define ITEMSET_SET_RULE 134217728
+//#define ITEMSET_RULE (ITEMSET_RULE_FRQ + ITEMSET_RULE_INFRQ + ITEMSET_RULE_RFRQ + ITEMSET_RULE_RINFRQ + ITEMSET_RFRQ + ITEMSET_RINFRQ + ITEMSET_SET_RULE) // for check any rule is true
+#define ITEMSET_RULE (ITEMSET_RULE_FRQ + ITEMSET_RULE_INFRQ + ITEMSET_RULE_RFRQ + ITEMSET_RULE_RINFRQ + ITEMSET_SET_RULE) // for check any rule is true
+
+#ifndef ITEMSET_INTERVAL
+#define ITEMSET_INTERVAL 500000
+#endif
+
+/* Output information about ITEMSET structure. flag&1: print frequency constraint */
+void ITEMSET_print ( ITEMSET *II, int flag);
+
+/* topk.end>0 => initialize heap for topk mining */
+/* all pointers will be set to 0, but not for */
+/* if topK mining, set topk.end to "K" */
+void ITEMSET_init (ITEMSET *I);
+void ITEMSET_init2 (ITEMSET *I, char *fname, char *tp_fname, PERM *perm, size_t item_max, size_t item_max_org); // hamuro add tp_fname
+void ITEMSET_end (ITEMSET *I);
+
+/* sum the counters computed by each thread */
+void ITEMSET_merge_counters (ITEMSET *I);
+
+/*******************************************************************/
+/* output at the termination of the algorithm */
+/* print #of itemsets of size k, for each k */
+/*******************************************************************/
+void ITEMSET_last_output (ITEMSET *I);
+
+/* output frequency, coverage */
+void ITEMSET_output_frequency (ITEMSET *I, int core_id);
+
+/* output an itemset to the output file */
+void ITEMSET_output_itemset (ITEMSET *I, QUEUE *occ, int core_id);
+
+/* output itemsets with adding all combination of "add"
+ at the first call, i has to be "add->t" */
+void ITEMSET_solution (ITEMSET *I, QUEUE *occ, int core_id);
+
+/*************************************************************************/
+/* ourput a rule */
+/*************************************************************************/
+void ITEMSET_output_rule (ITEMSET *I, QUEUE *occ, double p1, double p2, size_t item, int core_id);
+
+/*************************************************************************/
+/* check all rules for a pair of itemset and item */
+/*************************************************************************/
+void ITEMSET_check_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, size_t item, int core_id);
+
+/*************************************************************************/
+/* check all rules for an itemset and all items */
+/*************************************************************************/
+void ITEMSET_check_all_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, QUEUE *jump, WEIGHT total, int core_id);
+
+#endif
+
+
+
+
--- /dev/null
+
+#include <iostream>
+#include <ruby.h>
+#include <kgmod.h>
+#include <kgMessage.h>
+//#include <kgCSV.h>
+//#include <kgCSVout.h>
+//#include <kgruby.h>
+//#include <kgcut.h>
+//#include <kgcut.h>
+
+using namespace std;
+using namespace kglib;
+//using namespace kgmod;
+
+extern "C" {
+ void Init_lcm(void);
+ int LCM_main (const char* args[], int* iRecNo, int* oRecNo, double* topk_weight);
+}
+
+/*
+ * = Lcm LCM
+ *
+ * === 書式
+ * Lcm.new("f=fields","[-r]","[i=infile]","[o=outfile]")
+ *
+ * === 引数
+ * i= : 入力トランザクションファイル名
+ * w= : ウェイトファイル名
+ * o= : パターン出力ファイル名
+ * t= : トランザクションID-パターンID出力ファイル名
+ * K= : 上位K個の頻出パターンを出力する
+ * l= : 最小パターン長
+ * u= : 最大パターン長
+ * s= : 最小サポート
+ * S= : 最大サポート
+ * g= : アイテム間ギャップ長制限
+ * G= : ウィンドウサイズ
+ *
+ * === 例
+ * * Lcm.new("f=顧客CD,日付,金額").run
+ *
+ * === 参照
+ * {mcutコマンドマニュアル}[http://kgmod.jp/mcmd/index.php?mcut]
+ *
+ */
+VALUE lcmFunc(int argc, VALUE *argv, VALUE self) try {
+ kgArgs args;
+ kgEnv env;
+ string name; // rubyスクリプト名
+ string argstr;
+
+ try { // kgmodのエラーはrubyのエラーとは別に検知する(メッセージ表示のため)
+
+ // 引数をopetionsにセット
+ VALUE options;
+ rb_scan_args(argc, argv,"01",&options);
+
+ // rubyの引数文字列を一旦argstrに退避させてからtoken分割する。
+ // 退避させないと、ruby変数としての文字列を変更してしまうことになる。
+ if(TYPE(options)==T_NIL){
+ argstr="";
+ }else if(TYPE(options)==T_STRING){
+ argstr=RSTRING_PTR(options);
+ }else{
+ rb_raise(rb_eRuntimeError,"1st argument must be String");
+ }
+ vector<char *> opts = splitToken(const_cast<char*>(argstr.c_str()), ' ');
+
+ // 引数文字列へのポインタの領域はここでauto変数に確保する
+ kgAutoPtr2<char*> argv;
+ char** vv;
+ try{
+ argv.set(new char*[opts.size()+1]);
+ vv = argv.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+
+ // vv配列0番目はコマンド名
+ vv[0]=const_cast<char*>("lcm");
+
+ size_t vvSize;
+ for(vvSize=0; vvSize<opts.size(); vvSize++){
+ vv[vvSize+1] = opts.at(vvSize);
+ }
+ vvSize+=1;
+
+ // 引数をセット!!
+ args.add(vvSize,const_cast<const char**>(vv));
+
+ // argsに指定した引数の存在チェック
+ args.paramcheck("i=,w=,o=,t=,K=,l=,u=,s=,S=,type=,M=",false);
+
+ // -----------------------------------------------------
+ // 各種引数の設定
+ const char* argsAR[20];
+ vector<string> argtmp(20);
+ argtmp[0] = args.toString("i=",true );
+ argtmp[1] = args.toString("w=",false);
+ argtmp[2] = args.toString("o=",false);
+ argtmp[3] = args.toString("t=",false);
+ argtmp[4] = args.toString("K=",false);
+ argtmp[5] = args.toString("l=",false);
+ argtmp[6] = args.toString("u=",false);
+ argtmp[7] = args.toString("s=",false);
+ argtmp[8] = args.toString("S=",false);
+ argtmp[9] = args.toString("type=",false);
+ argtmp[10] = args.toString("M=",false);
+ for(size_t i=0;i<11;i++){
+ argsAR[i] = argtmp[i].c_str();
+ }
+
+ double topk_weight=0;
+
+ // K=が指定された時は、topkのsupport(weight)を求め、再度LCMを実行する。
+ if(*argsAR[4]!='\0'){
+ char buf[100];
+ argsAR[4]="";
+ if(topk_weight > atof(argsAR[7])){
+ sprintf(buf,"%f",topk_weight);
+ argsAR[7]=buf;
+ }
+ }
+
+ int iRecNo=0;
+ int oRecNo=0;
+ int ret = LCM_main(argsAR, &iRecNo, &oRecNo, &topk_weight);
+
+ return INT2NUM(ret);
+
+ }catch(kgError& err){ // kgmod関係エラーのchatch
+ err.addModName(name);
+ kgMsg msg(kgMsg::ERR, &env);
+ msg.output(err.message());
+ throw;
+ }
+
+}catch(...){
+ rb_raise(rb_eRuntimeError,"Error at lcm()");
+}
+
+void Init_lcm(void) {
+ // モジュール定義:MCMD::xxxxの部分
+ VALUE mcmd=rb_define_module("MCMD");
+
+ rb_define_module_function(mcmd,"lcm" ,
+ (VALUE (*)(...))lcmFunc , -1);
+}
+
--- /dev/null
+/* Linear time Closed itemset Miner for Frequent Itemset Mining problems */
+/* 2004/4/10 Takeaki Uno, e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about LCM for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+
+#ifndef _lcm_c_
+#define _lcm_c_
+
+#define WEIGHT_DOUBLE
+#define TRSACT_DEFAULT_WEIGHT 1
+
+#define LCM_UNCONST 16777216 // use the complement graph of the constraint graph
+#define LCM_POSI_EQUISUPP 33554432 // an item will be dealt as "equisupp" when "positive"-frequency is equal to the positive-frequency of the current itemset
+
+#define ERROR_RET
+
+#include"trsact.c"
+#include"sgraph.c"
+#include"problem.c"
+
+void LCM_error (){
+ ERROR_MES = "command explanation";
+ print_err ("LCM: [FCMfQIq] [options] input-filename support [output-filename]\n\
+F:frequent itemset mining, C:closed frequent itemset mining\n\
+M:maximal frequent itemset mining, P:positive-closed itemset mining\n\
+f:output frequency following to each output itemset\n\
+A:output positive/negative frequency, and their ratio\n\
+Q:output frequency and coverages preceding to itemsets\n\
+q:no output to standard output, V:show progress of computation\n\
+I:output ID's of transactions including each pattern\n\
+i:do not output itemset to the output file (only rules)\n\
+s:output confidence and item frequency by absolute values\n\
+t:transpose the input database (item i will be i-th transaction, and i-th transaction will be item i)\n\
+[options]\n\
+-K [num]:output [num] most frequent itemsets\n\
+-l,-u [num]:output itemsets with size at least/most [num]\n\
+-U [num]:upper bound for support(maximum support)\n\
+-w [filename]:read weights of transactions from the file\n\
+-c,-C [filename]:read item constraint/un-constraint file\n\
+-S [num]:stop aftre outputting [num] solutions\n\
+-i [num]: find association rule for item [num]\n\
+-a,-A [ratio]: find association rules of confidence at least/most [ratio]\n\
+-r,-R [ratio]: find association rules of relational confidence at least/most [ratio]\n\
+-f,F [ratio]: output itemsets with frequency no less/greater than [ratio] times the frequency given by product of the probability of each item appearance\n\
+-p,-P [num]: output itemset only if (frequency)/(abusolute frequency) is no less/no greater than [num]\n\
+-n,-N [num]: output itemset only if its negative frequency is no less/no greater than [num] (negative frequency is the sum of weights of transactions having negative weights)\n\
+-o,-O [num]: output itemset only if its positive frequency is no less/no greater than [num] (positive frequency is the sum of weights of transactions having positive weights)\n\
+-m,-M [filename]:read/write item permutation from/to file [filename]\n\
+if the 1st letter of input-filename is '-', be considered as 'parameter list'\n");
+ EXIT;
+}
+
+// hamuro add begin
+void LCM_read_param2 (PROBLEM *PP, char* args[]){
+
+ char* ifile = args[ 0];
+ char* wfile = args[ 1];
+ char* ofile = args[ 2];
+ char* tfile = args[ 3];
+ char* topK = args[ 4];
+ char* lenLB = args[ 5];
+ char* lenUB = args[ 6];
+ char* supLB = args[ 7];
+ char* supUB = args[ 8];
+ char* ptype = args[ 9]; // C: closed pattern, M: maximal, F: frequent
+ char* pfile = args[10]; // -M
+
+ ITEMSET *II = &PP->II;
+
+ if(*ptype!='\0'){
+ switch(*ptype){
+ case 'C': PP->problem |= PROBLEM_CLOSED ; PP->TT.flag |= TRSACT_INTSEC; break;
+ case 'M': PP->problem |= PROBLEM_MAXIMAL; PP->TT.flag |= TRSACT_UNION ; break;
+ default : PP->problem |= PROBLEM_FREQSET; II->flag |= ITEMSET_ALL ; break;
+ }
+ }
+
+ II->flag |= ITEMSET_FREQ; // fix 'f' (output frequency)
+ II->flag |= ITEMSET_TRSACT_ID; // fix 'I' (output transaction ID)
+
+ if(*ifile!='\0') PP->trsact_fname = ifile;
+ if(*wfile!='\0'){PP->trsact_wfname = wfile; // '-w'
+ II->flag |= ITEMSET_OUTPUT_POSINEGA;}
+ if(*ofile!='\0') PP->output_fname = ofile;
+ if(*tfile!='\0') PP->trapat_fname = tfile;
+ if(*topK !='\0'){
+ if ( PP->problem & PROBLEM_MAXIMAL )
+ error ("M command and -K option can not be given simltaneously", EXIT);
+ II->topk.end = atoi(topK); // topK
+ }
+/*else{
+ II->topk.end = 0;
+ II->topk.v = NULL; // topK
+ }
+*/
+ if(*lenLB!='\0') II->lb = atoi(lenLB); // '-l'
+ if(*lenUB!='\0') II->ub = atoi(lenUB); // '-u'
+ if(*supUB!='\0') II->frq_ub = (WEIGHT)atof(supUB); // -S
+ if(*pfile!='\0'){PP->trsact_pfname = pfile; PP->TT.flag |= TRSACT_WRITE_PERM;}
+
+ if ( II->topk.end==0 ){
+ if(supLB!=NULL) II->frq_lb = (WEIGHT)atof(supLB); // minimum support
+ }
+}
+// hamuro add end
+
+
+/***********************************************************************/
+/* read parameters given by command line */
+/***********************************************************************/
+void LCM_read_param (int argc, char *argv[], PROBLEM *PP){
+ ITEMSET *II = &PP->II;
+ int c=1, f=0;
+ if ( argc < c+3 ){ LCM_error (); return; }
+
+ if ( !strchr (argv[c], 'q') ){ II->flag |= SHOW_MESSAGE; PP->TT.flag |= SHOW_MESSAGE; }
+ if ( strchr (argv[c], 'f') ) II->flag |= ITEMSET_FREQ;
+ if ( strchr (argv[c], 'Q') ) II->flag |= ITEMSET_PRE_FREQ;
+ if ( strchr (argv[c], 'A') ) II->flag |= ITEMSET_OUTPUT_POSINEGA;
+ if ( strchr (argv[c], 'C') ){ PP->problem |= PROBLEM_CLOSED; PP->TT.flag |= TRSACT_INTSEC; }
+ else if ( strchr (argv[c], 'F') ){ PP->problem |= PROBLEM_FREQSET; II->flag |= ITEMSET_ALL; }
+ else if ( strchr (argv[c], 'M') ){ PP->problem |= PROBLEM_MAXIMAL; PP->TT.flag |= TRSACT_UNION; }
+ else error ("one of F, C, M has to be given", EXIT);
+ if ( strchr (argv[c], 'R') ){ PP->problem |= ITEMSET_POSI_RATIO; II->flag |= ITEMSET_IGNORE_BOUND; }
+ if ( strchr (argv[c], 'P') ) PP->problem |= LCM_POSI_EQUISUPP;
+ if ( strchr (argv[c], 'V') ) II->flag |= SHOW_PROGRESS;
+ if ( strchr (argv[c], 'I') ) II->flag |= ITEMSET_TRSACT_ID;
+ if ( strchr (argv[c], 'i') ) II->flag |= ITEMSET_NOT_ITEMSET;
+ if ( strchr (argv[c], 's') ) II->flag |= ITEMSET_RULE_SUPP;
+ if ( strchr (argv[c], 't') ) PP->TT.flag |= LOAD_TPOSE;
+ c++;
+
+ while ( argv[c][0] == '-' ){
+ switch (argv[c][1]){
+ case 'K': if ( PP->problem & PROBLEM_MAXIMAL )
+ error ("M command and -K option can not be given simltaneously", EXIT);
+ II->topk.end = atoi (argv[c+1]);
+ break; case 'm': PP->trsact_pfname = argv[c+1];
+ break; case 'M': PP->trsact_pfname = argv[c+1]; PP->TT.flag |= TRSACT_WRITE_PERM;
+ break; case 'l': II->lb = atoi (argv[c+1]);
+ break; case 'u': II->ub = atoi(argv[c+1]);
+ break; case 'U': II->frq_ub = (WEIGHT)atof(argv[c+1]);
+ break; case 'w': PP->trsact_wfname = argv[c+1];
+ break; case 'c': PP->sgraph_fname = argv[c+1];
+ break; case 'C': PP->sgraph_fname = argv[c+1]; PP->problem |= LCM_UNCONST;
+ break; case 'S': II->max_solutions = atoi(argv[c+1]);
+ break; case 'f': II->prob_lb = atof(argv[c+1]); II->flag |= ITEMSET_RFRQ; f++;
+ break; case 'F': II->prob_ub = atof(argv[c+1]); II->flag |= ITEMSET_RINFRQ; f++;
+ break; case 'i': II->target = atoi(argv[c+1]);
+ break; case 'a': II->ratio_lb = atof(argv[c+1]); II->flag |= ITEMSET_RULE_FRQ; f|=1;
+ break; case 'A': II->ratio_ub = atof(argv[c+1]); II->flag |= ITEMSET_RULE_INFRQ; f|=1;
+ break; case 'r': II->ratio_lb = atof(argv[c+1]); II->flag |= ITEMSET_RULE_RFRQ; f|=2;
+ break; case 'R': II->ratio_ub = atof(argv[c+1]); II->flag |= ITEMSET_RULE_RINFRQ; f|=2;
+ break; case 'P': II->flag |= ITEMSET_POSI_RATIO; II->flag |= ITEMSET_IGNORE_BOUND; II->rposi_ub = atof(argv[c+1]); f|=4;
+ break; case 'p': II->flag |= ITEMSET_POSI_RATIO; II->flag |= ITEMSET_IGNORE_BOUND; II->rposi_lb = atof(argv[c+1]); f|=4;
+ break; case 'n': II->nega_lb = atof(argv[c+1]);
+ break; case 'N': II->nega_ub = atof(argv[c+1]);
+ break; case 'o': II->posi_lb = atof(argv[c+1]);
+ break; case 'O': II->posi_ub = atof(argv[c+1]);
+ break; default: goto NEXT;
+ }
+ c += 2;
+ if ( argc < c+2 ){ LCM_error (); return; }
+ }
+
+ NEXT:;
+ if ( (f&3)==3 || (f&5)==5 || (f&6)==6 ) error ("-f, -F, -a, -A, -p, -P, -r and -R can not specified simultaneously", EXIT);
+ if ( f && (II->flag & ITEMSET_PRE_FREQ) ) BITRM (II->flag, ITEMSET_PRE_FREQ);
+
+ if ( ( PP->problem & PROBLEM_CLOSED ) && PP->sgraph_fname )
+ error ("closed itemset mining does not work with item constraints", EXIT);
+
+ if ( (PP->problem & PROBLEM_FREQSET) && (II->flag & (ITEMSET_RULE + ITEMSET_RFRQ + ITEMSET_RINFRQ)) ){
+ PP->problem |= PROBLEM_CLOSED; BITRM (PP->problem, PROBLEM_FREQSET);
+ BITRM (II->flag, ITEMSET_ALL);
+ }
+ PP->trsact_fname = argv[c];
+ if ( II->topk.end==0 ) II->frq_lb = (WEIGHT)atof(argv[c+1]);
+ if ( argc>c+2 ) PP->output_fname = argv[c+2];
+}
+
+/*********************************************************************/
+/* add an item to itemset, and update data */
+/*********************************************************************/
+void LCM_add_item (PROBLEM *PP, QUEUE *Q, QUEUE_INT item){
+ QUEUE_INT *x;
+ ARY_INS (*Q, item);
+ PP->II.itemflag[item] = 1;
+ if ( PP->sgraph_fname )
+ MQUE_MLOOP (PP->SG.edge.v[item], x, item) PP->itemary[*x]++;
+}
+
+/*********************************************************************/
+/* delete an item from itemset, and update data */
+/*********************************************************************/
+void LCM_del_item (PROBLEM *PP, QUEUE *Q){
+ QUEUE_INT *x, item = Q->v[--Q->t];
+ PP->II.itemflag[item] = 0;
+ if ( PP->sgraph_fname )
+ MQUE_MLOOP (PP->SG.edge.v[item], x, item) PP->itemary[*x]--;
+}
+
+/* remove unnecessary transactions which do not include all posi_closed items */
+/* scan of each transaction is up to item */
+void LCM_reduce_occ_by_posi_equisupp (PROBLEM *PP, QUEUE *occ, QUEUE_INT item, QUEUE_INT full){
+ QUEUE_ID ii=0;
+ TRSACT *TT = &PP->TT;
+ ITEMSET *II = &PP->II;
+ QUEUE_INT *x, *y, *z, cnt;
+
+ MQUE_FLOOP (*occ, x){
+ if ( TT->w[*x]>= 0 ) continue;
+ cnt = 0;
+ MQUE_MLOOP (TT->T.v[*x], y, item) if ( II->itemflag[*y] == 2 ) cnt++;
+ if ( cnt==full ) occ->v[ii++] = *x;
+ else {
+ II->frq -= TT->w[*x];
+ MQUE_MLOOP (TT->T.v[*x], z, item) PP->occ_w[*z] -= TT->w[*x];
+ }
+ }
+ occ->t = ii;
+ MQUE_FLOOP (PP->itemcand, x){
+ if ( II->itemflag[*x] == 2 ) II->itemflag[*x] = 1;
+ }
+}
+
+/*************************************************************************/
+/* ppc check and maximality check */
+/* INPUT: O:occurrence, jump:items, th:support, frq:frequency, add:itemset
+ OUTPUT: maximum item i s.t. frq(i)=frq
+ OPERATION: remove infrequent items from jump, and
+ insert items i to "add" s.t. frq(i)=frq */
+/*************************************************************************/
+/* functions
+ 1. when closed itemset mining or maximal frequent itemset mining, find all items
+ included in all transactions in occ (checked by pfrq, occ_w
+ if there is such an item with index>item, ppc condition is violated, and return non-negative value
+ 2. when constraint graph is given, set the frequency (occ_w) of the items which can
+ not be added to itemset to infrequent number.
+ 3. count the size of reduced database
+ 4. call LCM_reduce_occ_posi
+ */
+QUEUE_INT LCM_maximality_check (PROBLEM *PP, QUEUE *occ, QUEUE_INT item, QUEUE_INT *fmax, QUEUE_INT *cnt){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ QUEUE_INT m = TT->T.clms, full=0, *x;
+ WEIGHT w=-WEIGHTHUGE;
+ *fmax = TT->T.clms; *cnt=0;
+
+ MQUE_FLOOP (TT->jump, x){
+ if ( II->itemflag[*x] == 1) continue;
+//QUEUE_perm_print (&II->itemset, II->perm);
+ if ( PP->sgraph_fname && ( (((PP->problem & LCM_UNCONST)==0) && (PP->itemary[*x]>0) ) ||
+ ((PP->problem & LCM_UNCONST) && (PP->itemary[*x]<II->itemset.t ))) ){
+ // e can not be added by item constraint
+// PP->occ_pw[e] = PP->occ_w[e] = II->frq_lb -1;
+ II->itemflag[*x] = 3;
+ } else if ( ISEQUAL(PP->occ_pw[*x],II->pfrq) && ( ISEQUAL(PP->occ_w[*x],II->frq) || (PP->problem & LCM_POSI_EQUISUPP) ) ){ // check e is included in all transactions in occ
+ if ( *x<item ){
+ if ( !PP->sgraph_fname ){ // add item as "equisupport"
+ LCM_add_item (PP, &II->add, *x);
+ if ( (PP->problem&LCM_POSI_EQUISUPP) && (II->flag&ITEMSET_RULE) ) II->itemflag[*x] = 0; // in POSI_EQUISUPP, occ_w[*x] is not equal to II->frq, thus we have to deal it in the rule mining
+ }
+ if ( !ISEQUAL(PP->occ_w[*x],II->frq) ){ full++; II->itemflag[*x] = 2; }
+ } else m = *x; // an item in prefix can be added without going to another closed itemset
+ } else {
+ if ( *x<item ) (*cnt)++;
+ II->itemflag[*x] = PP->occ_pw[*x] < PP->th? 3: 0; // mark item by freq/infreq
+ if ( PP->occ_w[*x] > w ){
+ *fmax = *x;
+ w = PP->occ_w[*x];
+ }
+ }
+ }
+ if ( full && (PP->problem & LCM_POSI_EQUISUPP) && m<item ) // m<item always holds in frequent itemset mining
+ LCM_reduce_occ_by_posi_equisupp (PP, occ, item, full);
+ return (m);
+}
+
+/***************************************************************/
+/* iteration of LCM ver. 5 */
+/* INPUT: item:tail of the current solution, t_new,buf:head of the list of
+ ID and buffer memory of new transactions */
+/*************************************************************************/
+void LCM (PROBLEM *PP, int item, QUEUE *occ, WEIGHT frq, WEIGHT pfrq){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ int bnum = TT->buf.num, bblock = TT->buf.block_num;
+ int wnum = TT->wbuf.num, wblock = TT->wbuf.block_num;
+ VEC_ID new_t = TT->new_t;
+ QUEUE_INT cnt, f, *x, m, e, imax = PP->clms? item: TT->T.clms;
+ QUEUE_ID js = PP->itemcand.s, qt = II->add.t, i;
+ WEIGHT rposi=0.0;
+
+//fprintf(stderr,"ppoo=%ld %d\n",(*occ).v,(*occ).t);
+
+//TRSACT_print (TT, occ, NULL);
+//printf ("itemset: %f ::::", II->frq); QUEUE_print__ ( &II->itemset);
+//printf ("itemset: %f ::::", II->frq); QUEUE_perm_print ( &II->itemset, II->perm);
+//printf ("add:"); QUEUE_perm_print ( &II->add, II->perm);
+//for (i=0 ; i<II->imax ; i++ ) printf ("%d(%d) ", II->perm[i], II->itemflag[i]); printf ("\n");
+ II->iters++;
+ PP->itemcand.s = PP->itemcand.t;
+// if ( II->flag&ITEMSET_POSI_RATIO && pfrq!=0 ) II->frq /= (pfrq+pfrq-II->frq);
+ if ( II->flag&ITEMSET_POSI_RATIO && pfrq!=0 ) rposi = pfrq / (pfrq+pfrq-II->frq);
+ TRSACT_delivery (TT, &TT->jump, PP->occ_w, PP->occ_pw, occ, imax);
+ // if the itemset is empty, set frq to the original #trsactions, and compute item_frq's
+ if ( II->itemset.t == 0 ){
+ if ( TT->total_w_org != 0.0 )
+ FLOOP (i, 0, TT->T.clms) II->item_frq[i] = PP->occ_w[i]/TT->total_w_org;
+ }
+
+ II->frq = frq; II->pfrq = pfrq;
+ m = LCM_maximality_check (PP, occ, item, &f, &cnt);
+// printf ("add: "); QUEUE_print__ ( &II->add);
+ if ( !(PP->problem & PROBLEM_FREQSET) && m<TT->T.clms ){ // ppc check
+ MQUE_FLOOP (TT->jump, x) TT->OQ[*x].end = 0;
+ goto END;
+ }
+ if ( !(PP->problem&PROBLEM_MAXIMAL) || f>=TT->T.clms || PP->occ_w[f]<II->frq_lb ){
+ if ( !(II->flag & ITEMSET_POSI_RATIO) || (rposi<=II->rposi_ub && rposi>=II->rposi_lb) ){
+ II->prob = 1.0;
+ MQUE_FLOOP (II->itemset, x) II->prob *= II->item_frq[*x];
+ MQUE_FLOOP (II->add, x) II->prob *= II->item_frq[*x];
+ ITEMSET_check_all_rule (II, PP->occ_w, occ, &TT->jump, TT->total_pw_org, 0); // if (ERROR_MES) return;
+ }
+ }
+ // select freqeut (and addible) items with smaller indices
+ MQUE_FLOOP (TT->jump, x){
+ TT->OQ[*x].end = 0; // in the case of freqset mining, automatically done by rightmost sweep;
+ if ( *x<item && II->itemflag[*x] == 0 ){
+ ARY_INS (PP->itemcand, *x);
+ PP->occ_w2[*x] = PP->occ_w[*x];
+ if ( TT->flag & TRSACT_NEGATIVE ) PP->occ_pw2[*x] = PP->occ_pw[*x];
+ }
+ }
+ if ( QUEUE_LENGTH_(PP->itemcand)==0 || II->itemset.t >= II->ub ) goto END;
+ qsort_QUEUE_INT (PP->itemcand.v+PP->itemcand.s, PP->itemcand.t-PP->itemcand.s, -1);
+//QUEUE_print__ (&PP->itemcand);
+ qsort_QUEUE_INT (II->add.v+qt, II->add.t-qt, -1);
+
+// database reduction
+ if ( cnt>2 && (II->flag & ITEMSET_TRSACT_ID)==0 && II->itemset.t >0){
+ TRSACT_find_same (TT, occ, item);
+ TRSACT_merge_trsact (TT, &TT->OQ[TT->T.clms], item);
+ TRSACT_reduce_occ (TT, occ);
+ }
+// occurrence deliver
+ TRSACT_deliv (TT, occ, item);
+
+// loop for recursive calls
+ cnt = QUEUE_LENGTH_ (PP->itemcand); f=0; // for showing progress
+ while ( QUEUE_LENGTH_ (PP->itemcand) > 0 ){
+ e = QUEUE_ext_tail_ (&PP->itemcand);
+ if ( PP->occ_pw2[e] >= MAX(II->frq_lb, II->posi_lb) ){ // if the item is frequent
+ LCM_add_item (PP, &II->itemset, e);
+ LCM (PP, e, &TT->OQ[e], PP->occ_w2[e], PP->occ_pw2[e]); // recursive call
+if ( ERROR_MES ) return;
+ LCM_del_item (PP, &II->itemset);
+ }
+ TT->OQ[e].end = TT->OQ[e].t = 0; // clear the occurrences, for the further delivery
+ PP->occ_w[e] = PP->occ_pw[e] = -WEIGHTHUGE; // unnecessary?
+
+ if ( (II->flag & SHOW_PROGRESS) && (II->itemset.t == 0 ) ){
+ f++; print_err ("%d/%d (%lld iterations)\n", f, cnt, II->iters);
+ }
+ }
+
+ TT->new_t = new_t;
+ TT->buf.num = bnum, TT->buf.block_num = bblock;
+ TT->wbuf.num = wnum, TT->wbuf.block_num = wblock;
+
+ END:;
+ while ( II->add.t > qt ) LCM_del_item (PP, &II->add);
+ PP->itemcand.t = PP->itemcand.s;
+ PP->itemcand.s = js;
+}
+
+/*************************************************************************/
+/* initialization of LCM main routine */
+/*************************************************************************/
+void LCM_init (PROBLEM *PP){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ SGRAPH *SG = &PP->SG;
+ PERM *sperm = NULL, *tmp=NULL;
+ QUEUE_INT i;
+
+ II->X = TT;
+ II->flag |= ITEMSET_ITEMFRQ + ITEMSET_ADD;
+ PP->clms = ((PP->problem&PROBLEM_FREQSET)&&(II->flag&ITEMSET_RULE)==0);
+ PROBLEM_alloc (PP, TT->T.clms, TT->T.t, 0, TT->perm, PROBLEM_ITEMCAND +(PP->sgraph_fname?PROBLEM_ITEMARY:0) +((TT->flag&TRSACT_NEGATIVE)?PROBLEM_OCC_PW: PROBLEM_OCC_W) +((PP->problem&PROBLEM_FREQSET)?0:PROBLEM_OCC_W2));
+ PP->th = (II->flag&ITEMSET_RULE)? ((II->flag&ITEMSET_RULE_INFRQ)? -WEIGHTHUGE: II->frq_lb * II->ratio_lb ): II->frq_lb; // threshold for database reduction
+ if ( TT->flag&TRSACT_SHRINK ) PP->oo = QUEUE_dup_ (&TT->OQ[TT->T.clms]); // preserve occ
+ else { QUEUE_alloc (&PP->oo, TT->T.t); ARY_INIT_PERM(PP->oo.v, TT->T.t); PP->oo.t = TT->T.t; }
+ TT->perm = NULL;
+ TT->OQ[TT->T.clms].t = 0;
+ print_mes (PP->TT.flag, "separated at %d\n", PP->TT.sep);
+ if ( !(TT->sc) ) calloc2 (TT->sc, TT->T.clms+2, "LCM_init: item_flag", return);
+ free2 (II->itemflag); II->itemflag = TT->sc; // II->itemflag and TT->sc shares the same memory
+ II->frq = TT->total_w_org; II->pfrq = TT->total_pw_org;
+
+ if ( PP->sgraph_fname ){
+ if ( SG->edge.t < TT->T.clms )
+ print_mes (PP->problem, "#nodes in constraint graph is smaller than #items\n");
+ if ( TT->perm ){
+ malloc2 (sperm, SG->edge.t, "LCM_init: sperm", EXIT);
+ ARY_INIT_PERM (sperm, SG->edge.t);
+ FLOOP (i, 0, MIN(TT->T.t, SG->edge.t)) sperm[i] = TT->perm[i];
+ ARY_INV_PERM (tmp, sperm, SG->edge.t, "LCM_init:INV_PERM", {free(sperm);EXIT;});
+ SGRAPH_replace_index (SG, sperm, tmp);
+ mfree (tmp, sperm);
+ SG->perm = NULL;
+ }
+
+ SG->edge.flag |= LOAD_INCSORT +LOAD_RM_DUP;
+ SETFAMILY_sort (&SG->edge);
+ }
+ II->total_weight = TT->total_w;
+}
+
+/*************************************************************************/
+/* main of LCM ver. 5 */
+/*************************************************************************/
+//int LCM_main (int argc, char *argv[]){ // hamuro comment out
+int LCM_main (char* args[], int* iRecCount, int* oRecCount, double* topk_weight){
+
+ PROBLEM PP;
+ ITEMSET *II = &PP.II;
+ TRSACT *TT = &PP.TT;
+ SGRAPH *SG = &PP.SG;
+
+ PROBLEM_init (&PP);
+ //LCM_read_param (argc, argv, &PP); // hamuro comment out
+ LCM_read_param2 (&PP, args); // hamuro add
+if ( ERROR_MES ) return (1);
+ TT->flag |= LOAD_PERM +TRSACT_FRQSORT +LOAD_DECSORT +LOAD_RM_DUP +TRSACT_MAKE_NEW +TRSACT_DELIV_SC +TRSACT_ALLOC_OCC + ((II->flag & ITEMSET_TRSACT_ID)?0: TRSACT_SHRINK) ;
+ if ( II->flag&ITEMSET_RULE ) TT->w_lb = -WEIGHTHUGE; else TT->w_lb = II->frq_lb;
+ SG->flag = LOAD_EDGE;
+ PROBLEM_init2 (&PP, PROBLEM_PRINT_SHRINK + PROBLEM_PRINT_FRQ);
+
+ *iRecCount = TT->rows_org; // hamuro add
+
+ if ( !ERROR_MES ){
+ LCM_init (&PP);
+//fprintf(stderr,"ppoo=%ld %d\n",PP.oo.v,PP.oo.t);
+ if ( !ERROR_MES ) LCM (&PP, TT->T.clms, &PP.oo, TT->total_w_org, TT->total_pw_org);
+ ITEMSET_last_output (II);
+ *topk_weight = II->topk_weight; // hamuro add
+ }
+
+ *oRecCount = II->patID; // hamuro add
+
+ TT->sc = NULL;
+ PROBLEM_end (&PP);
+ return (ERROR_MES?1:0);
+}
+
+/*******************************************************************************/
+#ifndef _NO_MAIN_
+#define _NO_MAIN_
+int main (int argc, char *argv[]){
+ int iRecCount=0;
+ int oRecCount=0;
+ double topk_weight=0;
+ char* args[]={"dat1","","xxa","","","","","2","","",""};
+
+ LCM_main(args,&iRecCount,&oRecCount,&topk_weight);
+
+ //return (LCM_main (argc, argv));
+}
+#endif
+/*******************************************************************************/
+
+#endif
+
+
--- /dev/null
+/* Common problem input/output routines /structure
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/***************************************************/
+
+#ifndef _problem_c_
+#define _problem_c_
+
+#include"problem.h"
+
+#include"stdlib2.c"
+#include"queue.c"
+#include"itemset.c"
+
+void PROBLEM_error (){
+ ERROR_MES = "command explanation";
+ EXIT;
+}
+
+/*************************************************************************/
+/* PROBLEM and ITEMSET initialization */
+/*************************************************************************/
+void PROBLEM_init (PROBLEM *P){
+ P->start_time = clock();
+ P->problem = 0;
+ P->input_fname = P->output_fname = P->weight_fname = NULL;
+ P->table_fname = P->position_fname = NULL;
+
+ P->trapat_fname = NULL; // hamuro add
+
+ P->sgraph_fname = P->sgraph2_fname = NULL;
+ P->sgraph_wfname = P->sgraph2_wfname = NULL;
+ P->agraph_fname = P->agraph2_fname = NULL;
+ P->trsact_fname = P->trsact2_fname = NULL;
+ P->trsact_fname2 = P->trsact2_fname2 = NULL;
+ P->trsact_wfname = P->trsact2_wfname = NULL;
+ P->trsact_wfname2 = P->trsact2_wfname2 = NULL;
+ P->trsact_pfname = P->trsact2_pfname = NULL;
+ P->seq_fname = P->seq2_fname = NULL;
+ P->fstar_fname = P->fstar2_fname = NULL;
+ P->mat_fname = P->mat2_fname = NULL;
+ P->smat_fname = P->smat2_fname = NULL;
+ P->setfamily_fname = P->setfamily2_fname = NULL;
+ P->setfamily_wfname = P->setfamily2_wfname = NULL;
+
+ P->root = 0;
+ P->dir = P->edge_dir = 0;
+ P->th = P->th2 = P->th3 = 0;
+ P->ratio = P->ratio2 = 0;
+ P->num = P->siz = P->dim = P->len = 0;
+ P->rows = 0;
+ P->clms = 0;
+
+ ITEMSET_init (&P->II);
+ ITEMSET_init (&P->II2);
+
+ P->vf = P->dep = NULL;
+ P->ff = INIT_QUEUE;
+
+ P->shift = NULL;
+ P->occ_w = P->occ_pw = P->occ_w2 = P->occ_pw2 = NULL;
+
+ P->itemjump = P->itemcand = P->vecjump = P->veccand = INIT_QUEUE; // for delivery
+ P->OQ = P->OQ2 = P->VQ = P->VQ2 = NULL; // for delivery
+ P->itemary = NULL;
+ P->itemmark = P->itemflag = P->vecmark = P->vecflag = NULL; // mark for vector
+ P->occ_t = P->vecary = NULL;
+ P->oo = INIT_QUEUE;
+
+#ifdef _alist_h_
+ P->occ = INIT_MALIST;
+#endif
+
+#ifdef _trsact_h_
+ TRSACT_init (&P->TT);
+ TRSACT_init (&P->TT2);
+#endif
+#ifdef _sgraph_h_
+ P->SG = INIT_SGRAPH;
+ P->SG2 = INIT_SGRAPH;
+#endif
+#ifdef _agraph_h_
+ P->AG = INIT_AGRAPH;
+ P->AG2 = INIT_AGRAPH;
+#endif
+#ifdef _seq_h_
+ SEQ_init (&P->SS);
+ SEQ_init (&P->SS2);
+#endif
+#ifdef _fstar_h_
+ P->FS = INIT_FSTAR;
+ P->FS2 = INIT_FSTAR;
+#endif
+
+#ifdef _vec_h_
+ P->MM = INIT_MAT;
+ P->MM2 = INIT_MAT;
+ P->SM = INIT_SMAT;
+ P->SM2 = INIT_SMAT;
+ P->FF = INIT_SETFAMILY;
+ P->FF2 = INIT_SETFAMILY;
+#endif
+}
+
+/*************************************************************************/
+/* PROBLEM initialization */
+/* all pointers are set to NULL, but don't touch filenames */
+/* load_flag, flag to give TRSACT_load */
+/* II->item_max will be item_max when do not load problem */
+/* II-> */
+/*************************************************************************/
+void PROBLEM_init2 (PROBLEM *P, int flag){
+ int f=0;
+/******************************/
+#ifdef _trsact_h_
+ if ( P->trsact_fname ){
+ TRSACT_load (&P->TT, P->trsact_fname, P->trsact_fname2, P->trsact_wfname, P->trsact_wfname2, P->trsact_pfname); if (ERROR_MES) goto ERR;
+ if ( P->TT.flag & SHOW_MESSAGE ){
+ print_err ("trsact: %s", P->trsact_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %zd", P->TT.rows_org, P->TT.clms_org, P->TT.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT.T.t, P->TT.T.clms, P->TT.T.eles);
+ if ( P->trsact_wfname ) print_err (" ,weightfile %s", P->trsact_wfname);
+ if ( P->trsact_wfname2 ) print_err (" ,2nd-weightfile %s", P->trsact_wfname2);
+ if ( P->trsact_pfname ) print_err (" ,item-order-file %s", P->trsact_pfname);
+ print_err ("\n");
+ }
+ }
+ if ( P->trsact2_fname ){
+ TRSACT_load (&P->TT2, P->trsact2_fname, P->trsact2_fname2, P->trsact2_wfname, P->trsact2_wfname2, P->trsact2_pfname); if (ERROR_MES) goto ERR;
+ if ( P->TT2.flag & SHOW_MESSAGE ){
+ print_err ("trsact2: %s", P->trsact2_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact2_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %zd", P->TT2.rows_org, P->TT2.clms_org, P->TT2.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT2.T.t, P->TT2.T.clms, P->TT2.T.eles);
+ if ( P->trsact2_wfname ) print_err (" ,weightfile2 %s", P->trsact2_wfname);
+ if ( P->trsact2_wfname2 ) print_err (" ,2nd-weightfile2 %s", P->trsact2_wfname2);
+ if ( P->trsact2_pfname ) print_err (" ,item-order-file2 %s", P->trsact2_pfname);
+ print_err ("\n");
+ }
+ }
+#endif
+#ifdef _sgraph_h_
+ if ( P->sgraph_fname ){
+ SGRAPH_load (&P->SG, P->sgraph_fname, P->sgraph_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->SG.flag, "sgraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->sgraph_fname, SGRAPH_NODE_NUM(P->SG), P->SG.edge.eles/2, P->SG.in.eles);
+ }
+ if ( P->sgraph2_fname ){
+ SGRAPH_load (&P->SG, P->sgraph2_fname, P->sgraph2_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->SG2.flag, "sgraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->sgraph2_fname, SGRAPH_NODE_NUM(P->SG2), P->SG2.edge.eles/2, P->SG2.in.eles);
+ }
+#endif
+#ifdef _agraph_h_
+ if ( P->agraph_fname ){
+ AGRAPH_load (&P->AG, P->agraph_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->AG.flag, "agraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->agraph_fname, P->AG.node_num, P->AG.edge_num, P->AG.arc_num);
+ }
+ if ( P->agraph2_fname ){
+ AGRAPH_load (&P->AG2, P->agraph_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->AG2.flag, "agraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->agraph2_fname, P->AG2.node_num, P->AG2.edge_num, P->AG2.arc_num);
+ }
+#endif
+#ifdef _fstar_h_
+ if ( P->fstar_fname ){
+ FSTAR_load (&P->FS, P->fstar_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->FS.flag, "agraph: %s ,#nodes %d(%d,%d) ,#edges %zd\n", P->fstar_fname, P->FS.node_num, P->FS.in_node_num, P->FS.out_node_num, P->FS.edge_num);
+ }
+ if ( P->fstar2_fname ){
+ FSTAR_load (&P->FS2, P->fstar2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->FS2.flag, "agraph2: %s ,#nodes %d(%d,%d) ,#edges %zd\n", P->fstar2_fname, P->FS2.node_num, P->FS2.in_node_num, P->FS2.out_node_num, P->FS2.edge_num);
+ }
+
+#endif
+#ifdef _vec_h_
+ if ( P->mat_fname ){
+ MAT_load (&P->MM, P->mat_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->MM.flag, "mat: %s ,#rows %d ,#clms %d\n", P->mat_fname, P->MM.t, P->MM.clms);
+ }
+ if ( P->mat2_fname ){
+ MAT_load (&P->MM2, P->mat2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->MM2.flag, "mat2: %s ,#rows %d ,#clms %d\n", P->mat2_fname, P->MM2.t, P->MM2.clms);
+ }
+ if ( P->smat_fname ){
+ SMAT_load (&P->SM, P->smat_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->SM.flag, "smat: %s ,#rows %d ,#clms %d ,#eles %zd\n", P->smat_fname, P->SM.t, P->SM.clms, P->SM.eles);
+ }
+ if ( P->smat2_fname ){
+ SMAT_load (&P->SM2, P->smat2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->SM2.flag, "smat2: %s ,#rows %d ,#clms %d ,#eles %zd\n", P->smat2_fname, P->SM2.t, P->SM2.clms, P->SM2.eles);
+ }
+ if ( P->setfamily_fname ){
+ SETFAMILY_load (&P->FF, P->setfamily_fname, P->setfamily_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->FF.flag, "setfamily: %s ,#rows %d ,#clms %d ,#eles %zd", P->setfamily_fname, P->FF.t, P->FF.clms, P->FF.eles);
+ if ( P->setfamily_wfname ) print_mes (P->FF.flag, " ,weightfile %s", P->setfamily_wfname);
+ print_mes (P->FF.flag, "\n");
+ }
+ if ( P->setfamily2_fname ){
+ SETFAMILY_load (&P->FF2, P->setfamily2_fname, P->setfamily2_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->FF2.flag, "setfamily2: %s ,#rows %d ,#clms %d ,#eles %zd", P->setfamily2_fname, P->FF2.t, P->FF2.clms, P->FF2.eles);
+ if ( P->setfamily2_wfname ) print_mes (P->FF2.flag, " ,weightfile %s", P->setfamily2_wfname);
+ print_mes (P->FF2.flag, "\n");
+ }
+#endif
+ if (P->input_fname){ f=1; print_err (" input: %s", P->input_fname); }
+ if (P->weight_fname){ f=1; print_err (" weight: %s", P->weight_fname); }
+ //if (P->output_fname){ f=1; print_err (" output to: %s",P->output_fname); } // hamuro comment out
+ if ( f )print_err ("\n");
+
+/******************************/
+
+ if ( flag&SHOW_MESSAGE ){
+ ITEMSET_print (&P->II, (flag&PROBLEM_PRINT_FRQ)? 1: 0);
+ if ( flag&PROBLEM_PRINT_DENSE ){
+ print_err ("density threshold");
+ fprint_real (stderr, P->dense);
+ print_err ("\n");
+ }
+ }
+
+ if ( !ERROR_MES ) return;
+ ERR:;
+ PROBLEM_end (P);
+ EXIT;
+}
+
+/* termination of problem */
+void PROBLEM_end (PROBLEM *P){
+ ITEMSET *II = &P->II;
+#ifdef _trsact_h_
+ TRSACT_end (&P->TT);
+ TRSACT_end (&P->TT2);
+#endif
+#ifdef _sgraph_h_
+ SGRAPH_end (&P->SG);
+ SGRAPH_end (&P->SG2);
+#endif
+#ifdef _agraph_h_
+ AGRAPH_end (&P->AG);
+ AGRAPH_end (&P->AG2);
+#endif
+#ifdef _seq_h_
+ SEQ_end (&P->SS);
+ SEQ_end (&P->SS2);
+#endif
+#ifdef _fstar_h_
+ FSTAR_end (&P->FS);
+ FSTAR_end (&P->FS2);
+#endif
+#ifdef _vec_h_
+ MAT_end (&P->MM);
+ MAT_end (&P->MM2);
+ SMAT_end (&P->SM);
+ SMAT_end (&P->SM2);
+ SETFAMILY_end (&P->FF);
+ SETFAMILY_end (&P->FF2);
+#endif
+
+/******************************/
+
+ mfree (P->vf, P->dep);
+ QUEUE_end (&P->ff);
+
+ ITEMSET_end (II);
+ ITEMSET_end (&P->II2);
+
+ if ( P->occ_pw2 != P->occ_pw && P->occ_pw2 != P->occ_w2 ) free2 (P->occ_pw2);
+ if ( P->occ_w2 != P->occ_w ) free2 (P->occ_w2);
+ if ( P->occ_pw != P->occ_w ) free2 (P->occ_pw);
+ mfree (P->shift, P->occ_t, P->occ_w);
+
+ if ( P->OQ ) free2 (P->OQ[0].v);
+ if ( P->OQ2 ) free2 (P->OQ2[0].v);
+ if ( P->VQ ) free2 (P->VQ[0].v);
+ if ( P->VQ2 ) free2 (P->VQ2[0].v);
+ mfree (P->OQ, P->OQ2, P->VQ, P->VQ2);
+
+ mfree (P->itemary, P->itemflag, P->itemmark, P->vecary, P->vecflag, P->vecmark);
+ QUEUE_end (&P->itemcand);
+ QUEUE_end (&P->itemjump);
+
+ QUEUE_end (&P->veccand);
+ QUEUE_end (&P->vecjump);
+ QUEUE_end (&P->oo);
+
+#ifdef _alist_h_
+ MALIST_end (&P->occ);
+#endif
+
+#ifdef _undo_h_
+ ALISTundo_end ();
+#endif
+
+ P->end_time = clock();
+ if ( print_time_flag )
+ print_err ("computation_time= %3f\n", ((double)(P->end_time - P->start_time))/CLOCKS_PER_SEC);
+
+ PROBLEM_init (P);
+}
+
+/* allocate arrays and structures */
+void PROBLEM_alloc (PROBLEM *P, size_t siz, size_t siz2, size_t siz3, PERM *perm, int f){
+#ifdef _alist_h_
+ ALIST_ID i;
+#endif
+
+ if ( f&PROBLEM_SHIFT ) calloc2 (P->shift, siz+2, "PROBLEM_alloc: shift", goto ERR);
+ if ( f&PROBLEM_OCC_T ) calloc2 (P->occ_t, siz+2, "PROBLEM_alloc:occ_t", goto ERR);
+ if ( f&(PROBLEM_OCC_W+PROBLEM_OCC_PW) ) calloc2 (P->occ_w, siz+2, "PROBLEM_alloc:occ_w", goto ERR);
+ if ( f&PROBLEM_OCC_PW ){
+ calloc2 (P->occ_pw, siz+2, "PROBLEM_alloc:occ_pw", goto ERR);
+ } else P->occ_pw = P->occ_w;
+ if ( f&PROBLEM_OCC_W2 ){
+ calloc2 (P->occ_w2, siz+2, "PROBLEM_alloc:occ_w", goto ERR);
+ if ( f&PROBLEM_OCC_PW ){
+ calloc2 (P->occ_pw2, siz+2, "PROBLEM_alloc:occ_pw", goto ERR);
+ } else P->occ_pw2 = P->occ_w2;
+ } else { P->occ_w2 = P->occ_w; P->occ_pw2 = P->occ_pw; }
+
+ if ( f&PROBLEM_ITEMFLAG ) calloc2 (P->itemflag, siz+2, "PROBLEM_alloc:itemflag", goto ERR);
+ if ( f&PROBLEM_ITEMMARK ) calloc2 (P->itemmark, siz+2, "PROBLEM_alloc:itemmark", goto ERR);
+ if ( f&PROBLEM_ITEMARY ) calloc2(P->itemary, siz+2,"PROBLEM_alloc:itemary", goto ERR);
+ if ( f&PROBLEM_ITEMJUMP ) QUEUE_alloc (&P->itemjump, siz+2);
+ if ( f&PROBLEM_ITEMCAND ) QUEUE_alloc (&P->itemcand, siz+2);
+
+ if ( f&PROBLEM_VECFLAG ) calloc2 (P->vecflag, siz+2, "PROBLEM_alloc:vecflag", goto ERR);
+ if ( f&PROBLEM_VECMARK ) calloc2 (P->vecmark, siz2+2, "PROBLEM_alloc:vecmark", goto ERR);
+ if ( f&PROBLEM_VECARY ) calloc2 (P->vecary, siz2+2, "PROBLEM_alloc:vecary", goto ERR);
+ if ( f&PROBLEM_VECJUMP ) QUEUE_alloc (&P->vecjump, siz2+2);
+ if ( f&PROBLEM_VECCAND ) QUEUE_alloc (&P->veccand, siz2+2);
+
+#ifdef _alist_h_
+ if ( f&PROBLEM_OCC3){
+ MALIST_alloc (&P->occ, siz, siz2+2); // element=>
+if ( ERROR_MES ) goto ERR;
+ if ( f&PROBLEM_OCC2 )
+ FLOOP (i, 0, siz) MALIST_ins_tail (&P->occ, (f&PROBLEM_OCC1)?siz: 0, i, 0);
+ }
+#endif
+
+ ITEMSET_init2 (&P->II, P->output_fname, P->trapat_fname, perm, siz, siz3); // hamuro add P->trapat_fname
+ if ( P->II.target<siz && P->II.perm ) P->II.target = P->II.perm[P->II.target];
+
+#ifdef _undo_h_
+ ALISTundo_init ();
+#endif
+
+ return;
+ ERR:;
+ PROBLEM_end (P);
+ EXIT;
+}
+
+#endif
+
+
--- /dev/null
+/* Common problem input/output routines /structure
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/***************************************************/
+
+#ifndef _problem_h_
+#define _problem_h_
+
+#include"stdlib2.h"
+#include"queue.h"
+#include"itemset.h"
+
+#define PROBLEM_FREQSET 1
+#define PROBLEM_MAXIMAL 2
+#define PROBLEM_CLOSED 4
+
+/***** parameters for PROBLEM initialization, given to flag *****/
+
+#define PROBLEM_PRINT_DENSE 4 // print density threshold
+#define PROBLEM_PRINT_SHRINK 8 // print properties of shrinked database
+#define PROBLEM_PRINT_FRQ 16 // print density threshold
+#define PROBLEM_NORMALIZE 32 // print density threshold
+
+#define PROBLEM_ITEMARY 128 // alloc itemary
+#define PROBLEM_ITEMJUMP 256 // alloc itemjump
+#define PROBLEM_ITEMFLAG 512 // alloc itemflag
+#define PROBLEM_ITEMMARK 1024 // alloc itemmark
+#define PROBLEM_ITEMCAND 2048 // alloc itemcand
+#define PROBLEM_VECARY 4096 // alloc itemary
+#define PROBLEM_VECJUMP 8192 // alloc vecjump
+#define PROBLEM_VECFLAG 16384 // alloc vecflag
+#define PROBLEM_VECMARK 32768 // alloc vecmark
+#define PROBLEM_VECCAND 65536 // alloc veccand
+//4194304
+#define PROBLEM_OCC_T 524288 // alloc occ_t
+#define PROBLEM_SHIFT 1048576 // allocate shift
+#define PROBLEM_OCC_W 2097152 // weight/positive-weight sum for items
+#define PROBLEM_OCC_PW 4194304 // weight/positive-weight sum for items
+#define PROBLEM_OCC_W2 8388608 // weight/positive-weight sum for items
+
+#define PROBLEM_OCC1 16 // alloc occ
+#define PROBLEM_OCC2 32 // alloc occ and ins all to list 0
+#define PROBLEM_OCC3 48 // alloc occ and ins all to list "siz"
+
+typedef struct {
+ clock_t start_time, end_time;
+ int problem;
+ double dense;
+ char *input_fname;
+ char *output_fname;
+ char *trapat_fname; // hamuro add (output file for transaciton ID - pattern ID)
+ char *weight_fname;
+ char *table_fname, *table2_fname;
+ char *position_fname, *position2_fname;
+
+ char *sgraph_fname, *sgraph2_fname;
+ char *sgraph_wfname, *sgraph2_wfname;
+ char *agraph_fname, *agraph2_fname;
+ char *trsact_fname, *trsact_fname2, *trsact_wfname, *trsact_wfname2, *trsact_pfname;
+ char *trsact2_fname, *trsact2_fname2, *trsact2_wfname, *trsact2_wfname2, *trsact2_pfname;
+ char *seq_fname, *seq2_fname;
+ char *fstar_fname, *fstar2_fname;
+ char *mat_fname, *mat2_fname;
+ char *smat_fname, *smat2_fname;
+ char *setfamily_fname, *setfamily2_fname;
+ char *setfamily_wfname, *setfamily2_wfname;
+
+ ITEMSET II, II2;
+ QUEUE ff; // for agraph search
+ int *vf, *dep; // for agraph search
+
+ int root, dir, edge_dir;
+ double th, th2, th3; // thresholds
+ double ratio, ratio2; // ratio
+ int num, siz, dim, len;
+ QUEUE_INT clms;
+ VEC_ID rows;
+
+ QUEUE_ID **shift;
+ QUEUE itemjump, itemcand, vecjump, veccand, *OQ, *OQ2, *VQ, *VQ2; // for delivery
+ QUEUE_INT *itemary;
+ int *itemmark, *itemflag, *vecmark, *vecflag; // mark for vector
+ VEC_ID *vecary, *occ_t;
+ WEIGHT *occ_w, *occ_pw, *occ_w2, *occ_pw2;
+ QUEUE oo;
+
+#ifdef _alist_h_
+ MALIST occ;
+#endif
+
+#ifdef _sgraph_h_
+ SGRAPH SG, SG2;
+#endif
+
+#ifdef _agraph_h_
+ AGRAPH AG, AG2;
+#endif
+
+#ifdef _trsact_h_
+ TRSACT TT, TT2;
+#endif
+
+#ifdef _seq_h_
+ SEQ SS, SS2;
+#endif
+
+#ifdef _fstar_h_
+ FSTAR FS, FS2;
+#endif
+
+#ifdef _vec_h_
+ MAT MM, MM2;
+ SMAT SM, SM2;
+ SETFAMILY FF, FF2;
+#endif
+
+} PROBLEM;
+
+
+/***** print filename information ****/
+void PROBLEM_print (PROBLEM *P);
+
+/***** print usage of the program *****/
+void PROBLEM_error ();
+
+/***** read parameters given by command line *****/
+void PROBLEM_read_param (int argc, char *argv[], PROBLEM *P);
+
+/***** PROBLEM and ITEMSET initialization *****/
+/* all pointers are set to NULL, but don't touch filenames */
+void PROBLEM_init (PROBLEM *P);
+
+/***** PROBLEM initialization: load the files given by filenames ******/
+void PROBLEM_init2 (PROBLEM *P, int flag);
+
+/***** allocate memory according to flag *****/
+void PROBLEM_alloc (PROBLEM *PP, size_t siz, size_t siz2, size_t siz3, PERM *p, int f);
+
+/* termination of problem */
+void PROBLEM_end (PROBLEM *PP);
+
+
+#endif
+
+
--- /dev/null
+/* Library of queue: spped priority implementation
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _queue_c_
+#define _queue_c_
+
+
+#include"queue.h"
+#include"stdlib2.c"
+
+QSORT_TYPE(QUEUE_INT, QUEUE_INT)
+QSORT_TYPE(QUEUE_ID, QUEUE_ID)
+QUEUE INIT_QUEUE = {TYPE_QUEUE,NULL,0,0,0};
+QUEUE_INT common_QUEUE_INT, *common_QUEUE_INTp;
+
+/* initialization, not fill the memory by 0 */
+void QUEUE_alloc (QUEUE *Q, QUEUE_ID siz){
+ *Q = INIT_QUEUE;
+ Q->end = siz+1;
+ malloc2 (Q->v, siz+1, "QUEUE_alloc: Q->v", EXIT);
+}
+
+/* termination processing */
+void QUEUE_end (QUEUE *Q){
+ free2 (Q->v);
+ *Q = INIT_QUEUE;
+}
+
+
+/* tranpose the matrix ; counting/transpose/memory_allocate */
+void QUEUE_delivery(QUEUE *OQ, VEC_ID *c, QUEUE *jump, QUEUE *Q, QUEUE *occ, VEC_ID t, QUEUE_INT M){ VEC_ID i, e;
+ QUEUE_INT *x;
+ FLOOP(i, 0, occ? occ->t: t){
+ e = occ? occ->v[i]: i;
+ if ( c ){
+ if ( jump ){ MLOOP (x, Q[e].v, M){ if ( c[*x]==0 ) ARY_INS (*jump, *x); c[*x]++; }
+ } else { MLOOP (x, Q[e].v, M){ c[*x]++; }}
+ } else {
+ if ( jump ){ MLOOP (x, Q[e].v, M){ if ( OQ[*x].t==0 ) ARY_INS (*jump, *x); ARY_INS (OQ[*x], e); }
+ } else MLOOP (x, Q[e].v, M){ ARY_INS (OQ[*x], e); }
+ }
+ }
+}
+
+/* sort a QUEUE with WEIGHT, with already allocated memory */
+void QUEUE_perm_WEIGHT (QUEUE *Q, WEIGHT *w, PERM *invperm, int flag){
+ WEIGHT y;
+ if ( w ){
+ qsort_perm__QUEUE_INT (Q->v, Q->t, invperm, flag);
+ ARY_INVPERMUTE_ (w, invperm, y, Q->t);
+ }
+ qsort_QUEUE_INT (Q->v, Q->t, flag);
+}
+
+/* remove (or unify) the consecutive same ID's in a QUEUE (duplication delete, if sorted) */
+void QUEUE_rm_dup_WEIGHT (QUEUE *Q, WEIGHT *w){
+ VEC_ID j, jj=0;
+ if ( w ){
+ FLOOP (j, 1, Q->t){
+ if ( Q->v[j-1] != Q->v[j] ){
+ Q->v[++jj] = Q->v[j];
+ w[jj] = w[j];
+ } else w[jj] += w[j];
+ }
+ } else FLOOP (j, 1, Q->t){
+ if ( Q->v[j-1] != Q->v[j] ) Q->v[++jj] = Q->v[j];
+ }
+ if ( Q->t>0 ) Q->t = jj+1;
+}
+
+/***********************************************************************/
+/* duplicate occ's in jump, ( copy occ's to allocated QUEUE array) */
+/* Q[i].end := original item, clear each original occ */
+/* buffer size is multiplied by u */
+/*******************************************************/
+void QUEUE_occ_dup (QUEUE *jump, QUEUE **QQ, QUEUE *Q, WEIGHT **ww, WEIGHT *w, WEIGHT **ppw, WEIGHT *pw, int u){
+ QUEUE_ID i, l=QUEUE_LENGTH_(*jump);
+ size_t cnt=0;
+ QUEUE_INT e;
+ char *buf;
+ int unit = sizeof(*Q) + (w?sizeof(*w):0) + (pw?sizeof(*pw):0);
+
+ ENMAX (u, sizeof(e));
+ QUEUE_FE_LOOP_ (*jump, i, e) cnt += Q[e].t;
+ if ( cnt == 0 ){ *QQ=NULL; return; }
+ malloc2 (buf, l*unit + (cnt+l)*u, "QUEUE_occ_dup: buf", EXIT);
+ *QQ = (QUEUE*)buf; buf += sizeof(*Q) *l;
+ if ( w ){ *ww = (WEIGHT *)buf; buf += sizeof(*w)*l; }
+ if ( pw ){ *ppw = (WEIGHT *)buf; buf += sizeof(*pw)*l; }
+ QUEUE_FE_LOOP_ (*jump, i, e){
+ (*QQ)[i].end = e;
+ (*QQ)[i].v = (QUEUE_INT *)buf;
+ (*QQ)[i].t = Q[e].t;
+ memcpy (buf, Q[e].v, (Q[e].t+1)*u);
+ buf += (Q[e].t+1) *u;
+ if ( w ) (*ww)[i] = w[e];
+ if ( pw ) (*ppw)[i] = pw[e];
+ }
+}
+
+
+/* return the position of the first element having value e. return -1 if no such element exists */
+LONG QUEUE_ele (QUEUE *Q, QUEUE_INT e){
+ QUEUE_INT *x;
+ MQUE_FLOOP (*Q, x)
+ if ( *x == e ) return (x - Q->v);
+ return (-1);
+}
+
+/* insert an element to the tail */
+void QUEUE_ins_ (QUEUE *Q, QUEUE_INT e){
+ Q->v[Q->t] = e;
+ Q->t++;
+}
+void QUEUE_ins (QUEUE *Q, QUEUE_INT e){
+ Q->v[Q->t] = e;
+ QUEUE_INCREMENT (*Q, Q->t);
+ if (Q->s == Q->t ) error_num ("QUEUE_ins: overflow", Q->s, EXIT);
+}
+
+/* insert an element to the head */
+void QUEUE_ins_head_ (QUEUE *Q, QUEUE_INT e){
+ Q->s--;
+ Q->v[Q->s] = e;
+}
+void QUEUE_ins_head (QUEUE *Q, QUEUE_INT e){
+ QUEUE_DECREMENT(*Q,Q->s);
+ Q->v[Q->s] = e;
+ if (Q->s == Q->t ) error_num ("QUEUE_ins_head: underflow", Q->s, EXIT);
+}
+
+/* extract an element from the head, without checking underflow */
+QUEUE_INT QUEUE_ext_ (QUEUE *Q){
+ (Q->s)++;
+ return (Q->v[Q->s-1]);
+}
+QUEUE_INT QUEUE_ext (QUEUE *Q){
+ QUEUE_INT e;
+ if (Q->s == Q->t ) error_num ("QUEUE_ext: empty queue", Q->s, EXIT0);
+ e = Q->v[Q->s];
+ QUEUE_INCREMENT(*Q,Q->s);
+ return ( e);
+}
+
+/* extract an element from the tail, without checking underflow */
+QUEUE_INT QUEUE_ext_tail_ (QUEUE *Q){
+ (Q->t)--;
+ return (Q->v[Q->t]);
+}
+QUEUE_INT QUEUE_ext_tail (QUEUE *Q){
+ if ( Q->s == Q->t ) error_num ("QUEUE_ext_tail: empty queue", Q->s, EXIT0);
+ QUEUE_DECREMENT(*Q,Q->t);
+ return (Q->v[Q->t]);
+}
+
+/* remove the j-th element and replace it by the tail */
+void QUEUE_rm_ (QUEUE *Q, QUEUE_ID j){
+ Q->t--;
+ Q->v[j] = Q->v[Q->t];
+}
+void QUEUE_rm (QUEUE *Q, QUEUE_ID j){
+ if ( Q->s <= Q->t ){
+ if ( j < Q->s || j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ } else if ( j < Q->s && j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ QUEUE_DECREMENT(*Q,Q->t);
+ Q->v[j] = Q->v[Q->t];
+}
+
+/* remove the j-th element and replace it by the head */
+void QUEUE_rm_head_ (QUEUE *Q, QUEUE_ID j){
+ Q->v[j] = Q->v[Q->s];
+ Q->s++;
+}
+void QUEUE_rm_head (QUEUE *Q, QUEUE_ID j){
+ if ( Q->s <= Q->t ){
+ if ( j < Q->s || j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ } else if ( j < Q->s && j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ Q->v[j] = Q->v[Q->s];
+ QUEUE_INCREMENT(*Q,Q->s);
+}
+
+/* remove the j-th element and shift the following elements to fill the gap */
+int QUEUE_rm_ele_ (QUEUE *Q, QUEUE_INT e){
+ QUEUE_ID i;
+ QUEUE_F_LOOP (*Q, i){
+ if ( Q->v[i] == e ){
+ memcpy ( &(Q->v[i]), &(Q->v[i+1]), (Q->t-i-1)*sizeof(QUEUE_INT));
+ Q->t--;
+ return (1);
+ }
+ }
+ return (0);
+}
+/* insert e to the position determined by the increasing order of elements */
+void QUEUE_ins_ele_ (QUEUE *Q, QUEUE_INT e){
+ QUEUE_ID i;
+ QUEUE_INT ee;
+ QUEUE_BE_LOOP_ (*Q, i, ee){
+ if ( ee<e ) break;
+ Q->v[i+1] = ee;
+ }
+ Q->v[i+1] = e;
+ Q->t++;
+}
+
+/* Append Q2 to the tail of Q1. Q2 will not be deleted */
+void QUEUE_concat_ (QUEUE *Q1, QUEUE *Q2){
+ memcpy ( &(Q1->v[Q1->t]), &(Q2->v[Q2->s]), (Q2->t-Q2->s)*sizeof(QUEUE_INT));
+ Q1->t += Q2->t-Q2->s;
+}
+void QUEUE_concat (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID e = Q2->s;
+ while ( e != Q2->t){
+ QUEUE_ins (Q1, Q2->v[e]);
+ QUEUE_INCREMENT(*Q2,e);
+ }
+}
+/* Append Q2 to the tail of Q1. Q2 will be deleted */
+void QUEUE_append_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_concat_ (Q1, Q2);
+ QUEUE_RMALL (*Q2);
+}
+void QUEUE_append (QUEUE *Q1, QUEUE *Q2){ // more improvement can be
+ while ( Q2->s != Q2->t )
+ QUEUE_ins (Q1, QUEUE_ext(Q2));
+}
+
+/* Append from j to jj th elements to the tail of Q1. Q2 will not be deleted */
+void QUEUE_subconcat_ (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj){
+ for ( ; j<=jj ; j++){
+ Q1->v[Q1->t] = Q2->v[j];
+ Q1->t++;
+ }
+}
+void QUEUE_subconcat (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj){
+ while (1){
+ QUEUE_ins (Q1, Q2->v[j]);
+ if ( j == jj ) break;
+ QUEUE_INCREMENT(*Q2,j);
+ }
+}
+
+/* initialize Q1 by length of Q2, and copy Q2 to Q1 */
+void QUEUE_store_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_alloc (Q1, QUEUE_LENGTH(*Q2));
+ QUEUE_concat_ (Q1, Q2);
+}
+void QUEUE_store (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_alloc (Q1, QUEUE_LENGTH(*Q2));
+ QUEUE_concat (Q1, Q2);
+}
+/* copy Q2 to Q1 and delete Q2 */
+void QUEUE_restore_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat_ (Q1, Q2);
+ QUEUE_end (Q2);
+}
+void QUEUE_restore (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat (Q1, Q2);
+ QUEUE_end (Q2);
+}
+
+/* copy Q2 to Q1 */
+void QUEUE_cpy_ (QUEUE *Q1, QUEUE *Q2){
+ Q1->s = Q1->t = 0;
+ QUEUE_concat_ (Q1, Q2);
+}
+void QUEUE_cpy (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat (Q1, Q2);
+}
+/* copy l elements of Q2 starting from s2 to the s1th position of Q1.
+ size of Q1 is not increasing */
+void QUEUE_subcpy_ (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l){
+ memcpy ( &(Q1->v[s1]), &(Q2->v[s2]), (l-s2)*sizeof(QUEUE_INT));
+}
+void QUEUE_subcpy (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l){
+ for ( ; s2!=l ; QUEUE_INCREMENT(*Q1,s1),QUEUE_INCREMENT(*Q2,s2) )
+ Q1->v[s1] = Q2->v[s2];
+ Q1->v[s1] = Q2->v[s2];
+}
+
+/* duplicate Q2 to Q1. The memory size will be the length of Q2 */
+QUEUE QUEUE_dup_ (QUEUE *Q){
+ QUEUE QQ;
+ QUEUE_alloc (&QQ, QUEUE_LENGTH_(*Q));
+ QUEUE_cpy_ (&QQ, Q);
+ return (QQ);
+}
+
+/* merge Q1 and Q2 by insert all elements of Q2 to Q1 with deleting duplications. Both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_merge_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->t-1, j=Q2->t-1, t=i+j-Q2->s+1;
+ QUEUE_INT ei, ej;
+ if ( i+1 == Q1->s || j+1 == Q2->s ){
+ QUEUE_concat_ (Q1, Q2);
+ return;
+ }
+ Q1->t = t+1;
+ ei = Q1->v[i];
+ ej = Q2->v[j];
+ while (1){
+ if ( ei > ej ){
+ Q1->v[t] = ei;
+ if ( i == Q1->s ){
+ QUEUE_subcpy_ (Q1, Q1->s, Q2, Q2->s, j);
+ return;
+ }
+ i--;
+ ei = Q1->v[i];
+ } else {
+ Q1->v[t] = ej;
+ if ( j == Q2->s ) return;
+ j--;
+ ej = Q2->v[j];
+ }
+ t--;
+ }
+}
+void QUEUE_merge (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->t, j=Q2->t;
+ QUEUE_INT ei, ej;
+ QUEUE_ID t = (Q1->t + QUEUE_LENGTH(*Q2)-1) % Q1->end;
+ if ( QUEUE_LENGTH(*Q1) + QUEUE_LENGTH(*Q2) >= Q1->end ){
+ printf ("QUEUE_merge: overflow Q1->end="QUEUE_INTF", Q1length="QUEUE_INTF", Q2length="QUEUE_INTF"\n", Q1->end, QUEUE_LENGTH(*Q1), QUEUE_LENGTH(*Q2));
+ exit (1);
+ }
+ if ( i == Q1->s || j == Q2->s ){
+ QUEUE_concat (Q1, Q2);
+ return;
+ }
+
+ Q1->t = t;
+ QUEUE_DECREMENT(*Q1,i);
+ QUEUE_DECREMENT(*Q2,j);
+ ei = Q1->v[i];
+ ej = Q2->v[j];
+ while (1){
+ if ( ei > ej ){
+ Q1->v[t] = ei;
+ if ( i == Q1->s ){
+ QUEUE_subcpy (Q1, Q1->s, Q2, Q2->s, (j+Q2->end-Q2->s)%Q2->end);
+ return;
+ }
+ QUEUE_DECREMENT(*Q1,i);
+ ei = Q1->v[i];
+ } else {
+ Q1->v[t] = ej;
+ if ( j == Q2->s ) return;
+ QUEUE_DECREMENT(*Q2,j);
+ ej = Q2->v[j];
+ }
+ QUEUE_DECREMENT(*Q1,t);
+ }
+}
+
+/* delete all elements of Q1 included in Q2.
+ both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_minus_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t){
+ if (Q1->v[i] > Q2->v[i2] ) i2++;
+ else {
+ if (Q1->v[i] < Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ ii++;
+ }
+ i++;
+ }
+ }
+ while ( i != Q1->t ){
+ Q1->v[ii] = Q1->v[i];
+ i++;
+ ii++;
+ }
+ Q1->t = ii;
+}
+void QUEUE_minus (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t ){
+ if ( Q1->v[i] > Q2->v[i2] ) QUEUE_INCREMENT (*Q2, i2);
+ else {
+ if ( Q1->v[i] < Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ QUEUE_INCREMENT (*Q1, i);
+ }
+ }
+ while ( i != Q1->t ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, i);
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ Q1->t = ii;
+}
+
+/* Delete all elements of Q1 which are not included in Q2.
+ both Q1 and Q2 have to be sorted in increasing order */
+QUEUE_ID QUEUE_intsec_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, c=0;
+ while ( i != Q1->t ){
+ if ( Q1->v[i] > Q2->v[i2] ){
+ if ( ++i2 == Q2->t ) break;
+ } else {
+ if ( Q1->v[i] == Q2->v[i2] ) c++;
+ i++;
+ }
+ }
+ return (c);
+}
+void QUEUE_and_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t ){
+ if ( Q1->v[i] > Q2->v[i2] ){
+ if ( ++i2 == Q2->t ) break;
+ } else {
+ if ( Q1->v[i] == Q2->v[i2] ) Q1->v[ii++] = Q1->v[i];
+ i++;
+ }
+ }
+ Q1->t = ii;
+}
+void QUEUE_and (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t){
+ if ( Q1->v[i] > Q2->v[i2] ) QUEUE_INCREMENT (*Q2, i2);
+ else {
+ if ( Q1->v[i] == Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ QUEUE_INCREMENT (*Q1, i);
+ }
+ }
+ Q1->t = ii;
+}
+
+/* insertion sort */
+void QUEUE_sort (QUEUE *Q){
+ QUEUE_ID i = Q->s, j, jj;
+ QUEUE_INT e;
+ if ( i== Q->t ) return;
+ QUEUE_INCREMENT(*Q,i);
+ for ( ; i!=Q->t ; QUEUE_INCREMENT(*Q,i) ){
+ e=Q->v[i];
+ j=i;
+ while (1){
+ jj = j;
+ QUEUE_DECREMENT(*Q,j);
+ if ( Q->v[j] <= e ) { Q->v[jj] = e; break; }
+ Q->v[jj] = Q->v[j];
+ if ( j == Q->s) { Q->v[j] = e; break; }
+ }
+ }
+}
+
+
+/* print a queue */
+void QUEUE_print (QUEUE *Q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+/* permutation version */
+void QUEUE_perm_print (QUEUE *Q, QUEUE_ID *q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", q[Q->v[i]]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+void QUEUE_printn (QUEUE *Q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+}
+void QUEUE_perm_printn (QUEUE *Q, QUEUE_ID *q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ",q[Q->v[i]]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+}
+void QUEUE_print_ (QUEUE *Q){
+ QUEUE_ID i;
+ printf("s="QUEUE_IDF",t="QUEUE_INTF": ", Q->s, Q->t);
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ",Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+
+void QUEUE_print__ (QUEUE *Q){
+ QUEUE_ID i;
+ printf("s="QUEUE_IDF",t="QUEUE_IDF": ", Q->s, Q->t);
+ for ( i=Q->s ; i!=Q->t ; i++ ) printf (QUEUE_INTF" ",Q->v[i]);
+ printf ("\n");
+}
+
+#endif
--- /dev/null
+/* Library of queue: spped priority implementation
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _queue_h_
+#define _queue_h_
+
+#include"stdlib2.h"
+
+#ifndef QUEUE_INT
+ #ifdef QUEUE_INT_LONG
+ #define QUEUE_INT LONG // define the type before if change is needed
+ #define QUEUE_INTHUGE LONGHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_INTF "%lld"
+ #else
+ #define QUEUE_INT int // define the type before if change is needed
+ #define QUEUE_INTHUGE INTHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_INTF "%d"
+ #endif
+#endif
+
+#ifndef QUEUE_ID
+ #ifdef QUEUE_ID_LONG
+ #define QUEUE_ID LONG // define the type before if change is needed
+ #define QUEUE_IDHUGE LONGHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_IDF "%lld"
+ #else
+ #define QUEUE_ID int // define the type before if change is needed
+ #define QUEUE_IDHUGE INTHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_IDF "%d"
+ #endif
+#endif
+
+typedef struct {
+ unsigned char type; // type of the structure
+ QUEUE_INT *v; // pointer to the array
+ QUEUE_ID end; // the length of the array
+ QUEUE_ID t; // end position+1
+ QUEUE_ID s; // start position
+} QUEUE;
+
+/* QUEUE stores at most end-1 elements. Overflow occurs after inserting end-1 elements */
+
+#define QUEUE_INCREMENT(Q,i) ((i)=((i)>=(Q).end-1)?0:(i)+1)
+#define QUEUE_DECREMENT(Q,i) ((i)=(i)==0?(Q).end-1:(i)-1)
+#define QUEUE_LENGTH(Q) (((Q).t-(Q).s+(Q).end)%(Q).end)
+#define QUEUE_LENGTH_(Q) ((Q).t-(Q).s)
+
+/* macro for loop w.r.t., QUEUE */
+#define QUEUE_F_LOOP(Q,i) for((i)=(Q).s;(i)!=(Q).t;((i)=((i)>=(Q).end-1)?0:(i)+1))
+#define QUEUE_F_LOOP_(Q,i) for((i)=(Q).s;(i)<(Q).t;(i)++)
+#define QUEUE_FE_LOOP(Q,i,x) for((i)=(Q).s,x=(Q).v[i];(i)!=(Q).t;((i)=((i)>=(Q).end-1)?0:(i)+1),x=(Q).v[i])
+#define QUEUE_FE_LOOP_(Q,i,x) for((i)=(Q).s,x=(Q).v[i];(i)<(Q).t;(i)++,x=(Q).v[i])
+#define QUEUE_B_LOOP(Q,i) for((i)=(Q).t==0?(Q).end-1:(Q).t-1;(i)!=(Q).s;(i)=(i)==0?(Q).end-1:(i)-1)
+#define QUEUE_B_LOOP_(Q,i) for((i)=(Q).t-1;(i)>=(Q).s;(i)--)
+#define QUEUE_BE_LOOP(Q,i,x) for((i)=(Q).t==0?(Q).end-1:(Q).t-1,x=(Q).v[i];(i)!=(Q).s;(i)=(i)==0?(Q).end-1:(i)-1,x=(Q).v[i])
+#define QUEUE_BE_LOOP_(Q,i,x) for((i)=(Q).t-1;((i)>=(Q).s)?((x=(Q).v[i])||1):0;(i)--)
+
+#define QUEUE_RMALL(Q) ((Q).t=(Q).s)
+#define QUEUE_RMALL_(Q) ((Q).t=0)
+#define QUEUE_HEAD(Q) ((Q).v[(Q).s])
+#define QUEUE_TAIL_(Q) ((Q).v[(Q).t-1])
+
+extern QUEUE INIT_QUEUE;
+extern QUEUE_INT common_QUEUE_INT, *common_QUEUE_INTp;
+QSORT_TYPE_HEADER(QUEUE_INT, QUEUE_INT)
+QSORT_TYPE_HEADER(QUEUE_ID, QUEUE_ID)
+
+
+/* initialization, not fill the memory by 0 */
+void QUEUE_init (QUEUE *Q, QUEUE_ID siz);
+
+/* termination processing */
+void QUEUE_end (QUEUE *Q);
+
+/* delivery: transpose that matrinx (transaction database) Q. Each row of the
+ transposed matrix is called occurrence.
+
+variables to be set.
+OQ:array for occurrences, c: for counting frequency, jump: list of items with non-empty OQ
+if c!=NULL, count the frequency and set to c, and set occurrences to OQ, otherwise.
+if jump==NULL, then the list of non-empty item will not be generated
+Q:matrix, of an array of QUEUE, occ: list of rows of Q to be scaned, t; maximum ID of the
+ row to be scaned; if occ==NULL, occ will be ignored, otherwise t will be ignored.
+ M: end mark of each QUEUE. */
+void QUEUE_delivery(QUEUE *OQ, VEC_ID *c, QUEUE *jump, QUEUE *Q, QUEUE *occ, VEC_ID t, QUEUE_INT M);
+/* sort a QUEUE with WEIGHT, with already allocated memory (size have to no less than the size of QUEUE) */
+void QUEUE_perm_WEIGHT (QUEUE *Q, WEIGHT *w, PERM *invperm, int flag);
+
+/* remove (or unify) the consecutive same ID's in a QUEUE (duplication delete, if sorted) */
+void QUEUE_rm_dup_WEIGHT (QUEUE *Q, WEIGHT *w);
+
+/***********************************************************************/
+/* duplicate occ's in jump, ( copy occ's to allocated QUEUE array) */
+/* Q[i].end := original item, clear each original occ */
+/* buffer size is multiplied by u */
+/*******************************************************/
+
+
+void QUEUE_occ_dup (QUEUE *jump, QUEUE **QQ, QUEUE *Q, WEIGHT **ww, WEIGHT *w, WEIGHT **ppw, WEIGHT *pw, int u);
+
+/* return the position of the first element having value e. return -1 if no such element exists */
+LONG QUEUE_ele (QUEUE *Q, QUEUE_INT e);
+
+/* insert an element to the tail/head */
+void QUEUE_ins_ (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins_head_ (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins_head (QUEUE *Q, QUEUE_INT e);
+
+/* extract an element from the head/tail, without checking the underflow */
+QUEUE_INT QUEUE_ext_ (QUEUE *Q);
+QUEUE_INT QUEUE_ext (QUEUE *Q);
+QUEUE_INT QUEUE_ext_tail_ (QUEUE *Q);
+QUEUE_INT QUEUE_ext_tail (QUEUE *Q);
+
+/* remove the j-th element and replace it by the tail/head or shift */
+void QUEUE_rm_ (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm_head_ (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm_head (QUEUE *Q, QUEUE_ID j);
+int QUEUE_rm_ele_ (QUEUE *Q, QUEUE_INT e);
+
+/* Append Q2 to the tail of Q1. Q2 will (not) be deleted */
+void QUEUE_append_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_append (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_concat_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_concat (QUEUE *Q1, QUEUE *Q2);
+
+/* Append from j to jj th elements to the tail of Q1. Q2 will not be deleted */
+void QUEUE_subconcat_ (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj);
+void QUEUE_subconcat (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj);
+
+/* initialize Q1 by length of Q2, and copy Q2 to Q1 */
+void QUEUE_store_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_store (QUEUE *Q1, QUEUE *Q2);
+/* copy Q2 to Q1 and delete Q2 */
+void QUEUE_restore_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_restore (QUEUE *Q1, QUEUE *Q2);
+
+/* copy Q2 to Q1 */
+void QUEUE_cpy_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_cpy (QUEUE *Q1, QUEUE *Q2);
+QUEUE QUEUE_dup_ (QUEUE *Q);
+/* copy l elements of Q2 starting from s2 to the s1th position of Q1.
+ size of Q1 is not increasing */
+void QUEUE_subcpy_ (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l);
+void QUEUE_subcpy (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l);
+
+/* merge/minum/intersection of Q1 and Q2, and set Q1 to it.
+ Both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_merge_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_merge (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_minus_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_minus (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_and_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_and (QUEUE *Q1, QUEUE *Q2);
+
+/* insertion sort */
+void QUEUE_sort (QUEUE *Q);
+
+ /* print */
+void QUEUE_print (QUEUE *Q);
+void QUEUE_print_ (QUEUE *Q);
+
+
+#endif
--- /dev/null
+/* graph library by array list
+ 12/Feb/2002 by Takeaki Uno
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _sgraph_c_
+#define _sgraph_c_
+
+#include"sgraph.h"
+#include"vec.c"
+
+SGRAPH INIT_SGRAPH = {TYPE_SGRAPH,INIT_SETFAMILY_,INIT_SETFAMILY_,INIT_SETFAMILY_,0,0,NULL,NULL};
+
+/* initialization */
+void SGRAPH_alloc (SGRAPH *G, QUEUE_ID nodes, size_t edge_num, size_t arc_num){
+ if ( edge_num > 0 ){
+ SETFAMILY_alloc (&G->edge, nodes, NULL, nodes, edge_num);
+ if ( G->flag&LOAD_EDGEW && (!ERROR_MES) ) SETFAMILY_alloc_weight (&G->edge);
+ }
+ if ( arc_num > 0 ){
+ SETFAMILY_alloc (&G->in, nodes, NULL, nodes, arc_num);
+ SETFAMILY_alloc (&G->out, nodes, NULL, nodes, arc_num);
+ if ( G->flag&LOAD_EDGEW && (!ERROR_MES) ){
+ SETFAMILY_alloc_weight (&G->in);
+ SETFAMILY_alloc_weight (&G->out);
+ }
+ }
+ if (G->flag&LOAD_NODEW) calloc2 (G->node_w, nodes, "SGRAPH_alloc: node_w", G->node_w=0);
+ if ( ERROR_MES ){ SGRAPH_end (G); EXIT; }
+}
+
+/* copy graph G to graph G2. Underconstruction */
+//void SGRAPH_cpy (SGRAPH *G2, SGRAPH *G){}
+
+/* free graph object */
+void SGRAPH_end (SGRAPH *G){
+ SETFAMILY_end (&G->edge);
+ SETFAMILY_end (&G->in);
+ SETFAMILY_end (&G->out);
+ mfree (G->wbuf, G->perm);
+ *G = INIT_SGRAPH;
+}
+
+
+/* make an edge between u and v.
+ If they are already connected, it will be a multiple edge */
+void SGRAPH_edge_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w){
+ if ( G->edge.w ){
+ G->edge.w[u][G->edge.v[u].t] = w;
+ G->edge.w[v][G->edge.v[v].t] = w;
+ }
+ ARY_INS (G->edge.v[u], v);
+ ARY_INS (G->edge.v[v], u);
+ G->edge.eles += 2;
+}
+
+/* make an arc between u and v.
+ If they are already connected, it will be a multiple arc */
+void SGRAPH_arc_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w){
+ if ( G->out.w ) G->out.w[u][G->out.v[u].t] = w;
+ if ( G->in.w ) G->in.w[v][G->in.v[v].t] = w;
+ ARY_INS (G->out.v[u], v);
+ ARY_INS (G->in.v[v], u);
+ G->in.eles++;
+ G->out.eles++;
+}
+
+/* Delete the edge connecting u and v. If edge (u,v) does not exist, nothing will occur. */
+void SGRAPH_edge_rm_iter (SETFAMILY *M, QUEUE_INT u, QUEUE_INT v){
+ LONG i;
+ if ( (i = QUEUE_ele (&M->v[u], v)) >= 0 ){
+ QUEUE_rm (&M->v[u], i);
+ if ( M->w ) M->w[u][i] = M->w[u][M->v[u].t];
+ M->eles--;
+ }
+}
+
+/* Delete the edge connecting u and v. If edge (u,v) does not exist, nothing will occur. */
+void SGRAPH_edge_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v){
+ SGRAPH_edge_rm_iter (&G->edge, u, v);
+ SGRAPH_edge_rm_iter (&G->edge, v, u);
+}
+
+/* Delete the arc connecting u and v. If arc (u,v) does not exist, nothing will occur. */
+void SGRAPH_arc_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v){
+ SGRAPH_edge_rm_iter (&G->out, u, v);
+ SGRAPH_edge_rm_iter (&G->in, v, u);
+}
+
+/* print graph by numbers */
+void SGRAPH_print (SGRAPH *G){
+ VEC_ID i;
+ QUEUE_ID j;
+ QUEUE_INT e;
+
+ printf ("#node "VEC_IDF" ,#edge %zd ,#arc %zd\n", SGRAPH_NODE_NUM(*G), G->edge.eles, G->in.eles);
+ FLOOP (i, 0, SGRAPH_NODE_NUM(*G)){
+ printf ("NODE "VEC_IDF" ", i);
+ if ( G->node_w ){ putchar ('('); print_WEIGHT (G->node_w[i]); putchar (')'); }
+ printf (" >>\n");
+ if ( G->edge.v && G->edge.v[i].t ){
+ printf (" edge : ");
+ ARY_FLOOP (G->edge.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->edge.w ){ putchar ('('); print_WEIGHT (G->edge.w[i][j]); putchar (')'); }
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ if ( G->in.w ){
+ if ( G->in.v[i].t ){
+ printf (" in-arc : ");
+ ARY_FLOOP (G->in.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->in.w ){ putchar ('('); print_WEIGHT (G->in.w[i][j]); putchar (')'); }
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ }
+ if ( G->out.w ){
+ if ( G->out.v[i].t ){
+ printf (" out-arc : ");
+ ARY_FLOOP (G->out.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->out.w ){ putchar ('('); print_WEIGHT (G->out.w[i][j]); putchar (')');}
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ }
+ }
+}
+
+/* Output a graph to file
+ Vertices, edges, arcs less than node_num, edge_num, arc_num are written to the file. Input parameters are
+ (graph) (file name) (flag)
+ SGRAPH_READ_NODEW 512 // read node weight
+ SGRAPH_READ_EDGEW 1024 // read edge weight
+*/
+/*
+ format of file:(including notifications to make input file)
+
+ the ith row corresponds to node i-1, and
+ ID list of nodes adjacent to i, and having ID > i, for undirected graph
+ ID list of nodes adjacent to i by out-going arc of i, for directed graph
+ Separator is ",", but graph load routine accepts any letter for
+ separator but not a number.
+ If the graph has both edges and arcs, write them in two lines separately,
+ so a node then uses two lines, and #nodes = #lines/2.
+
+ == Notifications to make input file ==
+ Notice that if 0th line has node 2, and the 2nd line has 0, then there
+ will be multiple edge (0,2) and (2,0).
+ The read routine does not make error with multiple edges, it is allowed.
+
+ The ID of nodes begin from 0. After reading graph, node_num is set to
+ node_end.
+
+ Input file example, without weights, E={(0,1),(0,2),(1,1),(1,3),(2,3)}
+===========
+ 1,2
+ 1 3
+ 3
+
+ [EOF]
+=========
+ Nodes are 0,1, and 2, both edges and arcs exist, with node/edge/arc weights)
+ 5000,1,30
+ 0,50,1,20,
+ 100,1,3
+ 2,20
+ 200
+
+ [EOF]
+=======
+ where node weights are 5000, 100, 200, and edges and their weights are
+ (0,1),30, (1,1),3
+ arcs and their weights are (0,0),50, (0,1), 20, (1,2), 20
+
+ In the case of bipartite graph, write the adjacent-node lists only for
+ the node in node set one.
+
+
+*/
+
+/* graph load routine. Allocate memory as much as the size of input file.
+ parameters are,
+ (graph) (file name)
+ LOAD_EDGE // read undirected edge from file
+ LOAD_ARC // read directed arc from file
+ LOAD_BIPARTITE // load bipartite graph
+ LOAD_NODEW // read node weight
+ LOAD_EDGEW // read edge weight
+*/
+/* In the bipartite case, even if the IDs of node set 2 begin from 0, i.e.,
+ overlaps with node 1, the routine automatically correct them. */
+/* Directed bipartite graph, all arcs are considered to be from node set 1
+ to node set 2. If both directions exist, read as a general graph, and set
+ node1_num later in some way. */
+/* The routine compares the maximum node index and #lines, and set #node
+ to the larger one. However, if node weight exists, weights will be included
+ in the candidates of maximum index, thus in this case we fix #node := #lines.
+ In the case of bipartite graph, the routine compares, but the weights of
+ non-existing lines will be -1. */
+
+/* make the opposite direction edge, for each edge; buffers have to be already doubly allocated */
+void SGRAPH_load_delivery (SGRAPH *G, SETFAMILY *OO, SETFAMILY *MM, QUEUE_ID *c){
+ VEC_ID i;
+ QUEUE_ID j;
+ QUEUE_INT e;
+ FLOOP (i, 0, MM->t) c[i] = MM->v[i].t;
+ FLOOP (i, 0, MM->t){
+ FLOOP (j, 0, c[i]){
+ e = MM->v[i].v[j];
+ if ( OO->w ) OO->w[e][OO->v[e].t] = MM->w[i][j];
+ ARY_INS (OO->v[e], i);
+ }
+ }
+}
+
+/* make the opposite direction edge, for each edge; buffers have to be already doubly allocated */
+void SGRAPH_mk_opposite_edge (SGRAPH *G, QUEUE_ID *c){
+ VEC_ID i;
+ size_t j, jj;
+ j = G->edge.eles; // shift the arrays to insert edges of opposite directions
+ BLOOP (i, G->edge.t, 0){
+ j -= G->edge.v[i].t+c[i];
+ jj = G->edge.v[i].t+1;
+ do {
+ jj--;
+ G->edge.buf[j+i+jj] = G->edge.v[i].v[jj];
+ } while ( jj>0 );
+ G->edge.v[i].end += c[i];
+ G->edge.v[i].v = &G->edge.buf[j+i];
+ if ( G->edge.w ){
+ memcpy ( &G->edge.buf[j], G->edge.w[i], sizeof(WEIGHT)*G->edge.v[i].t );
+ G->edge.w[i] = &G->edge.wbuf[j];
+ }
+ }
+}
+
+/* load edges/arcs (determined by G->flag) from file */
+void SGRAPH_load (SGRAPH *G, char *fname, char *wfname){
+ VEC_ID i;
+ QUEUE_ID *c;
+ SETFAMILY *F1, *F2;
+
+ if ( G->flag&LOAD_EDGE ){ F1 = F2 = &G->edge; G->edge.flag |= LOAD_DBLBUF; }
+ else { F1 = &G->in; F2 = &G->out; }
+ SETFAMILY_load (F1, fname, wfname);
+ // adjact so that #rows and #colums are the same
+ if ( !(G->flag&LOAD_BIPARTITE)){
+ if ( F1->clms < F1->t ){
+ F1->clms = F1->t;
+ FLOOP (i, 0, F1->t) F1->v[i].v[F1->v[i].t] = F1->t; // re-set endmark
+ } else if ( F1->clms > F1->t ){
+ reallocx_ (F1->v, F1->t, F1->clms, INIT_QUEUE, "SGRAPH_load: v", EXIT);
+ FLOOP (i, F1->t, F1->clms){
+ F1->v[i].v = F1->v[F1->t -1].v +F1->v[F1->t -1].t +1 +(i -(F1->t-1));
+ F1->v[i].v[0] = F1->clms;
+ } // re-set endmark
+ F1->t = F1->clms;
+ }
+ }
+
+ calloc2 (c, F1->t, "SGRAPH_load: c", EXIT);
+ QUEUE_delivery (NULL, c, NULL, F1->v, NULL, F1->t, F1->t);
+// SETFAMILY_print (stdout, F1);
+
+ if ( F1 != F2 ) SETFAMILY_alloc (F2, F1->t, c, F1->t, 0);
+ else {
+ G->edge.eles *= 2; G->edge.ele_end *= 2;
+ SGRAPH_mk_opposite_edge (G, c); // shift the arrays to insert edges of opposite directions
+ }
+
+ SGRAPH_load_delivery (G, F2, F1, c);
+ free (c);
+ F2->clms = F2->t; FLOOP (i, 0, F2->t) F2->v[i].v[F2->v[i].t] = F2->t; // re-set endmark
+
+ F1->flag |= G->flag; SETFAMILY_sort (F1);
+ if ( F1 != F2 ){ F2->flag |= G->flag; SETFAMILY_sort (F2); }
+}
+
+/* replace node i by perm[i] */
+void SGRAPH_replace_index (SGRAPH *G, PERM *perm, PERM *invperm){
+ QUEUE_INT *x;
+ VEC_ID i;
+ QUEUE Q;
+ WEIGHT *w, ww;
+
+ FLOOP (i, 0, G->edge.t)
+ if ( G->edge.v ){
+ MQUE_FLOOP (G->edge.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->edge.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->in.v ){
+ MQUE_FLOOP (G->in.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->in.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->out.v ){
+ MQUE_FLOOP (G->out.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->out.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->edge.w ) ARY_INVPERMUTE (G->edge.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->in.w ) ARY_INVPERMUTE (G->in.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->out.w ) ARY_INVPERMUTE (G->out.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->node_w ) ARY_INVPERMUTE (G->node_w, invperm, ww, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ G->perm = perm;
+}
+
+/* sort the nodes by Q->t, increasing if flag=1, decreasing if flag=-1 */
+void SGRAPH_perm_node (SGRAPH *G, PERM *tmp){
+ VEC_ID c1=0, c2=G->node1_num, i;
+ PERM *perm;
+ malloc2 (perm, G->edge.t, "SGRAPH_perm_node", {free(tmp);EXIT;});
+ FLOOP (i, 0, G->edge.t)
+ if ( tmp[i]<G->node1_num ) perm[tmp[i]] = c1++; else perm[tmp[i]] = c2++;
+ ARY_INV_PERM_ (tmp, perm, G->edge.t);
+ SGRAPH_replace_index (G, perm, tmp);
+ free2 (tmp);
+}
+
+#endif
--- /dev/null
+/* graph library by array list
+ 12/Feb/2002 by Takeaki Uno
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/****************************************************************************/
+/* d = degree of node i := G->edge/in/out.v[i].t
+ d = max/min (in/out) degree := VEC_MAXT(d,G->edge.v/in.v/out.v,0,...->t) (VEC_MINT, resp.)
+ #nodes := SGRAPH_NODE_NUM(G)
+ #edges := G->edge.eles/2
+ #arcs := G->in.eles or G->out.eles
+ load_node_weight := ARY_LOAD_WEIGHT(G->node_w,WEIGHT,filename,counter,"errormes", EXIT)
+ load_node_weight := ARY_LOAD_WEIGHT(G->node_w,WEIGHT,filename,counter,"errormes", EXIT)
+
+ sort_node by size := SGRAPH_sort_node_iter (G, qsort_perm_VECt ((VEC *)Q, G->node_end, flag)
+ sort_node by weight := SGRAPH_sort_node_iter (G, qsort_perm_WEIGHT (w, G->node_end, flag)
+*/
+/****************************************************************************/
+
+#ifndef _sgraph_h_
+#define _sgraph_h_
+
+#include"stdlib2.h"
+#include"vec.h"
+
+
+/* structure for graph */
+typedef struct {
+ unsigned char type; // structure type flag
+ SETFAMILY edge, in, out; // setfamily for edge, in-arc, out-arc
+ QUEUE_INT node1_num; // the size of vertex set 1, bipartite case. otherwise 0
+ int flag; // flag for load routine
+ WEIGHT *node_w, *wbuf; // pointer to the node weight array(int)
+ PERM *perm; // node permutation (nodes->original)
+} SGRAPH;
+extern SGRAPH INIT_SGRAPH;
+
+#define SGRAPH_NODE_NUM(G) MAX((G).edge.t,(G).in.t)
+
+/*************** initialization/termination ***********************/
+
+/* initialization, termination, allocate arrays for weights, copy and duplication */
+void SGRAPH_alloc (SGRAPH *G, int node_num, size_t edge_num, size_t arc_num);
+void SGRAPH_cpy (SGRAPH *G2, SGRAPH *G);
+void SGRAPH_end (SGRAPH *G);
+
+
+/**************** addition/deletion **********************************/
+
+/* make/take/remove edge e as connecting vertices u and v,
+ and edge (u,v).
+ do nothing if when make already existing edge, or delete non-existing edge.
+ with range check of parameters */
+
+void SGRAPH_edge_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w);
+void SGRAPH_edge_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v);
+void SGRAPH_arc_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w);
+void SGRAPH_arc_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v);
+
+
+/******************* node/edge sort, and duplication reduction *********************/
+
+/* subroutine of sort_edge_list */
+void SGRAPH_sort_edge_list_iter (QUEUE *Q, WEIGHT **w, PERM *invperm, VEC_ID i, int flag);
+
+/* sort each array list, increasing if flag=1, and decreasing if flag=-1 */
+void SGRAPH_sort_edge_list (SGRAPH *G, int flag);
+
+/* replace node i by perm and invperm */
+void SGRAPH_replace_index (SGRAPH *G, PERM *perm, PERM *invperm);
+
+/* sort the nodes by permutation given by tmp */
+PERM *SGRAPH_sort_node_iter (SGRAPH *G, PERM *tmp);
+
+/* sort the nodes by degrees, increasing if flag=1, decreasing if flag=-1 */
+PERM *SGRAPH_sort_node_t (SGRAPH *G, QUEUE *Q, int flag);
+
+/* sort the nodes by node_weight, increasing if flag=1, decreasing if flag=-1 */
+PERM *SGRAPH_sort_node_w (SGRAPH *G, WEIGHT *w, int flag);
+
+/* remove multiple edges/arcs and self loops
+ it works only when after applying sort_incident_edges */
+void SGRAPH_simple (SGRAPH *G, int flag);
+
+
+
+
+/******************* print routines *************************************/
+
+
+/* print graph by numbers */
+void SGRAPH_print (SGRAPH *G);
+
+/* Write the graph to file. Edges, arcs, and nodes from 0 to node_num/edge_num/arc_num are written to file. Parameters are
+ (graph) (file name) (not write edge weight => 0) (not write node weight => 0) */
+void SGRAPH_save (SGRAPH *G, char *fname);
+
+/* graph load routine. Allocate memory as much as the size of input file.
+ parameters are,
+ (graph) (file name) (read edges?) (read arcs?) (read node weights?) (read edge weight?) (bipartite?) */
+/* In the row of each vertex, write only vertices larger than it connected by an edge */
+void SGRAPH_load (SGRAPH *G, char *fname, char *wfname);
+void SGRAPH_load_node_weight (SGRAPH *G, char *filename);
+
+/*
+ format of file:(including notifications to make input file)
+
+ the ith row corresponds to node i-1, and
+ ID list of nodes adjacent to i, and having ID > i, for undirected graph
+ ID list of nodes adjacent to i by out-going arc of i, for directed graph
+ Separator is ",", but graph load routine accepts any letter for
+ separator but not a number.
+ If the graph has both edges and arcs, write them in two lines separately,
+ so a node then uses two lines, and #nodes = #lines/2.
+
+ == Notifications to make input file ==
+ Notice that if 0th line has node 2, and the 2nd line has 0, then there
+ will be multiple edge (0,2) and (2,0).
+ The read routine does not make error with multiple edges, it is allowed.
+
+ The ID of nodes begin from 0. After reading graph, node_num is set to
+ node_end.
+
+ Input file example, without weights, E={(0,1),(0,2),(1,1),(1,3),(2,3)}
+===========
+ 1,2
+ 1 3
+ 3
+
+ [EOF]
+=========
+ Nodes are 0,1, and 2, both edges and arcs exist, with node/edge/arc weights)
+ 5000,1,30
+ 0,50,1,20,
+ 100,1,3
+ 2,20
+ 200
+
+ [EOF]
+=======
+ where node weights are 5000, 100, 200, and edges and their weights are
+ (0,1),30, (1,1),3
+ arcs and their weights are (0,0),50, (0,1), 20, (1,2), 20
+
+ In the case of bipartite graph, write the adjacent-node lists only for
+ the node in node set one.
+
+
+*/
+
+
+/*************************************************************************/
+
+
+#endif
+
+
+
+
+
+
+
+
--- /dev/null
+/* library for standard macros and functions */
+/* by Takeaki Uno 2/22/2002, e-mail: uno@nii.jp
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _stdlib2_c_
+#define _stdlib2_c_
+
+#include"stdlib2.h"
+
+int common_int;
+size_t common_size_t;
+LONG common_LONG;
+INT common_INT, common_INT2;
+double common_double;
+char *common_charp, *common_pnt;
+FILE *common_FILE;
+FILE2 common_FILE2;
+PERM common_PERM, *common_PERMp;
+VEC_VAL common_VEC_VAL, *common_VEC_VALp;
+VEC_ID common_VEC_ID;
+extern WEIGHT common_WEIGHT, *common_WEIGHTp;
+
+char *ERROR_MES = NULL;
+int print_time_flag=0;
+PARAMS internal_params;
+#ifdef MULTI_CORE
+int SPIN_LOCK_dummy;
+#endif
+FILE2 INIT_FILE2 = {TYPE_FILE2,NULL,NULL,NULL,NULL};
+VEC INIT_VEC = {TYPE_VEC,NULL,0,0};
+FILE_COUNT INIT_FILE_COUNT = {0,0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,0,0,NULL,NULL,0,0,NULL,NULL};
+
+ /* bitmasks, used for bit operations */
+int BITMASK_UPPER1[32] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+ 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+ 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+ 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+ 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+ 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+ 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+ 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000 };
+int BITMASK_UPPER1_[32] = { 0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0,
+ 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
+ 0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000,
+ 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
+ 0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000,
+ 0xffe00000, 0xffc00000, 0xff800000, 0xff000000,
+ 0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000,
+ 0xe0000000, 0xc0000000, 0x80000000, 0x00000000 };
+
+int BITMASK_LOWER1[32] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff };
+int BITMASK_LOWER1_[32] = { 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff };
+
+int BITMASK_1[32] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000 };
+int BITMASK_31[32] = { 0xfffffffe, 0xfffffffd, 0xfffffffb, 0xfffffff7,
+ 0xffffffef, 0xffffffdf, 0xffffffbf, 0xffffff7f,
+ 0xfffffeff, 0xfffffdff, 0xfffffbff, 0xfffff7ff,
+ 0xffffefff, 0xffffdfff, 0xffffbfff, 0xffff7fff,
+ 0xfffeffff, 0xfffdffff, 0xfffbffff, 0xfff7ffff,
+ 0xffefffff, 0xffdfffff, 0xffbfffff, 0xff7fffff,
+ 0xfeffffff, 0xfdffffff, 0xfbffffff, 0xf7ffffff,
+ 0xefffffff, 0xdfffffff, 0xbfffffff, 0x7fffffff };
+
+int BITMASK_16[8] = { 0x0000000f, 0x000000f0, 0x00000f00, 0x0000f000,
+ 0x000f0000, 0x00f00000, 0x0f000000, 0xf0000000 };
+int BITMASK_UPPER16[8] = { 0xffffffff, 0xfffffff0, 0xffffff00, 0xfffff000,
+ 0xffff0000, 0xfff00000, 0xff000000, 0xf0000000 };
+int BITMASK_LOWER16[8] = { 0x0000000f, 0x000000ff, 0x00000fff, 0x0000ffff,
+ 0x000fffff, 0x00ffffff, 0x0fffffff, 0xffffffff };
+int BITMASK_FACT16[8] = { 0x1, 0x10, 0x100, 0x1000,
+ 0x10000, 0x100000, 0x1000000,0x10000000 };
+
+/* free many pointers */
+void mfree_(void *x, ...){
+ va_list argp;
+ void *a;
+ va_start (argp, x);
+ while((a = va_arg(argp, void *)) != (void*)1){ free (a); }
+ va_end (argp);
+}
+
+/* compute the minimum prime no less than n */
+#define MINPRIME_END 6000
+LONG min_prime (LONG n){
+ LONG i, j=30, k;
+ char f[MINPRIME_END];
+ while(1) {
+ FLOOP (i, 0, j) f[i]=0;
+ for ( i=3 ; i*i < n+j ; i+=2 )
+ for ( k=((n+i-1)/i)*i ; k<i+j ; k+=i ) f[(k-n)/2] = 1;
+ FLOOP (i, 0, j) if ( f[i] == 0 ) return (n+ i*2+1);
+ j *= 2;
+ }
+}
+
+/* decompose the string by separator, and set v[i] to each resulted string.
+ consecutive separators are regarded as one separator. */
+/* string s has to have end mark 0 at the end */
+/* original string s will be written, so that each separator will be end mark 0 */
+/* at most [num] strings will be generated */
+int string_decompose ( char **v, char *s, char sep, int max){
+ int i=0;
+ char *ss = s;
+ do {
+ while (*ss == sep) ss++;
+ if ( *ss == 0 ) break;
+ v[i++] = ss;
+ while (*ss != sep){
+ if ( *ss == 0 ) break;
+ ss++;
+ }
+ if ( *ss == 0 ) break;
+ *ss = 0;
+ ss++;
+ } while ( i<max);
+ return (i);
+}
+
+/***********************************************************************/
+/***********************************************************************/
+#ifdef USE_MATH
+#define NORMAL_RAND_BASE 1000000
+
+/* make two random numbers under normal distribution N(0,1) */
+void rand_mk_2normal (double *a, double *b){
+ double r1, r2;
+ do {
+ r1 = ((double)(rand()%NORMAL_RAND_BASE))/NORMAL_RAND_BASE;
+ } while (r1==0);
+ r2 = ((double)(rand()%NORMAL_RAND_BASE))/NORMAL_RAND_BASE;
+ r1 = sqrt(-log(r1)*2);
+ r2 *= 2*PI;
+ *a = r1*sin(r2);
+ *b = r1*cos(r2);
+}
+
+/* make a random point on a supersphere of d-dim., and set to double array already allocated */
+void rand_d_gaussian (double *p, int d){
+ int i;
+ double a, b;
+ for (i=0 ; i<d ; i+=2){
+ rand_mk_2normal ( &a, &b);
+ p[i] = a;
+ if ( i+1 < d ) p[i+1] = b;
+ }
+}
+void rand_sphere (double *p, int d){
+ rand_d_gaussian (p, d);
+ ARY_NORMALIZE (p, d);
+}
+#endif
+
+/******************** file I/O routines ********************************/
+
+int FILE_err; /* signals 0: for normal termination
+ 1: read a number, then encountered a newline,
+ 2: read a number, then encountered the end-of-file
+ 5: read no number, and encountered a newline
+ 6: read no number, and encountered the end-of-file */
+
+
+void FILE2_flush (FILE2 *fp){
+ if ( fp->buf > fp->buf_org ){
+ fwrite ( fp->buf_org, fp->buf-fp->buf_org, 1, fp->fp);
+ fp->buf = fp->buf_org;
+ }
+}
+void FILE2_close (FILE2 *fp){
+ fclose2 (fp->fp);
+ free2 (fp->buf_org);
+}
+void FILE2_closew (FILE2 *fp){
+ FILE2_flush (fp);
+ fclose2 (fp->fp);
+ free2 (fp->buf_org);
+}
+void FILE2_reset (FILE2 *fp){
+ fp->buf = fp->buf_org;
+ fp->buf_end = fp->buf_org-1;
+ fseek (fp->fp, 0, SEEK_SET);
+}
+/* fast file routine, getc, putc, puts, */
+int FILE2_getc (FILE2 *fp){
+ int c;
+ if ( fp->buf >= fp->buf_end ){
+ if ( (fp->buf_end < fp->buf_org+FILE2_BUFSIZ) && (fp->buf_end>=fp->buf_org) ) return (-1);
+ fp->buf = fp->buf_org;
+ fp->buf_end = fp->buf_org + fread (fp->buf, 1, FILE2_BUFSIZ, fp->fp);
+ return (FILE2_getc (fp));
+ }
+ c = (unsigned char)(*(fp->buf));
+ fp->buf++;
+ return (c);
+}
+void FILE2_puts (FILE2 *fp, char *s){
+ while ( *s != 0 ){
+ *(fp->buf) = *s;
+ s++;
+ fp->buf++;
+ }
+}
+void FILE2_putc (FILE2 *fp, char c){
+ *(fp->buf) = c;
+ fp->buf++;
+}
+/* fast file routine, print number, c is the char to be printed preceding to the number
+ if c==0, nothing will be printed preceding the number
+ if len<0 then the #digits following '.' does not change (filed by '0') */
+void FILE2_print_int (FILE2 *fp, LONG n, char c){
+ LONG nn = n;
+ char *s;
+ if ( c ) FILE2_putc ( fp, c);
+ if ( n == 0 ){ *(fp->buf) = '0'; fp->buf++; return; }
+ if ( n < 0 ){ *(fp->buf) = '-'; fp->buf++; n = -n; }
+ while ( nn>0 ){ nn /= 10; fp->buf++; }
+ s = fp->buf-1;
+ *(fp->buf) = 0;
+ while ( n>0 ){ *s = '0'+n%10; s--; n/=10; }
+}
+/******/
+void FILE2_print_real (FILE2 *fp, double n, int len, char c){
+ int i=0, flag=1;
+ double j=1;
+ char *back;
+
+ if ( c ) FILE2_putc (fp, c);
+ if ( n<0 ){ FILE2_putc (fp, '-'); n *= -1; }
+ while ( n >= j ) j*=10;
+ if ( j==1 ){ *(fp->buf) = '0'; fp->buf++; }
+ else while ( j>1 ){
+ j /= 10;
+ i = (int)(n/j);
+ *(fp->buf) = '0'+i;
+ n -= j*i;
+ fp->buf++;
+ }
+ *(fp->buf) = '.'; back = fp->buf;
+ fp->buf++;
+ if ( len<0 ){ len = -len; flag = 0; }
+ for ( ; len>0 ; len--){
+ n *= 10.0;
+ i = (int)n;
+ *(fp->buf) = '0'+i;
+ n -= i;
+ fp->buf++;
+ if ( i>0 ) back = fp->buf;
+ }
+ if ( flag ) fp->buf = back;
+}
+/******/
+void FILE2_print_WEIGHT (FILE2 *fp, WEIGHT w, int len, char c){
+#ifdef WEIGHT_DOUBLE
+ FILE2_print_real(fp, w, len, c);
+#else
+ FILE2_print_int(fp, w, c);
+#endif
+}
+
+/* Read an integer/a double from the file and return it,
+ with read through the non-numeric letters.
+ If it reaches to the end-of-file, then set FILE_err=2, if it reads a
+ newline, then set FILE_err=1.
+ If read either the end-of-file or newline before reading an integer,
+ return 5, and 6 */
+FILE_LONG FILE2_read_int (FILE2 *fp){
+ FILE_LONG item;
+ int flag =1;
+ int ch;
+ FILE_err = 0;
+ do {
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 5; return (-INTHUGE); }
+ if ( ch < 0 ){ FILE_err = 6; return (-INTHUGE); }
+ if ( ch=='-' ) flag = -1;
+ } while ( ch<'0' || ch>'9' );
+ for ( item=(int)(ch-'0') ; 1 ; item=item*10 +(int)(ch-'0') ){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 1; return (flag*item); }
+ if ( ch < 0 ){ FILE_err = 2; return (flag*item); }
+ if ( (ch < '0') || (ch > '9')) return (flag*item);
+ }
+}
+double FILE2_read_double (FILE2 *fp){
+ double item, geta=1;
+ int sign=1, ch;
+ FILE_err = 0;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch < 0 ){ FILE_err = 6; return (-DOUBLEHUGE); }
+ if ( ch == '\n' ){ FILE_err = 5; return (-DOUBLEHUGE); }
+ if ( ch=='-' ) sign *= -1;
+ else if ( ch=='.' ) geta = 0.1;
+ else if ( ch>='0' && ch<='9' ) break;
+ else { sign = 1; geta = 1; }
+ }
+
+ item = geta * (ch-'0');
+ if ( geta < 1.0 ) geta *= .1;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 1; return (item*sign); }
+ if ( ch<0 ){ FILE_err = 2; return (item*sign); }
+ if ( ch == '.' ) geta = .1;
+ else if ( (ch < '0') || (ch > '9')) return (item*sign);
+ else if ( geta < 1.0 ){
+ item += geta*(ch-'0');
+ geta *= 0.1;
+ } else item = item*10 + (ch-'0');
+ }
+}
+
+/* read a WEIGHT from file */
+WEIGHT FILE2_read_WEIGHT (FILE2 *fp){
+#ifdef WEIGHT_DOUBLE
+ return (FILE2_read_double(fp));
+#else
+ return (FILE2_read_int(fp));
+#endif
+}
+
+/* read through the file until newline or EOF */
+void FILE2_read_until_newline (FILE2 *fp){
+ int ch;
+ if (FILE_err & 3) return;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 5; return; }
+ if ( ch < 0 ){ FILE_err = 6; return; }
+ }
+}
+
+void FILE2_printf (FILE2 *fp, char *mes, ...){
+ va_list argp;
+ va_start (argp, mes);
+ sprintf (fp->buf, mes, argp);
+ va_end (argp);
+}
+
+/* print a real number in a good style */
+void fprint_real (FILE *fp, double f){
+ char s[200];
+ size_t i;
+ i = sprintf (s, "%f", f);
+ while ( s[i-1] == '0' ) i--;
+ if ( s[i-1] == '.' ) i--;
+ s[i] = 0;
+ fprintf (fp, s);
+}
+void print_real (double f){
+ fprint_real (stdout, f);
+}
+
+void fprint_WEIGHT (FILE *fp, WEIGHT f){
+#ifdef WEIGHT_DOUBLE
+ fprint_real (fp, f);
+#else
+ fprintf (fp, "%d", f);
+#endif
+}
+void print_WEIGHT (WEIGHT f){
+ fprint_WEIGHT (stdout, f);
+}
+
+/* count the clms, rows, items, each row size, each column size */
+/* file types can be, array list and element list*/
+/* support transpose */
+FILE_COUNT FILE2_count (FILE2 *fp, int flag, int skip_rows, int int_rows, int skip_clms, int int_clms, size_t row_limit){
+ FILE_COUNT_INT k=0, j;
+ LONG x, y, t=0;
+ int fr = flag&FILE_COUNT_ROWT, fc = flag&FILE_COUNT_CLMT;
+ int fe = flag&LOAD_ELE, ft = flag&LOAD_TPOSE;
+ FILE_COUNT C = INIT_FILE_COUNT;
+ C.flag = flag;
+
+ FLOOP (j, 0, skip_rows) FILE2_read_until_newline (fp);
+
+ do {
+ if ( fe ){
+ FLOOP (j, 0, skip_clms){ FILE2_read_double (fp); if ( FILE_err&3 ) goto ROW_END; }
+ x = FILE2_read_int (fp); if ( FILE_err&3 ) goto ROW_END;
+ y = FILE2_read_int (fp); if ( FILE_err&4 ) goto ROW_END;
+ FILE2_read_until_newline (fp);
+ } else {
+ if ( k==0 ) FLOOP (j, 0, skip_clms){ FILE2_read_double (fp); if (FILE_err&3) goto ROW_END; }
+ x = t;
+ y = FILE2_read_int (fp); if (FILE_err&4 ) goto ROW_END;
+ FLOOP (j, 0, int_clms){ FILE2_read_double (fp); if (FILE_err&3 ) break; }
+ k++;
+ }
+
+ if ( ft ) SWAP_INT (x, y);
+ if ( y >= C.clms ){
+ C.clms = y+1;
+ if ( fc ) reallocx (C.clmt, C.clm_end, y, 0, "file_count: clmt", goto END);
+ }
+ if ( x >= C.rows ){
+ C.rows = x+1;
+ if ( fr ) reallocx (C.rowt, C.row_end, x, 0, "file_count: rowt", goto END);
+ }
+ if ( x < C.clm_btm || C.eles == 0 ) C.clm_btm = x;
+ if ( y < C.row_btm || C.eles == 0 ) C.row_btm = y;
+ if ( fc ) C.clmt[y]++;
+ if ( fr ) C.rowt[x]++;
+ C.eles++;
+
+ ROW_END:;
+ if ( !fe && (FILE_err&1) ){
+ t++; C.rows = t;
+ ENMAX (C.clm_max, k);
+ ENMAX (C.clm_min, k);
+ FLOOP (j, 0, int_rows) FILE2_read_until_newline (fp);
+ if ( row_limit>0 && t>=row_limit ) break;
+ } else if ( row_limit>0 && C.eles>=row_limit ) break;
+
+ } while ( (FILE_err&2)==0 );
+ END:;
+ if ( C.rowt ){
+ ARY_MAX (C.row_max, k, C.rowt, 0, C.rows);
+ ARY_MIN (C.row_min, k, C.rowt, 0, C.rows);
+ }
+ if ( fe && C.clmt ){
+ ARY_MAX (C.clm_max, k, C.clmt, 0, C.clms);
+ ARY_MIN (C.clm_min, k, C.clmt, 0, C.clms);
+ }
+ if ( ERROR_MES ) mfree (C.rowt, C.clmt);
+ return (C);
+}
+
+
+/* SLIST:very simple one-sided list */
+void SLIST_init (int *l, int num, int siz){
+ malloc2 (l, num+siz, "SLIST_init: l", EXIT);
+ ARY_FILL (l, num, num+siz, -1);
+}
+void SLIST_end (int *l){ free (l); }
+#define SLIST_INS(l,m,e) (l[e]=l[m],l[m]=e);
+
+QSORT_TYPE (int, int)
+QSORT_TYPE (uint, unsigned int)
+QSORT_TYPE (double, double)
+QSORT_TYPE (char, char)
+QSORT_TYPE (uchar, unsigned char)
+QSORT_TYPE (short, short)
+QSORT_TYPE (ushort, unsigned short)
+QSORT_TYPE (WEIGHT, WEIGHT)
+QSORT_TYPE (LONG, LONG)
+QSORT_TYPE (VEC_ID, VEC_ID)
+QSORT_TYPE (VEC_VAL, VEC_VAL)
+QSORT_TYPE (VEC_VAL2, VEC_VAL2)
+QSORT_TYPE (FILE_COUNT_INT, FILE_COUNT_INT)
+
+/* qsort according to "->t" */
+int qsort_cmp_VECt (const void *x, const void *y){
+ if ( ((VEC *)x)->t < ((VEC *)y)->t ) return (-1);
+ else return ( ((VEC *)x)->t > ((VEC *)y)->t);
+}
+int qsort_cmp__VECt (const void *x, const void *y){
+ if ( ((VEC *)x)->t > ((VEC *)y)->t ) return (-1);
+ else return ( ((VEC *)x)->t < ((VEC *)y)->t);
+}
+void qsort_VECt (VEC *v, size_t siz, int unit){
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (VEC);
+ if ( unit < 0 ) qsort (v, siz, -unit, qsort_cmp__VECt);
+ else qsort (v, siz, unit, qsort_cmp_VECt);
+}
+
+int qqsort_cmp_VECt (const void *x, const void *y){
+ if ( QQSORT_ELEt(VEC,x) < QQSORT_ELEt(VEC,y) ) return (-1);
+ else return ( QQSORT_ELEt(VEC,x) > QQSORT_ELEt(VEC,y) );
+}
+int qqsort_cmp__VECt (const void *x, const void *y){
+ if ( QQSORT_ELEt(VEC,x) > QQSORT_ELEt(VEC,y) ) return (-1);
+ else return ( QQSORT_ELEt(VEC,x) < QQSORT_ELEt(VEC,y) );
+}
+void qsort_perm__VECt (VEC *v, size_t siz, PERM *perm, int unit){
+ if ( unit == 1 || unit==-1 ) unit *= sizeof(VEC);
+ common_int=MAX(unit,-unit); common_charp=(char *)v;
+ if (unit<0) qsort (perm, siz, sizeof(PERM), qqsort_cmp__VECt);
+ else qsort (perm, siz, sizeof(PERM), qqsort_cmp_VECt);
+}
+
+PERM *qsort_perm_VECt (VEC *v, size_t siz, int unit){
+ PERM *perm;
+ malloc2 (perm, siz, "qsort_perm_VECt: perm", EXIT0);
+ ARY_INIT_PERM(perm,siz);
+ qsort_perm__VECt (v, siz, perm, unit);
+ return(perm);
+}
+
+#ifdef STDLIB2_RADIX_SORT // radix sort with 1M byte static memory
+
+#define RADIX_SORT_BUCKET_SIZ 2048
+/* sort of integer array with combination of radix sort and quick sort */
+/* flag&1: sort in decreasing order */
+
+// sort by lower bits
+void intarray_sort_iter (unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ size_t k, x;
+ int i, ii, j, flag=1;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ buf = bbuf; buf2 = bbuf2;
+ if ( init_flag == 1 ){
+ init_flag = 0;
+ ARY_FILL (cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[(*((unsigned int *)aa)) & (RADIX_SORT_BUCKET_SIZ-1)]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP (x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = *((unsigned int *)buf) & (RADIX_SORT_BUCKET_SIZ-1); // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy ( buf2, aaa, unit);
+ memcpy ( aaa, buf, unit);
+ SWAP_PNT ( buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy ( aa, buf, unit);
+ }
+ cnt[i]=0; // difference!!
+ }
+}
+// sort by middle bits
+void intarray_sort_iter_ ( unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ int i, ii, j, flag=1;
+ size_t k, x;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ buf = bbuf; buf2 = bbuf2;
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ if ( init_flag == 1 ){
+ init_flag = 0;
+ ARY_FILL ( cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[((*((unsigned int *)aa))/RADIX_SORT_BUCKET_SIZ) & (RADIX_SORT_BUCKET_SIZ-1)]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP(x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = (*((unsigned int *)buf)/RADIX_SORT_BUCKET_SIZ) & (RADIX_SORT_BUCKET_SIZ-1); // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy (buf2, aaa, unit);
+ memcpy (aaa, buf, unit);
+ SWAP_PNT (buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy (aa, buf, unit);
+ }
+ }
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ intarray_sort_iter ( (unsigned int*)(((char*)a)+unit*k), cnt[ii]-k, unit*flag);
+ k = cnt[ii];
+ cnt[i]=0;
+ }
+}
+
+// sort by upper bits
+void intarray_sort ( unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ int i, ii, j, flag=1;
+ size_t k, x;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ buf = bbuf; buf2 = bbuf2;
+ if ( init_flag == 1){
+ init_flag = 0;
+ ARY_FILL (cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[(*((unsigned int *)aa)) / RADIX_SORT_BUCKET_SIZ / RADIX_SORT_BUCKET_SIZ]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP (x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = *((unsigned int *)buf) / RADIX_SORT_BUCKET_SIZ / RADIX_SORT_BUCKET_SIZ; // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy (buf2, aaa, unit);
+ memcpy (aaa, buf, unit);
+ SWAP_PNT (buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy ( aa, buf, unit);
+ }
+ }
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ intarray_sort_iter_ ( (unsigned int*)(((char*)a)+unit*k), cnt[ii]-k, unit*flag);
+ k = cnt[ii];
+ cnt[i]=0;
+ }
+
+/*
+ for ( i=0 ; i<siz ; i++){
+ k = *((int *)(((char*)a) + i*unit));
+ printf ("%d %d,%d\n", k, k/65536, k&65535);
+ }
+*/
+}
+
+#endif
+
+/* radix sort for array of structures, by their integer members
+ ranging from mm to m */
+/* sort array "perm" according to (int/void*) array "a".
+ if perm==NULL, allocate memory and for perm */
+/* return the permutation array of the result of the sorting
+ in the decreasing order if unit<0 (unimplemented!!!) */
+int *radix_sort ( void *a, size_t siz, int unit, int mm, int m, int *perm){
+ int *ll, *l, k, i, t, flag=1;
+ malloc2 (l, m-mm, "radix_sort", EXIT0);
+ ARY_FILL (l, 0, m-mm, -1);
+ malloc2 (ll, siz, "radix_sort: ll", {free2(l);EXIT0;});
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ FLOOP (i, 0, siz){
+ k = (*((int *)(((char *)a) + unit*i ))) - mm;
+ ll[i] = l[k];
+ l[k] = i;
+ }
+ if ( perm ){
+ i=0; FLOOP (k, 0, m-mm){
+ while ( l[k] >= 0 ){
+ t = l[k];
+ l[k] = ll[t];
+ ll[t] = perm[i];
+ i++;
+ }
+ }
+ memcpy (perm, ll, sizeof(int)*siz);
+ free ( ll);
+ free ( l);
+ return ( perm);
+ } else {
+ i=0; FLOOP (k, 0, m-mm){
+ while ( l[k] >= 0 ){
+ t = l[k];
+ l[k] = ll[t];
+ ll[t] = i;
+ i++;
+ }
+ }
+ free (l);
+ return (ll);
+ }
+}
+
+/* permutate structure array *tt of unit size unit of size num, according to perm array *pp */
+/* num has to be <INTHUGE/2 */
+/* unit<0 means decreasing order (un-implemented!!!) */
+void structure_permute (void *tt, int unit, int num, void *pp, int weight_siz){
+ int i, ii, *ip, flag=1;
+ char *tmp, *t=(char *)tt, *p=(char *)pp;
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ malloc2 (tmp, unit, "structure_permute: tmp", EXIT);
+ FLOOP (i, 0, num){
+ ip = (int *)(p + (sizeof(int)+weight_siz)*i + weight_siz);
+ if ( *ip< num && *ip != i ){
+ ii = i;
+ memcpy ( tmp, t + unit*i, unit);
+ while (1) {
+ if ( *ip == i ){
+ memcpy ( t+unit*ii, tmp, unit);
+ *ip += num;
+ break;
+ }
+ memcpy ( t+unit*ii, t+unit*(*ip), unit);
+ ii = *ip;
+ *ip += num;
+ ip = (int *)(p + (sizeof(int)+weight_siz)*ii + weight_siz);
+ }
+ } else *ip += num;
+ }
+ FLOOP (i, 0, num) *(int *)(p + (sizeof(int)+weight_siz)*i + weight_siz ) -= num;
+ free (tmp);
+}
+
+
+
+#endif
+
+
+/******************************************/
+/* ==== terminology for comments ====
+ range check: to check the input parameter is valid, or in the valid range.
+ If a function does not have this, its comment has "no range check"
+ */
+
+/* ==== rules for the name of functions and routines ====
+ init: initialization for an object, structure, etc. memory is allocated
+ if needed.
+ end: compared to init, termination of structures, etc.
+ free allocated memory if it exists, but not free itself.
+ different from ordinary new, create, del, free.
+
+ cpy: copy an object without allocating memory
+ dup: make a duplication of an object with allocating new memory
+
+ new: new. allocate memory for new object. also used for re-allocation from
+ the list of deleted objects
+ del: delete. free memory, or insert it to the list of deleted objects
+
+ ins : insert. insert an element (active, not deleted) to an object, possible
+ at the given position.
+ out : extract. extract an element, possibly specified, from an object.
+ it will be not deleted.
+ rm : extract, and delete
+ rmall: delete all (specified) elements of an object
+ mk : make. new+ins\81B
+ mv : move. move the elements from an object to another,
+ or change the position.
+
+ update : update an object, possibly of specified position, to the exact,
+ or to the current one.
+ chg : change the status of an object to the specified one.
+
+ prv: point the previous element
+ nxt: point the next element
+ end: the maximum size (allocated size) of an array, etc.
+ num: the (current) number of elements in an array, etc.
+ kth: for the use of "first k object"
+ tkth: for the use of "first k object from the end". to kth.
+ rnd: random
+ print: print structure and etc.
+ find: search or find an specified element from the set of structures, etc.
+*/
+
+/* ==== rules for the name of variables ====
+ - use i or j for the counter in loops
+ - use e for elements
+ - use k for the specified rank
+ - use f or flag for flagment
+ - use m for maximum value or minimum value
+ - use c for counters
+*/
+
+
--- /dev/null
+/* library for standard macros and functions
+ by Takeaki Uno 2/22/2002 e-mail: uno@nii.jp
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _stdlib2_h_
+#define _stdlib2_h_
+
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include<math.h>
+#include<time.h>
+#include<stdarg.h>
+
+#if defined(__cplusplus) && defined(__GNUC__)
+ #define _cplusplus_
+#endif
+
+#ifdef MULTI_CORE
+#include <pthread.h>
+#endif
+
+/* comment out the following line if no error check is needed */
+//#define ERROR_CHECK
+/* comment out the following if exit is not needed after each error routine */
+//#define ERROR_RET
+
+
+
+#ifdef ERROR_RET // definition of the process for errors
+ #define EXIT return
+ #define EXIT0 return(0)
+#else
+ #define EXIT exit(1)
+ #define EXIT0 exit(1)
+#endif
+
+// for dealing with files more than 2GB
+#define _LARGEFILE_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+// 64bit integer
+#ifndef LONG
+ #define LONG long long
+ #define LONGHUGE 9000000000000000000LL
+ #define LONGF "%lld"
+#endif
+
+// actual int (most proper sized integer, for the processor)
+#ifdef INT_64
+ #define INT LONG
+ #define INTF LONGF
+#else
+ #define INT int
+ #define INTF "%d"
+#endif
+
+#ifndef FILE_LONG
+ #define FILE_LONG LONG
+ #define FILE_LONGHUGE LONGHUGE
+ #define FILE_LONGF "%lld"
+#endif
+
+#define UINTHUGE 4000000000U
+#define INTHUGE 2000000000
+#define USHORTHUGE 32767
+#define SHORTHUGE 65535
+#define DOUBLEHUGE 999999999999999999999999999999.9
+#define ISEQUAL_VALUE 0.0000001
+#define ISEQUAL_VALUE2 0.00001
+#define PI 3.1415926535897932384647950288
+#define PI_INT 31416
+#define NPE 2.718281828459045235360287471352
+#define NPE_INT 27183
+#define MULTI_CORE_MAX 64
+
+#ifndef WEIGHT
+ #ifdef WEIGHT_DOUBLE
+ #define WEIGHT double
+ #define WEIGHTHUGE DOUBLEHUGE
+ #define WEIGHTF "%f"
+ #else // define WEIGHT by int if it's undefined
+ #define WEIGHT int
+ #define WEIGHTHUGE INTHUGE
+ #define WEIGHTF "%d"
+ #endif
+#endif
+
+#ifndef PERM
+ #ifdef PERM_LONG
+ #define PERM LONG
+ #define PERMHUGE LONGHUGE
+ #define PERMF "%lld"
+ #else
+ #define PERM int
+ #define PERMHUGE INTHUGE
+ #define PERMF "%d"
+ #endif
+#endif
+
+
+extern int common_int;
+extern size_t common_size_t;
+extern LONG common_LONG;
+extern INT common_INT, common_INT2;
+extern double common_double;
+extern char *common_pnt, *common_charp;
+extern FILE *common_FILE;
+extern WEIGHT common_WEIGHT, *common_WEIGHTp;
+extern char *ERROR_MES;
+extern int print_time_flag;
+typedef struct {
+ int i1, i2, i3, i4, i5, i6, i7, i8, i9;
+ LONG l1, l2, l3, l4, l5, l6, l7, l8, l9;
+ double d1, d2, d3, d4, d5, d6, d7, d8, d9;
+ char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
+ void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
+} PARAMS;
+extern PARAMS internal_params;
+
+/* swap macro for integer, double, char, and pointer */
+#define SWAP_INT(a,b) (common_LONG=a,a=b,b=common_LONG)
+#define SWAP_DOUBLE(a,b) (common_double=a,a=b,b=common_double)
+#ifdef _cplusplus_
+ #define SWAP_PNT(a,b) (common_pnt=(typeof(common_pnt))a,a=(typeof(a))b,b=(typeof(b))common_pnt)
+#else
+ #define SWAP_PNT(a,b) (common_pnt=(void *)a,a=(void *)b,b=(void *)common_pnt)
+#endif
+
+/* lock&unlock for multi-core mode */
+#ifdef MULTI_CORE
+ extern int SPIN_LOCK_dummy;
+ #define SPIN_LOCK(b,a) (SPIN_LOCK_dummy=(((b)>1)&&pthread_spin_lock(&(a))))
+ #define SPIN_UNLOCK(b,a) (SPIN_LOCK_dummy=(((b)>1)&&pthread_spin_unlock(&(a))))
+#else
+ #define SPIN_LOCK(b,a)
+ #define SPIN_UNLOCK(b,a)
+#endif
+
+#define TYPE_VEC 1
+#define TYPE_MAT 2
+#define TYPE_SVEC 3
+#define TYPE_SMAT 4
+#define TYPE_QUEUE 5
+#define TYPE_SETFAMILY 6
+#define TYPE_TRSACT 7
+#define TYPE_ALIST 8
+#define TYPE_MALIST 9
+#define TYPE_AGRAPH 10
+#define TYPE_SGRAPH 11
+#define TYPE_AHEAP 12
+#define TYPE_BASE 13
+#define TYPE_FSTAR 14
+#define TYPE_FILE2 15
+
+
+
+
+/* random */
+#define rnd(a) (random()%(a))
+#define prob(a) ((random()%65536)<(int)((a)*65536.0))
+
+#define MARK 1
+#define UNMARK 0
+#define TRUE 1
+#define FALSE 0
+
+/* equal/inequal with allowing numerical error for double */
+#define ISEQUAL(a,b) ((a)-(b)<ISEQUAL_VALUE&&(b)-(a)<ISEQUAL_VALUE)
+#define ISGREAT(a,b) ((a)-(b)>ISEQUAL_VALUE)
+#define ISLESS(a,b) ((b)-(a)>ISEQUAL_VALUE)
+#define RANGE(a,b,c) (((a)<=(b))&&((b)<=(c)))
+#define BITRM(a,b) ((a)-=((a)&(b)));
+
+/* macro for getting maximum/minimum of two values */
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define ENMAX(a,b) ((a)=((a)>(b)?(a):(b)))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define ENMIN(a,b) ((a)=((a)<(b)?(a):(b)))
+
+/* error routine */
+#define error(mes,x) do{ERROR_MES=mes;fprintf(stderr,"%s\n",mes);x;}while(0)
+#define error_num(mes,n,x) do{ERROR_MES=mes;fprintf(stderr,"%s: %g\n",mes,(double)(n));x;}while(0)
+#define error_str(mes,s,x) do{ERROR_MES=mes;fprintf(stderr,"%s: %s\n",mes,s);x;}while(0)
+#define print_err(...) fprintf(stderr,__VA_ARGS__)
+#define print_mes(flag,...) do{if((flag)&1)fprintf(stderr,__VA_ARGS__);}while(0)
+#define mfree(...) mfree_(NULL, __VA_ARGS__,(void *)1)
+
+
+/* basec array operations and loops */
+#define ARY_FILL(f,start,end,c) do{for(common_size_t=(start);common_size_t<(end);common_size_t++)(f)[common_size_t]=(c);}while(0)
+#define ARY_INS(f,b) do{(f).v[(f).t++]=(b);}while(0)
+#define ARY_FLOOP(V,i,x) for( (i)=0,x=(V).v[0] ; (i)<(V).t ; (i)++,x=(V).v[i])
+#define ARY_BLOOP(V,i,x) for( (i)=(V).t-1,x=i>0?(V).v[i]:0 ; (i)>=0 ; (i)--,x=i>0?(V).v[i]:0)
+#define FLOOP(i,x,y) for ((i)=(x) ; (i)<(y) ; (i)++)
+#define BLOOP(i,x,y) for ((i)=(x) ; ((i)--)>(y) ; )
+#define MLOOP(z,x,M) for ((z)=(x) ; *(z)<(M) ; (z)++)
+
+
+/* allocate memory, and exit with error message if fault */
+#ifdef _cplusplus_
+#define malloc2(f,b,c,x) do{if(!((f)=(typeof(f))malloc(((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define calloc2(f,b,c,x) do{if(!((f)=(typeof(f))calloc(sizeof((f)[0]),b))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define realloc2(f,b,c,x) do{if(!(f=(typeof(f))realloc(f,((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#else
+#define malloc2(f,b,c,x) do{if(!((f)=malloc(((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define calloc2(f,b,c,x) do{if(!((f)=calloc(sizeof((f)[0]),b))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define realloc2(f,b,c,x) do{if(!(f=realloc(f,((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#endif
+
+#define malloc2d(f,b,d,c,x) do{malloc2(f,b,c,x);malloc2((f)[0],(b)*(d)+2,c,{free2(f);x;});FLOOP(common_size_t,0,b)(f)[common_size_t]=&((f)[0][common_size_t*(d)]);}while(0)
+#define calloc2d(f,b,d,c,x) do{malloc2(f,b,c,x);calloc2((f)[0],(b)*(d)+2,c,{free2(f);x;});FLOOP(common_size_t,0,b)(f)[common_size_t]=&((f)[0][common_size_t*(d)]);}while(0)
+
+/* reallocate memory and expand the memory size */
+#define reallocx_(f,end,end2,e,c,x) do{realloc2(f,end2,c,x);FLOOP(common_size_t,end,end2)(f)[common_size_t]=(e);}while(0)
+#define reallocx(f,end,i,e,c,x) do{if((i)>=(end)){reallocx_(f,end,MAX((end)*2+100,(i)+1),e,c,x);end=MAX((end)*2,(i)+1);}}while(0)
+
+/* basic array operations */
+#define ARY_DUP(f,p,end,c,x) do{malloc2(f,end,c,x);memcpy(f,p,sizeof(*(f))*(end));}while(0)
+#define ARY_MAX(m,i,f,x,y) do{(m)=(f)[x];(i)=(x);FLOOP(common_INT,(x)+1,(y))if((m)<(f)[common_INT]){(i)=common_INT;(m)=(f)[i];}}while(0)
+#define ARY_MIN(m,i,f,x,y) do{(m)=(f)[x];(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)>(f)[common_INT]){(i)=common_INT;(m)=(f)[i];}}while(0)
+#define ARY_SUM(f,v,x,y) do{(f)=0;FLOOP(common_INT,x,y)(f)+=(v)[common_INT];}while(0)
+#define ARY_NORM(f,v,b) do{(f)=0;FLOOP(common_INT,0,b)(f)+=(v)[common_INT]*(v)[common_INT];(f)=sqrt(f);}while(0)
+#define ARY_NORMALIZE(v,b) do{ARY_NORM(common_double,v,b);FLOOP(common_INT,0,b)(v)[common_INT]/=common_double;}while(0)
+#define ARY_INPRO(f,u,v,b) do{(f)=0;for (common_INT=0 ; common_INT<(b)-3 ; common_INT+=4) (f)+=(u)[common_INT]*(v)[common_INT] + (u)[common_INT+1]*(v)[common_INT+1] + (u)[common_INT+2]*(v)[common_INT+2] + (u)[common_INT+3]*(v)[common_INT+3]; if (common_INT+1<(b)){(f)+=(u)[common_INT]*v[common_INT]+(u)[common_INT+1]*(v)[common_INT+1]; if (common_INT+2<(b)) (f)+=(u)[common_INT+2]*(v)[common_INT+2];} else if (common_INT<(b)) (f)+=(u)[common_INT]*(v)[common_INT];}while(0)
+
+//#define ARY_DIST(f,u,v,b) do{(f)=0;for (common_size_t=0 ; common_size_t<(b)-3 ; common_size_t+=4)(f)+=(u)[common_size_t]*(v)[common_size_t]; if (common_size_t+1<(b)){(f)+=(u)[common_size_t]*v[common_size_t]+(u)[common_size_t+1]*(v)[common_size_t+1]; if (common_size_t+2<(b)) (f)+=(u)[common_size_t+2]*(v)[common_size_t+2];} else if (common_size_t<b) (f)+=(u)[common_size_t]*(v)[common_size_t];}while(0)
+
+/* macros for permutation arrays */
+#define ARY_INIT_PERM(f,end) do{FLOOP(common_INT,0,end)(f)[common_INT]=common_INT;}while(0)
+#define ARY_INV_PERM_(f,p,end) do{ARY_FILL(f,0,end,-1);FLOOP(common_INT,0,end)if((p)[common_INT]>=0&&(p)[common_INT]<(end))(f)[(p)[common_INT]]=common_INT;}while(0)
+#define ARY_INV_PERM(f,p,end,c,x) do{malloc2(f,end,c,x);ARY_INV_PERM_(f,p,end);}while(0)
+#define ARY_RND_PERM_(f,end) do{(f)[0]=0;FLOOP(common_INT,1,end){common_INT2=rnd(common_INT+1);(f)[common_INT]=(f)[common_INT2];(f)[common_INT2]=common_INT;}}while(0)
+#define ARY_RND_PERM(f,end,c,x) do{malloc2(f,end,c,x);ARY_RND_PERM_(f,end);}while(0)
+ /* permute f so that f[i]=f[p[i]] (inverse perm). p will be destroyed (filled by end) */
+#define ARY_INVPERMUTE_(f,p,s,end) do{ FLOOP(common_INT,0,end){ if ( (p)[common_INT]<(end) ){ (s)=(f)[common_INT]; do { common_INT2=common_INT; common_INT=(p)[common_INT]; (f)[common_INT2]=(f)[common_INT]; (p)[common_INT2]=end; }while ( (p)[common_INT]<(end) ); (f)[common_INT2] = (s);}}}while(0)
+ /* permute f so that f[i]=f[p[i]] (inverse perm). not destroy p by allocating tmp memory */
+#define ARY_INVPERMUTE(f,p,s,end,c,x) do{ calloc2(common_pnt,end,c,x);FLOOP(common_INT,0,end){ if ( common_pnt[common_INT]==0 ){ (s)=(f)[common_INT]; do{ common_INT2=common_INT; common_INT=(p)[common_INT]; (f)[common_INT2]=(f)[common_INT]; common_pnt[common_INT2]=1; }while( common_pnt[common_INT]==0 ); (f)[common_INT2] = (s);}} free(common_pnt); }while(0)
+//#define ARY_PERM(f,p,s,mark,end) do{FLOOP(common_size_t,0,end){ }}while(0)
+
+/* macros for printing (writing to file) arrays */
+#define ARY_PRINT(f,x,y,a) do{FLOOP(common_size_t,x,y)printf(a,(f)[common_size_t]);printf("\n");}while(0)
+#define ARY_FPRINT(fp,f,x,y,a) do{FLOOP(common_size_t,x,y)fprintf((FILE *)fp,a,(f)[common_size_t]);fputc('\n',(FILE *)fp);}while(0)
+#define ARY_EXP(f,a,c,x) do{reallocx((f).v,a,(f).end,(f).t,e,c,x);}while(0)
+
+#define ST_MAX(m,i,S,a,x,y) do{(m)=(S)[x].a;(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)<(S)[common_INT].a){(i)=common_INT;(m)=(S)[i].a;}}while(0)
+#define ST_MIN(m,i,S,a,x,y) do{(m)=(S)[x].a;(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)>(S)[common_INT].a){(i)=common_INT;(m)=(S)[i].a;}}while(0)
+#define ST_SUM(k,S,a,x,y) do{(k)=0;FLOOP(common_INT,x,y)(k)+=(S)[common_INT].a;}while(0)
+#define ST_FILL(S,a,start,end,c) do{for(common_INT=(start);common_INT<(end);common_INT++)(S)[common_INT].a = (c);}while(0)
+#define ST_PRINT(S,a,x,y,f) do{FLOOP(common_size_t,x,y)printf(f,(S)[common_size_t].a );printf("\n");}while(0)
+
+
+
+/* a macro for open files with exiting if an error occurs */
+#define fopen2(f,a,b,c,x) do{if(!((f)=fopen(a,b))){ERROR_MES="file open error";fprintf(stderr,"file open error: %s, file name %s, open mode %s\n",c,a,b);x;}}while(0)
+#define FILE2_open(f,a,b,c,x) do{if(a)fopen2((f).fp,a,b,c,x);else(f).fp=NULL;malloc2((f).buf_org,FILE2_BUFSIZ+1,c,x);(f).buf=(f).buf_org;(f).buf_end=(f).buf_org-1;}while(0)
+#define FILE2_open_(f,a,c,x) do{(f).fp=a;malloc2((f).buf_org,FILE2_BUFSIZ+1,c,x);(f).buf=(f).buf_org;(f).buf_end=(f).buf_org-1;}while(0)
+
+/* macros for allocating memory with exiting if an error occurs */
+#define free2(a) do{if(a){free(a);(a)=NULL;}}while(0)
+#define free2d(a) do{if(a){free2((a)[0]);}free(a);(a)=NULL;}while(0)
+#define fclose2(a) do{if(a){fclose(a);(a)=NULL;}}while(0)
+
+/* macros for reading integers from file, d=0 read one-line, d=1 read all file */
+//#define ARY_SCAN(k,a,fp,d) do{(k)=0;do{do{FILE2_read_##a(&(fp));}while((FILE_err&6)==8-(d)*4);if(FILE_err&(4-2*(d)))break;(k)++;}while((FILE_err&(3-(d)))==0);}while(0)
+#define ARY_SCAN(k,a,fp,d) do{(k)=0;do{do{FILE2_read_##a(&(fp));}while((FILE_err&((d)*5))==5);if(RANGE(5+(d),FILE_err,6))break;(k)++;}while((FILE_err&(3-(d)))==0);}while(0)
+#define ARY_READ(f,a,k,fp) do{FLOOP(common_size_t,0,k){do{(f)[common_size_t]=FILE2_read_##a(&(fp));}while((FILE_err&6)==4);if(FILE_err&2)break;}}while(0)
+#define ARY_LOAD(f,a,k,n,d,c,x) do{FILE2_open(common_FILE2,n,"r",c,x);ARY_SCAN(k,a,common_FILE2,d);malloc2(f,(k)+1,c,x);FILE2_reset(&common_FILE2);ARY_READ(f,a,k,common_FILE2);FILE2_close(&common_FILE2);}while(0)
+#define ARY_WRITE(n,f,k,q,c,x) do{fopen2(common_FILE,n,"w",c,x);ARY_FPRINT(common_FILE,f,0,k,q);fclose(common_FILE);}while(0)
+
+/* macros for generalized queue; end mark is necessary for INTSEC */
+#define MQUE_FLOOP(V,z) for((z)=(V).v;(z)<(V).v+(V).t ; (z)++)
+
+#ifdef _cplusplus_
+ #define MQUE_FLOOP_(V,z,s) for((z)=(V).v ; (char *)(z)<((char *)(V).v)+(V).t*(s) ; (z)=(typeof(z))(((char *)(z))+(s)))
+#else
+ #define MQUE_FLOOP_(V,z,s) for((z)=(V).v ; (char *)(z)<((char *)(V).v)+(V).t*(s) ; (z)=(void *)(((char *)(z))+(s)))
+#endif
+
+#define MQUE_MLOOP(V,z,M) for((z)=(V).v; *((QUEUE_INT *)z)<(M) ; (z)++)
+
+/// !!! errr MQUE_INTSEC !!!!!
+#define MQUE_INTSEC(f,U,V) do{\
+common_INT=0;(f)=0;\
+FLOOP(common_INT2,0,(U).t){\
+ while(*((QUEUE_INT *)(&((V).v[common_INT])))<*((QUEUE_INT *)(&((U).v[common_INT2])))&&common_INT<(V).t){ \
+ if (++common_INT >= (V).t) break;\
+ }if(*((QUEUE_INT *)(&((V).v[common_INT])))==*((QUEUE_INT *)(&((U).v[common_INT2]))))(f)++;\
+}}while(0)
+#define MQUE_UNION(f,U,V) do{MQUE_INTSEC(f,U,V);(f)=(U).t+(V).t-(f);}while(0)
+#define MQUE_DIF(f,U,V) do{MQUE_INTSEC(f,U,V);(f)=(U).t+(V).t-(f)-(f);}while(0)
+#define MQUE_RM_DUP(V) do{\
+if((V).t>1){\
+ common_INT=1;\
+ FLOOP(common_INT2,1,(V).t){\
+ if ( *((QUEUE_INT *)(&((V).v[common_INT2-1]))) != *((QUEUE_INT *)(&((V).v[common_INT2]))) ) (V).v[common_INT++]=(V).v[common_INT2];\
+ } (V).t=common_INT;\
+ }\
+}while(0)
+
+#define MQUE_UNIFY(V,a) do{\
+if((V).t>1){\
+ common_INT=0;\
+ FLOOP(common_INT2,1,(V).t){\
+ if ( *((QUEUE_INT *)(&((V).v[common_INT2-1]))) != *((QUEUE_INT *)(&((V).v[common_INT2]))) ) (V).v[++common_INT]=(V).v[common_INT2];\
+ else *((a*)(((QUEUE_INT *)(&((V).v[common_INT2])))+1)) += *((a*)(((QUEUE_INT *)(&((V).v[common_INT2])))+1));\
+ } (V).t=common_INT+1;\
+}}while(0)
+
+
+
+
+#ifndef VEC_VAL
+ #ifdef VEC_VAL_CHAR
+ #define VEC_VAL char
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END 128
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%hhd"
+ #elif defined(VEC_VAL_UCHAR)
+ #define VEC_VAL unsigned char
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END 256
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%hhu"
+ #elif defined(VEC_VAL_INT)
+ #define VEC_VAL int
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END INTHUGE
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%d"
+ #else
+ #define VEC_VAL double
+ #define VEC_VAL2 double
+ #define VEC_VAL_END DOUBLEHUGE
+ #define VEC_VAL2_END DOUBLEHUGE
+ #define VEC_VALF "%f"
+ #endif
+#endif
+
+#ifndef VEC_ID
+ #ifdef VEC_ID_LONG
+ #define VEC_ID LONG
+ #define VEC_ID_END LONGHUGE
+ #define VEC_IDF "%lld"
+ #else
+ #define VEC_ID int
+ #define VEC_ID_END INTHUGE
+ #define VEC_IDF "%d"
+ #endif
+#endif
+
+/* vector */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ VEC_VAL *v;
+ VEC_ID end;
+ VEC_ID t;
+} VEC;
+
+extern VEC INIT_VEC;
+extern PERM common_PERM, *common_PERMp;
+extern VEC_VAL common_VEC_VAL, *common_VEC_VALp;
+extern VEC_ID common_VEC_ID;
+
+/* tranpose the matrix ; counting/transpose/memory_allocate */
+#define MQUE_DELIVERY_CNT(c,jump,f,y,M) do{ \
+FLOOP(common_VEC_ID, 0, (f).t){ \
+ MQUE_MLOOP( (f).v[common_VEC_ID], y, M){ \
+ if( (c)[*((QUEUE_INT *)y)] == 0 ) ARY_INS(jump, *((QUEUE_INT *)y)); \
+ (c)[*((QUEUE_INT *)y)]++; \
+ } \
+}}while(0)
+#define MQUE_DELIVERY(occ,jump,f,y,M) do{ \
+FLOOP (common_VEC_ID, 0, (f).t){ \
+ MQUE_MLOOP ((f).v[common_VEC_ID], y, M){ \
+ if( (occ)[*((QUEUE_INT *)y)].t == 0 ) ARY_INS( jump, *((QUEUE_INT *)y)); \
+ ARY_INS( (occ)[*((QUEUE_INT *)y)], common_VEC_ID); \
+ } \
+}}while(0)
+#ifdef _cplusplus_
+#define MQUE_ALLOC(Q,rows,rowt,unit,ext,x) do{ \
+common_size_t=0; \
+FLOOP (common_VEC_ID, 0, rows) common_size_t += rowt[common_VEC_ID]; \
+calloc2 (Q, (rows)+1, "MQUE_ALLOC: Q", x); \
+malloc2 (common_pnt, (common_size_t+(rows)*(ext)+2)*((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit)), "MQUE_ALLOC: Q.v", {free(Q);x;}); \
+FLOOP (common_VEC_ID, 0, rows){ \
+ (Q)[common_VEC_ID].end = rowt[common_VEC_ID]; \
+ (Q)[common_VEC_ID].v = (typeof((Q)[common_VEC_ID].v))common_pnt; \
+ common_pnt += ((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit))*(rowt[common_VEC_ID]+(ext));\
+}}while(0)
+#else
+#define MQUE_ALLOC(Q,rows,rowt,unit,ext,x) do{ \
+common_size_t=0; \
+FLOOP (common_VEC_ID, 0, rows) common_size_t += rowt[common_VEC_ID]; \
+calloc2 (Q, (rows)+1, "MQUE_ALLOC: Q", x); \
+malloc2 (common_pnt, (common_size_t+(rows)*(ext)+2)*((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit)), "MQUE_ALLOC: Q.v", {free(Q);x;}); \
+FLOOP (common_VEC_ID, 0, rows){ \
+ (Q)[common_VEC_ID].end = rowt[common_VEC_ID]; \
+ (Q)[common_VEC_ID].v = (void *)common_pnt; \
+ common_pnt += ((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit))*(rowt[common_VEC_ID]+(ext));\
+}}while(0)
+#endif
+
+/*********************************************************/
+
+#define SHOW_MESSAGE 1 // not print messages
+#define SHOW_PROGRESS 2 // show progress of the computation
+#define LOAD_PERM 8 // permute the nodes/items by something
+#define LOAD_RM_DUP 16 // duplicate items in each row, for loading data
+#define LOAD_INCSORT 32 // sort rows in increasing order, for loading data
+#define LOAD_DECSORT 64 // sort rows in decreasing order, for loading data
+#define LOAD_ELE 128 // load tuple-list file
+#define LOAD_TPOSE 256 // transpose the file when load
+#define LOAD_DBLBUF 512 // transpose the file when load
+#define LOAD_WSORT 1024 // sort rows by their weights
+#define LOAD_SIZSORT 2048 // sort rows by their sizes
+#define LOAD_DECROWSORT 4096 // sort rows in decreasing order
+
+#define LOAD_EDGEW 16384 // read edge weight
+#define LOAD_ARCW 32768 // read arc weight
+#define LOAD_NODEW 65536 // read node weight
+#define LOAD_BIPARTITE 131072 // read bipartite graph
+#define LOAD_EDGE 262144 // read edge
+#define LOAD_ARC 524288 // read arc
+
+#define FILE_COUNT_ROWT 32 // count size of each row
+#define FILE_COUNT_CLMT 64 // count size of each column
+
+#define FILE2_BUFSIZ 16384
+typedef struct { // structure for fast file reader routines
+ unsigned char type; // type definition
+ FILE *fp;
+ char *buf_org, *buf, *buf_end; // head/current/tail of buffer
+} FILE2;
+extern FILE2 INIT_FILE2, common_FILE2;
+
+void FILE2_flush (FILE2 *fp);
+void FILE2_close (FILE2 *fp);
+void FILE2_closew (FILE2 *fp);
+void FILE2_reset (FILE2 *fp);
+int FILE2_getc (FILE2 *fp);
+void FILE2_puts (FILE2 *fp, char *s);
+void FILE2_putc (FILE2 *fp, char c);
+
+/* message output */
+//void print_mes (int flag, char *mes, ...);
+//void print_err (char *mes, ...);
+void mfree_(void *x, ...);
+
+/* compute the minimum prime no less than n */
+LONG min_prime (LONG n);
+
+/* decompose the string by separator, and set v[i] to each resulted string.
+ consecutive separators are regarded as one separator. */
+int string_decompose (char **v, char *s, char sep, int max);
+
+/* make two random numbers under normal distribution N(0,1) */
+void rand_mk_2normal (double *a, double *b);
+/* make a random point on a supersphere of d-dim., and set to double array already allocated */
+void rand_d_gaussian (double *p, int d);
+void rand_sphere (double *p, int d);
+
+
+
+/* Read an integer from the file and return it,
+ with read through the non-numeric letters.
+ If it reaches to the end-of-file, then set FILE_err=2, if it reads a
+ newline, then set FILE_err=1.
+ If read either the end-of-file or newline before reading an integer,
+ return -1 */
+FILE_LONG FILE2_read_int (FILE2 *fp);
+double FILE2_read_double (FILE2 *fp);
+WEIGHT FILE2_read_WEIGHT (FILE2 *fp);
+
+/* fast file routine, print number, c is the char to be printed preceding to the number
+ if c==0, nothing will be printed preceding the number
+ if len<0 then the #digits following '.' does not change (filed by '0') */
+void FILE2_print_int (FILE2 *fp, LONG n, char c);
+void FILE2_print_real (FILE2 *fp, double n, int len, char c);
+void FILE2_print_WEIGHT (FILE2 *fp, WEIGHT w, int len, char c);
+void FILE2_printf (FILE2 *fp, char *mes, ...);
+
+/* print a real number in a good style */
+void fprint_real (FILE *fp, double f);
+void print_real (double f);
+void fprint_WEIGHT (FILE *fp, WEIGHT f);
+void print_WEIGHT (WEIGHT f);
+
+#define FILE_COUNT_INT VEC_ID
+#define FILE_COUNT_INTF VEC_IDF
+typedef struct {
+ int flag;
+ FILE_COUNT_INT clms, rows, eles, clm_end, row_end, row_btm, clm_btm; // #rows, #column, #elements, minimum elements
+ FILE_COUNT_INT row_min, row_max, clm_min, clm_max; // maximum/minimum size of column
+ FILE_COUNT_INT *rowt, *clmt; // size of each row/clmn
+ WEIGHT total_rw, total_cw, *rw, *cw; // WEIGHTs for rows/columns ... reserved.
+ FILE_COUNT_INT rw_end, cw_end;
+ PERM *rperm, *cperm; // permutation (original->internal) of rows and columns
+} FILE_COUNT;
+
+extern FILE_COUNT INIT_FILE_COUNT;
+
+/* count the clms, rows, items, each row size, each column size */
+/* file types can be, array list and element list*/
+/* support transpose */
+FILE_COUNT FILE2_count (FILE2 *fp, int flag, int skip_rows, int int_rows, int skip_clms, int int_clms, size_t row_limit);
+
+/******************* integer array routines **************************/
+
+/******************************* permutation routines ****************/
+/* permutation is given by an integer array */
+
+/* sort an array of size "siz", composed of a structure of size "unit" byte
+ in the order of perm */
+/* use temporary memory of siz*unit byte */
+//void perm_struct (void *a, int unit, int *perm, size_t siz);
+
+/* SLIST:very simple one-sided list */
+void SLIST_init (int *l, int num, int siz);
+void SLIST_end (int *l);
+#define SLIST_INS(l,m,e) (l[e]=l[m],l[m]=e);
+
+#define QQSORT_ELE(a,x) ((a *)(&(common_pnt[(*((PERM *)(x)))*common_int])))
+#define QQSORT_ELEt(a,x) (((a *)&(common_pnt[(*((PERM *)x))*common_int]))->t)
+/* quick sort macros */
+#define QSORT_TYPE(a,b) \
+int qsort_cmp_##a (const void *x, const void *y){ \
+ if ( *((b *)x) < *((b *)y) ) return (-1); else return ( *((b *)x) > *((b *)y) ); \
+} \
+int qsort_cmp__##a (const void *x, const void *y){ \
+ if ( *((b *)x) > *((b *)y) ) return (-1); else return ( *((b *)x) < *((b *)y) ); \
+} \
+int qqsort_cmp_##a (const void *x, const void *y){ \
+ b *xx=QQSORT_ELE(b,x), *yy=QQSORT_ELE(b,y); \
+ if ( *xx < *yy ) return (-1); \
+ else return ( *xx > *yy ); \
+} \
+int qqsort_cmp__##a (const void *x, const void *y){ \
+ b *xx=QQSORT_ELE(b,x), *yy=QQSORT_ELE(b,y); \
+ if ( *xx > *yy ) return (-1); \
+ else return ( *xx < *yy ); \
+} \
+void qsort_##a (b *v, size_t siz, int unit){ \
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (b); \
+ if (unit<0) qsort (v, siz, -unit, qsort_cmp__##a); else qsort (v, siz, unit, qsort_cmp_##a); \
+} \
+void qsort_perm__##a (b *v, size_t siz, PERM *perm, int unit){ \
+ ARY_INIT_PERM(perm,siz); \
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (b); \
+ common_int=MAX(unit,-unit); common_pnt=(char *)v; \
+ if (unit<0) qsort (perm, siz, sizeof(PERM), qqsort_cmp__##a); \
+ else qsort (perm, siz, sizeof(PERM), qqsort_cmp_##a); \
+} \
+PERM *qsort_perm_##a (b *v, size_t siz, int unit){ \
+ PERM *perm; malloc2(perm, siz, "qsort_perm_##a:perm", EXIT0); \
+ qsort_perm__##a (v, siz, perm, unit); return(perm); \
+}
+#define QSORT_TYPE_HEADER(a,b) \
+int qsort_cmp_##a (const void *x, const void *y); \
+int qsort_cmp__##a (const void *x, const void *y); \
+int qqsort_cmp_##a (const void *x, const void *y); \
+int qqsort_cmp__##a (const void *x, const void *y); \
+void qsort_##a(b *v, size_t siz, int unit); \
+void qsort_perm__##a(b *v, size_t siz, PERM *perm, int unit); \
+PERM *qsort_perm_##a(b *v, size_t siz, int unit);
+
+QSORT_TYPE_HEADER(int, int)
+QSORT_TYPE_HEADER(uint, unsigned int)
+QSORT_TYPE_HEADER(double, double)
+QSORT_TYPE_HEADER(char, char)
+QSORT_TYPE_HEADER(uchar, unsigned char)
+QSORT_TYPE_HEADER(short, short)
+QSORT_TYPE_HEADER(ushort, unsigned short)
+QSORT_TYPE_HEADER(WEIGHT, WEIGHT)
+QSORT_TYPE_HEADER(LONG, LONG)
+QSORT_TYPE_HEADER(VEC_ID, VEC_ID)
+QSORT_TYPE_HEADER(VEC_VAL, VEC_VAL)
+QSORT_TYPE_HEADER(VEC_VAL2, VEC_VAL2)
+QSORT_TYPE_HEADER(FILE_COUNT_INT, FILE_COUNT_INT)
+
+int qsort_cmp_VECt (const void *x, const void *y);
+int qsort_cmp__VECt (const void *x, const void *y);
+void qsort_VECt (VEC *v, size_t siz, int unit);
+int qqsort_cmp_VECt (const void *x, const void *y);
+int qqsort_cmp__VECt (const void *x, const void *y);
+void qsort_perm__VECt (VEC *v, size_t siz, PERM *perm, int unit);
+PERM *qsort_perm_VECt (VEC *v, size_t siz, int unit);
+
+/* sort index(int)/WEIGHT array and return the indices of the result */
+/* perm[i*2] := rank of ith cell */
+/* perm[i*2+1] := index of ith smallest cell */
+/* flag!=NULL => opposite direction sort */
+
+//int *int_index_sort (int *w, size_t siz, int flag);
+//int *WEIGHT_index_sort (WEIGHT *w, size_t siz, int flag);
+
+/* radix sort for array of structures, by their integer members
+ ranging from mm to m */
+/* sort array "perm" according to (int/void*) array "a".
+ if perm==NULL, allocate memory and for perm */
+/* return the permutation array of the result of the sorting
+ in the decreasing order if unit<0 (unimplemented!!!) */
+int *radix_sort (void *a, size_t siz, int unit, int mm, int m, int *perm);
+
+/* permutate structure array *tt of unit size unit of size num, according to perm array *pp */
+/* num has to be <INTHUGE/2 */
+/* unit<0 means decreasing order (un-implemented!!!) */
+void structure_permute (void *tt, int unit, int num, void *pp, int weight_siz);
+
+#ifdef STDLIB2_RADIX_SORT // radix sort with 1M byte static memory
+void intarray_sort_iter (unsigned int *a, size_t siz, int unit);
+void intarray_sort_iter_ (unsigned int *a, size_t siz, int unit);
+void intarray_sort (unsigned *a, size_t siz, int unit);
+#endif
+
+ /* bitmasks, used for bit operations */
+extern int BITMASK_UPPER1[32];
+extern int BITMASK_UPPER1_[32];
+extern int BITMASK_LOWER1[32];
+extern int BITMASK_LOWER1_[32];
+extern int BITMASK_1[32];
+extern int BITMASK_31[32];
+extern int BITMASK_16[8];
+extern int BITMASK_UPPER16[8];
+extern int BITMASK_LOWER16[8];
+extern int BITMASK_FACT16[8];
+
+
+#endif
+
+
+/******************************************/
+/* ==== terminology for comments ====
+ range check: to check the input parameter is valid, or in the valid range.
+ If a function does not have this, its comment has "no range check"
+ */
+
+/* ==== rules for the name of functions and routines ====
+ init: initialization for an object, structure, etc. memory is allocated
+ if needed.
+ end: compared to init, termination of structures, etc.
+ free allocated memory if it exists, but not free itself.
+ different from ordinary new, create, del, free.
+
+ cpy: copy an object without allocating memory
+ dup: make a duplication of an object with allocating new memory
+
+ new: new. allocate memory for new object. also used for re-allocation from
+ the list of deleted objects
+ del: delete. free memory, or insert it to the list of deleted objects
+
+ ins : insert. insert an element (active, not deleted) to an object, possible
+ at the given position.
+ out : extract. extract an element, possibly specified, from an object.
+ it will be not deleted.
+ rm : extract, and delete
+ rmall: delete all (specified) elements of an object
+ mk : make. new+ins\81B
+ mv : move. move the elements from an object to another,
+ or change the position.
+
+ update : update an object, possibly of specified position, to the exact,
+ or to the current one.
+ chg : change the status of an object to the specified one.
+
+ prv: point the previous element
+ nxt: point the next element
+ end: the maximum size (allocated size) of an array, etc.
+ num: the (current) number of elements in an array, etc.
+ kth: for the use of "first k object"
+ tkth: for the use of "first k object from the end". to kth.
+ rnd: random
+ print: print structure and etc.
+ find: search or find an specified element from the set of structures, etc.
+*/
+
+/* ==== rules for the name of variables ====
+ - use i or j for the counter in loops
+ - use e for elements
+ - use k for the specified rank
+ - use f or flag for flagment
+ - use m for maximum value or minimum value
+ - use c for counters
+*/
+
+
--- /dev/null
+/* QUEUE based Transaction library, including database reduction.
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _trsact_c_
+#define _trsact_c_
+
+// #define WEIGHT_DOUBLE
+
+#include"trsact.h"
+#include"base.c"
+#include"vec.c"
+
+/***********************************/
+/* print transactions */
+/***********************************/
+void TRSACT_print (TRSACT *T, QUEUE *occ, PERM *p){
+ VEC_ID i, t;
+ QUEUE_ID j;
+ QUEUE_INT e;
+ FLOOP (i, 0, occ? occ->t: T->T.t){
+ t = occ? *((QUEUE_INT *)(&(((char *)(occ->v))[i*T->occ_unit]))): i;
+ if ( occ ) printf (QUEUE_INTF "::: ", t);
+ ARY_FLOOP (T->T.v[t], j, e){
+ printf (QUEUE_INTF, p? p[e]: e);
+ if ( T->T.w ) printf ("(" WEIGHTF ")", T->T.w[t][j]);
+ printf (",");
+ }
+ if ( T->w ) printf (" :" WEIGHTF " ", T->w[t]);
+ printf (" (" QUEUE_INTF ")\n", T->T.v[t].end);
+ }
+}
+
+/*
+void TRSACT_prop_print (TRSACT *T){
+ print_err ("trsact: %s", P->trsact_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %zd", P->TT.rows_org, P->TT.clms_org, P->TT.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT.T.t, P->TT.T.clms, P->TT.T.eles);
+ if ( P->trsact_wfname ) print_err (" ,weightfile %s", P->trsact_wfname);
+ if ( P->trsact_wfname2 ) print_err (" ,2nd-weightfile %s", P->trsact_wfname2);
+ if ( P->trsact_pfname ) print_err (" ,item-order-file %s", P->trsact_pfname);
+ print_err ("\n");
+}
+*/
+
+/* initialization of structure TRSACT */
+void TRSACT_init (TRSACT *T){
+ T->type = TYPE_TRSACT;
+ T->flag = 0;
+ T->T = INIT_SETFAMILY;
+ T->clms_org = T->clm_max = 0;
+ T->rows_org = T->row_max = T->end1 = T->sep = 0;
+ T->perm = T->loaded_perm = T->loaded_inperm = NULL;
+ T->trperm = NULL;
+ T->w = T->pw = NULL;
+
+ T->clm_lb = 0;
+ T->clm_ub = VEC_ID_END;
+ T->row_lb = 0;
+ T->row_ub = QUEUE_IDHUGE;
+ T->w_lb = -WEIGHTHUGE; T->w_ub = WEIGHTHUGE;
+
+ T->eles_org = 0;
+ T->total_w = T->total_pw = T->total_w_org = T->total_pw_org =0;
+
+ T->jump = INIT_QUEUE;
+ T->str_num = 0;
+ T->head = T->strID = NULL;
+
+ T->th = 1;
+ T->mark = NULL;
+ T->shift = NULL;
+ T->occ_unit = sizeof(QUEUE_INT);
+ T->OQ = NULL;
+ T->sc = NULL;
+
+ T->new_t = 0;
+ T->buf = INIT_BASE;
+ T->wbuf = INIT_BASE;
+ T->occ_unit = sizeof(QUEUE_INT);
+}
+
+/**************************************************************/
+void TRSACT_end (TRSACT *T){
+ if ( T->OQ ){ free2 (T->OQ->v ); free2 (T->OQ[T->T.clms].v); }
+ free2 (T->T.w);
+ SETFAMILY_end (&T->T);
+ if ( T->w != T->pw ) free2 (T->pw);
+ mfree (T->w, T->perm, T->trperm, T->loaded_perm, T->loaded_inperm);
+ mfree (T->mark, T->shift, T->sc, T->OQ, T->head, T->strID);
+ QUEUE_end (&T->jump);
+ BASE_end (&T->buf);
+ BASE_end (&T->wbuf);
+ TRSACT_init (T);
+}
+
+/*****************************************/
+/* scan file "fp" with weight file wfp and count #items, #transactions in the file. */
+/* count weight only if wfp!=NULL */
+/* T->rows_org, clms_org, eles_org := #items, #transactions, #all items */
+/* ignore the transactions of size not in range T->clm_lb - clm_ub */
+/* T->total_w, total_pw := sum of (positive) weights of transactions */
+/* C->clmt[i],C->cw[i] := the number/(sum of weights) of transactions including i */
+/****************************************/
+void TRSACT_file_count (TRSACT *T, FILE_COUNT *C, FILE2 *fp, char *wf){
+ QUEUE_INT i, item, kk=0, k, jump_end=0;
+ WEIGHT w, s;
+ VEC_ID *jump=NULL;
+ FILE2 wfp;
+
+ if ( wf ){
+ FILE2_open (wfp, wf, "r", "TRSACT_file_count:weight file", goto ERR);
+ ARY_SCAN (kk, WEIGHT, wfp, 1);
+ kk += T->rows_org;
+ realloc2 (C->rw, kk+1, "TRSACT_file_count: C->rw", goto ERR);
+ FILE2_reset (&wfp);
+ ARY_READ (C->rw, double, kk, wfp);
+ ARY_MIN (w, i, C->rw, 0, kk);
+ if ( w<0 ) T->flag |= TRSACT_NEGATIVE;
+ FILE2_close (&wfp);
+ }
+ do {
+ s=0;
+ k=0;
+ w = wf? (T->rows_org<kk? C->rw[T->rows_org]: TRSACT_DEFAULT_WEIGHT): 1;
+ do {
+ item = FILE2_read_int (fp);
+ if ( (FILE_err&4)==0 ){
+ ENMAX (T->clms_org, item+1); // update #items
+ reallocx (jump, jump_end, k, 0, "TRSACT_file_count: jump", goto ERR);
+ jump[k] = item;
+ k++;
+ s += wf? (item<kk? MAX(C->rw[item],0): TRSACT_DEFAULT_WEIGHT): 1;
+
+ // count/weight-sum for the transpose mode
+ reallocx (C->clmt, C->clm_end, item, 0, "TRSACT_file_count:clmt",goto ERR);
+ C->clmt[item]++;
+ if ( !(T->flag&LOAD_TPOSE) ){
+ reallocx (C->cw, C->cw_end, item, 0, "TRSACT_file_count: cw", goto ERR);
+ C->cw[item] += MAX(w,0); // sum up positive weights
+ }
+ }
+ } while ( (FILE_err&3)==0);
+
+ // count/weight-sum for the transpose mode
+ reallocx (C->rowt, C->row_end, T->rows_org, 0, "TRSACT_file_count:rowt", goto ERR);
+ C->rowt[T->rows_org] = k;
+ if ( T->flag&LOAD_TPOSE ){
+ reallocx (C->cw, C->cw_end, T->rows_org, 0, "TRSACT_file_count: cw", goto ERR);
+ C->cw[T->rows_org] = s; // sum up positive weights
+ }
+ if ( k==0 && FILE_err&2 ) break;
+ T->rows_org++; // increase #transaction
+
+ if ( !wf ) s = k; // un-weighted case; weighted sum is #included-items
+ if ( k==0 ){
+ T->str_num++; // increase #streams if empty transaction is read
+ } else {
+ T->eles_org += k;
+ if ( (!(T->flag&LOAD_TPOSE) && !RANGE (T->row_lb, k, T->row_ub))
+ || ((T->flag&LOAD_TPOSE) && (!RANGE(T->w_lb, s, T->w_ub) || !RANGE (T->clm_lb, k, T->clm_ub)) ) ) FLOOP (i, 0, k) C->clmt[jump[i]]--;
+ }
+ } while ( (FILE_err&2)==0);
+ free2 (jump);
+ // swap the variables in transpose mode
+ if ( C->rw == NULL ){ T->total_w_org = T->total_pw_org = T->rows_org; return; }
+ C->clm_btm = MIN(kk, T->rows_org);
+ reallocx (C->rw, kk, T->rows_org, TRSACT_DEFAULT_WEIGHT, "TRSACT_file_count: rw", goto ERR);
+ FLOOP (k, 0, T->rows_org){
+ T->total_w_org += C->rw[k];
+ T->total_pw_org += MAX(C->rw[k],0);
+ }
+ return;
+ ERR:;
+ mfree (C->rw, C->cw, C->clmt, C->rowt, jump);
+ EXIT;
+}
+
+/* allocate memory, set permutation, and free C.clmt,rowt,rw,cw */
+int TRSACT_alloc (TRSACT *T, char *pfname, FILE_COUNT *C){
+ VEC_ID t, tt=0, ttt=T->clms_org, h, flag, org;
+ FILE_COUNT_INT *ct;
+ size_t s=0;
+ PERM *q, *p=NULL;
+ char *buf;
+
+ // swap variables in the case of transpose
+ if ( T->flag & LOAD_TPOSE ){
+ SWAP_INT (T->clms_org, T->rows_org);
+ SWAP_PNT (C->clmt, C->rowt);
+ }
+
+ if ( T->flag&TRSACT_SHRINK ) T->flag |= LOAD_DBLBUF;
+ // count valid columns/elements
+
+ if ( pfname && !(T->flag&TRSACT_WRITE_PERM) ){
+ ARY_LOAD (p, QUEUE_INT, ttt, pfname, 1, "TRSACT_load: item order file", EXIT0);
+ } else {
+ if ( T->flag&LOAD_PERM ){
+ if ( T->flag&TRSACT_FRQSORT )
+ p = qsort_perm_WEIGHT (C->cw, T->clms_org, (T->flag&LOAD_INCSORT)?1:-1);
+ else p = qsort_perm_FILE_COUNT_INT (C->clmt, T->clms_org, (T->flag&LOAD_INCSORT)?1:-1);
+ }
+ if ( pfname ) ARY_WRITE (pfname, p, T->clms_org, PERMF " ", "TRSACT_alloc: item-order output", EXIT0);
+ }
+ malloc2 (C->cperm, T->clms_org, "TRSACT_alloc: cperm", EXIT0);
+ ARY_FILL (C->cperm, 0, T->clms_org, MAX(T->clms_org, ttt));
+ for ( tt=ttt ; tt<T->clms_org ; tt++ ) C->cperm[tt] = tt; // filling perm of remaining items
+
+ FLOOP (t, 0, MAX(ttt, T->clms_org)){
+ tt = (p&&t<ttt)? p[t]: t;
+ if ( tt >= T->clms_org ) continue;
+ if ( RANGE(T->w_lb, C->cw[tt], T->w_ub) && RANGE (T->clm_lb, C->clmt[tt], T->clm_ub)){
+ s += C->clmt[tt];
+ C->cperm[tt] = T->T.clms++;
+ } else C->cperm[tt] = T->clms_org+1;
+ }
+ free2 (p);
+
+ // count valid rows/elements
+ if ( T->flag&(LOAD_SIZSORT+LOAD_WSORT) ){
+ if ( T->flag&LOAD_WSORT && C->rw )
+ p = qsort_perm_WEIGHT (C->rw, T->rows_org, (T->flag&LOAD_DECROWSORT)?-1:1);
+ else p = qsort_perm_FILE_COUNT_INT (C->rowt, T->rows_org, (T->flag&LOAD_DECROWSORT)?-1:1);
+ }
+ malloc2 (C->rperm, T->rows_org, "TRSACT_alloc: rperm", EXIT0);
+ FLOOP (t, 0, T->rows_org){ // compute #elements according to rowt, and set rperm
+ tt = p? p[t]: t;
+ if ( RANGE (T->row_lb, C->rowt[tt], T->row_ub) ){
+ C->rperm[tt] = T->T.t++;
+ T->T.eles += C->rowt[t];
+ } else C->rperm[tt] = T->rows_org+1;
+ }
+
+ free2 (p); free2 (C->cw);
+ flag = (T->T.eles > s && !(T->flag & LOAD_TPOSE) );
+ if ( flag ) T->T.eles = s;
+
+ T->T.end = T->T.t * ((T->flag&LOAD_DBLBUF)? 2: 1)+1;
+ malloc2 (T->w, T->T.end, "TRSACT_alloc: T->w", EXIT0);
+ if ( TRSACT_NEGATIVE ) malloc2 (T->pw, T->T.end, "TRSACT_alloc: T->pw", EXIT0);
+ else T->pw = NULL;
+ malloc2 (T->trperm, T->T.t, "TRSACT_alloc: T->trperm", EXIT0);
+ malloc2 (T->T.v, T->T.end, "TRSACT_alloc: T->T.v", EXIT0);
+ malloc2 (buf, (T->T.eles+T->T.end+1)*T->T.unit, "TRSACT_alloc: T->T.buf", EXIT0);
+ T->T.buf = (QUEUE_INT *)buf;
+ malloc2 (T->perm, T->T.clms+1, "TRSACT_alloc: T->perm", EXIT0);
+ QUEUE_alloc (&T->jump, T->T.clms+1);
+ BASE_alloc (&T->buf, sizeof(QUEUE_INT), MAX(T->row_max*4, (T->T.eles+T->T.end+1)/10+100));
+ BASE_alloc (&T->wbuf, sizeof(WEIGHT), MAX(T->row_max*4, (T->T.eles+T->T.end+1)/10+100));
+ if ( T->flag&TRSACT_SHRINK ){
+ malloc2 (T->mark, T->T.end, "TRSACT_alloc: mark", EXIT0);
+ malloc2 (T->shift, T->T.end, "TRSACT_alloc: shift", EXIT0);
+ calloc2 (T->sc, T->T.clms, "TRSACT_alloc: sc", EXIT0);
+ }
+ if ( T->flag&TRSACT_MULTI_STREAM ){
+ malloc2 (T->head, T->str_num+2, "TRSACT_alloc: haed", EXIT0);
+ malloc2 (T->strID, (T->flag&LOAD_TPOSE)?T->T.clms:T->T.end, "TRSACT_alloc:ID", EXIT0);
+ }
+ if ( T->flag&TRSACT_UNION )
+ calloc2 (T->T.w, T->T.end, "TRSACT_alloc: T->T.w", EXIT0);
+
+if ( ERROR_MES ) return(0);
+
+ // set variables w.r.t rows
+ tt=0; FLOOP (t, 0, T->rows_org){
+ if ( C->rperm[t] <= T->rows_org ){
+ T->T.v[tt] = INIT_QUEUE;
+ T->trperm[tt] = t;
+ C->rperm[t] = tt;
+ T->w[tt] = C->rw? C->rw[t]: 1;
+ if ( T->pw ) T->pw[tt] = MAX (T->w[tt], 0);
+ if ( !flag ){
+ T->T.v[tt].v = (QUEUE_INT *)buf;
+ buf += (C->rowt[t]+1)*T->T.unit;
+ }
+ tt++;
+ }
+ }
+ free2 (C->rw);
+ // make the inverse perm of items
+ FLOOP (t, 0, T->clms_org)
+ if ( C->cperm[t] <= T->clms_org ) T->perm[C->cperm[t]] = t;
+
+ // set head of each stream, and stream ID of each transaction
+ if ( T->flag&TRSACT_MULTI_STREAM ){
+ malloc2 (T->head, T->str_num+2, "TRSACT_alloc: haed", EXIT0);
+ malloc2 (T->strID, (T->flag&LOAD_TPOSE)?T->T.clms:T->T.end, "TRSACT_alloc:ID", EXIT0);
+ }
+ org = (T->flag&LOAD_TPOSE)? T->clms_org: T->rows_org;
+ q = (T->flag&LOAD_TPOSE)? C->cperm: C->rperm;
+ ct = (T->flag&LOAD_TPOSE)? C->clmt: C->rowt;
+ h=1; tt=0; FLOOP (t, 0, org){
+ if ( q[t] <= org ){
+ if ( t == T->end1 && T->sep==0 ) T->sep = tt;
+ if ( t == T->sep && T->sep>0 ) T->sep = tt;
+ if ( T->strID ) T->strID[tt] = h;
+ tt++;
+ }
+ if ( T->head && ct[t]==0 ) T->head[h++] = tt+1;
+ }
+
+ T->new_t = T->T.t;
+ free2 (C->rowt); free2 (C->clmt);
+ return ( flag );
+}
+
+
+/* load the file to allocated memory according to permutation, and free C.rw, C.cw */
+void TRSACT_file_read (TRSACT *T, FILE2 *fp, FILE_COUNT *C, VEC_ID *t, int flag){
+ QUEUE_INT item;
+
+ FILE2_reset (fp);
+ do {
+ if ( flag ) T->T.v[*t].v = *t? T->T.v[*t-1].v + T->T.v[*t-1].t +1: T->T.buf;
+ do {
+ item = FILE2_read_int (fp);
+ if ( (FILE_err&4)==0 ){
+// printf ("%d %d %d %d\n", C->rperm[*t], T->rows_org, C->cperm[item], T->clms_org );
+ if ( T->flag&LOAD_TPOSE ){
+ if ( C->rperm[item]<=T->rows_org && C->cperm[*t]<=T->clms_org )
+ ARY_INS (T->T.v[ C->rperm[item] ], C->cperm[*t]);
+ } else if ( C->rperm[*t]<=T->rows_org && C->cperm[item]<=T->clms_org )
+ ARY_INS (T->T.v[ C->rperm[*t] ], C->cperm[item]);
+ }
+ } while ( (FILE_err&3)==0);
+ (*t)++;
+ } while ( (FILE_err&2)==0 );
+}
+
+/* sort the transactions and items according to the flag, allocate OQ, and database reduction */
+void TRSACT_sort (TRSACT *T, FILE_COUNT *C, int flag){
+ VEC_ID t, *p;
+ int f;
+ PERM pp;
+ QUEUE Q;
+ QUEUE_ID i;
+
+ FLOOP (t, 0, T->T.t)
+ T->T.v[t].v[T->T.v[t].t] = T->T.clms;
+ if ( flag )
+ flag = (T->flag&(LOAD_SIZSORT+LOAD_WSORT)? ((T->flag&LOAD_DECROWSORT)? -1:1):0) *sizeof(QUEUE);
+ if ( flag ){ // sort rows for the case that some columns are not read
+ qsort_perm__VECt ((VEC *)T->T.v, T->T.t, C->rperm, flag);
+ ARY_INVPERMUTE (T->T.v, C->rperm, Q, T->T.t, "TRSACT_sort: ARY_INVPERMUTE", EXIT);
+ ARY_INVPERMUTE_ (T->trperm, C->rperm, pp, T->T.t);
+ }
+ free2 (C->rperm); free2 (C->cperm);
+
+ if ( T->flag & LOAD_PERM ) flag = 1;
+ else flag = (T->flag&LOAD_INCSORT)? 1: ((T->flag&LOAD_DECSORT)? -1: 0);
+ if ( flag ) FLOOP (t, 0, T->T.t) qsort_QUEUE_INT (T->T.v[t].v, T->T.v[t].t, flag);
+ if ( T->flag & LOAD_RM_DUP ) FLOOP (t, 0, T->T.t) MQUE_RM_DUP (T->T.v[t]);
+ ST_MAX (T->row_max, i, T->T.v, t, 0, T->T.t);
+
+ if ( T->flag&(TRSACT_ALLOC_OCC+TRSACT_SHRINK) ){
+ calloc2 (p, T->T.clms, "TRSACT_sort: p", EXIT);
+ QUEUE_delivery (NULL, p, NULL, T->T.v, NULL, T->T.t, T->T.clms);
+ ARY_MAX (T->clm_max, i, p, 0, T->T.clms);
+ MQUE_ALLOC (T->OQ, T->T.clms, p, T->occ_unit, 1, EXIT);
+ QUEUE_alloc (&T->OQ[T->T.clms], MAX(T->T.t, T->clm_max));
+ FLOOP (i, 0, T->T.clms+1) T->OQ[i].end = 0; // end is illegally set to 0, for the use in "TRSACT_find_same"
+ ARY_INIT_PERM (T->OQ[T->T.clms].v, T->T.t); // initial occurrence := all transactions
+ T->OQ[T->T.clms].t = T->T.t;
+ free (p);
+ }
+
+ // shrinking database
+ if ( T->flag&TRSACT_SHRINK ){
+ Q = T->OQ[T->T.clms];
+ T->OQ[T->T.clms].t = 0;
+ TRSACT_find_same (T, &Q, T->T.clms);
+ f = T->flag; // preserve the flag
+ BITRM (T->flag ,TRSACT_MAKE_NEW +TRSACT_UNION +TRSACT_INTSEC);
+ TRSACT_merge_trsact (T, &T->OQ[T->T.clms], T->T.clms); // just remove duplicated trsacts
+ T->flag = f; // recover flag
+ T->OQ[T->T.clms].t = 0;
+ FLOOP (t, 0, T->T.t) if ( T->mark[t]>0 ) ARY_INS(T->OQ[T->T.clms], t); // make resulted occ
+ }
+
+// QUEUE_delivery (T->OQ, NULL, NULL, T->T.v, &T->OQ[T->T.clms], T->T.t, T->T.clms);
+}
+
+/*****************************************/
+/* load transaction file and its weight */
+/*****************************************/
+void TRSACT_load (TRSACT *T, char *fname, char *fname2, char *wfname, char *wfname2, char *pfname){
+ FILE2 fp, fp2;
+ FILE_COUNT C = INIT_FILE_COUNT;
+ VEC_ID t=0;
+ int f;
+
+ FILE2_open (fp, fname, "r", "input-file open error", EXIT);
+ if ( fname2 ) FILE2_open (fp2, fname2, "r", "input-file2 open error", EXIT);
+ TRSACT_file_count (T, &C, &fp, wfname); if (ERROR_MES) goto END;
+ T->end1 = T->rows_org;
+ if ( fname2 ) TRSACT_file_count (T, &C, &fp2, wfname2); if (ERROR_MES) goto END;
+ f = TRSACT_alloc (T, pfname, &C); if (ERROR_MES) goto END;
+ TRSACT_file_read (T, &fp, &C, &t, f); if (ERROR_MES) goto END;
+ if ( fname2 ) TRSACT_file_read (T, &fp2, &C, &t, f); if (ERROR_MES) goto END;
+ TRSACT_sort (T, &C, f);
+
+ END:;
+ FILE2_close (&fp);
+ if (ERROR_MES) TRSACT_end (T);
+ return;
+}
+
+/* iteration of delivery; operate one transaction */
+/* use OQ.end to count the number of items */
+/* jump will be cleared (t := s) at the beginning */
+void TRSACT_delivery_iter (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, VEC_ID t, QUEUE_INT m){
+ WEIGHT *y=0;
+ QUEUE_INT *x;
+ int f = T->flag&TRSACT_NEGATIVE;
+
+ if ( T->T.w ) y = T->T.w[t];
+ MQUE_MLOOP (T->T.v[t], x, m){
+ if ( T->OQ[*x].end == 0 ){ ARY_INS (*jump, *x); w[*x] = 0; if ( f ) pw[*x] = 0; }
+ T->OQ[*x].end++;
+ if ( y ){
+ w[*x] += *y; if ( *y>0 && f) pw[*x] += *y;
+ y++;
+ } else {
+ w[*x] += T->w[t]; if ( f ) pw[*x] += T->pw[t];
+ }
+ }
+}
+
+void TRSACT_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, QUEUE *occ, QUEUE_INT m){
+ VEC_ID i, t;
+ char *b = (char *)(occ?occ->v: NULL);
+ jump->t = jump->s;
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ TRSACT_delivery_iter (T, jump, w, pw, t, m);
+ b += T->occ_unit;
+ }
+}
+
+/* usual delivery (make transpose) with checking sc
+ don't touch jump */
+/* if (T->flag&TRSACT_DELIV_SC), do not stack to items e with non-zero T->sc[e] */
+void TRSACT_deliv (TRSACT *T, QUEUE *occ, QUEUE_INT m){
+ VEC_ID i, t;
+ QUEUE_INT *x;
+ char *b = (char *)(occ?occ->v: NULL);
+ if ( T->flag&TRSACT_DELIV_SC ){
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ MQUE_MLOOP (T->T.v[t], x, m)
+ if ( !T->sc[*x] ) ARY_INS (T->OQ[*x], t);
+ b += T->occ_unit;
+ }
+ } else {
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ MQUE_MLOOP (T->T.v[t], x, m) ARY_INS (T->OQ[*x], t);
+ b += T->occ_unit;
+ }
+ }
+}
+
+/**************************************************************/
+/* Find identical transactions in a subset of transactions, by radix-sort like method */
+/* infrequent items (refer LCM_occ) and items larger than item_max are ignored */
+/* INPUT: T:transactions, occ:subset of T represented by indices, result:array for output, item_max:largest item not to be ignored */
+/* OUTPUT: if transactions i1, i2,..., ik are the same, they have same value in T->mark[i]
+ (not all) isolated transaction may have mark 1 */
+/* use 0 to end-1 of QQ temporary, and QQ[i].t and QQ[i].s have to be 0. */
+/*************************************************************************/
+void TRSACT_find_same (TRSACT *T, QUEUE *occ, QUEUE_INT end){
+ VEC_ID mark=0, t_end;
+ QUEUE *o=occ, *Q = T->T.v, *EQ, *QQ = T->OQ;
+ QUEUE_INT *x, *y, e;
+ QUEUE_ID ot = occ->t;
+
+ // initialization
+ MQUE_FLOOP (*occ, x){ T->mark[*x] = mark; T->shift[*x] = Q[*x].v; }
+ T->jump.t = T->jump.s; QQ[T->T.clms].s = 0;
+
+ while (1){
+ if ( o->t - o->s == 1 ) T->mark[o->v[--o->t]] = 1; // no same transactions; mark by 1
+ if ( o->t == 0 ) goto END;
+ // if previously inserted transactions are in different group, then change their marks with incrementing mark by one
+ mark++; for (x=&o->v[o->s] ; x <&o->v[o->t] ; x++) T->mark[*x] = mark;
+ t_end = o->t;
+ o->s = o->t = 0;
+
+ // insert each t to buckets
+ for (x=o->v ; x<o->v+t_end ; x++){
+ // get next item in transaction t
+ do {
+ e = *(T->shift[*x]);
+ T->shift[*x]++;
+ if ( e >= end ){ e = T->T.clms; break; }
+ } while ( T->sc[e] );
+ EQ = &QQ[e];
+ // if previously inserted transactions are in different group, then change their mark to the transaction ID of top transacion.
+ y = &(EQ->v[EQ->s]);
+ if ( EQ->s < EQ->t && T->mark[*y] != T->mark[*x] ){
+ if ( EQ->t - EQ->s == 1 ) T->mark[EQ->v[--EQ->t]] = 1; // the tail of the queue has no same transaction; mark the tail by 1
+ else {
+ mark++; for ( ; y< EQ->v + EQ->t ; y++) T->mark[*y] = mark;
+ EQ->s = EQ->t;
+ }
+ } else if ( EQ->t == 0 && e<T->T.clms ) ARY_INS (T->jump, e);
+ ARY_INS (*EQ, *x); // insert t to bucket of e
+ }
+ END:;
+ if ( QUEUE_LENGTH_(T->jump) == 0 ) break;
+ o = &QQ[QUEUE_ext_tail_ (&T->jump)];
+ }
+
+ // same transactions are in queue of item_max
+ if ( QQ[T->T.clms].t -QQ[T->T.clms].s == 1 ) T->mark[QQ[T->T.clms].v[--QQ[T->T.clms].t]] = 1;
+ if ( occ != &QQ[T->T.clms] ) occ->t = ot;
+}
+
+
+/****************************************************************************/
+/* copy transaction t to tt (only items i s.t. sc[i]==0) **/
+/* T->w has to be allocated. itemweight will be alocated even if T->w[t] == NULL */
+/****************************************************************************/
+void TRSACT_copy (TRSACT *T, VEC_ID tt, VEC_ID t, QUEUE_INT end){
+ QUEUE_INT *x, *buf;
+ WEIGHT *wbuf = NULL, tw = T->w[t], *w = T->T.w? T->T.w[t]: NULL;
+ int bnum = T->buf.num, bblock = T->buf.block_num, wflag = (w || (T->flag&TRSACT_UNION));
+
+ buf = (QUEUE_INT *)BASE_get_memory (&T->buf, T->T.v[t].t+1);
+if ( ERROR_MES ) return;
+ if ( wflag ) T->T.w[tt] = wbuf = (WEIGHT *)BASE_get_memory (&T->wbuf, T->T.v[t].t+1);
+if ( ERROR_MES ){ T->buf.num = bnum; T->buf.block_num = bblock; return; }
+ T->T.v[tt].v = buf;
+ T->w[tt] = T->w[t];
+ if ( T->flag&TRSACT_NEGATIVE ) T->pw[tt] = T->pw[t];
+ MQUE_MLOOP (T->T.v[t], x, end){
+ if ( !T->sc[*x] ){
+ *buf = *x; buf++;
+ if ( wflag ){ *wbuf = w? *w: tw; wbuf++; }
+ }
+ if ( w ) w++;
+ }
+ T->T.v[tt].t = buf - T->T.v[tt].v;
+ *buf = T->T.clms;
+ T->buf.num = buf - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) + 1;
+ if ( wflag ) T->wbuf.num = wbuf - ((WEIGHT *)T->wbuf.base[T->wbuf.block_num]) + 1;
+}
+
+/****************************************************************************/
+/* intersection of transaction t and tt (only items i s.t. sc[i]==0) **/
+/* shift is the array of pointers indicates the start of each transaction **/
+/****************************************************************************/
+void TRSACT_suffix_and (TRSACT *T, VEC_ID tt, VEC_ID t){
+ QUEUE_INT *x=T->shift[tt], *y=T->shift[t], *xx=T->shift[tt];
+ while ( *x < T->T.clms && *y < T->T.clms ){
+ if ( *x > *y ) y++;
+ else {
+ if ( *x == *y ){
+ if ( !T->sc[*x] ){ *xx = *x; xx++; }
+ y++;
+ }
+ x++;
+ }
+ }
+ T->T.v[tt].t = xx - T->T.v[tt].v;
+ *xx = T->T.clms;
+ T->buf.num = xx - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) + 1;
+}
+
+
+/***************************************************************************/
+/* take union of transaction t to tt (only items i s.t. pw[i]>=th) */
+/* CAUSION: t has to be placed at the last of trsact_buf2. */
+/* if the size of t inclreases, the following memory will be overwrited */
+/* if memory (T->buf, T->wbuf) is short, do nothing and return 1 */
+/* T->T.w[t] can be NULL, but T->T.w[x] can not */
+/***************************************************************************/
+void TRSACT_itemweight_union (TRSACT *T, VEC_ID tt, VEC_ID t){
+ int bnum = T->buf.num, bblock = T->buf.block_num;
+ QUEUE_ID siz = T->T.v[tt].t +T->T.v[t].t;
+ QUEUE_INT *xx_end = T->T.v[tt].v + siz, *xx = xx_end;
+ QUEUE_INT *x = T->T.v[tt].v + T->T.v[tt].t-1, *y = T->T.v[t].v + T->T.v[t].t-1;
+ WEIGHT *ww = T->T.w[tt] +siz, *wx = T->T.w[tt] +T->T.v[tt].t-1, *wy = T->T.w[t] +T->T.v[t].t-1;
+ WEIGHT tw = T->w[t];
+ int flag=0, wf = (T->T.w[t]!=NULL);
+
+ // if sufficiently large memory can not be taken from the current memory block, use the next block
+ if ( xx_end >= (QUEUE_INT *)T->buf.base[T->buf.block_num] +T->buf.block_siz ){
+ xx_end = xx = ((QUEUE_INT*)BASE_get_memory (&T->buf, T->buf.block_siz)) +siz;
+if (ERROR_MES) return;
+ ww = ((WEIGHT *)BASE_get_memory (&T->wbuf, T->wbuf.block_siz)) +siz;
+if ( ERROR_MES ){ T->buf.num = bnum; T->buf.block_num = bblock; return; }
+ flag =1;
+ }
+ if ( ERROR_MES ) return;
+
+ // take union and store it in the allocated memory
+ while ( x >= T->T.v[tt].v && y >= T->T.v[t].v ){
+ if ( *x > *y ){
+ if ( !T->sc[*x] ){ *xx = *x; *ww = *wx; xx--; ww--; }
+ x--; wx--;
+ if ( x < T->T.v[tt].v ){
+ while ( y >= T->T.v[t].v ){
+ if ( !T->sc[*y] ){ *xx = *y; *ww = wf? *wy: tw; xx--; ww--; }
+ y--; wy--;
+ }
+ }
+ } else {
+ if ( !T->sc[*y] ){
+ *ww = wf? *wy: tw; *xx = *y;
+ if ( *x == *y ){ *ww += *wx; x--; wx--; }
+ xx--; ww--;
+ }
+ y--; wy--;
+ if ( y < T->T.v[t].v ){
+ while ( x >= T->T.v[tt].v ){
+ if ( !T->sc[*x] ){ *xx = *x; *ww = *wx; xx--; ww--; }
+ x--; wx--;
+ }
+ }
+ }
+ }
+ T->T.v[tt].t = xx_end -xx;
+
+ // if [tt].v will overflow, set [tt].v to the top of next memory block
+ if ( flag ){
+ if ( T->T.v[tt].v + T->T.v[tt].t+1 >= (QUEUE_INT *)T->buf.base[T->buf.block_num-1] +T->buf.block_siz ){
+ T->T.v[tt].v = (QUEUE_INT *)T->buf.base[T->buf.block_num];
+ T->T.w[tt] = (WEIGHT *)T->wbuf.base[T->wbuf.block_num];
+ } else { // new memory block is allocated, but the transaction fits in the previous block
+ T->buf.block_num--;
+ T->wbuf.block_num--;
+ }
+ }
+
+ // copy the union to the original position
+ for ( x=T->T.v[tt].v,wx=T->T.w[tt] ; xx<xx_end ; ){
+ xx++; ww++;
+ *x = *xx; *wx = *ww;
+ x++; wx++;
+ }
+ *x = T->T.clms;
+ T->wbuf.num = T->buf.num = x - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) +1;
+ return;
+}
+
+
+
+/*****/
+/* merge duplicated transactions in occ according to those having same value in T->mark
+ the mark except for the representative will be zero, for each group of the same transactions
+ the mark of the representative will be its (new) ID +2 (one is for identical transaction) */
+/* T->flag&TRSACT_MAKE_NEW: make new trsact for representative
+ T->flag&TRSACT_INTSEC: take suffix intersection of the same trsacts
+ T->flag&TRSACT_UNION: take union of the same trsacts */
+/* o will be cleard after the execution */
+void TRSACT_merge_trsact (TRSACT *T, QUEUE *o, QUEUE_INT end){
+ VEC_ID mark = 0, tt=0;
+ QUEUE_INT *x;
+
+ MQUE_FLOOP (*o, x){
+ if ( mark == T->mark[*x] ){
+ T->mark[*x] = 0; // mark of unified (deleted) transaction
+ T->w[tt] += T->w[*x]; if ( T->pw ) T->pw[tt] += T->pw[*x];
+ if ( T->flag & TRSACT_INTSEC ){
+ TRSACT_suffix_and (T, tt, *x);
+ T->buf.num = T->T.v[tt].v - (QUEUE_INT *)T->buf.base[T->buf.block_num] +T->T.v[tt].t +1;
+ }
+ if ( T->flag & TRSACT_UNION ){
+ TRSACT_itemweight_union (T, tt, *x);
+ if ( ERROR_MES ) T->mark[*x] = *x+2; // do not merge if not enough memory
+ }
+ }
+ if ( mark != T->mark[*x] && T->mark[*x] > 1 ){ // *x is not the same to the previous, or memory short
+ mark = T->mark[*x];
+ if ( T->flag&TRSACT_MAKE_NEW ){
+ tt = T->new_t++;
+ TRSACT_copy (T, tt, *x, (T->flag&(TRSACT_INTSEC+TRSACT_UNION))? T->T.clms: end);
+ if ( ERROR_MES ){ T->new_t--; tt = *x; }
+ else for (T->shift[tt]=T->T.v[tt].v ; *(T->shift[tt])<end ; T->shift[tt]++);
+ } else tt = *x;
+ T->mark[*x] = tt+2;
+ }
+ }
+ o->t = o->s = 0;
+}
+
+/* remove the unified transactions from occ (consider T->occ_unit) */
+void TRSACT_reduce_occ (TRSACT *T, QUEUE *occ){
+ QUEUE_INT *x, *y=occ->v;
+ QUEUE_ID i=0;
+ if ( T->occ_unit == sizeof(QUEUE_INT) ){
+ MQUE_FLOOP (*occ, x){
+ if ( T->mark[*x] == 0 ) continue;
+ *y = T->mark[*x]>1? T->mark[*x]-2: *x;
+ y++; i++;
+ }
+ } else {
+ MQUE_FLOOP_ (*occ, x, T->occ_unit){
+ if ( T->mark[*x] == 0 ) continue;
+ memcpy (y, x, T->occ_unit);
+ *y = T->mark[*x]>1? T->mark[*x]-2: *x;
+ y = (QUEUE_INT *)(((char *)y)+T->occ_unit);
+ i++;
+ }
+ }
+ occ->t = i;
+}
+
+#endif
--- /dev/null
+/* QUEUE based Transaction library, including database reduction.
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _trsact_h_
+#define _trsact_h_
+
+// #define WEIGHT double
+// #define WEIGHT_DOUBLE
+
+#include"vec.h"
+#include"base.h"
+
+#ifndef WEIGHT
+#define WEIGHT int
+#ifdef WEIGHT_DOUBLE
+#undef WEIGHT_DOUBLE
+#endif
+#endif
+
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SETFAMILY T; // transaction
+ int flag; // flag
+ WEIGHT *w, *pw; // weight/positive-weight of transactions
+
+ QUEUE_INT clms_org, clm_max; // #items in original file
+ VEC_ID rows_org, row_max; // #transactions in the original file
+ VEC_ID end1, sep; // #trsact in 1st file, the ID of the last permed trsact of 1st file
+ size_t eles_org; // #elements in the original file
+ WEIGHT total_w, total_pw, total_w_org, total_pw_org;
+ WEIGHT th; // threshold for frequency of items
+ PERM *perm, *trperm, *loaded_perm, *loaded_inperm; // original item permutation loaded from permutation file (and inverse)
+
+ // lower/upper bound of #elements in a column/row. colunmn or row of out of range will be ignored
+ VEC_ID clm_lb, clm_ub;
+ QUEUE_ID row_lb, row_ub;
+ WEIGHT w_lb, w_ub;
+
+ VEC_ID str_num; // number of database (itemset stream/string datasets) in T
+ VEC_ID *head, *strID; // the head (beginning) of each stream, stream ID of each transaction
+ int occ_unit;
+
+ // for finding same transactions
+ QUEUE jump, *OQ; // queue of non-empty buckets, used in find_same_transactions
+ VEC_ID *mark; // marks for transactions
+ QUEUE_INT **shift; // memory for shift positions of each transaction
+ char *sc; // flag for non-active (in-frequent) items
+
+ // for extra transactions
+ VEC_ID new_t; // the start ID of un-used transactions
+ BASE buf; // buffer for transaction
+ BASE wbuf; // buffer for itemweights
+} TRSACT;
+
+#define TRSACT_FRQSORT 65536 // sort transactions in decreasing order
+#define TRSACT_ITEMWEIGHT 131072 // initialize itemweight by transaction weights
+#define TRSACT_SHRINK 262144 // do not allocate memory for shrink, but do for mining
+#define TRSACT_MULTI_STREAM 524288 // separate the datasets at each empty transaction
+#define TRSACT_UNION 1048576 // take union of transactions, at the database reduction
+#define TRSACT_INTSEC 2097152 // take intersection of transactions, at the database reduction
+#define TRSACT_MAKE_NEW 4194304 // make new transaction for each
+#define TRSACT_ALLOC_OCC 8388608 // make new transaction for each
+#define TRSACT_DELIV_SC 16777216 // look T->sc when delivery
+#define TRSACT_NEGATIVE 33554432 // flag for whether some transaction weights are negative or not
+//#define TRSACT_INIT_SHRINK 65536 // allocate memory for database reduction
+#define TRSACT_WRITE_PERM 67108864 // write item-order to file
+
+#ifndef TRSACT_DEFAULT_WEIGHT
+ #define TRSACT_DEFAULT_WEIGHT 0 // default weight of the transaction, for missing weights in weight file
+#endif
+
+/* print transactions */
+void TRSACT_print (TRSACT *T, QUEUE *occ, PERM *p);
+void TRSACT_prop_print (TRSACT *T);
+
+/**************************************************************/
+void TRSACT_init (TRSACT *T);
+
+/**************************************************************/
+void TRSACT_end (TRSACT *T);
+
+/*****************************************/
+/* scan file "fp" with weight file wfp and count #items, #transactions in the file. */
+/* count weight only if wfp!=NULL */
+/* T->rows_org, clms_org, eles_org := #items, #transactions, #all items */
+/* ignore the transactions of size not in range T->clm_lb - clm_ub */
+/* T->total_w, total_pw := sum of (positive) weights of transactions */
+/* C.clmt[i],C.cw[i] := the number/(sum of weights) of transactions including i */
+/****************************************/
+void TRSACT_file_count (TRSACT *T, FILE_COUNT *C, FILE2 *fp, char *wf);
+
+/* allocate memory, set permutation, and free C.clmt,rowt,rw,cw */
+int TRSACT_alloc (TRSACT *T, char *pfname, FILE_COUNT *C);
+
+/* load the file to allocated memory according to permutation, and free C.rw, C.cw */
+void TRSACT_file_read (TRSACT *T, FILE2 *fp, FILE_COUNT *C, VEC_ID *t, int flag);
+
+/*****************************************/
+/* load transaction file to TRSACT */
+void TRSACT_load (TRSACT *T, char *fname, char *fname2, char *wfname, char *wfname2, char *pfname);
+
+/* occurrence deliver (only counting) */
+/* WARNING: next cell of the last item of each transaction must be INTHUGE */
+/* compute occurrence for items less than max item, in the database induced
+ by occ */
+/* if jump!=0, all i with non-zero occ[i].t will be inserted to jump */
+/* be careful for overflow of jump */
+/* if occ==NULL, scan all transactions */
+/* flag&1: count only positive weights */
+void TRSACT_delivery_iter (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, VEC_ID t, QUEUE_INT m);
+void TRSACT_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, QUEUE *occ, QUEUE_INT m);
+// QUEUE *TRSACT_alloc_occ (TRSACT *T, QUEUE_INT end);
+//QUEUE_ID TRSACT_occ_dup (SETFAMILY *S, QUEUE *OQ, QUEUE *jump, WEIGHT *occ_w, WEIGHT *occ_pw);
+
+/**************************************************************/
+/* Find identical transactions in a subset of transactions, by radix-sort like method */
+/* infrequent items (refer LCM_occ) and items larger than item_max are ignored */
+/* INPUT: T:transactions, occ:subset of T represented by indices, result:array for output, item_max:largest item not to be ignored */
+/* OUTPUT: if transactions i1, i2,..., ik are the same, they have same value in T->mark[i]
+ (not all) isolated transaction may have mark 1 */
+/* use 0 to end-1 of QQ temporary, and QQ[i].t and QQ[i].s have to be 0. */
+/*************************************************************************/
+void TRSACT_find_same (TRSACT *T, QUEUE *occ, QUEUE_INT end);
+
+/* copy transaction t to tt (only items i s.t. pw[i]>=th) **/
+void TRSACT_copy (TRSACT *T, VEC_ID tt, VEC_ID t, QUEUE_INT end);
+
+/* intersection of transaction t and tt (only items i s.t. pw[i]>=th) **/
+/* shift is the array of pointers indicates the start of each transaction **/
+void TRSACT_suffix_and (TRSACT *T, VEC_ID tt, VEC_ID t);
+
+/* take union of transaction t to tt (only items i s.t. pw[i]>=th) */
+/* CAUSION: t has to be placed at the last of trsact_buf2. */
+/* if the size of t inclreases, the following memory will be overwrited */
+/* if memory (T->buf) is short, do nothing and return 1 */
+void TRSACT_itemweight_union (TRSACT *T, VEC_ID tt, VEC_ID t);
+
+
+/*****/
+/* remove duplicated transactions from occ, and add the weight of the removed trsacts to the representative one */
+/* duplicated trsacts are in occ[item_max]. Clear the queue when return */
+/* T->flag&TRSACT_MAKE_NEW: make new trsact for representative
+ T->flag&TRSACT_INTSEC: take suffix intersection of the same trsacts
+ T->flag&TRSACT_UNION: take union of the same trsacts */
+void TRSACT_merge_trsact (TRSACT *T, QUEUE *o, QUEUE_INT end);
+
+/* remove the unified transactions from occ (consider T->occ_unit) */
+void TRSACT_reduce_occ (TRSACT *T, QUEUE *occ);
+
+#ifdef _alist_h_
+
+/* occurrence deliver (only counting), for MALIST */
+//void TRSACT_MALIST_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, MALIST *occ, ALIST_ID l, QUEUE_INT m);
+//void TRSACT_MALIST_occ_deliver (TRSACT *TT, MALIST *occ, int l, int item_max);
+
+#endif
+
+#endif
--- /dev/null
+/* library for vector and sparse vector, and matrix */
+/* Takeaki Uno 27/Dec/2008 */
+
+#ifndef _vec_c_
+#define _vec_c_
+
+#include"vec.h"
+#include"stdlib2.c"
+#include"queue.c"
+
+MAT INIT_MAT = {TYPE_MAT,NULL,0,0,NULL,NULL,0,0,0};
+SVEC INIT_SVEC_ELE = {0,0};
+SVEC INIT_SVEC = {TYPE_SVEC,NULL,0,0};
+SMAT INIT_SMAT = {TYPE_SMAT,NULL,0,0,NULL,NULL,0,0,0,0};
+SETFAMILY INIT_SETFAMILY = INIT_SETFAMILY_;
+
+QSORT_TYPE (SVEC_VAL, SVEC_VAL)
+QSORT_TYPE (SVEC_VAL2, SVEC_VAL2)
+
+/* allocate memory according to rows and rowt */
+void VEC_alloc (VEC *V, VEC_ID clms){
+ *V = INIT_VEC;
+ V->end = clms;
+ calloc2 (V->v, clms+1, "VEC_alloc: V->v", EXIT);
+}
+
+/* terminate routine for VEC */
+void VEC_end (VEC *V){
+ free2 (V->v);
+ *V = INIT_VEC;
+}
+
+/* allocate memory according to rows and rowt */
+void MAT_alloc (MAT *M, VEC_ID rows, VEC_ID clms){
+ VEC_ID i;
+ calloc2 (M->v, rows+1, "MAT_alloc: M->v", EXIT);
+ calloc2 (M->buf, (clms+1) * (rows+1), "MAT_alloc: M->v", {free(M->v);EXIT;});
+ M->end = rows;
+ M->clms = clms;
+ FLOOP (i, 0, rows){
+ M->v[i].end = M->v[i].t = clms;
+ M->v[i].v = M->buf + i*(clms+1);
+ }
+}
+
+/* terminate routine for MAT */
+void MAT_end (MAT *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ *M = INIT_MAT;
+}
+
+/* allocate memory */
+void SVEC_alloc (SVEC *V, VEC_ID end){
+ *V = INIT_SVEC;
+ calloc2 (V->v, end+1, "SVEC_alloc: V->v", EXIT);
+ V->end = end;
+ V->t = 0;
+}
+
+/* terminate routine for SVEC */
+void SVEC_end (SVEC *V){
+ free2 (V->v);
+ *V = INIT_SVEC;
+}
+
+/* allocate memory according to rows and rowt */
+void SMAT_alloc (SMAT *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles){
+ VEC_ID i;
+ if ( eles == 0 ) ARY_SUM (M->ele_end, rowt, 0, rows); else M->ele_end = eles;
+ calloc2 (M->buf, M->ele_end*((M->flag&LOAD_DBLBUF)?2:1) +rows +2, "SMAT_alloc: buf", EXIT);
+ malloc2 (M->v, rows+1, "SMAT_alloc: M->v", {free(M->buf);EXIT;});
+ ARY_FILL (M->v, 0, rows, INIT_SVEC);
+ M->end = rows;
+ M->clms = clms;
+ if ( rowt ){
+ FLOOP (i, 0, rows){
+ M->v[i].v = i? M->v[i-1].v + rowt[i-1] +1: M->buf;
+ M->v[i].end = rowt[i];
+ }
+ }
+}
+
+/* terminate routine for MAT */
+void SMAT_end (SMAT *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ *M = INIT_SMAT;
+}
+
+
+
+/* allocate memory according to rows and rowt */
+/* if eles == 0, compute eles from rowt and rows */
+void SETFAMILY_alloc (SETFAMILY *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles){
+ VEC_ID i;
+ char *buf;
+ if ( eles == 0 ) ARY_SUM (M->ele_end, rowt, 0, rows); else M->ele_end = eles;
+ calloc2 (buf, (M->ele_end*((M->flag&LOAD_DBLBUF)?2:1) +((M->flag&LOAD_DBLBUF)?MAX(rows,clms):rows)+2)*M->unit, "SETFAMILY_alloc: buf", EXIT);
+ M->buf = (QUEUE_INT *)buf;
+ malloc2 (M->v, rows+1, "SETFAMILY_alloc: M->v", {free(M->buf);EXIT;});
+ ARY_FILL (M->v, 0, rows, INIT_QUEUE);
+ M->end = rows;
+ M->clms = clms;
+ if ( rowt ){
+ FLOOP (i, 0, rows){
+ M->v[i].v = (QUEUE_INT *)buf;
+ buf += (rowt[i] +1)*M->unit;
+ M->v[i].end = rowt[i]+1;
+ }
+ }
+}
+
+/* allocate memory according to rows and rowt */
+/* if eles == 0, compute eles from rowt and rows */
+void SETFAMILY_alloc_weight (SETFAMILY *M){
+ VEC_ID i;
+ calloc2 (M->w, M->end +1, "SETFAMILY_alloc_weight: w", EXIT);
+ calloc2 (M->wbuf, M->ele_end*((M->flag&LOAD_DBLBUF)?2:1)+1, "SETFAMILY_alloc_weight: *w", {free(M->w);EXIT;});
+ FLOOP (i, 1, M->t) M->w[i] = i? M->w[i-1] + M->v[i-1].t: M->wbuf;
+}
+
+/* terminate routine for MAT */
+void SETFAMILY_end (SETFAMILY *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ free2 (M->wbuf);
+ free2 (M->w);
+ *M = INIT_SETFAMILY;
+}
+
+/****************************************************************/
+/****************************************************************/
+/****************************************************************/
+
+/* read binary file for MAT */
+/* each unit-byte will be one number. if unit<0, the sign of unit is flipped, and each value is minesed the half of the maximum */
+void MAT_load_bin (MAT *M, FILE2 *fp, int unit){
+ VEC_ID flag=0, i, j, jj;
+ size_t siz=0;
+ VEC_VAL z, neg=0;
+
+ if ( unit < 0 ){
+ unit = -unit; flag = 1; neg=128;
+ FLOOP (jj, 0, unit-1) neg *= 256;
+ }
+ if ( M->t == 0 ){ // determine #rows if M->t is 0 (not specified)
+ fseek(fp->fp, 0, SEEK_END);
+ siz = ftell(fp->fp);
+ fseek(fp->fp, 0, SEEK_SET);
+ M->t = siz / unit / M->clms;
+ if ( M->flag & LOAD_TPOSE ) SWAP_INT (M->t, M->clms);
+ }
+ MAT_alloc (M, M->t, M->clms); if (ERROR_MES) return;
+ M->end = M->t;
+ FLOOP (i, 0, M->t){
+ FLOOP (j, 0, M->clms){
+ z=0; FLOOP (jj, 0, unit){ z *= 256; z += FILE2_getc (fp); }
+ if ( flag ) z -= neg;
+ if ( M->flag & LOAD_TPOSE ) M->v[j].v[i] = z;
+ else M->v[i].v[j] = z;
+ }
+ }
+}
+
+/* segmentation fault for illegal files */
+/* count/read the number in file for MAT */
+/* if *rows>0, only read count the numbers in a row, for the first scan. */
+void MAT_file_load (MAT *M, FILE2 *fp){
+ QUEUE_ID c;
+ VEC_ID t=0;
+ double p;
+
+ for ( t=0 ; (FILE_err&2)==0 ; t++){
+ ARY_SCAN (c, double, *fp, 0);
+ if ( M->flag & LOAD_TPOSE ){
+ if ( M->t == 0 ){ M->t = c; if ( M->clms>0 ) break; }
+ } else if ( M->clms == 0 ){ M->clms = c; if ( M->t>0 ) break; }
+ }
+ if ( M->flag & LOAD_TPOSE ){ if ( M->clms==0 ) M->clms = t;} else if ( M->t==0 ) M->t = t;
+ FILE2_reset (fp);
+ M->end = M->t;
+ MAT_alloc (M, M->t, M->clms); if (ERROR_MES) return;
+ FLOOP (t, 0, M->t ){
+ FLOOP (c, 0, M->clms){
+ p = FILE2_read_double(fp);
+ if ( M->flag&LOAD_TPOSE ) M->v[c].v[t] = p;
+ else M->v[t].v[c] = p;
+ if ( c>= ((M->flag&LOAD_TPOSE)? M->t: M->clms) ) break;
+ }
+ if ( !FILE_err ) FILE2_read_until_newline (fp);
+ if ( c>= ((M->flag&LOAD_TPOSE)? M->clms: M->t) ) break;
+ }
+}
+
+/* load file with switching the format according to the flag */
+void MAT_load (MAT *M, char *fname){
+ FILE2 fp;
+ int unit=0;
+#ifdef USE_MATH
+ VEC_ID i;
+#endif
+ if ( M->flag & VEC_LOAD_BIN ) unit = 1;
+ else if ( M->flag & VEC_LOAD_BIN2 ) unit = 2;
+ else if ( M->flag & VEC_LOAD_BIN4 ) unit = 4;
+ if ( M->flag & VEC_LOAD_CENTERIZE ) unit = -unit;
+
+ FILE2_open (fp, fname, "rb", "MAT_load", EXIT);
+ if ( unit ) MAT_load_bin (M, &fp, unit);
+ else MAT_file_load (M, &fp);
+ FILE2_close (&fp); if (ERROR_MES) EXIT;
+#ifdef USE_MATH
+ if ( M->flag&VEC_NORMALIZE ) FLOOP (i, 0, M->t) ARY_NORMALIZE (M->v[i].v,M->v[i].t);
+#endif
+}
+
+
+/* scan file and read the numbers for SMAT */
+/* flag&1? SMAT, SETFAMILY, flag&2? tuple list format: array list :*/
+void SMAT_file_load (SMAT *M, FILE2 *fp){
+ SVEC_VAL z=0;
+ VEC_ID flag= (M->type==TYPE_SMAT), t, x, y;
+ FILE_COUNT C;
+
+ C = FILE2_count (fp, (M->flag&(LOAD_ELE+LOAD_TPOSE)) | FILE_COUNT_ROWT, 0, 0, 0, 0, 0);
+ if ( M->clms == 0 ) M->clms = C.clms;
+ if ( M->t == 0 ) M->t = (M->flag&LOAD_ELE)? C.row_max: C.rows;
+ if ( flag ) SMAT_alloc (M, M->t, C.rowt, M->clms, 0);
+ else SETFAMILY_alloc ((SETFAMILY *)M, M->t, C.rowt, M->clms, 0);
+ free2 (C.rowt);
+ if ( ERROR_MES ) return;
+ FILE2_reset (fp);
+ t=0;
+ do {
+ if ( M->flag&LOAD_ELE ){
+ x = FILE2_read_int (fp);
+ y = FILE2_read_int (fp);
+ if ( flag ) z = FILE2_read_double (fp);
+ FILE2_read_until_newline (fp);
+ } else {
+ x = t;
+ y = FILE2_read_int (fp);
+ if ( FILE_err&4 ) goto LOOP_END2;
+ if ( flag ) z = FILE2_read_double (fp);
+ }
+ if ( M->flag&LOAD_TPOSE ) SWAP_INT (x, y);
+ if ( y >= M->clms || x >= M->t ) goto LOOP_END2;
+ if ( flag ){
+ M->v[x].v[M->v[x].t].i = y;
+ M->v[x].v[M->v[x].t].a = z;
+ M->v[x].t++;
+ } else ARY_INS (((SETFAMILY *)M)->v[x], y);
+ LOOP_END2:;
+ if ( !(M->flag&LOAD_ELE) && (FILE_err&3) ){ t++; if ( t >= M->t ) break; }
+ } while ( (FILE_err&2)==0 );
+}
+
+/* scan file and read the numbers for SMAT */
+/* flag&1? SMAT, SETFAMILY, flag&2? tuple list format: array list :*/
+void SETFAMILY_load_weight (SETFAMILY *M, char *fname){
+ FILE2 fp;
+ VEC_ID i;
+ QUEUE_ID j;
+ if ( M->flag&LOAD_TPOSE ) error ("transope and weight can't be specified simultaneously", EXIT);
+ FILE2_open (fp, fname, "r", "SETFAMILY_load_weight", EXIT);
+ SETFAMILY_alloc_weight (M);
+ FLOOP (i, 0, M->t){
+ FLOOP (j, 0, M->v[i].t)
+ M->w[i][j] = (WEIGHT)FILE2_read_double (&fp);
+ FILE2_read_until_newline (&fp);
+ }
+}
+
+
+/* load file with switching the format according to the flag */
+void SMAT_load (SMAT *M, char *fname){
+ FILE2 fp;
+ VEC_ID i;
+ M->type = TYPE_SMAT;
+ FILE2_open (fp, fname, "r", "SMAT_load", EXIT);
+ SMAT_file_load (M, &fp);
+ FILE2_close (&fp); if (ERROR_MES) EXIT;
+ FLOOP (i, 0, M->t) M->v[i].v[M->v[i].t].i = M->clms; // end mark
+
+#ifdef USE_MATH
+ if ( M->flag&VEC_NORMALIZE ) FLOOP (i, 0, M->t) SVEC_normalize (&M->v[i]); // normalize
+#endif
+ if (M->flag&LOAD_INCSORT)
+ FLOOP (i, 0, M->t) qsort_VEC_ID ((VEC_ID *)(M->v[i].v), M->v[i].t, sizeof(SVEC_ELE));
+ if (M->flag&LOAD_DECSORT)
+ FLOOP (i, 0, M->t) qsort_VEC_ID ((VEC_ID *)(M->v[i].v), M->v[i].t, -(int)sizeof(SVEC_ELE));
+ if (M->flag&LOAD_RM_DUP)
+ FLOOP (i, 0, M->t) MQUE_UNIFY (M->v[i], SVEC_VAL);
+ M->eles = M->ele_end;
+}
+
+/* sort and duplication check */
+void SETFAMILY_sort (SETFAMILY *M){
+ VEC_ID i;
+ PERM *p;
+ WEIGHT *ww;
+ QUEUE Q;
+ int flag = (M->flag&LOAD_INCSORT)? 1: ((M->flag&LOAD_DECSORT)? -1: 0);
+ if ( flag ){ // sort items in each row
+ malloc2 (p, M->clms, "SETFAMILY_sort: p", EXIT);
+ FLOOP (i, 0, M->t)
+ QUEUE_perm_WEIGHT (&M->v[i], M->w?M->w[i]:NULL, p, flag);
+ free (p);
+ }
+ flag = ((M->flag&LOAD_SIZSORT)? ((M->flag&LOAD_DECROWSORT)? -1: 1): 0) *sizeof(QUEUE);
+ if ( flag ){ // sort the rows
+ p = qsort_perm_VECt ((VEC *)M->v, M->t, flag);
+ ARY_INVPERMUTE_ (M->w, p, ww, M->t);
+ ARY_INVPERMUTE (M->v, p, Q, M->t, "SETFAMILY_sort: ARY_INVPERMUTE", EXIT);
+ free (p);
+ }
+ if (M->flag&LOAD_RM_DUP){ // unify the duplicated edges
+ FLOOP (i, 0, M->t)
+ QUEUE_rm_dup_WEIGHT (&M->v[i], M->w?M->w[i]:NULL);
+ }
+}
+
+/* scan file and load the data from file to SMAT structure */
+void SETFAMILY_load (SETFAMILY *M, char *fname, char *wfname){
+ FILE2 fp;
+ VEC_ID i;
+ M->type = TYPE_SETFAMILY;
+ FILE2_open (fp, fname, "r", "SETFAMILY_load", EXIT);
+ SMAT_file_load ((SMAT *)M, &fp);
+ FILE2_close (&fp); if(ERROR_MES) EXIT;
+ FLOOP (i, 0, M->t) M->v[i].v[M->v[i].t] = M->clms; // end mark
+
+ if ( !(M->flag&LOAD_ELE) && wfname ){
+ SETFAMILY_load_weight (M, wfname);
+ if ( ERROR_MES ){ SETFAMILY_end (M); EXIT; }
+ }
+
+ SETFAMILY_sort (M);
+ M->eles = M->ele_end;
+}
+
+/* print routines */
+void MAT_print (FILE *fp, MAT *M){
+ VEC *V;
+ MQUE_FLOOP (*M, V) ARY_FPRINT (fp, V->v, 0, V->t, VEC_VALF" ");
+}
+void SVEC_print (FILE *fp, SVEC *V){
+ SVEC_ELE *x;
+ MQUE_FLOOP (*V, x) fprintf (fp, "("QUEUE_IDF","SVEC_VALF") ", (*x).i, (*x).a);
+ fputc ('\n', fp);
+}
+void SMAT_print (FILE *fp, SMAT *M){
+ SVEC *V;
+ MQUE_FLOOP (*M, V) SVEC_print (fp, V);
+}
+void SETFAMILY_print (FILE *fp, SETFAMILY *M){
+ QUEUE *V;
+ MQUE_FLOOP (*M, V) ARY_FPRINT (fp, V->v, 0, V->t, QUEUE_INTF" ");
+}
+
+/*
+void SETFAMILY_print_WEIGHT (FILE *fp, SETFAMILY *M){
+ if ( M->w ){
+ printf (","); fprint_WEIGHT (stdout, M->w[i][j]); }
+ printf ("\n");
+}
+*/
+
+/****************************************************************/
+/** Inner product routines **************************************/
+/****************************************************************/
+SVEC_VAL2 SVEC_inpro (SVEC *V1, SVEC *V2){
+ VEC_ID i1, i2=0;
+ SVEC_VAL2 sum=0;
+ FLOOP (i1, 0, V1->t){
+ while (V2->v[i2].i < V1->v[i1].i) i2++;
+ if (V2->v[i2].i == V1->v[i1].i) sum += ((SVEC_VAL2)V2->v[i2].a)*V1->v[i1].a;
+ }
+ return (sum);
+}
+
+
+/* get ith vector */
+void *MVEC_getvec (void *M, int i, int flag){
+ MAT *MM = (MAT *)M;
+ if (MM->type==TYPE_MAT) return (&MM->v[i]);
+ if (MM->type==TYPE_SMAT) return (&((SVEC *)M)->v[i]);
+ if (MM->type==TYPE_SETFAMILY) return (&((QUEUE *)M)->v[i]);
+ return (NULL);
+}
+
+#ifdef USE_MATH
+
+/****************************************************************/
+/** Norm computation and normalization ************************/
+/****************************************************************/
+double SVEC_norm (SVEC *V){
+ SVEC_ELE *v;
+ double sum=0;
+ MQUE_FLOOP (*V, v) sum += ((double)(v->a)) * (v->a);
+ return (sqrt(sum));
+}
+void SVEC_normalize (SVEC *V){
+ SVEC_ELE *v;
+ double norm = SVEC_norm (V);
+ MQUE_FLOOP (*V, v) v->a /= norm;
+}
+
+/****************************************************************/
+/** Euclidean distance routines *********************************/
+/****************************************************************/
+
+/* compute the inner product of two vectors */
+double VEC_eucdist (VEC *V1, VEC *V2){
+ VEC_ID i, end=MIN(V1->end,V2->end);
+ double sum=0, a0, a1, a2, a3;
+ for (i=0 ; i<end ; i+=4){
+ a0 = ((double)V1->v[i])- ((double)V2->v[i]);
+ a1 = ((double)V1->v[i+1])- ((double)V2->v[i+1]);
+ a2 = ((double)V1->v[i+2])- ((double)V2->v[i+2]);
+ a3 = ((double)V1->v[i+3])- ((double)V2->v[i+3]);
+ sum += a0*a0 + a1*a1 + a2*a2 + a3*a3;
+ }
+ if ( i+1<end ){
+ a0 = ((double)V1->v[i])- ((double)V2->v[i]);
+ a1 = ((double)V1->v[i+1])- ((double)V2->v[i+1]);
+ sum += a0*a0 + a1*a1;
+ if ( i+2<end ){ a2 = ((double)V1->v[i+2])- ((double)V2->v[i+2]); sum += a2*a2; }
+ } else if ( i<end ){ a0 = ((double)V1->v[i])- ((double)V2->v[i]); sum += a0*a0; }
+ return (sqrt(sum));
+}
+
+/* compute the inner product of two vectors */
+double SVEC_eucdist (SVEC *V1, SVEC *V2){
+ VEC_ID i1, i2;
+ double sum=0, a;
+ for ( i1=i2=0 ; i1<V1->t && i2<V2->t ; ){
+ if (V2->v[i2].i > V1->v[i1].i) a = V1->v[i1].a;
+ else if (V2->v[i2].i < V1->v[i1].i) a = V2->v[i2].a;
+ else a = ((double)V2->v[i2].a) - ((double)V1->v[i1].a);
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/* compute the inner product of two vectors */
+double VEC_SVEC_eucdist (VEC *V1, SVEC *V2){
+ VEC_ID i, i2=0;
+ double sum=0, a;
+ FLOOP (i, 0, V1->end){
+ if ( i < V2->v[i2].i ) a = V1->v[i];
+ else { a = ((double)V1->v[i]) - ((double)V2->v[i2].a); i2++; }
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/**********************************************************/
+/* Euclidean distance of vector and set */
+double VEC_QUEUE_eucdist (VEC *V, QUEUE *Q){
+ VEC_ID i;
+ QUEUE_ID i2=0;
+ double sum=0, a;
+ FLOOP (i, 0, V->end){
+ if ( i < Q->v[i2] ) a = V->v[i];
+ else { a = ((double)V->v[i]) - 1.0; i2++; }
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/* compute Euclidean distance of two sets */
+double QUEUE_eucdist (QUEUE *Q1, QUEUE *Q2){
+ double f;
+ MQUE_UNION(f, *Q1, *Q2);
+ return (sqrt(f));
+}
+
+double MVEC_norm (void *V){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC){ ARY_NORM (p, VV->v, VV->t); return (p); }
+ if (VV->type==TYPE_SVEC) return (SVEC_norm ((SVEC *)V));
+ if (VV->type==TYPE_QUEUE) return (sqrt(((QUEUE*)V)->t));
+ return (0.0);
+}
+
+double MMAT_norm_i (void *M, int i){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_NORM (p, MM->v[i].v, MM->v[i].t); return (p); }
+ if (MM->type==TYPE_SMAT) return (SVEC_norm (&((SMAT *)M)->v[i]));
+ if (MM->type==TYPE_SETFAMILY) return (sqrt (((SETFAMILY *)M)->v[i].t));
+ return (0.0);
+}
+
+double MVEC_eucdist (void *V, void *U){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC) return (VEC_eucdist ((VEC *)V, (VEC *)U));
+ if (VV->type==TYPE_SVEC) return (SVEC_eucdist ((SVEC *)V, (SVEC *)U));
+ if (VV->type==TYPE_QUEUE){ MQUE_DIF (p, *((QUEUE *)V), *((QUEUE *)U)); return (sqrt(p));}
+ return (0.0);
+}
+
+double MMAT_eucdist_ij (void *M, int i, int j){
+ MAT *MM=(MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT) return (VEC_eucdist ( &MM->v[i], &MM->v[j] ));
+ if (MM->type==TYPE_SMAT) return (SVEC_eucdist ( &((SMAT *)M)->v[i], &((SMAT *)M)->v[j]));
+ if (MM->type==TYPE_SETFAMILY){ MQUE_DIF (p, ((SETFAMILY *)M)->v[i], ((SETFAMILY *)M)->v[j]); return (sqrt(p)); }
+ return (0.0);
+}
+
+
+#endif
+
+/**********************************************************/
+/** multi-vector routines ******************************/
+/**********************************************************/
+
+/* compute the inner product, Euclidean distance for multi vector */
+double MVEC_inpro (void *V, void *U){
+ VEC *VV = (VEC *)V, *UU = (VEC *)U;
+ double p;
+ if (VV->type==TYPE_VEC){
+ if (UU->type==TYPE_VEC){ ARY_INPRO (p, VV->v, UU->v, VV->t); return (p); }
+ if (UU->type==TYPE_SVEC){ ARY_SVEC_INPRO (p, *((SVEC *)U), VV->v); return (p); }
+ if (UU->type==TYPE_QUEUE){ ARY_QUEUE_INPRO (p, *((QUEUE *)U), VV->v); return (p); }
+ }
+ if (VV->type==TYPE_SVEC){
+ if (UU->type==TYPE_VEC){ ARY_SVEC_INPRO (p, *((SVEC *)V), UU->v); return (p);}
+ if (UU->type==TYPE_SVEC) return (SVEC_inpro ((SVEC *)V, (SVEC *)U));
+// if (UU->type==TYPE_QUEUE) return (VEC_QUEUE_inpro (V, U));
+ }
+ if (VV->type==TYPE_QUEUE){
+ if (UU->type==TYPE_VEC){ ARY_QUEUE_INPRO (p, *((QUEUE *)V), UU->v); return (p); }
+// else if (UU->type==TYPE_SVEC) return (SVEC_inpro (V, U));
+ if (UU->type==TYPE_QUEUE){ MQUE_INTSEC (p, *((QUEUE *)V), *((QUEUE *)U)); return (p);}
+ }
+ return (0.0);
+}
+
+double MVEC_double_inpro (void *V, double *w){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC){ ARY_INPRO (p, VV->v, w, VV->t); return (p); }
+ if (VV->type==TYPE_SVEC){ ARY_SVEC_INPRO (p, *((SVEC *)V), w); return (p); }
+ if (VV->type==TYPE_QUEUE){ ARY_QUEUE_INPRO (p, *((QUEUE *)V), w); return (p); }
+ return (0.0);
+}
+
+/* compute the inner product, euclidean distance for i,jth vector */
+double MMAT_inpro_ij (void *M, int i, int j){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_INPRO (p, MM->v[i].v, MM->v[j].v, MM->v[j].t); return (p); }
+ if (MM->type==TYPE_SMAT) return (SVEC_inpro (&((SMAT *)M)->v[i], &((SMAT *)M)->v[j]));
+ if (MM->type==TYPE_SETFAMILY){
+ p = QUEUE_intsec_ (&((SETFAMILY *)M)->v[i], &((SETFAMILY *)M)->v[j]); return (p); }
+ return (0.0);
+}
+
+double MMAT_double_inpro_i (void *M, int i, double *w){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_INPRO (p, MM->v[i].v, w, MM->v[i].t); return (p); }
+ if (MM->type==TYPE_SMAT){ ARY_SVEC_INPRO (p, ((SMAT *)M)->v[i], w); return (p); }
+ if (MM->type==TYPE_SETFAMILY){ ARY_QUEUE_INPRO (p, ((SETFAMILY *)M)->v[i], w); return (p); }
+ return (0.0);
+}
+
+
+
+#endif
+
+
--- /dev/null
+/* library for sparse vector */
+/* Takeaki Uno 27/Dec/2008 */
+
+#ifndef _vec_h_
+#define _vec_h_
+
+#define STDLIB2_USE_MATH
+
+#include"math.h"
+#include"queue.h"
+
+#ifndef SVEC_VAL
+ #ifdef SVEC_VAL_INT
+ #define SVEC_VAL int
+ #define SVEC_VAL2 LONG
+ #define SVEC_VAL_END INTHUGE
+ #define SVEC_VAL2_END LONGHUGE
+ #define SVEC_VALF "%d"
+ #else
+ #define SVEC_VAL double
+ #define SVEC_VAL2 double
+ #define SVEC_VAL_END DOUBLEHUGE
+ #define SVEC_VAL2_END DOUBLEHUGE
+ #define SVEC_VALF "%f"
+ #endif
+#endif
+
+#define VEC_LOAD_BIN 16777216 // read binary file
+#define VEC_LOAD_BIN2 33554432 // read binary file with 2byte for each number
+#define VEC_LOAD_BIN4 67108864 // read binary file with 4byte for each number
+#define VEC_LOAD_CENTERIZE 134217728 // read binary file, and minus the half(128) from each number
+#define VEC_NORMALIZE 268435456 // read binary file, and minus the half(128) from each number
+
+/* matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ VEC *v;
+ VEC_ID end;
+ VEC_ID t;
+ VEC_VAL *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles;
+} MAT;
+
+/* sparse vector, element */
+typedef struct {
+ QUEUE_ID i;
+ SVEC_VAL a;
+} SVEC_ELE;
+
+/* sparse vector, vector */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SVEC_ELE *v;
+ VEC_ID end;
+ VEC_ID t;
+} SVEC;
+
+/* sparse vector, matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SVEC *v;
+ VEC_ID end;
+ VEC_ID t;
+ SVEC_ELE *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles, ele_end;
+} SMAT;
+
+/* sparse vector, matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ QUEUE *v;
+ VEC_ID end;
+ VEC_ID t;
+ QUEUE_INT *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles, ele_end;
+ WEIGHT **w, *wbuf;
+ int unit;
+} SETFAMILY;
+
+#define INIT_SETFAMILY_ {TYPE_SETFAMILY,NULL,0,0,NULL,NULL,0,0,0,0,NULL,NULL,sizeof(QUEUE_INT)}
+
+extern MAT INIT_MAT;
+extern SVEC INIT_SVEC;
+extern SMAT INIT_SMAT;
+extern SETFAMILY INIT_SETFAMILY;
+
+QSORT_TYPE_HEADER (SVEC_VAL, SVEC_VAL)
+QSORT_TYPE_HEADER (SVEC_VAL2, SVEC_VAL2)
+
+#define ARY_QUEUE_INPRO(f,U,V) do{(f)=0;FLOOP(common_size_t, 0, (U).t)(f)+=(V)[(U).v[common_size_t]];}while(0)
+#define ARY_SVEC_INPRO(f,U,V) do{(f)=0;FLOOP(common_size_t, 0, (U).t)(f)+=((double)(U).v[common_size_t].a)*(V)[(U).v[common_size_t].i];}while(0)
+
+/* terminate routine for VEC */
+void VEC_end (VEC *V);
+void MAT_end (MAT *M);
+void SVEC_end (SVEC *V);
+void SMAT_end (SMAT *M);
+void SETFAMILY_end (SETFAMILY *M);
+
+/* allocate memory according to rows and rowt */
+void VEC_alloc (VEC *V, VEC_ID clms);
+void MAT_alloc (MAT *M, VEC_ID rows, VEC_ID clms);
+void SVEC_alloc (SVEC *V, VEC_ID end);
+void SMAT_alloc (SMAT *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles);
+void SETFAMILY_alloc (SETFAMILY *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles);
+void SETFAMILY_alloc_weight (SETFAMILY *M);
+
+/* count/read the number in file for MAT */
+/* if *rows>0, only read count the numbers in a row, for the first scan. */
+void MAT_load_bin (MAT *M, FILE2 *fp, int unit);
+void MAT_file_load (MAT *M, FILE2 *fp);
+void MAT_load (MAT *M, char *fname);
+void SMAT_load (SMAT *M, char *fname);
+void SETFAMILY_load (SETFAMILY *M, char *fname, char *wfname);
+void SETFAMILY_load_weight (SETFAMILY *M, char *fname);
+
+void MAT_print (FILE *fp, MAT *M);
+void SVEC_print (FILE *fp, SVEC *M);
+void SMAT_print (FILE *fp, SMAT *M);
+void SETFAMILY_print (FILE *fp, SETFAMILY *M);
+void SETFAMILY_print_weight (FILE *fp, SETFAMILY *M);
+
+
+/* norm, normalization **************************/
+double SVEC_norm (SVEC *V);
+void SVEC_normalize (SVEC *V);
+
+/* inner product **************************/
+SVEC_VAL2 SVEC_inpro (SVEC *V1, SVEC *V2);
+
+/** Euclidean distance routines *********************************/
+double VEC_eucdist (VEC *V1, VEC *V2);
+double SVEC_eucdist (SVEC *V1, SVEC *V2);
+double VEC_SVEC_eucdist (VEC *V1, SVEC *V2);
+double QUEUE_eucdist (QUEUE *Q1, QUEUE *Q2);
+double VEC_QUEUE_eucdist (VEC *V, QUEUE *Q);
+
+void VEC_rand_gaussian (VEC *V);
+
+/* compute the inner product, Euclidean distance for multi vector */
+double MVEC_norm (void *V);
+double MVEC_inpro (void *V, void *U);
+double MVEC_double_inpro (void *V, double *p);
+double MVEC_eucdist (void *V, void *U);
+
+/* compute the inner product, euclidean distance for i,jth vector */
+double MMAT_inpro_ij (void *M, int i, int j);
+double MMAT_double_inpro_i (void *M, int i, double *p);
+double MMAT_eucdist_ij (void *M, int i, int j);
+double MMAT_norm_i (void *M, int i);
+
+
+#endif
--- /dev/null
+commit 33e47cd166f76946c54af8689d0fd52405671be2
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+require "fileutils"
+require "rubygems"
+require "traDB.rb"
+require "taxonomy.rb"
+require "cls.rb"
+require "caep.rb"
+
+def help
+
+STDERR.puts <<EOF
+----------------------------
+mitemset.rb version 1.0
+----------------------------
+概要) LCMにより多頻度アイテム集合を列挙する
+特徴) 1) 分類階層を扱うことが可能
+ 2) 頻出パターン, 飽和頻出パターン, 極大頻出パターンの3種類のパターンを列挙可能
+ 3) クラスを指定することで、上記3パターンに関する顕在パターン(emerging patterns)を列挙可能
+書式) mitemset.rb i= [x=] [c=] [O=] [tid=] [item=] [taxo=] [class=] [type=] [s=] [S=] [l=] [u=] [top=] [-replaceTaxo] [T=] [-debug] [--help]
+
+例) mitemset.rb i=basket.csv tid=traID item=商品
+
+ ファイル名指定
+ i= : アイテム集合データベースファイル名【必須】
+ c= : クラスファイル名【オプション】*1
+ x= : taxonomyファイル名【オブション】*1
+ O= : 出力ディレクトリ名【オプション:default:./take_現在日付時刻】
+
+ 項目名指定
+ tid= : トランザクションID項目名(i=上の項目名)【必須】
+ item= : アイテム項目名(i=上の項目名)【必須】
+ class= : クラス項目名(c=上の項目名)【オプション:default="class"】
+ taxo= : 分類項目名を指定する(x=上の項目名)【条件付き必須:x=】
+
+ 列挙パラメータ
+ type= : 抽出するパターンの型【オプション:default:F, F:頻出集合, C:飽和集合, M:極大集合】
+ s= : 最小支持度(全トランザクション数に対する割合による指定)【オプション:default:0.05, 0以上1以下の実数】
+ S= : 最小支持度(件数による指定)【オプション】
+ l= : パターンサイズの下限(1以上20以下の整数)【オプション:default:1】
+ u= : パターンサイズの上限(1以上20以下の整数)【オプション:default:4】
+ p= : 最小事後確率【オプション:default:0.6】
+ g= : 最小増加率【オプション:default:1.5】
+ top= : 列挙するパターン数の上限【オプション:default:10000】*2
+ 0を指定すると制限なしとなる。
+
+ その他
+ -replaceTaxo : taxonomyを置換する
+ T= : ワークディレクトリ(default:/tmp)
+ -debug : デバッグモード(メッセージを詳細に出力し,ワークファイルを消去しない)
+ --help : ヘルプの表示
+
+ 注釈
+ *1 x=が指定されたとき、itemに対応するtaxonomyをトランザクションに追加して実行する。例えば、アイテムa,bのtaxonomyをX、c,dのtaxonomyをYとすると、あるトランザクションabdはabdXYとなる。
+ ただし-replaceTaxoが指定されると、taxonomyは追加ではなく置換して実行する。前例ではトランザクションabdはXYに置換される。
+ *2 top=が指定された時の動作: 例えばtop=10と指定すると、支持度が10番目高いパターンの支持度を最小支持度として頻出パターンを列挙する。よって、同じ支持度のパターンが複数個ある場合は10個以上のパターンが列挙されるかもしれない。
+
+# より詳しい情報源 http://www.nysol.jp
+# LCMの詳しい情報源 http://research.nii.ac.jp/~uno/codes-j.htm
+# Copyright(c) NYSOL 2012- All Rights Reserved.
+EOF
+exit
+end
+
+help() if ARGV.size <= 0
+
+args=MCMD::Margs.new(ARGV,"i=,c=,x=,O=,tid=,item=,class=,taxo=,type=,s=,S=,g=,p=,-uniform,l=,u=,top=,T=,-replaceTaxo,--help,-debug")
+help() if args.bool("--help")
+
+iFile = args.file("i=","r")
+cFile = args.file("c=","r")
+xFile = args.file("x=","r")
+
+t=Time.now
+outPath = args.file("O=", "w", "./take_#{t.year}#{t.month}#{t.day}#{t.hour}#{t.min}#{t.sec}")
+
+idFN = args.field("tid=", iFile, "tid" )
+itemFN = args.field("item=", iFile, "item" )
+clsFN = args.field("class=", cFile, "class")
+taxoFN = args.field("taxo=", xFile, "taxo" )
+idFN = idFN["names"].join(",") if idFN
+itemFN = itemFN["names"].join(",") if itemFN
+clsFN = clsFN["names"].join(",") if clsFN
+taxoFN = taxoFN["names"].join(",") if taxoFN
+
+eArgs=Hash.new
+eArgs["type" ] = args. str("type=","F" )
+eArgs["minSup" ] = args.float("s=" ,0.05 ,0 ,1 ) # 最小サポート
+eArgs["minCnt" ] = args. int("S=" ,0 ,0 ) # 最小サポート件数
+eArgs["minProb"] = args.float("p=" ,0.6 ,0.5,1 ) # 最小事後確率
+eArgs["minGR" ] = args.float("g=" ,nil ,1.0,nil ) # 最小GR
+eArgs["uniform"] = args. bool("-uniform") # クラス事前確率を一様と考えるかどうか
+eArgs["minLen" ] = args. int("l=" ,1 ,1 ,20 )
+eArgs["maxLen" ] = args. int("u=" ,5 ,1 ,20 )
+eArgs["top" ] = args. int("top=" ,10000,0 ,1000000)
+
+eArgs["nomodel"] = true
+
+if ["F","C","M"].index(eArgs["type"]) == nil then
+ raise "type= takes one of values: 'F', 'C', 'M'"
+end
+
+if eArgs["minLen"] > eArgs["maxLen"] then
+ raise "u= must be greater than or equal to l="
+end
+
+if eArgs["type"]=="M" then
+ eArgs["top"]=0
+end
+
+# 実行環境の設定
+# KG_VerboseLevel: スクリプト内部で利用するMCMDの表示メッセージ
+# KG_ScpVerboseLevel: スクリプトの表示メッセージ
+if args.bool("-debug") then
+ ENV["KG_VerboseLevel"] = "4"
+ ENV["KG_ScpVerboseLevel"] = "4"
+else
+ ENV["KG_VerboseLevel"] = "2"
+ ENV["KG_ScpVerboseLevel"] = "4"
+end
+
+#ワークファイルパス
+if args.str("T=")!=nil then
+ ENV["KG_TmpPath"] = args.str("T=").sub(/\/$/,"")
+end
+
+# V型DBの読み込み
+db=TAKE::TraDB.new(iFile,idFN,itemFN)
+
+# クラスファイルがあれば読み込み
+cls=nil
+if cFile!=nil then
+ cls=TAKE::Cls.new(cFile,idFN,clsFN,nil)
+end
+
+# taxonomyのセット
+taxo=nil
+if xFile!=nil then
+ taxo=TAKE::Taxonomy.new(xFile,itemFN,taxoFN)
+ if args.bool("-replaceTaxo") then
+ db.repTaxo(taxo) # taxonomyの置換
+ else
+ db.addTaxo(taxo) # taxonomyの追加
+ end
+end
+
+# モデル構築
+model=TAKE::Caep.new(db,cls,eArgs)
+
+# 出力
+system("mkdir -p #{outPath}")
+model.output(outPath)
+
+MCMD::msgLog("The final results are in the directory `#{outPath}'")
+
+# 終了メッセージ
+MCMD::endLog("#{$0} #{args.argv.join(' ')}")
--- /dev/null
+#!/usr/bin/env ruby
+
+require "rubygems"
+require "mcmd"
+
+require "enumLcmEp.rb"
+require "enumLcmIs.rb"
+
+module TAKE
+
+#=CAEPクラス(基底クラス: Cmodel)
+# 顕在パターン(Emerging Patterns)を利用した分類モデル
+#
+class Caep
+ attr_reader :dir
+ attr_reader :ev
+ attr_reader :t_ev
+ attr_reader :t_tid_score
+ attr_reader :t_tid_pats
+
+ #=== Caepクラスの初期化
+ #
+ #====引数
+ # ep: EP オブジェクト
+ #
+ #====機能
+ #* 列挙されたepに基づいて、分類モデル(caep)を構築する。
+ #
+ #====機能
+ #* epに基づいてモデルを構築する。
+ #* 構築されたモデルを評価する(Cmodelのメソッド全て利用可能)。
+ def initialize(db,cls,eArgs)
+ @temp=MCMD::Mtemp.new
+
+ @db = db
+ @cls = cls
+ @eArgs = eArgs
+
+ pat=nil
+ if @cls then
+ pat=TAKE::LcmEp.new(@db,@cls);
+ pat.enumerate(eArgs["type"],eArgs["minSup"],eArgs["minCnt"],eArgs["minGR"],eArgs["minProb"],eArgs["uniform"],eArgs["minLen"],eArgs["maxLen"],eArgs["top"])
+ else
+ pat=TAKE::LcmIs.new(@db);
+ pat.enumerate(eArgs["type"],eArgs["minSup"],eArgs["minLen"],eArgs["maxLen"],eArgs["top"],eArgs["minCnt"])
+ end
+
+ # クラス指定がない場合もしくは-nomodelが指定された場合はパターン列挙のみ
+ if not @cls or eArgs["nomodel"] then
+ @pat=pat
+ return
+ end
+ end
+
+ def output(outpath)
+ # クラス指定なしの場合
+ if @pat!=nil then
+ @pat.output(outpath)
+ end
+ return
+ end
+end
+
+end #module
+
--- /dev/null
+#!/usr/bin/env ruby
+require "rubygems"
+require "mcmd"
+
+module TAKE
+
+#=分類問題における分類クラスを扱うクラス
+# 新たにファイルを生成することはない。
+class Cls
+ @@limitSize = 10
+
+ # クラス項目名(String)
+ attr_reader :idFN
+ attr_reader :clsFN
+ attr_reader :file
+ attr_reader :t_file
+
+ # クラス名配列(=>String Array)
+ attr_reader :names
+ attr_reader :nameRecSize
+
+ attr_reader :recSize
+
+ # クラスサイズ(=>Fixnum)
+ attr_reader :size
+
+ #=== clsクラスの初期化
+ # 初期化方法は以下の2通り。
+ #* 与えられたCSVデータファイルによって初期化する。
+ # 第1引数: ファイル名
+ # 第2引数: そのファイル上のクラス項目名
+ # 第3引数: クラス項目名(デフォルトは第2引数)
+ # ファイルの中でクラス名が重複していても単一化して登録するので問題ない。
+ # ex. cls=Cls.new("tra.csv","customer type")
+ #
+ #* クラス項目名とクラス名配列を与えて初期化する。
+ # 第1引数: クラス項目名(String)
+ # 第2引数: クラス名配列(String Array)
+ # ex. cls=Cls.new("customer type",["good","normal","bad"])
+ #
+ #====機能
+ #* クラス数をカウントする(Cls.size)。
+ #* クラス名別件数を取得する(Cls.nameSize配列)。
+ def initialize(iFile,idFN,clsFN,t_iFile=nil)
+ @temp=MCMD::Mtemp.new
+
+ @iFile = iFile
+ @iPath = File.expand_path(@iFile)
+ @idFN = idFN
+ @clsFN = clsFN
+ @file = @temp.file
+ @t_iFile = t_iFile
+
+ # tid-クラス項目名ファイルの生成
+ f=""
+ f << "mcut f=#{@idFN},#{@clsFN} i=#{@iFile} |"
+ f << "msortf f=#{@idFN},#{@clsFN} |"
+ f << "muniq k=#{@idFN},#{@clsFN} o=#{@file}"
+ system(f)
+
+ # レコード数の計算
+ @recSize = MCMD::mrecount("i=#{@file}")
+
+ # クラス別件数
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "mcut f=#{@clsFN} i=#{@iFile} |"
+ f << "msortf f=#{@clsFN} |"
+ f << "mcount k=#{@clsFN} a=count o=#{xx1}"
+ system(f)
+
+ # クラス数
+ @size = MCMD::mrecount("i=#{xx1}")
+
+ # 文字列としてのクラス別件数配列を数値配列に変換する
+ @names = Array.new
+ @nameRecSize = Hash.new
+ MCMD::Mcsvin.new("i=#{xx1}"){|csv|
+ csv.each{|fldVal|
+ @names.push fldVal[csv.names[0]]
+ @nameRecSize[fldVal[csv.names[0]]]=fldVal[csv.names[1]].to_i
+ }
+ }
+
+ # テストファイル
+ if @t_iFile!=nil then
+ @t_file = @temp.file # テスト名
+ f=""
+ f << "mcut f=#{@idFN},#{@clsFN} i=#{@t_iFile} |"
+ f << "msortf f=#{@idFN},#{@clsFN} |"
+ f << "muniq k=#{@idFN},#{@clsFN} o=#{@t_file}"
+ system(f)
+ end
+ end
+
+public
+
+ def replaceFile(train,test)
+ @file = train
+ @t_file = test
+
+ # レコード数の計算
+ @recSize = MCMD::mrecount("i=#{@file}")
+
+ # クラス別件数
+ xx1=MCMD::Mtemp.new #("xx1","",true)
+ f=""
+ f << "mcut f=#{@clsFN} i=#{@iFile} |"
+ f << "msortf f=#{@clsFN} |"
+ f << "mcount k=#{@clsFN} a=count o=#{xx1.name}"
+ system(f)
+
+ # 文字列としてのクラス別件数配列を数値配列に変換する
+ @names.each{|cname|
+ @nameRecSize[cname] = 0
+ }
+ Mcsv.new("i=#{xx1.name}").each{|fldName,fldVal,recNo|
+ @nameRecSize[fldVal[fldName[0]]] = fldVal[fldName[1]].to_i
+ }
+ end
+end
+
+end #module
--- /dev/null
+#!/usr/bin/env ruby
+require "rubygems"
+require "mcmd"
+
+require "lcm"
+require "traDB.rb"
+require "cls.rb"
+
+module TAKE
+
+#========================================================================
+# 列挙関数:lcm 利用DB:TraDB
+#========================================================================
+class LcmEp
+ #@@intMax=2147483646
+ @@intMax=100
+
+ attr_reader :pFile # パターンファイル
+ attr_reader :db # データベース
+ attr_reader :cls # クラス
+ attr_reader :his # クラス
+ attr_reader :size # 列挙されたパターン数
+
+ # posトランザクションの重み計算
+ # マニュアルの式(10)
+ def calOmega(posCnt)
+ return @@intMax/posCnt
+ end
+
+ # LCM最小サポートの計算
+ # マニュアルの式(9)
+ def calSigma(minPos,minGR,posCnt,negCnt)
+ omegaF=@@intMax.to_f/posCnt.to_f
+ beta=minPos
+ w=posCnt.to_f/negCnt.to_f
+ sigma=(beta*(omegaF-w/minGR)).to_i # 切り捨て
+
+ return sigma
+ end
+
+ def reduceTaxo(pat,items)
+ tf=MCMD::Mtemp.new
+
+ if items.taxonomy==nil then
+ return pat
+ end
+
+ xxrt = tf.file
+ taxo=items.taxonomy
+ f=""
+ f << "mtrafld f=#{taxo.itemFN},#{taxo.taxoFN} -valOnly a=__fld i=#{taxo.file} o=#{xxrt}"
+ system(f)
+
+ # xxrtの内容:oyakoに親子関係にあるアイテム集合のリストが格納される
+ # __fld
+ # A X
+ # B X
+ # C Y
+ # D Z
+ # E Z
+ # F Z
+ oyako=ZDD.constant(0)
+ MCMD::Mcsvin.new("i=#{xxrt}"){|csv|
+ csv.each{|fldVal|
+ items=fldVal["__fld"]
+ oyako=oyako+ZDD.itemset(items)
+ }
+ }
+
+ # 親子リストにあるアイテム集合を含むパターンを削除する
+ pat=pat.restrict(oyako).iif(0,pat)
+
+ return pat
+ end
+
+ def initialize(db,cls)
+ @temp=MCMD::Mtemp.new
+
+ @db = db # 入力データベース
+ @cls = cls # 分類クラス
+ @file=@temp.file
+ items=@db.items
+
+ # 重みファイルの作成
+ # pos,negのTransactionオブジェクトに対してLCMが扱う整数アイテムによるトランザクションファイルを生成する。
+ # この時、pos,negを併合して一つのファイルとして作成され(@wNumTraFile)、
+ # 重みファイル(@weightFile[クラス])の作成は以下の通り。
+ # 1.対象クラスをpos、その他のクラスをnegとする。
+ # 2. negの重みは-1に設定し、posの重みはcalOmegaで計算した値。
+ # 3.@wNumTraFileの各行のクラスに対応した重みデータを出力する(1項目のみのデータ)。
+ @weightFile = Hash.new
+ @posWeight = Hash.new
+ @sigma = Hash.new
+ @cls.nameRecSize.each {|cName,posSize|
+ @weightFile[cName] = @temp.file
+ @posWeight[cName]=calOmega(posSize)
+
+ f=""
+ f << "mcut -nfno f=#{@cls.clsFN} i=#{@cls.file} |"
+ f << "mchgstr -nfn f=0 c=#{cName}:#{@posWeight[cName]} O=-1 o=#{@weightFile[cName]}"
+ system(f)
+ }
+
+ # アイテムをシンボルから番号に変換する。
+ f=""
+ f << "msortf f=#{@db.itemFN} i=#{@db.file} |"
+ f << "mjoin k=#{@db.itemFN} K=#{items.itemFN} m=#{items.file} f=#{items.idFN} |"
+ f << "mcut f=#{@db.idFN},#{items.idFN} |"
+ f << "msortf f=#{@db.idFN} |"
+ f << "mtra k=#{@db.idFN} f=#{items.idFN} |"
+ f << "mcut f=#{items.idFN} -nfno o=#{@file}"
+ system(f)
+ end
+
+
+ # 各種パラメータを与えて列挙を実行
+ def enumerate(type, minSup, minPos, minGR, minProb, uniform, lenLB=1, lenUB=4, top=10000)
+ @type = type
+ @lenLB = lenLB
+ @lenUB = lenUB
+ @top = top
+
+ pFiles=[]
+ tFiles=[]
+ tf=MCMD::Mtemp.new
+ @cls.nameRecSize.each{|cName,posSize|
+ negSize=@db.size-posSize
+ # minGRの計算
+ if minGR then
+ @minGR=minGR
+ else
+ if minProb then
+ if uniform then
+ @minGR = (minProb/(1-minProb)) * (@cls.size-1) # マニュアルの式(4)
+ else
+ @minGR = (minProb/(1-minProb)) * (negSize.to_f/posSize.to_f) # マニュアルの式(4)
+ end
+ end
+ end
+
+ # minSupCntの計算
+ if minPos then
+ @minPos = minPos
+ else
+ @minPos = (minSup * posSize.to_f + 0.99).to_i
+ end
+
+ xxp = tf.file
+ xxt = tf.file
+ @sigma[cName] = calSigma(@minPos,@minGR,posSize,negSize)
+
+ if(top==0) then
+ MCMD::lcm("type=#{@type} i=#{@file} s=#{@sigma[cName]} l=#{@lenLB} u=#{@lenUB} o=#{xxp} t=#{xxt} w=#{@weightFile[cName]}")
+ else
+ MCMD::lcm("type=#{@type} i=#{@file} s=#{@sigma[cName]} l=#{@lenLB} u=#{@lenUB} o=#{xxp} t=#{xxt} w=#{@weightFile[cName]} K=#{@top}")
+ end
+
+ # パターンのサポートを計算しCSV出力する
+ MCMD::msgLog("output patterns to CSV file ...")
+ xxpf=tf.file
+ pFiles << xxpf
+ items=@db.items
+ f=""
+ f << "mcut -nfni f=0:pid,1:pattern,3:pc,4:nc i=#{xxp} |"
+ f << "mcal c='round(${nc},1)' a=neg |"
+ f << "mcal c='round(${pc}/#{@posWeight[cName]},1)' a=pos |"
+ f << "mdelnull f=pattern |"
+ f << "msetstr v=#{cName} a=class |"
+ f << "msetstr v=#{posSize} a=posTotal |"
+ f << "msetstr v=#{@minPos} a=minPos |"
+ f << "msetstr v=#{@minGR} a=minGR |"
+ f << "mcut f=class,pid,pattern,pos,neg,posTotal,minPos,minGR o=#{xxpf}"
+ system(f)
+
+ s = MCMD::mrecount("i=#{xxpf}") # 列挙されたパターンの数
+ MCMD::msgLog("the number of contrast patterns on class `#{cName}' enumerated is #{s}")
+
+ # トランザクション毎に出現するパターンを書き出す
+ MCMD::msgLog("output tid-patterns ...")
+ xxtf=tf.file
+ tFiles << xxtf
+
+ xxt4=tf.file
+ f=""
+ f << "mcut f=#{@db.idFN} i=#{@db.file} |"
+ f << "muniq k=#{@db.idFN} |"
+ f << "mnumber S=0 a=__tno |"
+ f << "msortf f=__tno o=#{xxt4};"
+ system(f)
+
+ f=""
+ f << "mcut -nfni f=0:__tno,1:pid i=#{xxt} |"
+ f << "msortf f=__tno |"
+ f << "mjoin k=__tno m=#{xxt4} f=#{@db.idFN} |"
+ f << "msetstr v=#{cName} a=class |"
+ f << "mcut f=#{@db.idFN},class,pid o=#{xxtf}"
+ system(f)
+ }
+
+ # クラス別のパターンとtid-pidファイルを併合する
+ items=@db.items
+ @pFile = @temp.file
+ @tFile = @temp.file
+
+ xxtee0 = tf.file
+
+ pAll=pFiles.join(",")
+ tAll=tFiles.join(",")
+
+ f=""
+ # パターンファイル併合
+ f << "mcat i=#{pAll} |"
+ f << "msortf f=class,pid |"
+ f << "mnumber S=0 a=ppid o=#{xxtee0}"
+ system(f)
+
+ f=""
+ # パターンファイル計算
+ f << "mcut f=class,ppid:pid,pattern,pos,neg,posTotal,minPos,minGR i=#{xxtee0} |"
+ f << "msetstr v=#{@db.size} a=total |" # トータル件数
+ f << "mcal c='${total}-${posTotal}' a=negTotal |" # negのトータル件数
+ f << "mcal c='${pos}/${posTotal}' a=support |" # サポートの計算
+ f << "mcal c='if(${neg}==0,1.797693135e+308,(${pos}/${posTotal})/(${neg}/${negTotal}))' a=growthRate |"
+
+ if uniform then
+ f << "mcal c='(${pos}/${posTotal})/(${pos}/${posTotal}+(#{@cls.size}-1)*${neg}/${negTotal})' a=postProb |"
+ else
+ f << "mcal c='${pos}/(${pos}+${neg})' a=postProb1 |"
+ end
+ f << "mcal c='(${pos}/${posTotal})/(${pos}/${posTotal}+(#{@cls.size}-1)*${neg}/${negTotal})' a=postProb |"
+ f << "msel c='${pos}>=${minPos}&&${growthRate}>=${minGR}' |" # minSupとminGRによる選択
+ f << "mvreplace vf=pattern m=#{items.file} K=#{items.idFN} f=#{items.itemFN} |"
+ f << "mcut f=class,pid,pattern,pos,neg,posTotal,negTotal,total,support,growthRate,postProb |"
+ f << "mvsort vf=pattern |"
+ f << "msortf f=class%nr,postProb%nr,pos%nr o=#{@pFile}"
+ system(f)
+
+ if items.taxonomy then
+ MCMD::msgLog("reducing redundant rules in terms of taxonomy ...")
+ zdd=ZDD.constant(0)
+ MCMD::Mcsvin.new("i=#{@pFile}"){|csv|
+ csv.each{|fldVal|
+ items=fldVal['pattern']
+ zdd=zdd+ZDD.itemset(items)
+ }
+ }
+ zdd=reduceTaxo(zdd,@db.items)
+
+ xxp1=tf.file
+ xxp2=tf.file
+ xxp3=tf.file
+ zdd.csvout(xxp1)
+
+ f=""
+ f << "mcut -nfni f=1:pattern i=#{xxp1} |"
+ f << "mvsort vf=pattern |"
+ f << "msortf f=pattern o=#{xxp2}"
+ system(f)
+
+ f=""
+ f << "msortf f=pattern i=#{@pFile} |"
+ f << "mcommon k=pattern m=#{xxp2} |"
+ f << "msortf f=class%nr,postProb%nr,pos%nr o=#{xxp3}"
+ system(f)
+ system "mv #{xxp3} #{@pFile}"
+ end
+
+ xxp4=tf.file
+ f=""
+ f << "mcut f=class,pid i=#{@pFile} |"
+ f << "msortf f=class,pid o=#{xxp4}"
+ system(f)
+
+ f=""
+ # tid-pidファイル計算
+ f << "mcat i=#{tAll} |"
+ f << "msortf f=class,pid |"
+ f << "mcommon k=class,pid m=#{xxp4} |"
+ f << "msortf f=class,pid |"
+ f << "mjoin k=class,pid f=ppid m=#{xxtee0} |"
+ f << "mcut f=#{@db.idFN},class,ppid:pid |"
+ f << "msortf f=#{@db.idFN},class,pid o=#{@tFile}"
+ system(f)
+
+ @size = MCMD::mrecount("i=#{@pFile}") # 列挙されたパターンの数
+ MCMD::msgLog("the number of emerging patterns enumerated is #{@size}")
+ end
+
+ def output(outpath)
+ FileUtils.mv(@pFile,outpath+"/patterns.csv")
+ FileUtils.mv(@tFile,outpath+"/tid_pat.csv")
+ end
+end
+
+end #module
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+require "rubygems"
+require "mcmd"
+
+require "lcm"
+require "zdd"
+require "traDB.rb"
+
+module TAKE
+
+
+#========================================================================
+# 列挙関数:lcm 利用DB:TraDB
+#========================================================================
+class LcmIs
+ attr_reader :size # 列挙されたパターン数
+
+ def reduceTaxo(pat,items)
+ tf=MCMD::Mtemp.new
+
+ if items.taxonomy==nil then
+ return pat
+ end
+
+ xxrt = tf.file
+ taxo=items.taxonomy
+ f=""
+ f << "mtrafld f=#{taxo.itemFN},#{taxo.taxoFN} -valOnly a=__fld i=#{taxo.file} o=#{xxrt}"
+ system(f)
+
+ # xxrtの内容:oyakoに親子関係にあるアイテム集合のリストが格納される
+ # __fld
+ # A X
+ # B X
+ # C Y
+ # D Z
+ # E Z
+ # F Z
+ oyako=ZDD.constant(0)
+ MCMD::Mcsvin.new("i=#{xxrt}"){|csv|
+ csv.each{|fldVal|
+ items=fldVal["__fld"]
+ oyako=oyako+ZDD.itemset(items)
+ }
+ }
+
+ # 親子リストにあるアイテム集合を含むパターンを削除する
+ pat=pat.restrict(oyako).iif(0,pat)
+
+ return pat
+ end
+
+ def initialize(db)
+ @temp=MCMD::Mtemp.new
+
+ @db = db # 入力データベース
+
+ @file=@temp.file
+
+ items=@db.items
+
+ # アイテムをシンボルから番号に変換する。
+ f=""
+ f << "msortf f=#{@db.itemFN} i=#{@db.file} |"
+ f << "mjoin k=#{@db.itemFN} K=#{items.itemFN} m=#{items.file} f=#{items.idFN} |"
+ f << "mcut f=#{@db.idFN},#{items.idFN} |"
+ f << "msortf f=#{@db.idFN} |"
+ f << "mtra k=#{@db.idFN} f=#{items.idFN} |"
+ f << "mcut f=#{items.idFN} -nfno o=#{@file}"
+ system(f)
+ end
+
+ def enumerate(type, minSup, lenLB=1, lenUB=4, top=10000, minSupCnt=0)
+
+ tf=MCMD::Mtemp.new
+
+ @type = type
+ if minSupCnt!=0 then
+ @minSupCnt = minSupCnt
+ @minSup = minSupCnt.to_f / @db.size.to_f
+ else
+ @minSup = minSup.to_f
+ @minSupCnt = (@minSup * @db.size.to_f + 0.99).to_i
+ end
+ @lenLB = lenLB
+ @lenUB = lenUB
+ @top = top
+
+ xxp = tf.file #MCMD::Mtemp.new
+ xxt = tf.file #MCMD::Mtemp.new
+
+ if(top==0) then
+ MCMD::lcm("type=#{@type} i=#{@file} s=#{@minSupCnt} l=#{@lenLB} u=#{@lenUB} o=#{xxp} t=#{xxt}")
+ else
+ MCMD::lcm("type=#{@type} i=#{@file} s=#{@minSupCnt} l=#{@lenLB} u=#{@lenUB} o=#{xxp} t=#{xxt} K=#{@top}")
+ end
+
+ # パターンのサポートを計算しCSV出力する
+ MCMD::msgLog("output patterns to CSV file ...")
+ xxp0=tf.file
+ @pFile = @temp.file
+ items=@db.items
+ f=""
+ f << "mcut -nfni f=0:pid,1:pattern,2:count i=#{xxp} |"
+ f << "mdelnull f=pattern |"
+ f << "mvreplace vf=pattern m=#{items.file} K=#{items.idFN} f=#{items.itemFN} |"
+ f << "msetstr v=#{@db.size} a=total |" # トータル件数
+ f << "mcal c='${count}/${total}' a=support |" # サポートの計算
+ f << "mcut f=pid,pattern,count,total,support |"
+ f << "mtra -r f=pattern |"
+ f << "msortf f=pid,pattern |"
+ f << "mtra k=pid f=pattern |"
+ f << "mvsort vf=pattern |"
+ f << "msortf f=pattern o=#{xxp0}"
+ system(f)
+
+ # taxonomy指定がない場合(2010/11/20追加)
+ if items.taxonomy==nil then
+ FileUtils.cp(xxp0, @pFile)
+
+ # taxonomy指定がある場合
+ else
+ MCMD::msgLog("reducing redundant rules in terms of taxonomy ...")
+ zdd=ZDD.constant(0)
+ MCMD::Mcsvin.new("i=#{xxp0}"){|csv|
+ csv.each{|fldVal|
+ items=fldVal['pattern']
+ zdd=zdd+ZDD.itemset(items)
+ }
+ }
+
+ zdd=reduceTaxo(zdd,@db.items)
+ xxp1=tf.file
+ xxp2=tf.file
+ zdd.csvout(xxp1)
+ f=""
+ f << "mcut -nfni f=1:pattern i=#{xxp1} |"
+ f << "mvsort vf=pattern |"
+ f << "msortf f=pattern o=#{xxp2}"
+ system(f)
+
+ f=""
+ f << "msortf f=pattern i=#{xxp0} |"
+ f << "mcommon k=pattern m=#{xxp2} |"
+ f << "msortf f=support%nr o=#{@pFile}"
+ system(f)
+
+ end
+
+ @size = MCMD::mrecount("i=#{@pFile}") # 列挙されたパターンの数
+ MCMD::msgLog("the number of patterns enumerated is #{@size}")
+
+ # トランザクション毎に出現するシーケンスを書き出す
+ MCMD::msgLog("output tid-patterns ...")
+ @tFile = @temp.file
+
+ xxp3=tf.file
+ f=""
+ f << "mcut f=#{@db.idFN} i=#{@db.file} |"
+ f << "muniq k=#{@db.idFN} |"
+ f << "mnumber S=0 a=__tno |"
+ f << "msortf f=__tno o=#{xxp3}"
+ system(f)
+
+ xxp4=tf.file
+ f=""
+ f << "mcut f=pid i=#{@pFile} |"
+ f << "msortf f=pid o=#{xxp4}"
+ system(f)
+
+ f=""
+ f << "mcut -nfni f=0:__tno,1:pid i=#{xxt} |"
+ f << "msortf f=pid |"
+ f << "mcommon k=pid m=#{xxp4} |"
+ f << "msortf f=__tno |"
+ f << "mjoin k=__tno m=#{xxp3} f=#{@db.idFN} |"
+ f << "mcut f=#{@db.idFN},pid o=#{@tFile}"
+ system(f)
+ end
+
+ def output(outpath)
+ system "mv #{@pFile} #{outpath}/patterns.csv"
+ system "mv #{@tFile} #{outpath}/tid_pats.csv"
+ end
+end
+
+end #module
+
--- /dev/null
+#!/usr/bin/env ruby
+require "rubygems"
+require "mcmd"
+
+require "taxonomy.rb"
+
+module TAKE
+
+#=アイテムクラス
+# 頻出パターンマイニングで使われるアイテムを扱うクラス。
+#
+#===利用例
+# 以下tra.csvの内容
+# ---
+# items
+# a b c
+# a c
+# b
+# c b d
+#
+# 以下taxo.csvの内容
+# ---
+# item,taxo
+# a,X1
+# b,X1
+# c,X2
+# d,X2
+#
+# 以下rubyスクリプト
+# ---
+# require 'rubygems'
+# require 'mining'
+# items=Items.new("tra.csv","items","item")
+# puts items.file # => ./1252810329_1850/dat/1
+# puts items.itemFN # => "item"
+# puts items.idFN # => "iid"
+# puts items.size # => 4
+# puts items.taxonomy # =>nil
+#
+# taxo=Taxonomy.new("taxo.csv","item","taxo")
+# items.addTaxo(taxo)
+# puts items.file # => ./1252810329_1850/dat/3
+# puts items.itemFN # => "item"
+# puts items.idFN # => "iid"
+# puts items.size # => 4
+# p items.taxonomy # => #<Taxonomy:0x1698eac @itemSize=4, @iFile="taxo.csv", @taxoFN="taxo", @itemFN="item", ...,@file="./1252810329_1850/dat/2">
+#
+#=====./1252810329_1850/dat/1 の内容
+# item,iid
+# a,1
+# b,2
+# c,3
+# d,4
+#
+#=====./1252810329_1850/dat/3 の内容
+# item,iid
+# X1,5
+# X2,6
+# a,1
+# b,2
+# c,3
+# d,4
+#
+class Items
+ # itemsファイル (=>Mfile)
+ attr_reader :file
+
+ # アイテムの項目名(=>String)
+ attr_reader :itemFN
+
+ # id項目名(=>String)
+ attr_reader :idFN
+
+ # アイテムの種類数(=>Fixnum)
+ attr_reader :size
+
+ # 分類階層クラス(=>Taxonomy)
+ attr_reader :taxonomy
+
+private
+
+ #==初期化
+ #=====引数
+ # iFile: アイテム項目を含むファイル名
+ # itemFN: 新しいアイテム項目名
+ # idFN: 連番によるアイテムidの項目名(デフォルト:"iid")
+ #=====機能
+ #* iFile上のアイテム項目(@itemFN)からアイテム(@itemFN)と連番("num")の2項目からなるファイルを生成する。
+ #* itemFN項目の値としては、スペースで区切られた複数のアイテムであってもよい。
+ #* 同じアイテムが重複して登録されていれば単一化される。
+ #* アイテム順にソートされる。
+ #* アイテムの件数(種類数)がセットされる。
+ def initialize(iFile,itemFN,idFN="__iid")
+ @temp=MCMD::Mtemp.new
+
+ @iFile = Array.new
+ @iPath = Array.new
+ @iFile.push(iFile)
+ @iPath.push(File.expand_path(iFile))
+ @taxonomy = nil
+ @file = @temp.file # 出力ファイル名
+ @itemFN=itemFN
+ @idFN=idFN
+
+ f=""
+ f << "mcut f=#{itemFN} i=#{iFile} |"
+ f << "msortf f=#{itemFN} |"
+ f << "muniq k=#{itemFN} |"
+ f << "mnumber a=#{idFN} S=1 o=#{@file}"
+ system(f)
+
+ @size = MCMD::mrecount("i=#{@file}") # itemの数
+
+ end
+
+public
+
+ #==アイテムの追加
+ # iFileのitemFN項目をアイテムとして追加する。
+ #=====引数
+ # iFile: アイテム項目を含むファイル名
+ # itemFN: iFile上のアイテム項目名
+ #=====機能
+ #* itemFNとしては、スペースで区切られた複数のアイテムであってもよい。
+ #* 同じアイテムが重複していれば単一化される。
+ #* 追加後アイテム順にソートされる。
+ #* アイテム数が更新される。
+ def add(iFile,itemFN)
+
+ @iFile.push(iFile)
+ @iPath.push(File.expand_path(iFile))
+
+ xx=MCMD::Mtemp.new
+ xx1=xx.file
+ xx2=xx.file
+ f=""
+ f << "msortf f=#{@itemFN} i=#{iFile} |"
+ f << "mcommon k=#{@itemFN} m=#{@file} |"
+ f << "mcut f=#{itemFN}:#{@itemFN} |"
+ f << "msortf f=#{@itemFN} |"
+ f << "muniq k=#{@itemFN} |"
+ f << "mnumber S=#{@size+1} a=#{@idFN} o=#{xx1}"
+ system(f)
+
+ f=""
+ f << "mcat i=#{@file},#{xx1} |"
+ f << "msortf f=#{@itemFN} o=#{xx2}"
+ system(f)
+
+ # 新itemファイル登録&item数更新
+ FileUtils.mv(xx2,@file)
+ @size = MCMD::mrecount("i=#{@file}")
+
+ end
+
+ #==Taxonomyの設定
+ # Taxonomy(分類階層)を設定する。
+ #=====引数
+ # taxo: taxonomy オブジェクト
+ #=====機能
+ #* Taxonomyオブジェクトをメンバとして追加する。
+ #* 分類項目をアイテムとして追加する。
+ def addTaxo(taxo)
+
+ @taxonomy=taxo
+
+ add(@taxonomy.file,@taxonomy.taxoFN) # taxonomyをアイテムとして追加登録
+
+ end
+
+ def repTaxo(taxo)
+
+ #@taxonomy=taxo #replaceの場合はtaxonomyを登録しない
+
+ @file = @temp.file # 出力ファイル名
+ f=""
+ f << "mcut f=#{taxo.taxoFN}:#{@itemFN} i=#{taxo.file} |"
+ f << "msortf f=#{@itemFN} |"
+ f << "muniq k=#{@itemFN} |"
+ f << "mnumber a=#{@idFN} S=1 o=#{@file}"
+ system(f)
+
+ end
+
+end
+
+end # module
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+require "rubygems"
+require "mcmd"
+
+module TAKE
+
+#=分類階層(taxonomy)クラス
+# 一階層の分類階層(アイテム-分類)を扱うクラス。
+#
+#===利用例
+# 以下taxo.csvの内容
+# ---
+# item,taxo
+# a,X1
+# b,X1
+# c,X2
+# d,X2
+#
+# 以下rubyスクリプト
+# ---
+# require 'rubygems'
+# require 'mining'
+# taxo=Taxonomy("taxo.csv","item","taxo")
+# puts taxo.itemFN # => "item"
+# puts taxo.taxoFN # => "taxo"
+# puts taxo.itemSize # => 4 (アイテムは"a,b,c,d"の4種類)
+# puts taxo.taxoSize # => 2 (分類は"X1,X2"の2種類)
+# puts taxo.file # => ./1252379737_1756/dat/1
+#
+#=====./1252379737_1756/dat/1 の内容
+# item,taxo
+# a,X1
+# b,X1
+# c,X2
+# d,X2
+class Taxonomy
+ # アイテムの項目名(=>String)
+ attr_reader :itemFN
+
+ # 分類の項目名(=>String)
+ attr_reader :taxoFN
+
+ # アイテムの種類数(=>Fixnum)
+ attr_reader :itemSize
+
+ # 分類の種類数(=>Fixnum)
+ attr_reader :taxoSize
+
+ # taxonomyデータファイル名(=>String)
+ attr_reader :file
+
+ #=== taxonomyクラスの初期化
+ # 一階層の分類階層を扱う。
+ # アイテム項目とその分類名項目を持つファイルから分類階層オブジェクトを生成する。
+ #====引数
+ # iFile: taxonomyファイル名
+ # itemFN: アイテム項目名
+ # taxoFN: 分類項目名
+ #====機能
+ #* アイテム(itemFN)と分類(taxoFN)の2項目からなるファイルが規定のパス(Taxonomy.file)に書き出される。
+ #* 同じアイテムが重複して登録されていれば単一化して書き出される。
+ #* アイテム順にソートされる。
+ #* アイテム数と分類数を計算する。
+ def initialize(iFile,itemFN,taxoFN)
+ @temp=MCMD::Mtemp.new
+
+ @iFile = iFile
+ @iPath = File.expand_path(@iFile)
+ @itemFN = itemFN
+ @taxoFN = taxoFN
+
+ # item順に並べ替えてpathに書き出す
+ @file=@temp.file
+ f=""
+ f << "mcut f=#{@itemFN},#{@taxoFN} i=#{@iFile} |"
+ f << "msortf f=#{@itemFN},#{@taxoFN} |"
+ f << "muniq k=#{@itemFN},#{@taxoFN} o=#{@file}"
+ system(f)
+
+ # oFileに登録されているitemの数をカウントする
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "mcut f=#{@itemFN} i=#{iFile} |"
+ f << "mtrafld f=#{@itemFN} a=__fld -valOnly |"
+ f << "mtra f=__fld -r |"
+ f << "msortf f=__fld |"
+ f << "muniq k=__fld |"
+ f << "mcount a=size |"
+ f << "mcut f=size -nfno o=#{xx1}"
+ system(f)
+ tbl=MCMD::Mtable.new("i=#{xx1} -nfn")
+ @itemSize = tbl.cell(0,0).to_i
+
+ # oFileに登録されているtaxonomyの数をカウントする
+ xx2=tf.file
+ f=""
+ f << "mcut f=#{@taxoFN}:item i=#{@file} |"
+ f << "msortf f=item |"
+ f << "muniq k=item |"
+ f << "mcount a=size |"
+ f << "mcut f=size -nfno o=#{xx2}"
+ system(f)
+ tbl=MCMD::Mtable.new("i=#{xx2} -nfn")
+ @taxoSize = tbl.cell(0,0).to_i
+ end
+
+end
+
+end #module
+
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+require "rubygems"
+require "mcmd"
+
+require "items.rb"
+
+module TAKE
+
+#=トランザクションデータクラス
+# 頻出パターンマイニングで使われるトランザクションデータを扱うクラス。
+# トランザクションファイルは、トランザクションID項目とアイテム集合項目から構成される。
+# アイテム集合は、スペースで区切られた文字列集合として表現される。
+#
+#===利用例
+# 以下tra.csvの内容
+# ---
+# items
+# a b d
+# a d e
+# c e
+# a d
+# c d e
+# c e
+# a d e
+#
+# 以下taxo.csvの内容
+# ---
+# item,taxo
+# a,X1
+# b,X1
+# c,X2
+# d,X2
+# e,X2
+#
+# 以下rubyスクリプト
+# ---
+# require 'rubygems'
+# require 'mining'
+#
+# tra=TraDB.new("tra.csv",nil,"items")
+# puts tra.file # => ./1252813069_2179/dat/1
+# puts tra.numTraFile # => nil
+# puts tra.idFN # => tid
+# puts tra.itemsetFN # => items
+# puts tra.recCnt # => 7
+# p tra.items # => #<Items:0x16a39ec @iItemFN=["items"],...
+#
+# taxo=Taxonomy.new("taxo.csv","item","taxo")
+# tra.addTaxo(taxo)
+# tra.mkNumTra
+# puts tra.numTraFile #=> ./1252813069_2179/dat/6
+# p tra.items #=> #<Items:0x16a39ec @iItemFN=["items", "taxo"],..., @taxonomy=#<Taxonomy:0x168ba7c ...
+#
+#=====./1252813069_2179/dat/1 の内容
+# tid,items
+# 1,a b d
+# 2,a d e
+# 3,c e
+# 4,a d
+# 5,c d e
+# 6,c e
+# 7,a d e
+#
+#=====./1252813069_2179/dat/6 の内容
+# 1 2 3 4 5 6 7
+# 1 2 4 6 7
+# 1 4 5 6 7
+# 3 5 7
+# 1 4 6 7
+# 3 4 5 7
+# 3 5 7
+# 1 4 5 6 7
+#
+class TraDB
+ # トランザクションファイル名
+ attr_reader :file
+
+ # トランザクションID項目名(String)
+ attr_reader :idFN
+
+ # アイテム集合項目名(String)
+ attr_reader :itemFN
+
+ # レコード数(Num)
+ attr_reader :recCnt
+
+ # トランザクションサイズ(Num)
+ attr_reader :size
+
+ # Itemsクラス
+ attr_reader :items
+
+ attr_reader :taxonomy
+
+private
+
+ #=== TraDBクラスの初期化
+ #
+ #====引数
+ # iFile: transactionファイル名
+ # iItemsetFN: iFile上のアイテム集合項目名
+ # idFN: 新しく命名するトランザクションID項目名
+ # itemsetFN: 新しく命名するアイテム集合項目名
+ #
+ #====機能
+ #* トランザクションIDとアイテム集合の2項目から構成するトランザクションデータを新たに作成する。
+ #* ID項目が指定されていなければ、1から始まる連番によってID項目を新規に作成する。
+ #* トランザクション件数(iFileのレコード件数)を計算する。
+ #* アイテム集合項目からItemsオブジェクトを生成する。
+ def initialize(iFile,idFN,itemFN,t_iFile=nil)
+ @temp=MCMD::Mtemp.new
+
+ @iFile = iFile # 入力ファイル
+ @iPath = File.expand_path(@iFile) # フルパス
+ @idFN = idFN # トランザクションID項目名
+ @itemFN = itemFN # 入力ファイル上のアイテム集合項目名
+ @file = @temp.file # 出力ファイル名
+ @t_iFile= t_iFile # テストファイル
+
+ # 入力ファイルのidがnilの場合は連番を生成して新たなid項目を作成する。
+ f=""
+ f << "mcut f=#{@idFN},#{@itemFN} i=#{@iFile} |"
+ f << "msortf f=#{@idFN},#{@itemFN} |"
+ f << "muniq k=#{@idFN},#{@itemFN} o=#{@file}"
+ system(f)
+
+ # レコード数の計算
+ @recCnt = MCMD::mrecount("i=#{@file}")
+
+ # トランザクション数の計算
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "mcut f=#{@idFN} i=#{@file} |"
+ f << "muniq k=#{@idFN} |"
+ f << "mcount a=__cnt o=#{xx1}"
+ system(f)
+ tbl=MCMD::Mtable.new("i=#{xx1}")
+ num=tbl.name2num()["__cnt"]
+ @size = tbl.cell(num,0).to_i
+
+ # トランザクションデータからアイテムオブジェクトを生成
+ @items=TAKE::Items.new(@file,@itemFN)
+
+ end
+
+public
+ def replaceFile(train)
+
+ @file = train
+
+ # レコード数の計算
+ @recCnt = MCMD::mrecount("i=#{@file}")
+
+ # トランザクション数の計算
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "mcut f=#{@idFN} i=#{@file} |"
+ f << "muniq k=#{@idFN} |"
+ f << "mcount a=__cnt o=#{xx1}"
+ sysmte(f)
+ tbl=MCMD::Mtable.new("i=#{xx1}")
+ num=tbl.name2num()["__cnt"]
+ @size = tbl.cell(num,0).to_i
+
+ end
+
+ #=== taxonomyをトランザクションに追加
+ # トランザクションデータのアイテム集合に、対応するtaxonomyを追加する。
+ #
+ #====引数
+ # taxonomy: Taxonomyオブジェクト。
+ #
+ #====機能
+ #* トランザクションデータのアイテム集合項目におけるアイテム全てについて、対応するtaxonomyをアイテム集合として追加する。
+ def addTaxo(taxonomy)
+
+ @taxonomy=taxonomy
+
+ @items.addTaxo(@taxonomy) # アイテムクラスにtaxonomyを追加する
+
+ tFile =taxonomy.file
+ itemFN=taxonomy.itemFN
+ taxoFN=taxonomy.taxoFN
+
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "msortf f=#{@itemFN} i=#{@file} |"
+ f << "mnjoin k=#{@itemFN} K=#{itemFN} f=#{taxoFN} m=#{tFile} |"
+ f << "mcut f=#{@idFN},#{taxoFN}:#{@itemFN} o=#{xx1}"
+ system(f)
+
+ xx2=tf.file
+ f=""
+ f << "mcat i=#{@file},#{xx1} |"
+ f << "msortf f=#{@idFN},#{@itemFN} |"
+ f << "muniq k=#{@idFN},#{@itemFN} o=#{xx2}"
+ system(f)
+ @file = @temp.file
+
+ FileUtils.mv(xx2,@file)
+
+ end
+
+ def repTaxo(taxonomy)
+
+ #@taxonomy=taxonomy #replaceの場合はtaxonomyを登録しない
+
+ @items.repTaxo(taxonomy) # アイテムクラスをtaxonomyで置換する
+
+ tFile =taxonomy.file
+ itemFN=taxonomy.itemFN
+ taxoFN=taxonomy.taxoFN
+
+ tf=MCMD::Mtemp.new
+ xx1=tf.file
+ f=""
+ f << "msortf f=#{@itemFN} i=#{@file} |"
+ f << "mjoin k=#{@itemFN} K=#{itemFN} f=#{taxoFN} m=#{tFile} |"
+ f << "mcut f=#{@idFN},#{taxoFN}:#{@itemFN} |"
+ f << "msortf f=#{@idFN},#{@itemFN} |"
+ f << "muniq k=#{@idFN},#{@itemFN} o=#{xx1}"
+ system(f)
+
+ @file = @temp.file
+ FileUtils.mv(xx1,@file)
+
+ end
+end
+
+end # module
--- /dev/null
+tid,class
+01,pos
+02,pos
+03,pos
+04,pos
+05,pos
+06,pos
+07,neg
+08,neg
+09,neg
+10,neg
+11,neg
+12,neg
+13,pos
--- /dev/null
+tid,item
+T1,C
+T1,E
+T2,D
+T2,E
+T2,F
+T3,A
+T3,B
+T3,D
+T3,F
+T4,B
+T4,D
+T4,F
+T5,A
+T5,B
+T5,D
+T5,E
+T6,A
+T6,B
+T6,D
+T6,E
+T6,F
--- /dev/null
+item,taxonomy
+A,X
+B,X
+C,Y
+D,Z
+E,Z
+F,Z
--- /dev/null
+tid,class
+T1,pos
+T2,pos
+T3,neg
+T4,pos
+T5,neg
+T6,neg
--- /dev/null
+tid,class
+T1,cls1
+T2,cls1
+T3,cls1
+T4,cls1
+T5,cls2
+T6,cls2
--- /dev/null
+tid,time,item
+T1,0,C
+T1,2,B
+T1,3,A
+T1,7,C
+T2,2,D
+T2,3,A
+T2,5,B
+T2,6,C
+T3,1,C
+T3,2,B
+T3,4,D
+T3,8,E
+T4,2,A
+T4,5,C
+T4,6,B
+T4,7,B
+T4,9,C
+T5,0,B
+T5,1,A
+T5,2,D
+T5,3,D
+T5,7,C
+T5,9,C
+T6,0,A
+T6,5,B
+T6,6,D
+T6,8,B
+T6,9,C
--- /dev/null
+tid,class,A,B,C,D,E,F,G,H,I
+01,pos,1,,,,1,,1,,1
+02,pos,1,,1,,1,,1,,1
+03,pos,1,,1,1,,,,,
+04,pos,1,,1,1,1,1,,,
+05,pos,1,,,,,,,,
+06,pos,1,,,,,,,,
+07,neg,1,1,1,1,1,,1,1,1
+08,neg,1,1,1,,,1,,,
+09,neg,1,1,,1,1,1,,1,
+10,neg,1,1,,,1,,,1,
+11,neg,1,1,,,,,,,1
+12,neg,1,1,,1,,,,1,1
+13,pos,1,,1,1,1,,,,
--- /dev/null
+tid,time,item
+01,1,E
+01,2,I
+01,3,G
+01,4,E
+01,5,A
+02,3,A
+02,4,C
+02,5,C
+02,7,A
+02,8,G
+02,9,B
+03,1,D
+03,5,C
+03,6,A
+03,8,A
+03,9,C
+04,1,A
+04,2,C
+04,4,E
+04,6,A
+04,7,A
+04,8,F
+04,9,D
+05,6,B
+05,9,A
+06,4,A
+07,2,H
+07,3,C
+07,4,A
+07,6,C
+07,7,B
+07,8,G
+07,9,I
+07,11,G
+07,16,H
+08,2,A
+08,7,B
+08,9,C
+08,10,F
+09,1,A
+09,2,D
+09,3,E
+09,4,E
+09,5,E
+09,6,H
+09,7,F
+09,8,B
+10,2,B
+10,3,B
+10,7,A
+10,9,E
+10,10,A
+10,12,H
+11,4,B
+11,7,A
+11,8,I
+12,7,B
+12,8,A
+12,10,H
+12,12,D
+12,13,H
+12,15,I
+13,12,D
+13,14,C
+13,15,A
+13,16,A
+13,17,E
+13,18,A
+13,19,E
--- /dev/null
+item,taxo
+A,X1
+B,X1
+C,X2
+D,X2
+E,X2
+F,X2
+G,X3
+H,X3
+I,X3
--- /dev/null
+tid,class,items
+01,pos,A E G I
+02,pos,C A I G I
+03,pos,A A D
+04,pos,A C D E F
+05,pos,A
+06,pos,A
+07,neg,A B C D E G H I
+08,neg,A B C F
+09,neg,A B D E F H
+10,neg,A B E H
+11,neg,A B I
+12,neg,A B D H I
+13,pos,A C D E
--- /dev/null
+tid,item
+01,A
+01,E
+01,G
+01,I
+02,A
+02,C
+02,E
+02,G
+02,I
+03,A
+03,C
+03,D
+04,A
+04,C
+04,D
+04,E
+04,F
+05,A
+06,A
+07,A
+07,B
+07,C
+07,D
+07,E
+07,G
+07,H
+07,I
+08,A
+08,B
+08,C
+08,F
+09,A
+09,B
+09,D
+09,E
+09,F
+09,H
+10,A
+10,B
+10,E
+10,H
+11,A
+11,B
+11,I
+12,A
+12,B
+12,D
+12,H
+12,I
+13,A
+13,C
+13,D
+13,E
--- /dev/null
+
+# ローカルディレクトリで実行するときは以下のコメントを外す
+lexe='ruby -I../lib ../bin/'
+
+ip1=data
+op=xxresult
+mkdir -p $op
+
+# 頻出パターン列挙
+function itemsetMan {
+ ${lexe}mitemset.rb O=$op/man17 i=$ip1/man1.csv tid=tid item=item type=F S=2 c=$ip1/manc2.csv class=class
+ ${lexe}mitemset.rb O=$op/man16 i=$ip1/man1.csv tid=tid item=item type=F S=4 x=$ip1/man2.csv taxo=taxonomy -replaceTaxo
+ ${lexe}mitemset.rb O=$op/man15 i=$ip1/man1.csv tid=tid item=item type=F S=4 x=$ip1/man2.csv taxo=taxonomy
+ ${lexe}mitemset.rb O=$op/man18 i=$ip1/man1.csv tid=tid item=item type=F S=2 c=$ip1/manc2.csv class=class x=$ip1/man2.csv taxo=taxonomy
+ ${lexe}mitemset.rb O=$op/man14 i=$ip1/man1.csv tid=tid item=item type=F S=3 l=3 u=3
+ ${lexe}mitemset.rb O=$op/man11 i=$ip1/man1.csv tid=tid item=item type=F S=3
+ ${lexe}mitemset.rb O=$op/man12 i=$ip1/man1.csv tid=tid item=item type=C S=3
+ ${lexe}mitemset.rb O=$op/man13 i=$ip1/man1.csv tid=tid item=item type=M S=3
+}
+
+function itemset {
+ ${lexe}mitemset.rb O=$op/itemset01 i=$ip1/vdb.csv tid=tid item=item
+ ${lexe}mitemset.rb O=$op/itemset02 i=$ip1/vdb.csv tid=tid item=item type=C
+ ${lexe}mitemset.rb O=$op/itemset03 i=$ip1/vdb.csv tid=tid item=item type=M
+ ${lexe}mitemset.rb O=$op/itemset04 i=$ip1/vdb.csv tid=tid item=item x=$ip1/taxonomy.csv taxo=taxo
+ ${lexe}mitemset.rb O=$op/itemset05 i=$ip1/vdb.csv tid=tid item=item x=$ip1/taxonomy.csv taxo=taxo -replaceTaxo
+ ${lexe}mitemset.rb O=$op/itemset06 i=$ip1/vdb.csv tid=tid item=item s=0.5
+ ${lexe}mitemset.rb O=$op/itemset07 i=$ip1/vdb.csv tid=tid item=item S=5
+ ${lexe}mitemset.rb O=$op/itemset08 i=$ip1/vdb.csv tid=tid item=item l=3 u=3
+ ${lexe}mitemset.rb O=$op/itemset09 i=$ip1/vdb.csv tid=tid item=item x=$ip1/taxonomy.csv taxo=taxo l=3 u=3
+ ${lexe}mitemset.rb O=$op/itemset10 i=$ip1/vdb.csv tid=tid item=item top=10
+}
+
+itemset
+#itemsetMan
--- /dev/null
+追加修正ファイル
+print.cc : SAPPOROBDD/app/VSOP/print.ccをCoutだけでなくファイル出力もできるように変更
+vsop.h : SAPPOROBDD/app/VSOP/vsop.hをPrint.ccのプロトタイプ宣言を変更。
+SAPPOROBDD/src/BDDLCM/lcm-vsop.org.sed:original sed file
+SAPPOROBDD/src/BDDLCM/lcm-vsop.sed:Mac&Linux 対応版sedファイル
+SAPPOROBDD/src/BDDLCM/lcm-vsop_add.cc:lcmub対応
+SAPPOROBDD/src/BDDLCM/makefile.org:original makefile
+SAPPOROBDD/src/BDDLCM/makefile:lcmub対応makefile
+
+SAPPOROBDD/src/BDD+/makefile:-fPIC追加
+SAPPOROBDD/src/BDDc/makefile:-fPIC追加
+SAPPOROBDD/src/BDDLCM/makefile:lcmub対応makefile&-fPIC追加
+SAPPOROBDD/src/BDDXc/makefile:-fPIC追加
+
--- /dev/null
+******** BDD Package SAPPORO-Edition-1.0 ********
+ Copyright 2005 - Shin-ichi MINATO
+
+This form specifies the terms under which the software and
+documentation contained in this package distribution are provided.
+
+This software is distributed "as is", completely without warranty and
+service support. The author shall not liable for the condition or
+performance of the software.
+
+THE AUTHOR HEREBY DISCLAIM ALL IMPLIED WARRANTIES, INCLUDING THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE AUTHOR SHALL NOT BE LIABLE FOR ANY DAMAGES INCURRED
+BY THE RECIPIENT IN USE OF THE SOFTWARE AND DOCUMENTATION,
+INCLUDING DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES.
+
+The recipient can publish the research by utilizing this software,
+provided that the recipient specify the use of this software in the
+publication.
+
+This software can be redistributed, provided that the destination do
+not violates International Export Lows and that this form are
+appended to the software.
+
--- /dev/null
+BDD Package SAPPORO-Edition-1.0 (S. Minato, Hokkaido Univ. 2005)\r
+\r
+Directory structure:\r
+\r
+SAPPOROBDD/README This file.\r
+SAPPOROBDD/COPYRIGHT Copyright desdription of this package.\r
+SAPPOROBDD/app/ Source programs of BDD applications.\r
+SAPPOROBDD/include/ Header files.\r
+SAPPOROBDD/lib/ Compiled BDD library files are stored here.\r
+SAPPOROBDD/man/ Manuals of BDD package. (So far Japanese only..)\r
+SAPPOROBDD/src/ Source files of BDD package.\r
+SAPPOROBDD/src/BDDc/ Core of package written in C.\r
+SAPPOROBDD/src/BDDXc/ Part of package related to X11, written in C.\r
+SAPPOROBDD/src/BDDLCMc/ Part of package related to LCM, written in C.\r
+SAPPOROBDD/src/BDD+/ Main part of package written in C++.\r
+SAPPOROBDD/src/INSTALL Script for compiling all files in SAPPOROBDD/src/\r
+\r
+\r
--- /dev/null
+CC = g++
+YACC = yacc
+LEX = flex -l
+
+DIR = ../..
+INCL = $(DIR)/include
+LIB = $(DIR)/lib/BDD.a
+LIB64 = $(DIR)/lib/BDD64.a
+#XLIB64 = -lX11
+XLIB64 = /usr/X11R6/lib64/libX11.a
+
+PRG = vsop
+PRG64 = vsop64
+PRG_ST = vsop-static
+PRG64_ST = vsop64-static
+
+OPT = -O3 -DYY_ALWAYS_INTERACTIVE -I$(INCL)
+OPT64 = $(OPT) -DB_64
+OPT_ST = $(OPT) -DB_STATIC -static
+OPT64_ST = $(OPT64) -DB_STATIC -static
+
+OBJ = print.o table.o lex.yy.o y.tab.o yywrap.o
+OBJ64 = print_64.o table_64.o lex.yy_64.o y.tab_64.o yywrap_64.o
+OBJ_ST = print_st.o table.o lex.yy.o y.tab_st.o yywrap.o
+OBJ64_ST = print_64_st.o table_64.o lex.yy_64.o y.tab_64_st.o yywrap_64.o
+
+all: $(PRG)
+
+64: $(PRG64)
+
+static: $(PRG_ST)
+
+64static: $(PRG64_ST)
+
+$(PRG): $(OBJ) $(LIB)
+ $(CC) $(OPT) $(OBJ) $(LIB) -lX11 -o $(PRG)
+
+$(PRG64): $(OBJ64) $(LIB64)
+ $(CC) $(OPT64) $(OBJ64) $(LIB64) $(XLIB64) -o $(PRG64)
+
+$(PRG_ST): $(OBJ_ST) $(LIB)
+ $(CC) $(OPT_ST) $(OBJ_ST) $(LIB) -o $(PRG_ST)
+
+$(PRG64_ST): $(OBJ64_ST) $(LIB64)
+ $(CC) $(OPT64_ST) $(OBJ64_ST) $(LIB64) -o $(PRG64_ST)
+
+print.o: print.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c print.cc
+
+print_64.o: print.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c print.cc -o print_64.o
+
+print_st.o: print.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT_ST) -c print.cc -o print_st.o
+
+print_64_st.o: print.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64_ST) -c print.cc -o print_64_st.o
+
+table.o: table.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c table.cc
+
+table_64.o: table.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c table.cc -o table_64.o
+
+lex.yy.o: lex.yy.cc y.tab.h $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c lex.yy.cc
+
+lex.yy_64.o: lex.yy.cc y.tab.h $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c lex.yy.cc -o lex.yy_64.o
+
+lex.yy.cc: vsoplex.l
+ $(LEX) vsoplex.l
+ mv lex.yy.c lex.yy.cc
+
+y.tab.o: y.tab.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c y.tab.cc
+
+y.tab_64.o: y.tab.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c y.tab.cc -o y.tab_64.o
+
+y.tab_st.o: y.tab.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT_ST) -c y.tab.cc -o y.tab_st.o
+
+y.tab_64_st.o: y.tab.cc vsop.h $(INCL)/CtoI.h $(INCL)/ZBDDDG.h \
+ $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64_ST) -c y.tab.cc -o y.tab_64_st.o
+
+y.tab.h: vsopyacc.y++
+ $(YACC) -d vsopyacc.y++
+ mv y.tab.c y.tab.cc
+
+yywrap.o: yywrap.c
+ gcc $(OPT) -c yywrap.c
+
+yywrap_64.o: yywrap.c
+ gcc $(OPT64) -c yywrap.c -o yywrap_64.o
+
+clean:
+ rm -f *.o
+ rm -f lex.yy.*
+ rm -f y.tab.*
+
--- /dev/null
+VSOP (Valued Sum-Of-Products) Calculator
+
+Command syntax:
+ vsop [-BDDsize] [filename]
+
+vsop sparc executable file.
+vsop.help help text file referred by bemII.
+vsop.man program manual (in Japanese).
+COPYRIGHT copyright form
+README this file.
--- /dev/null
+#!/usr/bin/perl
+print "symbol /t\n";
+print "symbol ";
+while(<STDIN>){
+ while(/([0-9]+)/gi){
+ print "x$1 " ;
+ }
+}
+print "\n";
+
--- /dev/null
+// VSOP Print (v1.36)
+// Shin-ichi MINATO (Dec. 18, 2010)
+
+#include <cstdio>
+#include <iostream>
+#include <cstring>
+#include "CtoI.h"
+#include "vsop.h"
+#include "ZBDDDG.h"
+using namespace std;
+
+#define LINE 70
+
+BOut::BOut() { _column = 0; }
+
+BOut& BOut::operator << (const char* str)
+{
+ _column += strlen(str);
+ cout << str;
+ return *this;
+}
+
+void BOut::Delimit()
+{
+ if(_column >= LINE)
+ {
+ _column = 2;
+ cout << "\n ";
+ cout.flush();
+ }
+ else
+ {
+ _column++;
+ cout << " ";
+ }
+}
+
+void BOut::Return()
+{
+ _column = 0;
+ cout << "\n";
+ cout.flush();
+}
+
+BOut bout;
+
+static int PutNum(CtoI a, int base);
+int PutNum(CtoI a, int base)
+{
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ char* s = new char[d];
+ if(s == 0) return 1;
+
+ int err;
+ if(base == 16) err = a.StrNum16(s);
+ else err = a.StrNum10(s);
+ if(err == 1)
+ {
+ delete[] s;
+ return 1;
+ }
+ int len = strlen(s);
+ bout << s;
+ delete[] s;
+ return 0;
+}
+
+static int Depth;
+static int* S_Var;
+static int PFflag;
+static int PF(CtoI, int);
+static int PF(CtoI a, int base)
+{
+ if(a.IsConst())
+ {
+ if(a.TopDigit() & 1) { bout.Delimit(); bout << "-"; a = -a; }
+ else if(PFflag == 1) { bout.Delimit(); bout << "+"; }
+
+ PFflag = 1;
+ int c1 = (a != 1);
+ if(c1 || Depth == 0)
+ {
+ bout.Delimit();
+ if(PutNum(a, base) == 1) return 1;
+ }
+ for(int i=0; i<Depth; i++)
+ {
+ bout.Delimit();
+ bout << 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) == 1) return 1;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF(b, base);
+}
+
+int PrintCtoI(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+
+ if(a == 0) bout << " 0";
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ S_Var = new int[lev];
+ PFflag = 0;
+ int err = PF(a, 10);
+ delete[] S_Var;
+ if(err == 1)
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ }
+ bout.Return();
+ return 0;
+}
+
+int PrintCtoI_16(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+
+ if(a == 0) bout << " 0";
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ S_Var = new int[lev];
+ PFflag = 0;
+ int err = PF(a, 16);
+ delete[] S_Var;
+ if(err == 1)
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ }
+ bout.Return();
+ return 0;
+}
+
+int PrintDigital(CtoI a)
+{
+ int d = a.TopDigit();
+ for(int i=d; i>=0; i--)
+ {
+ if(d > 1)
+ {
+ char s[10];
+ sprintf(s, "%3d:", i);
+ bout << s;
+ }
+ if(PrintCtoI(a.Digit(i)) == 1) return 1;
+ }
+ return 0;
+}
+
+int PrintCase(CtoI a)
+{
+ char s[80];
+ while(CtoI_GT(a, 0) != 0)
+ {
+ if(a == CtoI_Null())
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ CtoI b = a.MaxVal();
+ b.StrNum10(s);
+ bout << s << ": ";
+ CtoI c = a.EQ_Const(b);
+ PrintCtoI(c);
+ a = a.FilterElse(c);
+ }
+ while(CtoI_LT(a, 0) != 0)
+ {
+ if(a == CtoI_Null())
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ CtoI b = a.MinVal();
+ b.StrNum10(s);
+ bout << s << ": ";
+ CtoI c = a.EQ_Const(b);
+ PrintCtoI(c);
+ a = a.FilterElse(c);
+ }
+ return 0;
+}
+
+static void PutCode(int, int);
+void PutCode(int num, int digit) // num < 8, digit <=3
+{
+ for(int i=3; i>=0; i--)
+ if(i >= digit) bout << " ";
+ else if((num & (1 << i)) == 0) bout << "0";
+ else bout << "1";
+}
+
+static int MapVar[6];
+
+static int MapNum(CtoI a);
+int MapNum(CtoI a)
+{
+ int ovf = 0;
+ if(a.TopItem() > 0)
+ {
+ a = a.MaxVal();
+ ovf = 1;
+ }
+ int d = a.TopDigit() / 3 + 14;
+ char* s = new char[d];
+ if(s == 0) return 1;
+
+ int err;
+ err = a.StrNum10(s);
+ if(err == 1)
+ {
+ delete[] s;
+ return 1;
+ }
+ int len = strlen(s);
+ if(ovf == 0)
+ {
+ for(int i=0; i<5-len; i++) bout << " ";
+ bout << " " << s;
+ }
+ else
+ {
+ for(int i=0; i<4-len; i++) bout << " ";
+ bout << "(" << s << ")";
+ }
+ delete[] s;
+ return 0;
+}
+
+static int Map(CtoI, int);
+int Map(CtoI a, int dim)
+{
+ if(a == CtoI_Null()) return 1;
+ int x, y;
+ switch(dim)
+ {
+ case 0:
+ if(MapNum(a) == 1) return 1;
+ bout.Return();
+ return 0;
+ case 1:
+ bout << " " << VTable.GetName(MapVar[0]);
+ bout.Return();
+ PutCode(0, 1);
+ bout << " |";
+ if(MapNum(a.Factor0(MapVar[0])) == 1) return 1;
+ bout.Return();
+ PutCode(1, 1);
+ bout << " |";
+ if(MapNum(a.Factor1(MapVar[0])) == 1) return 1;
+ bout.Return();
+ return 0;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ y = dim / 2;
+ x = dim - y;
+ break;
+ default: ;
+ }
+ int mx = 1 << x;
+ int my = 1 << y;
+ for(int i=0; i<y; i++)
+ bout << " " << VTable.GetName(MapVar[i]);
+ bout << " :";
+ for(int i=y; i<dim; i++)
+ bout << " " << VTable.GetName(MapVar[i]);
+ bout.Return();
+ bout << " ";
+ for(int i=0; i<mx; i++)
+ {
+ if(i == 0 || i == 4) bout << " |";
+ int m = i ^ (i >> 1);
+ bout << " ";
+ PutCode(m, x);
+ }
+ bout.Return();
+ for(int j=0; j<my; j++)
+ {
+ if(j == 4)
+ {
+ bout << " |";
+ if(x == 3) bout << " |";
+ bout.Return();
+ }
+ int n = j ^ (j >> 1);
+ PutCode(n, y);
+ n <<= x;
+ for(int i=0; i<mx; i++)
+ {
+ if(i == 0 || i == 4) bout << " |";
+ int m = n | (i ^ (i >> 1));
+ CtoI ax = a;
+ for(int k=0; k<dim; k++)
+ if((m & (1 << (dim-k-1))) == 0)
+ ax = ax.Factor0(MapVar[k]);
+ else ax = ax.Factor1(MapVar[k]);
+ if(MapNum(ax) == 1) return 1;
+ }
+ bout.Return();
+ }
+ return 0;
+}
+
+int MapAll(CtoI a)
+{
+ int i=0;
+ int n = VTable.Used();
+ for(int j=0; j<n; j++)
+ {
+ MapVar[i++] = BDD_VarOfLev(n-j);
+ if(i == 6) break;
+ }
+ return Map(a, i);
+}
+
+int MapSel(CtoI a)
+{
+ int i=0;
+ int n = VTable.Used();
+ for(int j=0; j<n; j++)
+ {
+ int var = BDD_VarOfLev(n-j);
+ if(a == CtoI_Null()) return 1;
+ if(a == a.Factor0(var)) continue;
+ MapVar[i++] = var;
+ if(i == 6) break;
+ }
+ return Map(a, i);
+}
+
+static void PrintD(ZBDDDG *, bddword);
+void PrintD(ZBDDDG* dg, bddword ndx)
+{
+ ZBDDDG_Tag tag, tag2;
+ tag.Set(dg, ndx);
+ bddword ndx0, ndx2;
+ int top;
+ switch(tag.Type())
+ {
+ case ZBDDDG_C0:
+ bout << "0";
+ break;
+ case ZBDDDG_P1:
+ bout << "OR(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ tag2.Set(dg, ndx0);
+ if(tag2.Type() != ZBDDDG_OR)
+ PrintD(dg, ndx0);
+ else
+ {
+ ndx0 = tag2.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ }
+ }
+ bout.Delimit();
+ bout << "1";
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_LIT:
+ top = tag.Func().Top();
+ bout << VTable.GetName(top);
+ break;
+ case ZBDDDG_AND:
+ bout << "AND(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_OR:
+ bout << "OR(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_OTHER:
+ bout << "[";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << "]";
+ break;
+ default:
+ bout << "???";
+ bout.Delimit();
+ break;
+ }
+}
+
+int PrintDecomp(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+ a = a.NonZero();
+ if(a == CtoI_Null()) return 1;
+ ZBDD f = a.GetZBDD();
+ ZBDDDG* dg = new ZBDDDG();
+ if(dg == 0) return 1;
+ bddword ndx = dg->Decomp(f);
+ if(ndx == ZBDDDG_NIL) { delete dg; return 1; }
+
+ PrintD(dg, ndx);
+ bout.Return();
+ delete dg;
+ return 0;
+}
+
+static int PrintDD_N;
+static void PrintDD(ZBDDDG *, bddword);
+void PrintDD(ZBDDDG* dg, bddword ndx)
+{
+ ZBDDDG_Tag tag, tag2;
+ tag.Set(dg, ndx);
+ bddword ndx0, ndx2;
+ char s[20];
+ int top;
+ int n;
+ switch(tag.Type())
+ {
+ case ZBDDDG_C0:
+ bout << "n0 [label=0];";
+ break;
+ case ZBDDDG_P1:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OR];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ tag2.Set(dg, ndx0);
+ if(tag2.Type() != ZBDDDG_OR)
+ PrintDD(dg, ndx0);
+ else
+ {
+ ndx0 = tag2.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ }
+ }
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << " [label=1];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+ PrintDD_N++;
+
+ break;
+ case ZBDDDG_LIT:
+ top = tag.Func().Top();
+
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=";
+ bout << VTable.GetName(top);
+ bout << "];";
+ bout.Return();
+
+ break;
+ case ZBDDDG_AND:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=AND];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ case ZBDDDG_OR:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OR];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ case ZBDDDG_OTHER:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OTHER];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ default:
+ bout << "???";
+ break;
+ }
+}
+
+int PrintDecompDot(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+ a = a.NonZero();
+ if(a == CtoI_Null()) return 1;
+ ZBDD f = a.GetZBDD();
+ ZBDDDG* dg = new ZBDDDG();
+ if(dg == 0) return 1;
+ bddword ndx = dg->Decomp(f);
+ if(ndx == ZBDDDG_NIL) { delete dg; return 1; }
+
+ bout << "digraph G {";
+ bout.Return();
+ PrintDD_N = 0;
+ PrintDD(dg, ndx);
+ bout << "}";
+ bout.Return();
+ delete dg;
+ return 0;
+}
+
--- /dev/null
+// VSOP Tables (v1.36)
+// Shin-ichi MINATO (Dec. 18, 2010)
+
+#include <cstring>
+#include <iostream>
+#include "CtoI.h"
+#include "vsop.h"
+using namespace std;
+
+struct VarEntry
+{
+ int _val;
+ int _gvar;
+ char* _name;
+ int _len;
+ int _var;
+
+ VarEntry(void);
+ ~VarEntry(void);
+};
+
+VarEntry::VarEntry(void)
+{
+ _val = 0;
+ _gvar = 0;
+ _var = 0;
+ _len = 0;
+ _name = 0;
+}
+
+VarEntry::~VarEntry(void) { if(_len > 0) delete[] _name; }
+
+typedef VarEntry* VarEntPtr;
+
+VarTable::VarTable(int size)
+{
+ if(size <= 0)
+ {
+ cerr << "Error at VarTable. (a)\n";
+ exit(1);
+ }
+ for(_hashsize=128; _hashsize<size; _hashsize<<=1)
+ ; // empty
+ _wheel = new VarEntry[_hashsize];
+ _index = new VarEntPtr[_hashsize>>1];
+ if(_wheel == 0 || _index == 0)
+ {
+ cerr << "Error at VarTable. (b)\n";
+ exit(1);
+ }
+ for(int i=0; i<(_hashsize>>1); i++) _index[i] = 0;
+ _used = 0;
+}
+
+VarTable::~VarTable()
+{
+ delete[] _wheel;
+ delete[] _index;
+}
+
+VarEntry* VarTable::GetEntry(char* name)
+{
+ if(name == 0)
+ {
+ cerr << "Error at VarTable. (c)\n";
+ exit(1);
+ }
+ int hash = 0;
+ for(int i=0; i<32; i++)
+ {
+ if(name[i] == 0) break;
+ hash = (hash * 123456 + name[i]) & (_hashsize - 1);
+ }
+ int i = hash;
+ while(_wheel[i]._len > 0)
+ {
+ if(strcmp(name, _wheel[i]._name) == 0)
+ return & _wheel[i];
+ i++;
+ i &= (_hashsize -1);
+ }
+ i = hash;
+ while(_wheel[i]._len > 0)
+ {
+ if(_wheel[i]._var == 0) break;
+ i++;
+ i &= (_hashsize -1);
+ }
+ _wheel[i]._len = strlen(name)+1;
+ _wheel[i]._name = new char[_wheel[i]._len];
+ strcpy(_wheel[i]._name, name);
+ return & _wheel[i];
+}
+
+int VarTable::GetID(char* name) { return GetEntry(name) -> _var; }
+
+char* VarTable::GetName(int var)
+{ return _index[var-BDDV_SysVarTop-1] -> _name; }
+
+int VarTable::GetValue(int var)
+{ return _index[var-BDDV_SysVarTop-1] -> _val; }
+
+int VarTable::GetGID(int var)
+{ return _index[var-BDDV_SysVarTop-1] -> _gvar; }
+
+void VarTable::SetB(char* name, int val)
+{
+ VarEntry* entry = GetEntry(name);
+ entry -> _val = val;
+ if(entry -> _var == 0)
+ {
+ entry -> _var = BDD_NewVarOfLev(1);
+ entry -> _gvar = entry -> _var;
+ _index[_used] = entry;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+void VarTable::SetB(char* name, int val, int gvar)
+{
+ VarEntry* entry = GetEntry(name);
+ entry -> _val = val;
+ entry -> _gvar = gvar;
+ if(entry -> _var == 0)
+ {
+ entry -> _var = BDD_NewVarOfLev(1);
+ _index[_used] = entry;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+void VarTable::SetT(char* name, int val)
+{
+ VarEntry* entry = GetEntry(name);
+ entry -> _val = val;
+ if(entry -> _var == 0)
+ {
+ entry -> _var = BDD_NewVar();
+ entry -> _gvar = entry -> _var;
+ _index[_used] = entry;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+void VarTable::SetT0(int var, char* name)
+{
+ VarEntry* entry = GetEntry(name);
+ entry -> _val = 1 << 15;
+ if(entry -> _var == 0)
+ {
+ entry -> _var = var;
+ entry -> _gvar = entry -> _var;
+ _index[_used] = entry;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+void VarTable::SetT(char* name, int val, int gvar)
+{
+ VarEntry* entry = GetEntry(name);
+ entry -> _val = val;
+ entry -> _gvar = gvar;
+ if(entry -> _var == 0)
+ {
+ entry -> _var = BDD_NewVar();
+ _index[_used] = entry;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+int VarTable::Used(void) { return _used; }
+
+void VarTable::Enlarge(void)
+{
+ int oldsize = _hashsize;
+ VarEntry* oldwheel = _wheel;
+ VarEntry** oldindex = _index;
+
+ _hashsize <<= 2;
+ _wheel = new VarEntry[_hashsize];
+ _index = new VarEntPtr[_hashsize>>1];
+ if(_wheel == 0 || _index == 0)
+ {
+ cerr << "Error at VarTable. (d)\n";
+ exit(1);
+ }
+ for(int i=0; i<(_hashsize>>1); i++) _index[i] = 0;
+ _used = 0;
+ for(int i=0; i<(oldsize>>1); i++)
+ {
+ VarEntry* oldentry = oldindex[i];
+ if(oldentry)
+ {
+ _used++;
+ VarEntry* entry = GetEntry(oldentry->_name);
+ entry -> _val = oldentry -> _val;
+ entry -> _gvar = oldentry -> _gvar;
+ entry -> _var = oldentry -> _var;
+ _index[i] = entry;
+ }
+ }
+ delete[] oldwheel;
+ delete[] oldindex;
+}
+
+//
+// FuncTable class definition
+//
+
+struct FuncEntry
+{
+ CtoI _ctoi;
+ char* _name;
+ short _len;
+ char _live;
+
+ FuncEntry(void);
+ ~FuncEntry(void);
+};
+
+FuncEntry::FuncEntry(void)
+{
+ _ctoi = CtoI_Null();
+ _name = 0;
+ _len = 0;
+ _live = 0;
+}
+
+FuncEntry::~FuncEntry(void) { if(_len > 0) delete[] _name; }
+
+FuncTable::FuncTable(int size)
+{
+ if(size <= 0)
+ {
+ cerr << "Error at FuncTable. (a)\n";
+ exit(1);
+ }
+ for(_hashsize=256; _hashsize<size; _hashsize<<=1)
+ ; // empty
+ _wheel = new FuncEntry[_hashsize];
+ if(_wheel == 0)
+ {
+ cerr << "Error at FuncTable. (b)\n";
+ exit(1);
+ }
+ _used = 0;
+}
+
+FuncTable::~FuncTable() { delete[] _wheel; }
+
+FuncEntry* FuncTable::GetEntry(char* name)
+{
+ if(name == 0)
+ {
+ cerr << "Error at FuncTable. (b)\n";
+ exit(1);
+ }
+ int hash = 0;
+ for(int i=0; i<32; i++)
+ {
+ if(name[i] == 0) break;
+ hash = (hash * 123456 + name[i]) & (_hashsize - 1);
+ }
+ int i = hash;
+ while(_wheel[i]._len > 0)
+ {
+ if(strcmp(name, _wheel[i]._name) == 0)
+ return & _wheel[i];
+ i++;
+ i &= (_hashsize -1);
+ }
+ i = hash;
+ while(_wheel[i]._len > 0)
+ {
+ if(_wheel[i]._live == 0) break;
+ i++;
+ i &= (_hashsize -1);
+ }
+ _wheel[i]._len = strlen(name)+1;
+ _wheel[i]._name = new char[_wheel[i]._len];
+ strcpy(_wheel[i]._name, name);
+ return & _wheel[i];
+}
+
+CtoI& FuncTable::GetCtoI(char* name) { return GetEntry(name) -> _ctoi; }
+
+void FuncTable::Set(char* name, CtoI& ctoi)
+{
+ FuncEntry* entry = GetEntry(name);
+ entry -> _ctoi = ctoi;
+ if(entry -> _live == 0)
+ {
+ entry -> _live = 1;
+ if(++_used >= (_hashsize>>1)) Enlarge();
+ }
+}
+
+int FuncTable::Used(void) { return _used; }
+
+void FuncTable::Enlarge(void)
+{
+ int oldsize = _hashsize;
+ FuncEntry* oldwheel = _wheel;
+
+ _hashsize <<= 2;
+ _wheel = new FuncEntry[_hashsize];
+ if(_wheel == 0)
+ {
+ cerr << "Error at FuncTable. (b)\n";
+ exit(1);
+ }
+ _used = 0;
+ for(int i=0; i<oldsize; i++)
+ if(oldwheel[i]._live != 0)
+ Set(oldwheel[i]._name, oldwheel[i]._ctoi);
+ delete[] oldwheel;
+}
+
+VarTable VTable;
+FuncTable FTable;
--- /dev/null
+******** VSOP (Valued Sum-Of-Products) Calculator ********
+ Copyright 2005 - Shin-ichi MINATO
+
+This form specifies the terms under which the software and
+documentation contained in this package distribution are provided.
+
+This software is distributed "as is", completely without warranty and
+service support. The author shall not liable for the condition or
+performance of the software.
+
+THE AUTHOR HEREBY DISCLAIM ALL IMPLIED WARRANTIES, INCLUDING THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE AUTHOR SHALL NOT BE LIABLE FOR ANY DAMAGES INCURRED
+BY THE RECIPIENT IN USE OF THE SOFTWARE AND DOCUMENTATION,
+INCLUDING DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES.
+
+The recipient can publish the research by utilizing this software,
+provided that the recipient specify the use of this software in the
+publication.
+
+This software can be redistributed, provided that the destination do
+not violates International Export Lows and that this form are
+appended to the software.
+
--- /dev/null
+// VSOP - Header (v1.39)
+// Shin-ichi MINATO (Nov. 22, 2013)
+
+#define PROMPT "vsop> "
+#define DOCUMENT "vsop.help"
+
+int yyparse();
+
+struct VarEntry;
+
+class VarTable
+{
+ int _used;
+ int _hashsize;
+ VarEntry* _wheel;
+ VarEntry** _index;
+
+ void Enlarge(void);
+ VarEntry* GetEntry(char *);
+public:
+ VarTable(int size = 64);
+ ~VarTable(void);
+ int GetID(char *);
+ char* GetName(int);
+ int GetValue(int);
+ int GetGID(int);
+ void SetB(char *, int);
+ void SetB(char *, int, int);
+ void SetT(char *, int);
+ void SetT0(int, char *);
+ void SetT(char *, int, int);
+ int Used(void);
+};
+
+struct FuncEntry;
+class CtoI;
+
+class FuncTable
+{
+ int _used;
+ int _hashsize;
+ FuncEntry* _wheel;
+
+ void Enlarge(void);
+ FuncEntry* GetEntry(char *);
+public:
+ FuncTable(int size = 256);
+ ~FuncTable(void);
+ int CheckNew(char *);
+ CtoI& GetCtoI(char *);
+ void Set(char *, CtoI &);
+ int Used(void);
+};
+
+class BOut
+{
+ short _column;
+public:
+ BOut(void);
+ BOut& operator <<(const char *);
+ void Delimit(void);
+ void Return(void);
+};
+
+extern VarTable VTable;
+extern FuncTable FTable;
+extern BOut bout;
+
+extern void yyerror(const char *);
+
+extern int PrintCtoI(CtoI);
+extern int PrintCtoI_16(CtoI);
+extern int PrintDigital(CtoI);
+extern int PrintCase(CtoI);
+extern int MapAll(CtoI);
+extern int MapSel(CtoI);
+
+extern int PrintDecomp(CtoI);
+extern int PrintDecompDot(CtoI);
--- /dev/null
+less << @EOF
+#### VSOP(v1.39) Help Document ####
+
+<Name convention>
+
+[a-z][a-zA-Z0-9_]* Symbol (You can use upto 65500 symbols).
+[A-Z][a-zA-Z0-9_]* Register variable for a VSOP
+[0-9]+ Constant number (base:10)
+0X[0-9A-F]+ Constant number (base:16)
+0B[01]+ Constant number (base:2)
+
+<Commands>
+
+symbol a b c ... Declares the symbols.
+symbol a(cost) b(cost) ... Declares the symbols with costs.
+symbol [a b] [c d e] ... Declares the groups of exclusive symbols.
+symbol Lists all the symbols.
+symbol /v Lists all the symbols with costs.
+symbol /t After that, symbols will be added at the top.
+symbol /b After that, symbols will be added at the bottom.
+F = <expr> Defines F as <expr>
+print <expr> Displays <expr>.
+print <flag> <expr> Displays <expr> in the format of <flag>.
+print "<string>" Prints <string>.
+? <expr> Displays <expr>.
+? <flag> <expr> Displays <expr> in the format of <flag>.
+? "<string>" Prints <string>.
+source <file> Executes the commands in <file>.
+help Displays this document.
+? Displays this document.
+exit Exits the program.
+quit Exits the program.
+
+<Operators in expressions>
+
+( <expr> ) Calculate first.
+<expr>.MaxVal Maximum value in the set.
+<expr>.MinVal Minimum value in the set.
+<expr>.TotalVal Total values of all terms in <expr>.
+<expr>.Items All symbols used in <expr> with total
+ values of related terms.
+<expr1>.TermsEQ(<expr2>) Filters terms in <expr1> equal to
+ the constant term of <expr2>.
+<expr1>.TermsNE(<expr2>) Filters terms in <expr1> not equal to
+ the constant term of <expr2>.
+<expr1>.TermsGT(<expr2>) Filters terms in <expr1> greater than
+ the constant term of <expr2>.
+<expr1>.TermsGE(<expr2>) Filters terms in <expr1> not less than
+ the constant term of <expr2>.
+<expr1>.TermsLT(<expr2>) Filters terms in <expr1> less than
+ the constant term of <expr2>.
+<expr1>.TermsLE(<expr2>) Filters terms in <expr1> not greater than
+ the constant term of <expr2>.
+<expr1>.Restrict(<expr2>) Filters terms in <expr1> each of which
+ includes one of combinations in <expr2>.
+<expr1>.Permit(<expr2>) Filters terms in <expr1> each of which is
+ included in one of combinations in <expr2>.
+<expr1>.PermitSym(<expr2>) Filters terms in <expr1> each of which consists
+ of up to <expr2> number of items.
+<expr1>.FreqPatA(<expr2>) Generates all frequent patterns in <expr1>
+ with the minimum support <expr2>.
+<expr1>.FreqPatM(<expr2>) Generates maximal frequent patterns in <expr1>
+ with the minimum support <expr2>.
+<expr1>.FreqPatC(<expr2>) Generates closed frequent patterns in <expr1>
+ with the minimum support <expr2>.
+<expr1>.SymGrp Generates symmetric item sets in <expr1>.
+<expr1> <expr2> Multiplication.
+<expr1> * <expr2> Multiplication.
+<expr1> / <expr2> Quotient of division.
+<expr1> % <expr2> Remainder of division.
+<expr1> @ <expr2> "Meet" operation. (see Knuth-book)
+<expr1> + <expr2> Addition.
+<expr1> - <expr2> Subtraction.
++ <expr> Multiplies 1. (no effect)
+- <expr> Multiplies -1.
+<expr1> == <expr2> Extracts combinations satisfying equation.
+<expr1> != <expr2> Extracts combinations satisfying inequation.
+<expr1> > <expr2> Extracts combinations satisfying inequation.
+<expr1> >= <expr2> Extracts combinations satisfying inequation.
+<expr1> < <expr2> Extracts combinations satisfying inequation.
+<expr1> <= <expr2> Extracts combinations satisfying inequation.
+<expr1> ? <expr2> : <expr3> If <expr1> then <expr2> else <expr3>.
+Import("filename") Imports ZBDD graph from the external file.
+Lcm("<switch>" "<filename>" <num>)
+ generates frequent patterns using LCM algorithm
+ from the FIMI format database file <filename>
+ with minimum support = <num>.
+ <switch> specifies LCM parameter as:
+ F all patterns,
+ C closed patterns,
+ M maximal patterns,
+ FQ all patterns with frequencies,
+ CQ closed patterns with frequencies,
+ MQ maximal patterns with frequencies.
+Lcm("<switch>" "<filename>" <num> "<filename2>")
+ generates frequent patterns using LCM algorithm
+ from the FIMI format database file <filename>
+ with minimum support = <num> and
+ variable order file <filename2>.
+ <switch> specifies LCM parameter as:
+ F all patterns,
+ C closed patterns,
+ M maximal patterns,
+ FQ all patterns with frequencies,
+ CQ closed patterns with frequencies,
+ MQ maximal patterns with frequencies.
+
+<Flags on Printing>
+
+/map Displays in a Karnough-map.
+/rmap Displays in a reduced Karnough-map.
+/hex Displays integers in hexa-decimal.
+/bit Displays in bit-wise expressions.
+/case Sorts all combinations by their values.
+/size Shows the size of the ZBDD.
+/count Shows the number of combinations in the set.
+/density Shows the density of combinations in the set.
+/value Shows the numerical value of the expression.
+/maxcover Shows a maximum-cost combination in the set.
+/maxcost Shows cost of the maximum-cost combination.
+/mincover Shows a minimum-cost combination in the set.
+/mincost Shows cost of the minimum-cost combination.
+/decomp Shows the simple disjoint decompositions.
+/plot Draws ZBDD graph on X-windows.
+/export Dumps ZBDD graph.
+/export "filename"
+ Export ZBDD graph to the external file.
+
+<Special characters>
+
+# ... Comment out 1 line.
+; ... multiple statements on 1 line.
+\ ... Escape of "return".
+
+<Example>
+***** VSOP (Valued Sum-Of-Products) calculator <v1.26> *****
+ vsop> symbol a b c d e
+ vsop> F = (a + 2 b)(c + d)
+ vsop> print F
+ a c + a d + 2 b c + 2 b d
+ vsop> print /rmap F
+ a b : c d
+ | 00 01 11 10
+ 00 | 0 0 0 0
+ 01 | 0 2 0 2
+ 11 | 0 0 0 0
+ 10 | 0 1 0 1
+ vsop> G = (2 a - d)(c - e)
+ vsop> print G
+ 2 a c - 2 a e - c d + d e
+ vsop> print /rmap G
+ a c : d e
+ | 00 01 11 10
+ 00 | 0 0 1 0
+ 01 | 0 0 0 -1
+ 11 | 2 0 0 0
+ 10 | 0 -2 0 0
+ vsop> H = F * G
+ vsop> print H
+ 4 a b c d - 4 a b c e + 4 a b c - 4 a b d e + a c d e - 2 a c e + 2 a
+ c - a d e + 2 b c d e - 4 b c d + 2 b d e
+ vsop> print /rmap H
+ a b : c d e
+ | 000 001 011 010 | 110 111 101 100
+ 00 | 0 0 0 0 | 0 0 0 0
+ 01 | 0 0 2 0 | -4 2 0 0
+ 11 | 0 0 -4 0 | 4 0 -4 4
+ 10 | 0 0 -1 0 | 0 1 -2 2
+ vsop> print /count H
+ 11
+ vsop> print /size H
+ 24 (35)
+ vsop> print H > 0
+ a b c d + a b c + a c d e + a c + b c d e + b d e
+ vsop> print (H > 0)? H: 0
+ 4 a b c d + 4 a b c + a c d e + 2 a c + 2 b c d e + 2 b d e
+ vsop> print (H > 0)? H: -H
+ 4 a b c d + 4 a b c e + 4 a b c + 4 a b d e + a c d e + 2 a c e + 2 a
+ c + a d e + 2 b c d e + 4 b c d + 2 b d e
+ vsop> print H / (a + b)
+ c d e - d e
+ vsop> print H / (a + b) * (a + b)
+ a c d e - a d e + b c d e - b d e
+ vsop> print H % (a + b)
+ 4 a b c d - 4 a b c e + 4 a b c - 4 a b d e - 2 a c e + 2 a c + b c d
+ e - 4 b c d + 3 b d e
+ vsop> print H / (c e)
+ - 4 a b + a d - 2 a + 2 b d
+ vsop> quit
+
+@EOF
--- /dev/null
+\e$B@0?tCMAH9g$;=89g7W;;%W%m%0%i%`\e(B VSOP \e$B$N;HMQK!\e(B\r
+\r
+1. \e$BBP>]5!<o$H5/F0K!\e(B\r
+\e$BK\%W%m%0%i%`$O\e(B Linux OS\e$B$GF0:n$9$k!#!J\e(Bgcc, g++, bison, flex\e$B$r;HMQ!K\e(B\r
+32\e$B%S%C%H7W;;5!$rA[Dj$7$F$$$k$,!"%3%s%Q%$%k%*%W%7%g%s@_Dj$K$h$j\e(B\r
+64\e$B%S%C%H5!$K$bBP1~2DG=$G$"$k!JL$3NG'!K!#\e(B\r
+\r
+\e$B%W%m%0%i%`$N5/F0J}K!$O!"\e(B\r
+vsop [-\e$B:GBg\e(BBDD\e$B@aE@?t\e(B] [\e$B%U%!%$%kL>\e(B]\r
+\e$B$G$"$k!#\e(B\r
+\r
+\e$B5/F0;~$K%U%!%$%kL>$r;XDj$9$k$H%U%!%$%k$K=q$+$l$?L?Na$r<B9T$9$k!#%U%!%$\e(B\r
+\e$B%kL>$r>J$/$HI8=`F~NO$+$iFI$_9~$`!#7W;;7k\e(B\e$B2L$OI8=`=PNO$K=PNO$5$l$k!#C<Kv\e(B\r
+\e$BF~=PNO$K$h$k%$%s%?%W%j%?7A<0$NMxMQK!$H!"%U%!%$%kF~=PNO$K$h$k%U%#%k%?7A<0\e(B\r
+\e$B$NMxMQK!$NN>J}$,2DG=$G$"$k!#\e(B\r
+\r
+VSOP\e$B$G$O!"FbIt$G@8@.$9$k\e(BBDD(\e$BLs\e(B30\e$B%P%$%H\e(B/\e$B@aE@\e(B)\e$B$,<g5-21$r$"$U$l$F#2<!\e(B\r
+\e$B5-21$,;H$o$l=P$9$H=hM}B.EY$,5^7c$K\e(B(100\e$BG\0J>e!KDc2<$9$k$?$a!"%^%7%s$N<g\e(B\r
+\e$B5-21%5%$%:$K1~$8$F:GBg\e(BBDD\e$B@aE@?t$r;XDj$7!"$=$NHO0OFb$G<B9T$9$k!#!J>J\e(B\r
+\e$BN,CM$O\e(B400000\e$B!#!K5-21NN0h$O!"5/F0;~$K:G>.8B3NJ]$5$l!"I,MW$K1~$8$F=y!9$K\e(B\r
+\e$B8B3&$^$G3HD%$5$l$k!#7W;;Cf$K;XDj$7$?:GBg@aE@?t$KC#$7\e(B\e$B$?>l9g$O7W;;$rBG$A\e(B\r
+\e$B$-$j!"7Y9p%a%C%;!<%8$r=PNO$9$k!J7W;;7k2L$O\e(B0\e$B$H$J$k!K!#\e(B\r
+\r
+\e$B!JNc!K\e(B\r
+vsop \e$B%$%s%?%W%j%?%b!<%I$G5/F0\e(B\r
+vsop script \e$B%U%!%$%kL>\e(B script \e$B$K=q$+$l$?L?Na$r<B9T\e(B\r
+vsop -100000 \e$B:GBg\e(BBDD\e$B@aE@?t\e(B 100000 \e$B$G5/F0\e(B\r
+\r
+\r
+2. \e$BJQ?tL>!&?tCM\e(B\r
+VSOP\e$B$G$O!"B?9`<0$N%"%$%F%`JQ?t$rI=$9!V%7%s%\%kJQ?t!W$H!"7W;;7k2L$r0l;~E*$K\e(B\r
+\e$BJ];}$9$k5-21>l=j$rI=$9!V%W%m%0%i%`JQ?t!W$r;HMQ$9$k!#%7%s%\%kJQ?t$O1Q>.J8;z\e(B\r
+\e$B$G;O$^$k1Q?t;zNs!"\e(B\e$B%W%m%0%i%`JQ?t$O1QBgJ8;z$G;O$^$k1Q?t;zNs$GI=$9!#1Q?t;zNs$O\e(B\r
+\e$B:GBg\e(B255\e$BJ8;z$^$G$G!"#2J8;zL\0J9_$K%"%s%@!<%P!<$r4^$s$G$b$h$$!#%7%s%\%kJQ?t$O\e(B\r
+\e$B:GBg\e(B65510\e$B8D$^$G;HMQ$G$-$k!#%W%m%0%i%`JQ?t$N8D?t$K@)Ls$O$J$$!#\e(B\r
+\r
+\e$B?tCM$O\e(B10\e$B?J?t$GI=8=$9$k!#?tCM$NHO0O$O@5Ii\e(B100\e$BK|%S%C%H$^$G86M}E*$K$O07$($k$,!"\e(B\r
+100\e$B%S%C%H$r1[$($k$h$&$JBg$-$J?t$r07$&$H7W;;;~4V$,A}Bg$9$k!#?t<0Cf$N78?t!&\e(B\r
+\e$BDj?t$O@0?tCM$N$_$K8B$i$l!">.?t$O;H$($J$$!#$J$*\e(Bsymbol\e$BJ8$NCf$G%7%s%\%kJQ?t\e(B\r
+\e$B$NCM\e(B(value)\e$B$rDj5A$9$k$H$-$K8B$j>.?t$,;H$(\e(B\e$B$k!#\e(B\r
+\r
+\e$B%3%^%s%I$NCf$G%U%!%$%kL>$r;XDj$9$k>l9g!"$*$h$SF~NO$7$?J8;zNs$r%(%3!<%P%C\e(B\r
+\e$B%/$5$;$k$H$-$K$O!"N>C<$r0zMQId\e(B\verb1"1\e$B$G0O$`!#\e(B\r
+\r
+\e$B!JNc!K\e(B\r
+\e$B%7%s%\%kJQ?t\e(B a b x1 x2 bdd a5A f_t6\r
+\e$B%W%m%0%i%`JQ?t\e(B A B X1 X2 BDD A5a F_t6\r
+\e$B?tCM\e(B 0 29 32767 -213\r
+\e$B%U%!%$%kL>!&J8;zNs\e(B "a" "b" "script1.bem" \r
+\r
+\r
+3. \e$BL?Na$N9=@.\e(B\r
+VSOP\e$B$O!"4pK\E*$K9TC10L!J#19T#1L?Na!K$GF0:n$9$k!##19T$KJ#?t8D$NL?Na\e(B\r
+\e$B$r=q$/>l9g$O!"%;%_%3%m%s\e(B ; \e$B$G6h@Z$k!#J#?t9T$K$o$?$C$F#1L?Na$r=q$/>l\e(B\r
+\e$B9g$O!"2~9T$ND>A0$K%P%C%/%9%i%C%7%e!V\e(B\\e$B!W$rCV$/!#J8Cf$K%7%c!<%W!V\e(B#\e$B!W$r\e(B\r
+\e$B=q$/$H!"<!$N2~9T$^$G%3%a%s%H$H$7$FFI$_Ht$P$5$l$k!#\e(B\r
+\r
+\e$B%W%m%0%i%`$N@)8f$K4X$9$kL?Na$H$7$F$O!"<!$N#3$D$,$"$k!#\e(B\r
+ source "\e$B%U%!%$%kL>\e(B" \e$B%U%!%$%k$K=q$+$l$?L?Na$r8F$S=P$7$F<B9T$9$k!#\e(B\r
+ help \e$B$^$?$O\e(B ? \e$B;HMQK!$rI=<($9$k!#\e(B\r
+ quit \e$B$^$?$O\e(B exit \e$B%W%m%0%i%`$r=*N;$9$k!#%U%!%$%k$N=*$j\e(B(EOF)\e$B$G$b=*N;!#\e(B\r
+\r
+VSOP\e$B$N7W;;$r<B9T$9$kL?Na$O!"<!$N#3<o$+$i$J$k!#\e(B\r
+\r
+\e$B!&@k8@J8\e(B --- \e$B;HMQ$9$k%7%s%\%kJQ?t$NL>A0$H$=$N?tCM$*$h$SE83+=g=x$r@k8@$9$k!#\e(B\r
+\e$B!&BeF~J8\e(B --- \e$B7W;;7k2L$r%W%m%0%i%`JQ?t$KBeF~$9$k!#\e(B\r
+\e$B!&=PNOJ8\e(B --- \e$B7W;;7k2L$r<o!9$N7A<0$GI=<($9$k!#\e(B\r
+\r
+\r
+4. \e$B@k8@J8\e(B\r
+\e$B@k8@J8$O!";HMQ$9$k%7%s%\%kJQ?t$NL>A0$H=g=x$r$"$i$+$8$a@k8@$9$k$b$N$G$"$k!#\e(B\r
+\r
+ symbol [ \e$B%7%s%\%kJQ?tL>\e(B [ , \e$B%7%s%\%kJQ?tL>\e(B, ...] ]\r
+\r
+\e$B6h@Z$j$N%3%s%^$O6uGr$G$b$h$$!#JQ?t$N=g=x$O!":8$+$i=g$K>e0L!J@h$KE83+$5\e(B\r
+\e$B$l$k!K$KG[CV$5$l$k!#%7%s%\%kJQ?tL>$r#1$D$b=q$+$J$+$C$?>l9g$O!"8=:_;HMQ\e(B\r
+\e$BCf$N%7%s%\%kJQ?t$,0lMwI=<($5$l$k!#\e(B\r
+\r
+\e$B$^$?!"\e(BVSOP\e$B$G$O!"%7%s%\%kJQ?t$KCM\e(B(value)\e$B$r;XDj$9$k$3$H$,$G$-$k!#\e(B\r
+\r
+ symbol [ \e$B%7%s%\%kJQ?tL>\e(B(\e$BBeF~CM\e(B) [ , \e$B%7%s%\%kJQ?tL>\e(B(\e$BBeF~CM\e(B), ...] ]\r
+\r
+\e$B>e5-$NCM\e(B(value)\e$B$H$O!"\e(Bprint\e$BJ8$N\e(B /value, /mincover, /mincost \e$B%9%$%C%A$N\e(B\r
+\e$B$H$-$K;HMQ$9$k$b$N$G!"3FJQ?t$K;XDj$7$??tCM$rBeF~$7$?$H$-$N<0A4BN$N?tCM$r\e(B\r
+\e$B7W;;$7$?$j!"%3%9%H:G>.$H$J$kAH9g$;$r$_$D$1$?$j$G$-$k!#\e(BVSOP\e$B$G$O07$&?tCM$O\e(B\r
+\e$B@0?t$K8B$i$l$F$$$k$,!"%7%s%\%kJQ?t$NCM\e(B(value)\e$B$K8B$j>.?t$r;HMQ$G$-\e(B\r
+\e$B$k!#$?$@$7<BAu$NET9g>e!"8GDj>.?tE@\e(B(\e$B@0?tIt\e(B16bit+\e$B>.?tIt\e(B16bit)\e$B7??tCM$H\e(B\r
+\e$B$7$F7W;;$5$l!"$=$NHO0O$rD6$($k$H7e$"$U$l!&7eMn$A$,H/@8$9$k!#CM$N;XDj$r>JN,\e(B\r
+\e$B$7$?>l9g$O!"\e(B0.5\e$B$,@_Dj$5$l$k!#\e(B\r
+\r
+\e$B@k8@J8$OJ#?t2s$KJ,$1$F<B9T$7$F$b$h$$$,!"$=$N>l9g!"$"$H$K@k\e(B\e$B8@$5$l$?%7%s\e(B\r
+\e$B%\%kJQ?t$,2<0L$KG[CV$5$l$k!#F1$8%7%s%\%kJQ?t$r#2EY@k8@$7$?>l9g!"JQ?t=g\e(B\r
+\e$B=x$OJQ$o$i$J$$$,!"CM$N;XDj$O8e$N@k8@$NJ}$,M-8z$H$J$k!#\e(B\r
+\e$B!JNc!K\e(B\r
+ symbol a, b, c\r
+ symbol b, d, e\r
+\e$B$H$9$k$H!"\e(Ba b c d e\e$B$N=g$K$J$k!#\e(B\r
+\r
+\e$B@k8@$7$F$$$J$$%7%s%\%kJQ?t$,;;=Q<0$NCf$G;H$o$l$?>l9g$O!"$=$N>l$G?7$?$K\e(B\r
+\e$B@k8@$7$?$b$N$H$7$F!":G>e0L$KDI2C$5$l$k!J7Y9p%a%C%;!<%8$,=P$k!K!#\e(B\r
+\e$B!JNc!K\e(B\r
+ symbol a, b, c\r
+ print a b + c d\r
+\e$B$H$9$k$H\e(B\e$B!"\e(Bd a b c \e$B$N=g$K$J$k!#\e(B\r
+\r
+\r
+5. \e$BBeF~J8\e(B\r
+\e$BBeF~J8$O!"1&JU$N;;=Q<0$r7W;;$7!"F@$i$l$?@0?tCMAH9g$;=89g$N<0$r\e(B\r
+\e$B:8JU$N%W%m%0%i%`JQ?t$KBeF~$9$k$b$N$G$"$k!#\e(B\r
+\r
+ \e$B%W%m%0%i%`JQ?tL>\e(B = \e$B<0\e(B\r
+\r
+\e$B%W%m%0%i%`JQ?tL>$O!"$"$i$+$8$a@k8@$9$kI,MW$O$J$$!#BeF~J8$N:8JU$K=i$a$F\e(B\r
+\e$B8=$l$?;~E@$G!"5-21NN0h$,3NJ]$5$l$k!#0lC6BeF~$5$l$?%W%m%0%i%`JQ?t$O!"0J\e(B\r
+\e$B8e!"1&JU$N<0$NCf$G;2>H$9$k$3$H$,$G$-$k!#%W%m%0%i%`JQ?t$N;HMQ8D?t$K@)8B\e(B\r
+\e$B$O$J$$!#F1$8%W%m%0%i%`JQ?t$K=E$M$FBeF~$9$k$H!"0JA0$NFbMF$,>C5n$5$l$?8e\e(B\r
+\e$B$K\e(B\e$B!"?7$7$$CM$,BeF~$5$l$k!#%7%s%\%kJQ?t$O1&JU$G;2>H$9$k$3$H$O$G$-$k$,:8\e(B\r
+\e$BJU$KCV$/$3$H$O$G$-$J$$!#$^$?BeF~$5$l$?$3$H$N$J$$%W%m%0%i%`JQ?t$r1&JU$G\e(B\r
+\e$B;2>H$9$k$3$H$O$G$-$J$$!#\e(B\r
+\r
+\e$B1&JU$N<0$G;HMQ$G$-$k1i;;;R$O0J2<$NDL$j$G$"$k!#1i;;;R$NM%@h=g0L$N9b$$=g$K\e(B\r
+\e$B5-=R$7$F$$$k!#\e(B\r
+\r
+ ( \e$B<0\e(B ) \e$B3g8LFb$r:GM%@h$G7W;;!#\e(B\r
+\e$B<0\e(B.MaxVal \e$B<0$K4^$^$l$k@0?tCM$N:GBgCM\e(B\r
+\e$B<0\e(B.MinVal \e$B<0$K4^$^$l$k@0?tCM$N:G>.CM\e(B\r
+\e$B<0\e(B.Items \e$B<0$KI=$l$k%"%$%F%`JQ?t\e(B\e$B$rNs5s$9$k!#\e(B\r
+\e$B<0\e(B.Restrict(\e$B<0\e(B) \e$BBh#1<0$K4^$^$l$kAH9g$;$NCf$+$i!"Bh#2<0Cf$N>/$J$/$H$b#1$D$N\e(B\r
+ \e$BAH9g$;$rJq4^$9$kMWAG$@$1$rCj=P$9$k!#\e(B\r
+\e$B<0\e(B.Permit(\e$B<0\e(B) \e$BBh#1<0$K4^$^$l$kAH9g$;$NCf$+$i!"Bh#2<0Cf$N>/$J$/$H$b#1$D$N\e(B\r
+ \e$BAH9g$;$KJq4^$5$l$kMWAG$@$1$rCj=P$9$k!#\e(B\r
+\e$B<0\e(B \e$B<0\e(B \e$B>h;;\e(B\r
+\e$B<0\e(B * \e$B<0\e(B \e$B>h;;\e(B\r
+\e$B<0\e(B / \e$B<0\e(B \e$B=|;;!J@0?t=|;;$N>&!K!#\e(B\r
+\e$B<0\e(B % \e$B<0\e(B \e$B>jM>!J@0?t=|;;$N>jM>!K!#\e(B\r
+\e$B<0\e(B + \e$B<0\e(B \e$B2C;;!#\e(B\r
+\e$B<0\e(B - \e$B<0\e(B \e$B8:;;!#\e(B\r
++ \e$B<0\e(B \e$B@5$NId9f!J2?$b$7$J$$!K!#\e(B\r
+- \e$B<0\e(B \e$BJd?t7W;;!#\e(B\r
+\e$B<0\e(B == \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,Ey$7$$$b$N$@$1$r<h$j=P$9!K!#\e(B\r
+\e$B<0\e(B != \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,Ey$7$/$J$$\e(B\e$B$b$N$@$1$r<h$j=P$9!K!#\e(B\r
+\e$B<0\e(B > \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,>r7o$rK~$?$9$b$N$@$1$r<h$j=P$9!K!#\e(B\r
+\e$B<0\e(B >= \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,>r7o$rK~$?$9$b$N$@$1$r<h$j=P$9!K!#\e(B\r
+\e$B<0\e(B < \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,>r7o$rK~$?$9$b$N$@$1$r<h$j\e(B\e$B=P$9!K!#\e(B\r
+\e$B<0\e(B <= \e$B<0\e(B \e$BHf3S1i;;!J>/$J$/$H$b0lJ}$N<0$K4^$^$l$kAH9g$;$G!"\e(B\r
+ \e$B$=$N@0?tCM$,>r7o$rK~$?$9$b$N$@$1$r<h$j=P$9!K!#\e(B\r
+\e$B<0\e(B ? \e$B<0\e(B : \e$B<0\e(B If-Then-Else\e$B1i;;!#Bh#1<0$K4^$^$l$kAH9g$;$KBP$7$F$O\e(B\r
+ \e$BBh#2<0$NCM$r$=$N$^$^JV$7!"Bh#1<0$K4^$^$l$J$$AH9g$;\e(B\r
+ \e$B$KBP$7$F$OBh#3<0$NCM$r$=$N$^$^JV$91i;;!#\e(B\r
+\r
+\r
+6. \e$B=PNOJ8\e(B\r
+\e$B=PNOJ8$N7A<0$O<!$NDL$j$G$"$k!#\e(B\r
+\r
+print [ /\e$B%9%$%C%A\e(B ] \e$B<0\e(B\r
+print "\e$BJ8;zNs\e(B"\r
+\r
+print \e$B$O!V\e(B?\e$B!W$GBeMQ$G$-$k!#%9%$%C%A$O=PNO7A<0$r;XDj$9$k$b$N$G!"\e(B\r
+\e$B>JN,$7$?>l9g$O!"3g8L$r4^$^$J$$@QOB7A$KE83+$7$?<0$rI=<($9$k!#\e(B\r
+\e$B0zMQId!V\e(B"\e$B!W$G0O$s$@J8;zNs$O$=$N$^$^%(%3!<%P%C%/$5$l$k!#\e(B\r
+\r
+\e$B0J2<$K!";HMQ$G$-$k%9%$%C%A$H$=$N;HMQNc$r<($9!#\e(B\r
+\r
+\e$B!J%9%$%C%AL5$7!K<0$N%+%C%3$rE83+$7$?@QOB7A$GI=<($9$k!#\e(B\r
+ /bit \e$BFbIt$N#2?J?t$N3F7e$NAH9g$;$r=g$KI=<(!#\e(B \r
+ /hex \e$B@0?tCM$r\e(B16\e$B?J?t$GI=8=$9$k@QOB7A\e(B\e$BI=<(!#\e(B\r
+ /map \e$B%+%k%N!<?^$GI=<(!#%"%$%F%`JQ?t#68D$^$GI=<($G$-$k!#\e(B\r
+ /rmap \e$B%+%k%N!<?^$GI=<(!#>iD9$J%"%$%F%`JQ?t$O>J$$$FI=<(!#\e(B\r
+ /case \e$B@0?tCM$4$H$K>l9gJ,$1$7$F@QOB7AI=<(!#\e(B\r
+ /size \e$B7W;;7k2L$N#B#D#D@aE@?t!J$*$h$S=hM}7OA4BN$N@aE@?t!K$rI=<(!#\e(B\r
+ /count \e$B<0$K8=$l$k\e(B(0\e$B0J30$NCM$r;}$D!KAH9g$;$N8D?t$rI=<(!#\e(B\r
+ /density \e$B=89g$NG;EY!J\e(B0\e$B0J30$NCM$r;}$DAH9g$;$NHfN(!K$rI=\e(B\e$B<(!#\e(B\r
+ /value \e$B%7%s%\%kJQ?t$K$9$Y$F?tCM$rBeF~$7$?$H$-$N<0$NCM$rI=<(\e(B\r
+ /maxcover \e$B<0$K4^$^$l$k!J\e(B0\e$B0J30$NCM$r;}$D!K%3%9%H:GBg$NAH9g$;$r#1$DI=<(!#\e(B\r
+ /maxcost \e$B%3%9%H:GBgAH9g$;$N%3%9%HCM$rI=<(!#\e(B\r
+ /mincover \e$B<0$K4^$^$l$k!J\e(B0\e$B0J30$NCM$r;}$D!K%3%9%H:G>.$NAH9g$;$r#1$DI=<(!#\e(B\r
+ /mincost \e$B%3%9%H:G>.AH9g$;$N%3%9%HCM$rI=<(!#\e(B\r
+ /plot \e$B#B#D#D$N7A$r?^<($9$k!#\e(B\r
+ /plot0 \e$B#B#D#D$N7A$r?^<($9$k!JH]Dj;^IT;HMQ!K\e(B\r
+\r
+\r
+7. \e$B<B9TNc\e(B\r
+\e$B!Z%$%s%?%W%j%?%b!<%I![\e(B\r
+***** VSOP (Valued Sum-Of-Products) calculator - ver 0.7 *****\r
+ vsop> symbol a b c d e\r
+ vsop> F = (a + 2 b)(c + d)\r
+ vsop> print F\r
+ a c + a d + 2 b c + 2 b d\r
+ vsop> print /rmap F\r
+ a b : c d\r
+ | 00 01 11 10\r
+ 00 | 0 0 0 0\r
+ 01 | 0 2 0 2\r
+ 11 | 0 0 0 0\r
+ 10 | 0 1 0 1\r
+ vsop> G = (2 a - d)(c - e)\r
+ vsop> print G\r
+ 2 a c - 2 a e - c d + d e\r
+ vsop> print /rmap G\r
+ a c : d e\r
+ | 00 01 11 10\r
+ 00 | 0 0 1 0\r
+ 01 | 0 0 0 -1\r
+ 11 | 2 0 0 0\r
+ 10 | 0 -2 0 0\r
+ vsop> H = F * G\r
+ vsop> print H\r
+ 4 a b c d - 4 a b c e + 4 a b c - 4 a b d e + a c d e - 2 a c e + 2 a\r
+ c - a d e + 2 b c d e - 4 b c d + 2 b d e\r
+ vsop> print /rmap H\r
+ a b : c d e\r
+ | 000 001 011 010 | 110 111 101 100\r
+ 00 | 0 0 0 0 | 0 0 0 0\r
+ 01 | 0 0 2 0 | -4 2 0 0\r
+ 11 | 0 0 -4 0 | 4 0 -4 4\r
+ 10 | 0 0 -1 0 | 0 1 -2 2\r
+ vsop> print /count H\r
+ 11\r
+ vsop> print /size H\r
+ 24 (35)\r
+ vsop> print H > 0\r
+ a b c d + a b c + a c d e + a c + b c d e + b d e\r
+ vsop> print (H > 0)? H: 0\r
+ 4 a b c d + 4 a b c + a c d e + 2 a c + 2 b c d e + 2 b d e\r
+ vsop> print (H > 0)? H: -H\r
+ 4 a b c d + 4 a b c e + 4 a b c + 4 a b d e + a c d e + 2 a c e + 2 a\r
+ c + a d e + 2 b c d e + 4 b c d + 2 b d e\r
+ vsop> print H / (a + b)\r
+ c d e - d e\r
+ vsop> print H / (a + b) * (a + b)\r
+ a c d e - a d e + b c d e - b d e\r
+ vsop> print H % (a + b)\r
+ 4 a b c d - 4 a b c e + 4 a b c - 4 a b d e - 2 a c e + 2 a c + b c d\r
+ e - 4 b c d + 3 b d e\r
+ vsop> print H / (c e)\r
+ - 4 a b + a d - 2 a + 2 b d\r
+ vsop> quit\r
+ \r
+\r
--- /dev/null
+%x src
+
+%{
+// VSOP Parser(Lex) (v1.36)
+// Shin-ichi MINATO (Dec. 18, 2010)
+
+#include <string.h>
+#include "CtoI.h"
+#include "y.tab.h"
+
+static const int textMax = 256;
+
+static void StrSave();
+void StrSave()
+{
+ yylval.name.str = new char[yyleng+1];
+ yylval.name.len = yyleng;
+ strcpy(yylval.name.str, yytext);
+}
+
+YY_BUFFER_STATE lastbuf = 0;
+
+%}
+
+%%
+
+"#"[^\n]*"\n" { return RETURN; }
+"\\\n" { ; }
+[ \t] { ; }
+";" { return SEMICOLON; }
+"\n" { return RETURN; }
+"\r\n" { return RETURN; }
+
+symbol { return SYMBOL; }
+print { return PRINT; }
+exit { return EXIT; }
+quit { return EXIT; }
+help { return HELP; }
+source { BEGIN(src); }
+
+"."MaxVal { return MAXVAL; }
+"."MinVal { return MINVAL; }
+"."TotalVal { return TOTALVAL; }
+"."Items { return ITEMS; }
+"."Always { return ALWAYS; }
+"."Restrict { return RESTRICT; }
+"."Permit { return PERMIT; }
+"."PermitSym { return PERMITSYM; }
+"."TermsEQ { return TEQ; }
+"."TermsNE { return TNE; }
+"."TermsGT { return TGT; }
+"."TermsGE { return TGE; }
+"."TermsLT { return TLT; }
+"."TermsLE { return TLE; }
+"."FreqPatA { return FPA; }
+"."FreqPatAV { return FPAV; }
+"."FreqPatM { return FPM; }
+"."FreqPatC { return FPC; }
+"."SymGrp { return SYMGRP; }
+Import { return IMPORT; }
+Lcm { return LCM; }
+
+"?" { return QUESTION; }
+"," { return COMMA; }
+"." { return PERIOD; }
+
+"=" { return ASSIGN; }
+
+"+" { return PLUS; }
+"-" { return MINUS; }
+"*" { return MULTIPLY; }
+"/" { return QUOTIENT; }
+"%" { return REMAINDER; }
+"@" { return MEET; }
+
+"==" { return EQ; }
+"!=" { return NE; }
+">" { return GT; }
+">=" { return GE; }
+"<" { return LT; }
+"<=" { return LE; }
+
+":" { return COLON; }
+
+"(" { return LPAREN; }
+")" { return RPAREN; }
+"[" { return LBRACKET; }
+"]" { return RBRACKET; }
+
+[a-z][a-zA-Z0-9_]* { StrSave(); return IDVAR; }
+[A-Z][a-zA-Z0-9_]* { StrSave(); return IDFUNC; }
+[0-9]+ { StrSave(); return NUMBER; }
+0[xX][0-9a-fA-F]+ { StrSave(); return NUMBER; }
+0[bB][01]+ { StrSave(); return NUMBER; }
+[0-9]*"."[0-9]+ { StrSave(); return RNUM; }
+\"[^\"^\n]+\" { StrSave(); return FNAME; }
+. { return UNKNOWN; }
+
+<src>[ \t] { ; }
+<src>"\\\n" { ; }
+<src>"\n" {
+ fprintf(stderr, "syntax error.\n");
+ BEGIN(INITIAL);
+}
+<src>[^ \t\n]+ {
+ if(lastbuf) fprintf(stderr, "nested source command.\n");
+ else
+ {
+ FILE* fp = fopen(yytext, "r");
+ if(!fp) fprintf(stderr, "can't open the file: %s\n", yytext);
+ else
+ {
+ lastbuf = YY_CURRENT_BUFFER;
+ yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
+ }
+ }
+ BEGIN(INITIAL);
+}
+
+<<EOF>> {
+ if(lastbuf == 0) yyterminate();
+ else
+ {
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(lastbuf);
+ lastbuf = 0;
+ }
+}
+
+
+%%
--- /dev/null
+%{
+// VSOP Parser(Yacc) (v1.39)
+// Shin-ichi MINATO (Nov. 22, 2013)
+
+#define YYMAXDEPTH 1000
+#include <cstdio>
+#include <cstring>
+#include <iostream>
+#include "CtoI.h"
+#include "ZBDDDG.h"
+#include "vsop.h"
+
+#ifdef B_64
+# define B_STRTOI strtoll
+# define B_ITOSTR(n, s) sprintf(s, "%lld", n)
+#else
+# define B_STRTOI strtol
+# define B_ITOSTR(n, s) sprintf(s, "%d", n)
+#endif
+
+using namespace std;
+
+extern int yylineno;
+extern char* yytext;
+extern FILE* yyin;
+extern int yywrap();
+extern int yylex();
+
+extern "C"
+{
+ extern int system(const char*);
+ extern int isatty(int);
+ extern void bddfree(bddword);
+}
+
+void yyerror(const char* s)
+{
+ cerr << s << " in line " << yylineno << ".\n";
+ cerr.flush();
+}
+
+int yywrap() { return(1); }
+
+#define NDEF 1000000
+
+int VarOrdTop;
+
+int main(int argc, char** argv)
+{
+
+ char* src = 0;
+ char* opt;
+ if(argc == 1) opt = 0;
+ else
+ {
+ opt = argv[1];
+ if(opt[0] != '-'){ src = opt; opt = 0; }
+ else if(argc > 2) src = argv[2];
+ }
+
+ if(src != 0 && (yyin = fopen(src, "r")) == 0)
+ {
+ fprintf(stderr, "can't open the file: %s\n", src);
+ return 1;
+ }
+
+ bddword nmax;
+ if(opt == 0) nmax = NDEF;
+ else nmax = B_STRTOI(opt+1, NULL, 10);
+
+ BDDV_Init(256, nmax);
+ VarOrdTop = 0;
+
+ if(src == 0 && isatty(0) == 1)
+ {
+ cerr << "***** VSOP (Valued Sum-Of-Products) calculator <v1.39> *****\n" << PROMPT;
+ cerr.flush();
+ }
+
+ yyparse();
+ exit(0);
+}
+
+struct OV
+{
+ char _ovf;
+
+ OV(void) { _ovf = 0; }
+ void Set(void) { _ovf = 1; }
+ char Check(void)
+ {
+ char a = _ovf;
+ _ovf = 0;
+ return a;
+ }
+} OVF;
+
+static const int power16 = 1 << 16;
+static const char BC_VSOP_VALUE = 50;
+static const char BC_VSOP_DENSITY = 51;
+static const char BC_VSOP_MAXCOST = 52;
+static const char BC_VSOP_MINCOST = 53;
+static const char BC_VSOP_PRODUCT = 54;
+
+static CtoI Product(CtoI, CtoI);
+CtoI Product(CtoI ac, CtoI bc)
+{
+ if(ac == 1) return bc;
+ if(bc == 1) return ac;
+ if(ac == CtoI_Null()) return ac;
+ if(bc == CtoI_Null()) return bc;
+ if(ac == 0) return 0;
+ if(bc == 0) return 0;
+
+ CtoI a = ac; CtoI b = bc;
+ int atop = a.Top();
+ int btop = b.Top();
+ if(BDD_LevOfVar(atop) < BDD_LevOfVar(btop))
+ {
+ a = bc; b = ac;
+ atop = a.Top(); btop = b.Top();
+ }
+
+ bddword ax = a.GetZBDD().GetID();
+ bddword bx = b.GetZBDD().GetID();
+ if(atop == btop && ax < bx)
+ {
+ a = bc; b = ac;
+ ax = a.GetZBDD().GetID();
+ bx = b.GetZBDD().GetID();
+ }
+
+ ZBDD z = BDD_CacheZBDD(BC_VSOP_PRODUCT, ax, bx);
+ if(z != -1) return CtoI(z);
+ BDD_RECUR_INC;
+
+ CtoI a0 = a.Factor0(atop);
+ CtoI a1 = a.Factor1(atop);
+ CtoI c;
+ if(atop != btop)
+ {
+ if(atop > BDDV_SysVarTop)
+ {
+ int azvar = VTable.GetGID(atop);
+ CtoI bz = b;
+ int bztop = bz.Top();
+ while(BDD_LevOfVar(azvar) <= BDD_LevOfVar(bztop))
+ {
+ bz = bz.Factor0(bztop);
+ bztop = bz.Top();
+ }
+ c = CtoI_Union(Product(a0, b), Product(a1, bz).AffixVar(atop));
+ }
+ else c = Product(a0, b) + Product(a1, b).TimesSysVar(atop);
+ }
+ else
+ {
+ CtoI b0 = b.Factor0(atop);
+ CtoI b1 = b.Factor1(atop);
+ if(atop > BDDV_SysVarTop)
+ {
+ int azvar = VTable.GetGID(atop);
+ CtoI az = a;
+ int aztop = az.Top();
+ while(BDD_LevOfVar(azvar) <= BDD_LevOfVar(aztop))
+ {
+ az = az.Factor0(aztop);
+ aztop = az.Top();
+ }
+ CtoI bz = b;
+ int bztop = bz.Top();
+ while(BDD_LevOfVar(azvar) <= BDD_LevOfVar(bztop))
+ {
+ bz = bz.Factor0(bztop);
+ bztop = bz.Top();
+ }
+ c = CtoI_Union(Product(a0, b0),
+ (Product(a1,bz)+Product(az,b1)+Product(a1,b1)).AffixVar(atop));
+ }
+ else if(atop > 1)
+ c = Product(a0,b0) + (Product(a1,b0)+Product(a0,b1)).TimesSysVar(atop)
+ + Product(a1,b1).TimesSysVar(atop - 1);
+ else BDDerr("CtoI::operator*(): SysVar overflow.");
+ }
+
+ BDD_RECUR_DEC;
+ BDD_CacheEnt(BC_VSOP_PRODUCT, ax, bx, c.GetZBDD().GetID());
+ return c;
+}
+
+static int Value(CtoI);
+int Value(CtoI a)
+{
+ if(a == CtoI()) return 0;
+ if(a == 0) return 0;
+ if(a == 1) return power16;
+
+ int val = BDD_CacheInt(BC_VSOP_VALUE, a.GetZBDD().GetID(), 0);
+ if(val <= BDD_MaxNode) return val;
+ BDD_RECUR_INC;
+
+ int var = a.Top();
+ float f;
+ if(var > BDDV_SysVarTop)
+ f = (float)VTable.GetValue(var) / power16;
+ else
+ {
+ f = -2;
+ for(int i=0; i<(BDDV_SysVarTop-var); i++) f *= f;
+ }
+ int val1 = Value(a.Factor1(var));
+ val = (int)(f * val1);
+ if(val)
+ {
+ if((val1<0)^(f<0)^(val<0)) OVF.Set();
+ }
+ else if((f!=0) && val1) OVF.Set();
+ int val0 = Value(a.Factor0(var));
+ val1 = val;
+ val += val0;
+ if(val1>0 && val0>0 && val<0) OVF.Set();
+ if(val1<0 && val0<0 && val>0) OVF.Set();
+
+ BDD_RECUR_DEC;
+ BDD_CacheEnt(BC_VSOP_VALUE, a.GetZBDD().GetID(), 0, val);
+ return val;
+}
+
+static const int power30 = 1 << 30;
+
+static int Density(ZBDD, int);
+int Density(ZBDD f, int tlev)
+{
+ if(f == -1) return 0;
+ if(f == 0) return 0;
+
+ int var = f.Top();
+ int lev = BDD_LevOfVar(var);
+ int c;
+ if(f == 1) c = power30;
+ else
+ {
+ c = BDD_CacheInt(BC_VSOP_DENSITY, f.GetID(), 0);
+ if(c > BDD_MaxNode)
+ {
+ BDD_RECUR_INC;
+ c = (Density(f.OffSet(var), lev-1) >> 1)
+ + (Density(f.OnSet0(var), lev-1) >> 1);
+ BDD_RECUR_DEC;
+ BDD_CacheEnt(BC_VSOP_DENSITY, f.GetID(), 0, c);
+ }
+ }
+ for(int i=1; i<=tlev-lev; i++) c >>= 1;
+ return c;
+}
+
+static int MaxCost(ZBDD);
+int MaxCost(ZBDD f)
+{
+ if(f == -1) return 0;
+ if(f == 0) return -power30;
+ if(f == 1) return 0;
+
+ int c = BDD_CacheInt(BC_VSOP_MAXCOST, f.GetID(), 0);
+ if(c <= BDD_MaxNode) return c;
+ BDD_RECUR_INC;
+
+ int var = f.Top();
+ int c0 = MaxCost(f.OffSet(var));
+ int c1 = MaxCost(f.OnSet0(var)) + VTable.GetValue(var);
+ c = (c0 > c1)? c0: c1;
+
+ BDD_RECUR_DEC;
+ BDD_CacheEnt(BC_VSOP_MAXCOST, f.GetID(), 0, c);
+ return c;
+}
+
+static int MinCost(ZBDD);
+int MinCost(ZBDD f)
+{
+ if(f == -1) return 0;
+ if(f == 0) return power30;
+ if(f == 1) return 0;
+
+ int c = BDD_CacheInt(BC_VSOP_MINCOST, f.GetID(), 0);
+ if(c <= BDD_MaxNode) return c;
+ BDD_RECUR_INC;
+
+ int var = f.Top();
+ int c0 = MinCost(f.OffSet(var));
+ int c1 = MinCost(f.OnSet0(var)) + VTable.GetValue(var);
+ c = (c0 > c1)? c1: c0;
+
+ BDD_RECUR_DEC;
+ BDD_CacheEnt(BC_VSOP_MINCOST, f.GetID(), 0, c);
+ return c;
+}
+
+int CurGID;
+
+%}
+%union
+{
+ struct
+ {
+ char* str;
+ int len;
+ } name;
+ CtoI* ctoi;
+ int num;
+}
+
+%right QUESTION COLON
+%left EQ NE
+%left GT GE LT LE
+%left PLUS MINUS
+%left MEET
+%right UMINUS UPLUS
+%left MULTIPLY QUOTIENT REMAINDER
+%left CAT
+%left LBRACKET
+%right PERIOD
+%right MAXVAL MINVAL TOTALVAL RESTRICT PERMIT PERMITSYM ITEMS ALWAYS
+%right TEQ TNE TGT TGE TLT TLE FPA FPAV FPM FPC SYMGRP
+%left LPAREN IDFUNC IDVAR NUMBER
+
+%start vsop
+
+%token SEMICOLON RETURN SYMBOL PRINT EXIT HELP
+%token TEQ TNE TGT TGE TLT TLE
+%token FPA FPAV FPM FPC SYMGRP IMPORT LCM //LCMA LCMC LCMM
+%token MAXVAL MINVAL TOTALVAL RESTRICT PERMIT PERMITSYM ITEMS ALWAYS
+%token QUESTION COMMA PERIOD ASSIGN
+%token PLUS MINUS MULTIPLY QUOTIENT REMAINDER MEET
+%token EQ NE GT GE LT LE
+%token COLON LPAREN RPAREN LBRACKET RBRACKET
+%token UNKNOWN
+%token<name> IDVAR IDFUNC FNAME NUMBER RNUM
+
+%type<ctoi> expr u_expr
+%type<num> value valnum
+%%
+
+vsop
+ : lines last
+ { if(yyin == stdin) cerr << "\n"; return(1); }
+ ;
+
+last
+ : EXIT RETURN
+ | /* empty */
+ ;
+
+lines
+ : lines commands RETURN
+ {
+ if(yyin == stdin && isatty(0) == 1)
+ cerr << PROMPT;
+ cerr.flush();
+ }
+ | lines error RETURN
+ {
+ yyerrok;
+ if(yyin == stdin && isatty(0) == 1)
+ {
+ cerr << PROMPT;
+ cerr.flush();
+ }
+ }
+ | /* empty */
+ ;
+
+commands
+ : commands SEMICOLON command
+ | command
+ ;
+
+command
+ : /* empty */
+ | define
+ | assign
+ | output
+ | help
+ {
+ system(DOCUMENT);
+ }
+ ;
+
+define
+ : SYMBOL symlist
+ | SYMBOL
+ {
+ int n = VTable.Used();
+ int gid0 = 0;
+ for(int i=n; i>0; i--)
+ {
+ int var = BDD_VarOfLev(i);
+ int gid = VTable.GetGID(var);
+ if(gid0 != gid && var != gid)
+ {
+ bout << "[";
+ }
+ bout << VTable.GetName(var);
+ if(gid0 == gid && var == gid)
+ bout << "]";
+ gid0 = gid;
+ bout.Delimit();
+ }
+ bout.Return();
+ }
+ | SYMBOL QUOTIENT IDVAR
+ {
+ if(strcmp($3.str, "v") == 0)
+ {
+ int n = VTable.Used();
+ int gid0 = 0;
+ for(int i=n; i>0; i--)
+ {
+ int var = BDD_VarOfLev(i);
+ int gid = VTable.GetGID(var);
+ if(gid0 != gid && var != gid)
+ {
+ bout << "[";
+ }
+ bout << VTable.GetName(var) << "(";
+ char s[32];
+ sprintf(s, "%g", (float)VTable.GetValue(var)/power16);
+ bout << s << ")";
+ if(gid0 == gid && var == gid)
+ bout << "]";
+ gid0 = gid;
+ bout.Delimit();
+ }
+ bout.Return();
+ }
+ else if(strcmp($3.str, "t") == 0)
+ {
+ VarOrdTop = 1;
+ cerr << "(a new symbol will be added at the top.)" << "\n";
+ }
+ else if(strcmp($3.str, "b") == 0)
+ {
+ VarOrdTop = 0;
+ cerr << "(a new symbol will be added at the bottom.)" << "\n";
+ }
+ else
+ {
+ yyerror("Illegal switch");
+ }
+ delete[] $3.str;
+ }
+ ;
+
+symlist
+ : symlist comma { CurGID = 0; } symatom
+ | { CurGID = 0; } symatom
+ ;
+
+symatom
+ : LBRACKET
+ gsymlist RBRACKET
+ | symbol
+ ;
+
+gsymlist
+ : gsymlist comma symbol
+ | symbol
+ ;
+
+symbol
+ : IDVAR
+ {
+ int id = VTable.GetID($1.str);
+ if(id != 0)
+ {
+ char s[256];
+ sprintf(s, "<WARNING> Duplicated symbol '%s' declared", $1.str);
+ yyerror(s);
+ }
+ else
+ {
+ if(CurGID == 0)
+ {
+ if(VarOrdTop) VTable.SetT($1.str, power16 >> 1);
+ else VTable.SetB($1.str, power16 >> 1);
+ CurGID = VTable.GetID($1.str);
+ }
+ else
+ {
+ if(VarOrdTop) VTable.SetT($1.str, power16 >> 1, CurGID);
+ else
+ {
+ int gid = CurGID;
+ VTable.SetB($1.str, power16 >> 1);
+ CurGID = VTable.GetID($1.str);
+ int n = VTable.Used();
+ for(int i=2; i<=n; i++)
+ {
+ if(VTable.GetGID(BDD_VarOfLev(i)) != gid) break;
+ char *name = VTable.GetName(BDD_VarOfLev(i));
+ int val = VTable.GetValue(BDD_VarOfLev(i));
+ VTable.SetB(name, val, CurGID);
+ }
+ }
+ }
+ }
+ delete[] $1.str;
+ }
+ | IDVAR LPAREN value RPAREN
+ {
+ int id = VTable.GetID($1.str);
+ if(id != 0)
+ {
+ char s[256];
+ sprintf(s, "<WARNING> Duplicated symbol '%s' declared", $1.str);
+ yyerror(s);
+ }
+ else
+ {
+ if(CurGID == 0)
+ {
+ if(VarOrdTop) VTable.SetT($1.str, $3);
+ else VTable.SetB($1.str, $3);
+ CurGID = VTable.GetID($1.str);
+ }
+ else
+ {
+ if(VarOrdTop) VTable.SetT($1.str, $3, CurGID);
+ else
+ {
+ int gid = CurGID;
+ VTable.SetB($1.str, $3);
+ CurGID = VTable.GetID($1.str);
+ int n = VTable.Used();
+ for(int i=2; i<=n; i++)
+ {
+ if(VTable.GetGID(BDD_VarOfLev(i)) != gid) break;
+ char *name = VTable.GetName(BDD_VarOfLev(i));
+ int val = VTable.GetValue(BDD_VarOfLev(i));
+ VTable.SetB(name, val, CurGID);
+ }
+ }
+ }
+ }
+ delete[] $1.str;
+ }
+ ;
+
+value
+ : valnum
+ { $$ = $1; }
+ | MINUS valnum
+ { $$ = - $2; }
+ ;
+
+valnum
+ : NUMBER
+ {
+ $$ = atoi($1.str) * power16;
+ delete[] $1.str;
+ }
+ | RNUM
+ {
+ $$ = (int)(atof($1.str) * power16);
+ delete[] $1.str;
+ }
+ ;
+
+comma
+ : COMMA
+ | /* empty */
+ ;
+
+assign
+ : IDFUNC ASSIGN expr
+ {
+ if(*$3 == CtoI_Null())
+ {
+ *$3 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ FTable.Set($1.str, *$3);
+ delete[] $1.str;
+ delete $3;
+ }
+ ;
+
+u_expr
+ : LPAREN expr RPAREN
+ { $$ = $2;}
+ | IDFUNC
+ {
+ CtoI f = FTable.GetCtoI($1.str);
+ if(f == CtoI_Null())
+ {
+ yyerror("<WARNING> Undefined variable appeared");
+ f = 0;
+ FTable.Set($1.str, f);
+ }
+ $$ = new CtoI(f);
+ delete[] $1.str;
+ }
+ | IDVAR
+ {
+ int var = VTable.GetID($1.str);
+ if(var == 0)
+ {
+ if(VarOrdTop)
+ {
+ VTable.SetT($1.str, power16/2);
+ char s[256];
+ sprintf(s, "<WARNING> Undeclared symbol '%s' added at the top", $1.str);
+ yyerror(s);
+ }
+ else
+ {
+ VTable.SetB($1.str, power16/2);
+ char s[256];
+ sprintf(s, "<WARNING> Undeclared symbol '%s' added at the bottom", $1.str);
+ yyerror(s);
+ }
+ var = VTable.GetID($1.str);
+ }
+ CtoI a = CtoI(1).AffixVar(var);
+ $$ = new CtoI(a);
+ delete[] $1.str;
+ }
+ | NUMBER
+ {
+ $$ = new CtoI(CtoI_atoi($1.str));
+ delete[] $1.str;
+ }
+ | u_expr MAXVAL
+ {
+ *$1 = $1 -> MaxVal();
+ $$ = $1;
+ }
+ | u_expr MINVAL
+ {
+ *$1 = $1 -> MinVal();
+ $$ = $1;
+ }
+ | u_expr TOTALVAL
+ {
+ *$1 = $1 -> TotalVal();
+ $$ = $1;
+ }
+ | u_expr RESTRICT LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterRestrict(*$4);
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr PERMIT LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterPermit(*$4);
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr PERMITSYM LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterPermitSym($4->GetInt());
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr ITEMS
+ {
+ *$1 = $1 -> TotalValItems();
+ $$ = $1;
+ }
+ | u_expr ALWAYS
+ {
+ *$1 = $1 -> NonZero().GetZBDD().Always();
+ $$ = $1;
+ }
+ | u_expr TEQ LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> EQ_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr TNE LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> NE_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr TGT LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> GT_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr TGE LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> GE_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr TLT LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> LT_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr TLE LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FilterThen($1 -> LE_Const($4->GetInt()));
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr FPA LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FreqPatA($4->GetInt() );
+ //*$1 = $1 -> ReduceItems($1->TotalValItems().GE_Const(*$4)).FreqPatA($4->GetInt());
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr FPAV LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FreqPatAV($4->GetInt() );
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr FPM LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FreqPatM($4->GetInt() );
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr FPC LPAREN expr RPAREN
+ {
+ *$1 = $1 -> FreqPatC($4->GetInt() );
+ $$ = $1;
+ delete $4;
+ }
+ | u_expr SYMGRP
+ {
+ *$1 = $1 -> NonZero().GetZBDD().SymGrp();
+ $$ = $1;
+ }
+ ;
+
+expr
+ : u_expr
+ { $$ = $1; }
+ | IMPORT LPAREN FNAME RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ FILE *fp;
+ fp = fopen($3.str+1, "r");
+ if(fp == NULL)
+ {
+ yyerror("Can't open the file");
+ $$ = new CtoI(0);
+ }
+ else
+ {
+ ZBDDV v = ZBDDV_Import(fp);
+ fclose(fp);
+ if(v != ZBDDV(-1))
+ {
+ int t = 1;
+ char s[32];
+ while(BDD_LevOfVar(v.Top()) > VTable.Used())
+ {
+ sprintf(s, "x%d", t);
+ while(VTable.GetID(s) != 0)
+ {
+ t++;
+ sprintf(s, "x%d", t);
+ }
+ VTable.SetT0(BDD_VarOfLev(t), s);
+ }
+ int len = v.Last()+1;
+ CtoI a = CtoI(0);
+ for(int i=0; i<len; i++)
+ a += CtoI(v.GetZBDD(i)).ShiftDigit(i);
+ $$ = new CtoI(a);
+ }
+ else
+ {
+ yyerror("<WARNING> import error");
+ $$ = new CtoI(0);
+ }
+ }
+ delete[] $3.str;
+ }
+ | LCM LPAREN FNAME FNAME NUMBER RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ $4.str[$4.len - 1] = 0;
+ int th = atoi($5.str);
+ if(strcmp($3.str+1, "F") == 0) CtoI_Lcm1($4.str+1, 0, th, 0);
+ else if(strcmp($3.str+1, "C") == 0) CtoI_Lcm1($4.str+1, 0, th, 1);
+ else if(strcmp($3.str+1, "M") == 0) CtoI_Lcm1($4.str+1, 0, th, 2);
+ else if(strcmp($3.str+1, "FQ") == 0) CtoI_Lcm1($4.str+1, 0, th, 10);
+ else if(strcmp($3.str+1, "CQ") == 0) CtoI_Lcm1($4.str+1, 0, th, 11);
+ else if(strcmp($3.str+1, "MQ") == 0) CtoI_Lcm1($4.str+1, 0, th, 12);
+ for(int i=VTable.Used(); i<CtoI_LcmItems(); i++)
+ {
+ char s[32];
+ int x = CtoI_LcmPerm(i);
+ sprintf(s, "x%d", i+1);
+ VTable.SetT(s, power16/2);
+ }
+ CtoI a = CtoI_Lcm2();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ delete[] $5.str;
+ }
+ | LCM LPAREN FNAME FNAME NUMBER FNAME RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ $4.str[$4.len - 1] = 0;
+ int th = atoi($5.str);
+ $6.str[$6.len - 1] = 0;
+ if(strcmp($3.str+1, "F") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 0);
+ else if(strcmp($3.str+1, "C") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 1);
+ else if(strcmp($3.str+1, "M") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 2);
+ else if(strcmp($3.str+1, "FQ") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 10);
+ else if(strcmp($3.str+1, "CQ") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 11);
+ else if(strcmp($3.str+1, "MQ") == 0) CtoI_Lcm1($4.str+1, $6.str+1, th, 12);
+ for(int i=VTable.Used(); i<CtoI_LcmItems(); i++)
+ {
+ char s[32];
+ int x = CtoI_LcmPerm(i);
+ sprintf(s, "x%d", i+1);
+ VTable.SetT(s, power16/2);
+ }
+ CtoI a = CtoI_Lcm2();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ delete[] $5.str;
+ delete[] $6.str;
+ }
+/*
+ | LCMA LPAREN FNAME NUMBER RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, 0, th, 10);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ }
+ | LCMC LPAREN FNAME NUMBER RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, 0, th, 1);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ }
+ | LCMM LPAREN FNAME NUMBER RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, 0, th, 2);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ }
+ | LCMA LPAREN FNAME NUMBER FNAME RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ $5.str[$5.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, $5.str+1, th, 0);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ delete[] $5.str;
+ }
+ | LCMC LPAREN FNAME NUMBER FNAME RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ $5.str[$5.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, $5.str+1, th, 1);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ delete[] $5.str;
+ }
+ | LCMM LPAREN FNAME NUMBER FNAME RPAREN
+ {
+ $3.str[$3.len - 1] = 0;
+ $5.str[$5.len - 1] = 0;
+ int th = atoi($4.str);
+ CtoI_Lcm1($3.str+1, $5.str+1, th, 2);
+ 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();
+ $$ = new CtoI(a);
+ delete[] $3.str;
+ delete[] $4.str;
+ delete[] $5.str;
+ }
+*/
+ | MINUS expr %prec UMINUS
+ {
+ *$2 = - *$2;
+ $$ = $2;
+ }
+ | PLUS expr %prec UPLUS
+ {
+ $$ = $2;
+ }
+ | expr u_expr %prec CAT
+ {
+ *$1 = Product(*$1, *$2);
+ $$ = $1;
+ delete $2;
+ }
+ | expr PLUS expr
+ {
+ *$1 = *$1 + *$3;
+ $$ = $1;
+ delete $3;
+ }
+ | expr MINUS expr
+ {
+ *$1 = *$1 - *$3;
+ $$ = $1;
+ delete $3;
+ }
+ | expr MEET expr
+ {
+ *$1 = CtoI_Meet(*$1, *$3);
+ //*$1 = ZBDD_Meet($1->NonZero().GetZBDD(), $3->NonZero().GetZBDD());
+ $$ = $1;
+ delete $3;
+ }
+ | expr EQ expr
+ {
+ *$1 = CtoI_EQ(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr NE expr
+ {
+ *$1 = CtoI_NE(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr GT expr
+ {
+ *$1 = CtoI_GT(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr GE expr
+ {
+ *$1 = CtoI_GE(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr LT expr
+ {
+ *$1 = CtoI_LT(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr LE expr
+ {
+ *$1 = CtoI_LE(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr QUESTION expr COLON expr
+ {
+ *$1 = CtoI_ITE(*$1, *$3, *$5);
+ $$ = $1;
+ delete $3;
+ delete $5;
+ }
+ | expr MULTIPLY expr
+ {
+ *$1 = Product(*$1, *$3);
+ $$ = $1;
+ delete $3;
+ }
+ | expr QUOTIENT expr
+ {
+ if(*$3 == 0)
+ {
+ yyerror("<WARNING> Divide by zero");
+ *$1 = 0;
+ }
+ else *$1 = *$1 / *$3;
+ $$ = $1;
+ delete $3;
+ }
+ | expr REMAINDER expr
+ {
+ if(*$3 == 0)
+ {
+ yyerror("<WARNING> Divide by zero");
+ *$1 = 0;
+ }
+ else *$1 = *$1 % *$3;
+ $$ = $1;
+ delete $3;
+ }
+ ;
+
+output
+ : print expr
+ {
+ if(*$2 == CtoI_Null())
+ {
+ *$2 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ if(PrintCtoI(*$2) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $2;
+ }
+ | print QUOTIENT IDVAR expr
+ {
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ else if(strcmp($3.str, "hex") == 0)
+ {
+ if(PrintCtoI_16(*$4) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $4;
+ }
+ else if(strcmp($3.str, "bit") == 0)
+ {
+ if(PrintDigital(*$4) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $4;
+ }
+ else if(strcmp($3.str, "case") == 0)
+ {
+ if(PrintCase(*$4) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $4;
+ }
+ else if(strcmp($3.str, "map") == 0)
+ {
+ if(MapAll(*$4) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $4;
+ }
+ else if(strcmp($3.str, "rmap") == 0)
+ {
+ if(MapSel(*$4) == 1)
+ yyerror("<WARNING> Memory overflow");
+ delete $4;
+ }
+ else if(strcmp($3.str, "size") == 0)
+ {
+ char s[32];
+ B_ITOSTR($4 -> Size(), s);
+ bout << " " << s;
+ bout.Delimit();
+ BDD_GC();
+ B_ITOSTR(BDD_Used(), s);
+ bout << "(" << s << ")";
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "count") == 0)
+ {
+ *$4 = $4 -> CountTerms();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+
+ int slen = $4->TopDigit() / 3 + 14;
+ char* s = new char[slen];
+ if(s == 0)
+ {
+ yyerror("<WARNING> Memory overflow");
+ }
+
+ $4 -> StrNum10(s);
+ bout << " " << s;
+ bout.Return();
+ delete[] s;
+ delete $4;
+ }
+ else if(strcmp($3.str, "density") == 0)
+ {
+ *$4 = $4 -> NonZero();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+
+ char s[32];
+ int d = Density($4 -> GetZBDD(), VTable.Used());
+ sprintf(s, "%g", (float)d / power30);
+ if(d == 0 && *$4 != 0)
+ yyerror("<WARNING> Bit underflow occurred");
+ bout << " " << s;
+ bout.Return();
+
+ delete $4;
+ }
+ else if(strcmp($3.str, "value") == 0)
+ {
+ char s[32];
+ sprintf(s, " %g", (float)Value(*$4)/power16);
+ if(OVF.Check()!= 0)
+ yyerror("<WARNING> Bit overflow occurred");
+ bout << s;
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "maxcover") == 0)
+ {
+ *$4 = $4 -> NonZero();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ if(*$4 == 0) bout << " 0";
+ else
+ {
+ ZBDD f = $4 -> 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();
+ delete $4;
+ }
+ else if(strcmp($3.str, "maxcost") == 0)
+ {
+ *$4 = $4 -> NonZero();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ if(*$4 == 0) bout << "<No cover.>";
+ else
+ {
+ char s[32];
+ int c = MaxCost($4 -> GetZBDD());
+ sprintf(s, "%g", (float)c / power16);
+ bout << s;
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "mincover") == 0)
+ {
+ *$4 = $4 -> NonZero();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ if(*$4 == 0) bout << " 0";
+ else
+ {
+ ZBDD f = $4 -> 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();
+ delete $4;
+ }
+ else if(strcmp($3.str, "mincost") == 0)
+ {
+ *$4 = $4 -> NonZero();
+ if(*$4 == CtoI_Null())
+ {
+ *$4 = 0;
+ yyerror("<WARNING> Memory overflow");
+ }
+ if(*$4 == 0) bout << "<No cover.>";
+ else
+ {
+ char s[32];
+ int c = MinCost($4 -> GetZBDD());
+ sprintf(s, "%g", (float)c / power16);
+ bout << s;
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "plot") == 0)
+ {
+#ifdef B_STATIC
+ bout << "sorry, not supported in this version.";
+ bout.Return();
+#else
+ $4 -> XPrint();
+#endif
+ delete $4;
+ }
+ else if(strcmp($3.str, "decomp") == 0)
+ {
+ if(PrintDecomp(*$4) == 1)
+ {
+ bout << "...";
+ bout.Return();
+ yyerror("<WARNING> Memory overflow");
+ }
+ delete $4;
+ }
+ else if(strcmp($3.str, "decompd") == 0)
+ {
+ if(PrintDecompDot(*$4) == 1)
+ {
+ bout << "...";
+ bout.Return();
+ yyerror("<WARNING> Memory overflow");
+ }
+ delete $4;
+ }
+ else if(strcmp($3.str, "imply0") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.Support();
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ if(t != t2)
+ {
+ int y = f.ImplyChk(t, t2);
+ if(y == 1)
+ {
+ bout << VTable.GetName(t);
+ bout << "->";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "symmetry") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.SymSet(t);
+ g -= g2;
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ bout << VTable.GetName(t);
+ bout << "==";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "imply") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.ImplySet(t);
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ bout << VTable.GetName(t);
+ bout << "->";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "coimply0") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.Support();
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ if(t != t2)
+ {
+ int y = f.CoImplyChk(t, t2);
+ if(y == 1)
+ {
+ bout << VTable.GetName(t);
+ bout << "->";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "coimply") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.CoImplySet(t);
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ bout << VTable.GetName(t);
+ bout << "->";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "coimply2") == 0)
+ {
+ ZBDD f = $4 -> NonZero().GetZBDD();
+ ZBDD g = f.Support();
+ while(g != 0)
+ {
+ int t = g.Top();
+ g = g.OffSet(t);
+ ZBDD g2 = f.CoImplySet(t) - f.ImplySet(t);
+ while(g2 != 0)
+ {
+ int t2 = g2.Top();
+ g2 = g2.OffSet(t2);
+ bout << VTable.GetName(t);
+ bout << "->";
+ bout << VTable.GetName(t2);
+ bout << ";";
+ bout.Delimit();
+ }
+ }
+ bout.Return();
+ delete $4;
+ }
+ else if(strcmp($3.str, "export") == 0)
+ {
+ int d = $4 -> TopDigit();
+ ZBDDV v = ZBDDV();
+ for(int i=0; i<=d; i++)
+ v += ZBDDV($4 -> Digit(i).GetZBDD(), i);
+ v.Export();
+ delete $4;
+ }
+ else
+ {
+ yyerror("Illegal switch");
+ delete $4;
+ }
+ delete[] $3.str;
+ }
+ | print QUOTIENT IDVAR FNAME expr
+ {
+ if(strcmp($3.str, "export") == 0)
+ {
+ $4.str[$4.len - 1] = 0;
+ FILE *fp;
+ fp = fopen($4.str+1, "w");
+ if(fp == NULL) yyerror("Can't open the file");
+ else
+ {
+ int d = $5 -> TopDigit();
+ ZBDDV v = ZBDDV();
+ for(int i=0; i<=d; i++)
+ v += ZBDDV($5 -> Digit(i).GetZBDD(), i);
+ v.Export(fp);
+ fclose(fp);
+ }
+ }
+ else
+ {
+ yyerror("Illegal switch");
+ }
+ delete[] $3.str;
+ delete[] $4.str;
+ delete $5;
+ }
+ ;
+ | print FNAME
+ {
+ $2.str[$2.len - 1] = 0;
+ cout << $2.str+1 << "\n";
+ delete[] $2.str;
+ }
+ ;
+
+print
+ : PRINT
+ | QUESTION
+ ;
+
+help
+ : HELP
+ | QUESTION
+ ;
+%%
+
--- /dev/null
+// ACC yywrap (SAPPORO-1.00)
+// Shin-ichi MINATO (Feb. 25, 2005)
+
+yywrap(){ return 1; }
+
--- /dev/null
+/********************************************\r
+ * BDD+ Manipulator (SAPPORO-1.58) - Header *\r
+ * (C) Shin-ichi MINATO (Nov. 22, 2013) *\r
+ ********************************************/\r
+\r
+class BDD;\r
+class BDDV;\r
+\r
+#ifndef _BDD_\r
+#define _BDD_\r
+\r
+#include <cstdlib>\r
+#include <cstdio>\r
+#include <cstring>\r
+#include <cctype>\r
+#include <iostream>\r
+\r
+#define BDD_CPP\r
+#include "bddc.h"\r
+\r
+using namespace std;\r
+\r
+//--------- Definition of "bddword" type --------\r
+#ifdef B_64\r
+ typedef unsigned long long bddword;\r
+#else\r
+ typedef unsigned int bddword;\r
+#endif\r
+\r
+//--------- External data for BDD ---------\r
+extern const bddword BDD_MaxNode;\r
+extern const int BDD_MaxVar;\r
+\r
+//----- External constant data for BDDV ---------\r
+extern int BDDV_Active;\r
+extern const int BDDV_SysVarTop;\r
+extern const int BDDV_MaxLen;\r
+extern const int BDDV_MaxLenImport;\r
+\r
+//--------- Stack overflow limitter ---------\r
+extern const int BDD_RecurLimit;\r
+extern int BDD_RecurCount;\r
+#define BDD_RECUR_INC \\r
+ {if(++BDD_RecurCount >= BDD_RecurLimit) \\r
+ BDDerr("BDD_RECUR_INC:Stack overflow ", (bddword) BDD_RecurCount);}\r
+#define BDD_RECUR_DEC BDD_RecurCount--\r
+\r
+class BDD\r
+{\r
+ bddword _bdd;\r
+\r
+public:\r
+ BDD(void) { _bdd = bddfalse; }\r
+ BDD(int a) { _bdd = (a==0)? bddfalse:(a>0)? bddtrue:bddnull; }\r
+ BDD(const BDD& f) { _bdd = bddcopy(f._bdd); }\r
+\r
+ ~BDD(void) { bddfree(_bdd); }\r
+\r
+ BDD& operator=(const BDD& f) { \r
+ if(_bdd != f._bdd) { bddfree(_bdd); _bdd = bddcopy(f._bdd); }\r
+ return *this; \r
+ }\r
+\r
+ BDD& operator&=(const BDD& f)\r
+ { BDD h; h._bdd = bddand(_bdd, f._bdd); return *this = h; }\r
+ BDD& operator|=(const BDD& f)\r
+ { BDD h; h._bdd = bddor(_bdd, f._bdd); return *this = h; }\r
+ BDD& operator^=(const BDD& f)\r
+ { BDD h; h._bdd = bddxor(_bdd, f._bdd); return *this = h; }\r
+ BDD& operator<<=(const int s)\r
+ { BDD h; h._bdd = bddlshift(_bdd, s); return *this = h; }\r
+ BDD& operator>>=(const int s)\r
+ { BDD h; h._bdd = bddrshift(_bdd, s); return *this = h; }\r
+\r
+ BDD operator~(void) const { BDD h; h._bdd = bddnot(_bdd); return h; }\r
+ BDD operator<<(int s) const\r
+ { BDD h; h._bdd = bddlshift(_bdd, s); return h; }\r
+ BDD operator>>(int s) const\r
+ { BDD h; h._bdd = bddrshift(_bdd, s); return h; }\r
+\r
+ int Top(void) const { return bddtop(_bdd); }\r
+ BDD At0(int v) const { BDD h; h._bdd = bddat0(_bdd, v); return h; }\r
+ BDD At1(int v) const { BDD h; h._bdd = bddat1(_bdd, v); return h; }\r
+ BDD Cofact(const BDD& f) const\r
+ { BDD h; h._bdd = bddcofactor(_bdd, f._bdd); return h; }\r
+ BDD Univ(const BDD& f) const\r
+ { BDD h; h._bdd = bdduniv(_bdd, f._bdd); return h; }\r
+ BDD Exist(const BDD& f) const\r
+ { BDD h; h._bdd = bddexist(_bdd, f._bdd); return h; }\r
+ BDD Support(void) const\r
+ { BDD h; h._bdd = bddsupport(_bdd); return h; }\r
+\r
+ bddword GetID(void) const {return _bdd; }\r
+ \r
+ bddword Size(void) const;\r
+ void Export(FILE *strm = stdout) const;\r
+ void Print(void) const;\r
+ void XPrint0(void) const;\r
+ void XPrint(void) const;\r
+\r
+ BDD Swap(const int&, const int&) const;\r
+ BDD Smooth(const int&) const;\r
+ BDD Spread(const int&) const;\r
+\r
+ friend BDD BDD_ID(bddword);\r
+};\r
+\r
+//--------- External functions for BDD ---------\r
+extern void BDD_Init(bddword, bddword);\r
+extern int BDD_NewVarOfLev(int);\r
+extern int BDD_VarUsed(void);\r
+extern bddword BDD_Used(void);\r
+extern void BDD_GC(void);\r
+extern BDD BDD_Import(FILE *strm = stdin);\r
+extern BDD BDD_Random(int, int density = 50);\r
+extern void BDDerr(const char *);\r
+extern void BDDerr(const char *, bddword);\r
+extern void BDDerr(const char *, const char *);\r
+\r
+//--------- Inline functions for BDD ---------\r
+inline int BDD_TopLev(void)\r
+ { return BDDV_Active? bddvarused() - BDDV_SysVarTop: bddvarused(); }\r
+\r
+inline int BDD_NewVar(void)\r
+ { return bddnewvaroflev(BDD_TopLev() + 1); }\r
+\r
+inline int BDD_LevOfVar(int v) { return bddlevofvar(v); }\r
+inline int BDD_VarOfLev(int lev) { return bddvaroflev(lev); }\r
+\r
+inline BDD BDD_ID(bddword bdd)\r
+ { BDD h; h._bdd = bdd; return h; }\r
+\r
+inline bddword BDD_CacheInt(unsigned char op, bddword fx, bddword gx)\r
+ { return bddrcache(op, fx, gx); }\r
+\r
+inline BDD BDD_CacheBDD(unsigned char op, bddword fx, bddword gx)\r
+ { return BDD_ID(bddcopy(bddrcache(op, fx, gx))); }\r
+\r
+inline void BDD_CacheEnt(unsigned char op, bddword fx, bddword gx, bddword hx)\r
+ { bddwcache(op, fx, gx, hx); }\r
+\r
+inline BDD BDDvar(int v) { return BDD_ID(bddprime(v)); }\r
+\r
+inline BDD operator&(const BDD& f, const BDD& g) \r
+ { return BDD_ID(bddand(f.GetID(), g.GetID())); }\r
+\r
+inline BDD operator|(const BDD& f, const BDD& g) \r
+ { return BDD_ID(bddor(f.GetID(), g.GetID())); }\r
+\r
+inline BDD operator^(const BDD& f, const BDD& g) \r
+ { return BDD_ID(bddxor(f.GetID(), g.GetID())); }\r
+\r
+inline int operator==(const BDD& f, const BDD& g) \r
+ { return f.GetID() == g.GetID(); }\r
+\r
+inline int operator!=(const BDD& f, const BDD& g) \r
+ { return f.GetID() != g.GetID(); }\r
+\r
+inline int BDD_Imply(const BDD& f, const BDD& g) \r
+ { return bddimply(f.GetID(), g.GetID()); }\r
+\r
+class BDDV\r
+{\r
+ BDD _bdd;\r
+ int _len;\r
+ int _lev;\r
+\r
+ int GetLev(int len) const {\r
+ int lev = 0;\r
+ for(len--; len>0; len>>=1) lev++;\r
+ return lev;\r
+ }\r
+\r
+public:\r
+ BDDV(void) { _bdd = 0; _len = 0; _lev = 0; }\r
+\r
+ BDDV(const BDDV& fv)\r
+ { _bdd = fv._bdd; _len = fv._len; _lev = fv._lev; } \r
+\r
+ BDDV(const BDD& f) {\r
+ int t = f.Top();\r
+ if(t > 0 && BDD_LevOfVar(t) > BDD_TopLev())\r
+ BDDerr("BDDV::BDDV: Invalid top var.", t);\r
+ _bdd = f;\r
+ _len = 1;\r
+ _lev = 0;\r
+ }\r
+\r
+ BDDV(const BDD&, int len);\r
+\r
+ ~BDDV(void) { }\r
+\r
+ BDDV& operator=(const BDDV& fv)\r
+ { _bdd = fv._bdd; _len = fv._len; _lev = fv._lev; return *this; } \r
+\r
+ BDDV& operator&=(const BDDV&);\r
+ BDDV& operator|=(const BDDV&);\r
+ BDDV& operator^=(const BDDV&);\r
+ BDDV& operator<<=(int);\r
+ BDDV& operator>>=(int);\r
+\r
+ BDDV operator~(void) const\r
+ { BDDV h; h._bdd = ~_bdd; h._len = _len; h._lev = _lev; return h; } \r
+ BDDV operator<<(int) const;\r
+ BDDV operator>>(int) const;\r
+\r
+ BDDV At0(int v) const {\r
+ if(v > 0 && BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("BDDV::At0: Invalid var.", v);\r
+ BDDV hv;\r
+ if((hv._bdd = _bdd.At0(v)) == -1) return BDDV(-1);\r
+ hv._len = _len;\r
+ hv._lev = _lev;\r
+ return hv;\r
+ }\r
+\r
+ BDDV At1(int v) const {\r
+ if(v > 0 && BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("BDDV::At1: Invalid var.", v);\r
+ BDDV hv;\r
+ if((hv._bdd = _bdd.At1(v)) == -1) return BDDV(-1);\r
+ hv._len = _len;\r
+ hv._lev = _lev;\r
+ return hv;\r
+ }\r
+\r
+ BDDV Cofact(const BDDV&) const;\r
+ BDDV Swap(int, int) const;\r
+ BDDV Spread(int) const;\r
+\r
+ int Top(void) const;\r
+\r
+ bddword Size() const;\r
+ void Export(FILE *strm = stdout) const;\r
+\r
+ BDDV Former(void) const {\r
+ BDDV hv;\r
+ if(_len <= 1) return hv;\r
+ if((hv._bdd = _bdd.At0(_lev)) == -1) return BDDV(-1);\r
+ hv._len = 1 << (_lev - 1);\r
+ hv._lev = _lev - 1;\r
+ return hv;\r
+ }\r
+\r
+ BDDV Latter(void) const {\r
+ BDDV hv;\r
+ if(_len == 0) return hv;\r
+ if(_len == 1) return *this;\r
+ if((hv._bdd = _bdd.At1(_lev)) == -1) return BDDV(-1);\r
+ hv._len = _len - (1 << (_lev - 1));\r
+ hv._lev = GetLev(hv._len);\r
+ return hv;\r
+ }\r
+\r
+ BDDV Part(int, int) const;\r
+ BDD GetBDD(int) const;\r
+\r
+ BDD GetMetaBDD(void) const { return _bdd; }\r
+ int Uniform(void) const\r
+ { return BDD_LevOfVar(_bdd.Top()) <= BDD_TopLev(); }\r
+ int Len(void) const { return _len; }\r
+\r
+ void Print() const;\r
+ void XPrint0() const;\r
+ void XPrint() const;\r
+\r
+ friend BDDV operator&(const BDDV&, const BDDV&);\r
+ friend BDDV operator|(const BDDV&, const BDDV&);\r
+ friend BDDV operator^(const BDDV&, const BDDV&);\r
+ friend BDDV operator||(const BDDV&, const BDDV&);\r
+};\r
+\r
+//----- External functions for BDDV ---------\r
+extern void BDDV_Init(bddword, bddword);\r
+extern int BDDV_NewVarOfLev(int);\r
+extern BDDV operator||(const BDDV&, const BDDV&);\r
+extern BDDV BDDV_Mask1(int, int);\r
+extern BDDV BDDV_Mask2(int, int);\r
+extern BDDV BDDV_Import(FILE *strm = stdin);\r
+\r
+//----- Inline functions for BDDV ---------\r
+inline int BDDV_UserTopLev(void) { return BDD_TopLev(); }\r
+inline int BDDV_NewVar(void) { return BDD_NewVar(); }\r
+inline int BDDV_NewVarOfLev(int lev) {return BDD_NewVarOfLev(lev); }\r
+\r
+inline BDDV operator&(const BDDV& fv, const BDDV& gv) {\r
+ BDDV hv;\r
+ if((hv._bdd = fv._bdd & gv._bdd) == -1) return BDDV(-1);\r
+ if(fv._len != gv._len) BDDerr("BDDV::operator&: Length mismatch");\r
+ hv._len = fv._len;\r
+ hv._lev = fv._lev;\r
+ return hv;\r
+}\r
+\r
+inline BDDV operator|(const BDDV& fv, const BDDV& gv) {\r
+ BDDV hv;\r
+ if((hv._bdd = fv._bdd | gv._bdd) == -1) return BDDV(-1);\r
+ if(fv._len != gv._len) BDDerr("BDDV::operator|: Length mismatch");\r
+ hv._len = fv._len;\r
+ hv._lev = fv._lev;\r
+ return hv;\r
+}\r
+\r
+inline BDDV operator^(const BDDV& fv, const BDDV& gv) {\r
+ BDDV hv;\r
+ if((hv._bdd = fv._bdd ^ gv._bdd) == -1) return BDDV(-1);\r
+ if(fv._len != gv._len) BDDerr("BDDV::operator^: Length mismatch");\r
+ hv._len = fv._len;\r
+ hv._lev = fv._lev;\r
+ return hv;\r
+}\r
+\r
+extern BDDV operator|(const BDDV&, const BDDV&);\r
+extern BDDV operator^(const BDDV&, const BDDV&);\r
+inline int operator==(const BDDV& fv, const BDDV& gv)\r
+\r
+ { return fv.GetMetaBDD() == gv.GetMetaBDD() && fv.Len() == gv.Len(); }\r
+\r
+inline int operator!=(const BDDV& fv, const BDDV& gv)\r
+ { return !(fv == gv); }\r
+\r
+inline int BDDV_Imply(const BDDV& fv, const BDDV& gv) {\r
+ return fv.Len() == gv.Len() \r
+ && BDD_Imply(fv.GetMetaBDD(), gv.GetMetaBDD());\r
+}\r
+\r
+inline BDDV& BDDV::operator&=(const BDDV& fv) { return *this = *this & fv; }\r
+inline BDDV& BDDV::operator|=(const BDDV& fv) { return *this = *this | fv; }\r
+inline BDDV& BDDV::operator^=(const BDDV& fv) { return *this = *this ^ fv; }\r
+inline BDDV& BDDV::operator<<=(int s) { return *this = *this << s; }\r
+inline BDDV& BDDV::operator>>=(int s) { return *this = *this >> s; }\r
+\r
+\r
+class BDD_Hash\r
+{\r
+ struct BDD_Entry\r
+ {\r
+ BDD _key;\r
+ void* _ptr;\r
+ BDD_Entry(void){ _key = -1; }\r
+ };\r
+\r
+ bddword _amount;\r
+ bddword _hashSize;\r
+ BDD_Entry* _wheel;\r
+\r
+ BDD_Entry* GetEntry(BDD);\r
+ void Enlarge(void);\r
+public:\r
+ BDD_Hash(void);\r
+ ~BDD_Hash(void);\r
+ void Clear(void);\r
+ void Enter(BDD, void *);\r
+ void* Refer(BDD);\r
+ bddword Amount(void);\r
+};\r
+\r
+#endif // _BDD_ \r
--- /dev/null
+/*****************************************
+ * BDDDG - Decomposition Graph *
+ * (SAPPORO-1.01) - Header *
+ * (C) Shin-ichi MINATO (July 4, 2005) *
+ *****************************************/
+
+#ifndef _BDDDG_
+#define _BDDDG_
+
+#include "BDD.h"
+
+#define BDDDG_InitSize 4
+
+#define BDDDG_NIL BDD_MaxNode
+
+#define BDDDG_C1 1
+#define BDDDG_LIT 2
+#define BDDDG_OR 3
+#define BDDDG_XOR 4
+#define BDDDG_OTHER 5
+
+#define BDDDG_PackIdx(ndx,inv) (((ndx)==BDDDG_NIL)? BDDDG_NIL:(((ndx)<<1)|inv))
+#define BDDDG_Ndx(idx) (((idx)==BDDDG_NIL)? BDDDG_NIL:((idx)>>1))
+#define BDDDG_Inv(idx) ((idx)&1)
+#define BDDDG_InvSet(idx) ((idx)|1)
+#define BDDDG_InvReset(idx) ((idx)&(~1))
+#define BDDDG_InvAlt(idx) ((idx)^1)
+
+class BDDDG
+{
+ struct Node;
+ struct NodeLink
+ {
+ bddword _idx;
+ bddword _nxt;
+ NodeLink(void){ _idx = BDDDG_NIL; _nxt = BDDDG_NIL; }
+ };
+
+ bddword _nodeSize;
+ bddword _nodeUsed;
+ bddword _linkSize;
+ bddword _linkUsed;
+ bddword* _hashWheel;
+ Node* _nodeA;
+ NodeLink* _linkA;
+ bddword _c1;
+
+ bddword HashIndex(BDD);
+ bddword NewNdx(BDD, char);
+ int EnlargeNode(void);
+ bddword NewLkx(bddword);
+ int EnlargeLink(void);
+ int LinkNodes(bddword, bddword);
+ int Merge3(bddword, bddword, bddword);
+ BDD Func0(BDD, BDD);
+ int LinkNodesC3(bddword, bddword);
+ void Print0(bddword);
+ bddword Merge(BDD, bddword, bddword);
+ bddword ReferIdx(BDD);
+ void PhaseSweep(bddword);
+ void MarkSweep(bddword);
+ void MarkSweepR(bddword);
+ int Mark1(bddword);
+ void Mark2R(bddword);
+ int MarkChkR(bddword);
+ void Mark3R(bddword);
+
+ struct Node
+ {
+ bddword _lkx;
+ BDD _f;
+ bddword _ndxP;
+ char _invP;
+ char _type; // NULL, C1, LIT, OR, XOR, OTHER
+ char _mark;
+ Node(void);
+ Node(BDD, char);
+ };
+
+public:
+ BDDDG(void);
+ ~BDDDG(void);
+ void Clear(void);
+ bddword NodeUsed(void);
+ int PrintDecomp(BDD);
+ bddword Decomp(BDD);
+ bddword NodeIdx(BDD);
+
+ friend class BDDDG_Tag;
+};
+
+class BDDDG_Tag
+{
+ BDDDG* _dg;
+ bddword _ndx;
+ bddword _lkx;
+public:
+ BDDDG_Tag(void);
+ int Set(BDDDG *, bddword);
+ bddword TopIdx(void);
+ bddword NextIdx(void);
+ char Type(void);
+ BDD Func(void);
+};
+
+#endif // _BDDDG_
+
--- /dev/null
+/******************************************
+ * Binary-to-Integer function class *
+ * (SAPPORO-1.55) - Header *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ******************************************/
+
+class BtoI;
+
+#ifndef _BtoI_
+#define _BtoI_
+
+#include "BDD.h"
+
+class BtoI
+{
+ BDDV _bddv;
+
+ BtoI Shift(int) const;
+ BtoI Sup(void) const;
+
+public:
+ BtoI(void) { _bddv = BDDV(0); }
+ BtoI(const BtoI& fv) { _bddv = fv._bddv; }
+ BtoI(const BDDV& fv) { _bddv = fv; }
+ BtoI(const BDD& f)
+ { _bddv = f; if(f != 0 && f != -1) _bddv = _bddv || BDDV(0); }
+ BtoI(int);
+ ~BtoI(void) { }
+
+ BtoI& operator=(const BtoI& fv) { _bddv = fv._bddv; return *this; }
+ BtoI& operator+=(const BtoI&);
+ BtoI& operator-=(const BtoI&);
+ BtoI& operator*=(const BtoI&);
+ BtoI& operator/=(const BtoI&);
+ BtoI& operator%=(const BtoI&);
+ BtoI& operator&=(const BtoI&);
+ BtoI& operator|=(const BtoI&);
+ BtoI& operator^=(const BtoI&);
+ BtoI& operator<<=(const BtoI&);
+ BtoI& operator>>=(const BtoI&);
+
+ BtoI operator-(void) const { return 0 - *this; }
+ BtoI operator~(void) const { return BtoI(~_bddv); }
+ BtoI operator!(void) const;
+ BtoI operator<<(const BtoI&) const;
+ BtoI operator>>(const BtoI& fv) const { return *this << -fv; }
+
+ BtoI UpperBound(void) const;
+ BtoI UpperBound(const BDD&) const;
+ BtoI LowerBound(void) const { return -(- *this).UpperBound(); }
+ BtoI LowerBound(const BDD& f) const { return -(- *this).UpperBound(f); }
+
+ BtoI At0(int v) const {
+ if(BDD_LevOfVar(v) > BDD_TopLev())
+ BDDerr("BtoI::At0: Invalid VarID.", v);
+ return BtoI(_bddv.At0(v)).Sup();
+ }
+
+ BtoI At1(int v) const {
+ if(BDD_LevOfVar(v) > BDD_TopLev())
+ BDDerr("BtoI::At1: Invalid VarID.", v);
+ return BtoI(_bddv.At1(v)).Sup();
+ }
+
+ BtoI Cofact(const BtoI&) const;
+
+ BtoI Spread(int k) const { return BtoI(_bddv.Spread(k)).Sup(); }
+
+ int Top(void) const { return _bddv.Top(); }
+
+ BDD GetSignBDD(void) const { return _bddv.GetBDD(Len() - 1); }
+
+ BDD GetBDD(int i) const
+ { return _bddv.GetBDD((i >= Len())? Len()-1: i); }
+
+ BDDV GetMetaBDDV(void) const { return _bddv; }
+
+ int Len(void) const { return _bddv.Len(); }
+
+ int GetInt(void) const;
+ int StrNum10(char *) const;
+ int StrNum16(char *) const;
+ bddword Size() const;
+
+ void Print() const;
+
+ friend int operator==(const BtoI&, const BtoI&);
+
+ friend BtoI operator+(const BtoI&, const BtoI&);
+ friend BtoI operator-(const BtoI&, const BtoI&);
+ friend BtoI operator&(const BtoI&, const BtoI&);
+ friend BtoI operator|(const BtoI&, const BtoI&);
+ friend BtoI operator^(const BtoI&, const BtoI&);
+ friend BtoI BtoI_ITE(const BDD&, const BtoI&, const BtoI&);
+};
+
+extern BtoI operator+(const BtoI&, const BtoI&);
+extern BtoI operator-(const BtoI&, const BtoI&);
+extern BtoI operator*(const BtoI&, const BtoI&);
+extern BtoI operator/(const BtoI&, const BtoI&);
+extern BtoI operator&(const BtoI&, const BtoI&);
+extern BtoI operator|(const BtoI&, const BtoI&);
+extern BtoI operator^(const BtoI&, const BtoI&);
+extern BtoI BtoI_ITE(const BDD&, const BtoI&, const BtoI&);
+
+extern BtoI BtoI_EQ(const BtoI&, const BtoI&);
+
+extern BtoI BtoI_atoi(char *);
+
+inline int operator==(const BtoI& a, const BtoI& b)
+ { return a._bddv == b._bddv; }
+
+inline int operator!=(const BtoI& a, const BtoI& b) { return !(a == b); }
+
+inline BtoI operator%(const BtoI& a, const BtoI&b )
+ { return a - (a / b) * b; }
+
+inline BtoI BtoI_ITE(const BtoI& a, const BtoI& b, const BtoI& c)
+ { return BtoI_ITE(~(BtoI_EQ(a, 0).GetBDD(0)), b, c); }
+
+inline BtoI BtoI_GT(const BtoI& a, const BtoI& b)
+ { return BtoI((b - a).GetSignBDD()); }
+
+inline BtoI BtoI_LT(const BtoI& a, const BtoI& b)
+ { return BtoI((a - b).GetSignBDD()); }
+
+inline BtoI BtoI_NE(const BtoI& a, const BtoI& b)
+ { return ! BtoI_EQ(a, b); }
+
+inline BtoI BtoI_GE(const BtoI& a, const BtoI& b)
+ { return ! BtoI_LT(a, b); }
+
+inline BtoI BtoI_LE(const BtoI& a, const BtoI& b)
+ { return ! BtoI_GT(a, b); }
+
+inline BtoI BtoI::operator!(void) const { return BtoI_EQ(*this, 0); }
+
+inline BtoI BtoI::Cofact(const BtoI& fv) const {
+ BDDV a = BDDV(BtoI_NE(fv, 0).GetBDD(0), Len());
+ return BtoI(_bddv.Cofact(a)).Sup();
+}
+
+#endif // _BtoI_
+
--- /dev/null
+/******************************************
+ * Combination-to-Integer function class *
+ * (SAPPORO-1.56) - Header *
+ * (C) Shin-ichi MINATO (June 8, 2013) *
+ ******************************************/
+
+class CtoI;
+
+#ifndef _CtoI_
+#define _CtoI_
+
+#include "ZBDD.h"
+
+
+class CtoI
+{
+ ZBDD _zbdd;
+
+public:
+ CtoI(void) { _zbdd = 0; }
+ CtoI(const CtoI& a) { _zbdd = a._zbdd; }
+ CtoI(const ZBDD& f) { _zbdd = f; }
+ CtoI(int);
+ ~CtoI(void) { }
+
+ CtoI& operator=(const CtoI& a) { _zbdd = a._zbdd; return *this; }
+ CtoI& operator+=(const CtoI&); // inline
+ CtoI& operator-=(const CtoI&); // inline
+ CtoI& operator*=(const CtoI&); // inline
+ CtoI& operator/=(const CtoI&); // inline
+ CtoI& operator%=(const CtoI&); // inline
+
+ int Top(void) const { return _zbdd.Top(); }
+ int TopItem(void) const;
+ int TopDigit(void) const;
+ int IsBool(void) const { return (BDD_LevOfVar(Top()) <= BDD_TopLev()); }
+ int IsConst(void) const { return TopItem() == 0; }
+
+ CtoI AffixVar(int v) const
+ { return CtoI((_zbdd.OffSet(v) + _zbdd.OnSet0(v)).Change(v)); }
+
+ CtoI Factor0(int v) const { return CtoI(_zbdd.OffSet(v)); }
+ CtoI Factor1(int v) const { return CtoI(_zbdd.OnSet0(v)); }
+
+ CtoI FilterThen(const CtoI&) const;
+ CtoI FilterElse(const CtoI&) const;
+
+ CtoI FilterRestrict(const CtoI&) const;
+ CtoI FilterPermit(const CtoI&) const;
+ CtoI FilterPermitSym(int) const;
+ CtoI Support(void) const
+ { CtoI h = IsBool()? *this: NonZero(); return CtoI(h._zbdd.Support()); }
+
+ CtoI NonZero(void) const;
+ CtoI Digit(int) const;
+ CtoI ConstTerm() const;
+
+ CtoI EQ_Const(const CtoI&) const;
+ CtoI NE_Const(const CtoI&) const;
+ CtoI GT_Const(const CtoI&) const;
+ CtoI GE_Const(const CtoI&) const;
+ CtoI LT_Const(const CtoI&) const;
+ CtoI LE_Const(const CtoI&) const;
+
+ CtoI MaxVal(void) const;
+ CtoI MinVal(void) const;
+
+ CtoI CountTerms(void) const;
+ CtoI TotalVal(void) const;
+ CtoI TotalValItems(void) const;
+
+ ZBDD GetZBDD(void) const { return _zbdd; }
+
+ CtoI Abs(void) const; // inline
+ CtoI Sign(void) const; // inline
+ CtoI operator-(void) const; // inline
+
+ CtoI TimesSysVar(int) const;
+ CtoI DivBySysVar(int) const;
+ CtoI ShiftDigit(int) const;
+
+ bddword Size(void) const;
+
+ int GetInt(void) const;
+
+ int StrNum10(char *) const;
+ int StrNum16(char *) const;
+
+ int PutForm(void) const;
+ void Print(void) const;
+
+ void XPrint(void) const;
+ void XPrint0(void) const;
+
+ CtoI ReduceItems(const CtoI&) const;
+ CtoI FreqPatA(int) const;
+ CtoI FreqPatAV(int) const;
+ CtoI FreqPatM(int) const;
+ CtoI FreqPatC(int) const;
+
+ CtoI FreqPatA2(int) const;
+
+// CtoI FilterClosed(CtoI);
+// CtoI FreqPatCV(int);
+
+ friend int operator==(const CtoI&, const CtoI&);
+ friend CtoI operator*(const CtoI&, const CtoI&);
+ friend CtoI operator/(const CtoI&, const CtoI&);
+ friend CtoI CtoI_Intsec(const CtoI&, const CtoI&);
+ friend CtoI CtoI_Union(const CtoI&, const CtoI&);
+ friend CtoI CtoI_Diff(const CtoI&, const CtoI&);
+ friend CtoI CtoI_Meet(const CtoI&, const CtoI&);
+};
+
+
+extern CtoI operator+(const CtoI&, const CtoI&);
+extern CtoI operator-(const CtoI&, const CtoI&);
+extern CtoI operator*(const CtoI&, const CtoI&);
+extern CtoI operator/(const CtoI&, const CtoI&);
+
+extern CtoI CtoI_GT(const CtoI&, const CtoI&);
+extern CtoI CtoI_GE(const CtoI&, const CtoI&);
+
+extern CtoI CtoI_atoi(char *);
+
+extern CtoI CtoI_Meet(const CtoI&, const CtoI&);
+
+extern int CtoI_Lcm1(char *, char *, int, int);
+extern CtoI CtoI_Lcm2(void);
+extern int CtoI_LcmItems(void);
+extern int CtoI_LcmPerm(int);
+extern CtoI CtoI_LcmA(char *, char *, int);
+extern CtoI CtoI_LcmC(char *, char *, int);
+extern CtoI CtoI_LcmM(char *, char *, int);
+extern CtoI CtoI_LcmAV(char *, char *, int);
+extern CtoI CtoI_LcmCV(char *, char *, int);
+extern CtoI CtoI_LcmMV(char *, char *, int);
+
+inline int operator==(const CtoI& a, const CtoI& b) { return a._zbdd == b._zbdd; }
+inline int operator!=(const CtoI& a, const CtoI& b) { return !(a == b); }
+inline CtoI operator%(const CtoI& a, const CtoI& b) { return a - (a / b) * b; }
+
+inline CtoI CtoI_Intsec(const CtoI& a, const CtoI& b)
+ { return CtoI(a._zbdd & b._zbdd); }
+
+inline CtoI CtoI_Union(const CtoI& a, const CtoI& b)
+ { return CtoI(a._zbdd + b._zbdd); }
+
+inline CtoI CtoI_Diff(const CtoI& a, const CtoI& b)
+ { return CtoI(a._zbdd - b._zbdd); }
+
+inline CtoI CtoI_ITE(const CtoI& a, const CtoI& b, const CtoI& c)
+ { return CtoI_Union(b.FilterThen(a), c.FilterElse(a)); }
+
+inline CtoI CtoI_NE(const CtoI& a, const CtoI& b)
+ { return CtoI_Union(CtoI_Diff(a, b), CtoI_Diff(b, a)).NonZero(); }
+
+inline CtoI CtoI_EQ(const CtoI& a, const CtoI& b)
+ { return CtoI_Diff(CtoI_Union(a, b).NonZero(), CtoI_NE(a, b)); }
+
+inline CtoI CtoI_LT(const CtoI& a, const CtoI& b) { return CtoI_GT(b, a); }
+inline CtoI CtoI_LE(const CtoI& a, const CtoI& b) { return CtoI_GE(b, a); }
+
+inline CtoI CtoI_Max(const CtoI& a, const CtoI& b)
+ { return CtoI_ITE(CtoI_GT(a, b), a, b); }
+inline CtoI CtoI_Min(const CtoI& a, const CtoI& b)
+ { return CtoI_ITE(CtoI_GT(a, b), b, a); }
+
+inline CtoI CtoI_Null(void) { return CtoI(ZBDD(-1)); }
+
+inline CtoI CtoI::Abs(void) const
+ { CtoI a = CtoI_GT(*this, 0); return CtoI_Union(FilterThen(a), FilterElse(a)); }
+
+inline CtoI CtoI::Sign(void) const
+ { CtoI a = CtoI_GT(*this, 0); return a - CtoI_Diff(NonZero(), a); }
+
+inline CtoI& CtoI::operator+=(const CtoI& a) { return *this = *this + a; }
+inline CtoI& CtoI::operator-=(const CtoI& a) { return *this = *this - a; }
+inline CtoI& CtoI::operator*=(const CtoI& a) { return *this = *this * a; }
+inline CtoI& CtoI::operator/=(const CtoI& a) { return *this = *this / a; }
+inline CtoI& CtoI::operator%=(const CtoI& a) { return *this = *this % a; }
+
+inline CtoI CtoI::operator-(void) const { return 0 - *this; }
+
+#endif // _CtoI_
+
--- /dev/null
+/***************************************************
+ * Multi-Level ZBDDV class (SAPPORO-1.00) - Header *
+ * (C) Shin-ichi MINATO (Aug 6, 2008 ) *
+ ***************************************************/
+
+class MLZBDDV;
+
+#ifndef _MLZBDDV_
+#define _MLZBDDV_
+
+#include "ZBDD.h"
+
+class MLZBDDV;
+
+class MLZBDDV
+{
+ int _pin;
+ int _out;
+ int _sin;
+ ZBDDV _zbddv;
+
+public:
+ MLZBDDV(void);
+
+ MLZBDDV(ZBDDV& zbddv);
+ MLZBDDV(ZBDDV& zbddv, int pin, int out);
+
+ ~MLZBDDV(void);
+
+ MLZBDDV& operator=(const MLZBDDV&);
+
+ int N_pin(void);
+ int N_out(void);
+ int N_sin(void);
+ ZBDDV GetZBDDV(void);
+
+ void Print(void);
+
+};
+
+#endif // _MLZBDDV_
+
--- /dev/null
+/************************************************
+ * PiDD class (SAPPORO-1.55) - Header *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ************************************************/
+
+class PiDD;
+
+#ifndef _PiDD_
+#define _PiDD_
+
+#include "ZBDD.h"
+
+class PiDD;
+
+#define PiDD_MaxVar 254
+
+#define PiDD_Y_YUV(y, u, v) ((y==u)? v:(y==v)? u:y)
+#define PiDD_U_XYU(x, y, u) ((x==u)? y:u)
+
+#define PiDD_X_Lev(lev) (PiDD_XOfLev[lev])
+#define PiDD_Y_Lev(lev) (PiDD_LevOfX[PiDD_XOfLev[lev]] -lev +1)
+#define PiDD_Lev_XY(x,y) (PiDD_LevOfX[x] -y +1)
+
+extern int PiDD_TopVar;
+extern int PiDD_VarTableSize;
+extern int PiDD_LevOfX[PiDD_MaxVar];
+extern int *PiDD_XOfLev;
+
+extern int PiDD_NewVar(void);
+extern int PiDD_VarUsed(void);
+
+extern PiDD operator*(const PiDD&, const PiDD&);
+extern PiDD operator/(const PiDD&, const PiDD&);
+
+class PiDD
+{
+ ZBDD _zbdd;
+public:
+ PiDD(void) { _zbdd = 0; }
+ PiDD(int a) { _zbdd = a; }
+ PiDD(const PiDD& f) { _zbdd = f._zbdd; }
+ PiDD(const ZBDD& zbdd) { _zbdd = zbdd; }
+
+ ~PiDD(void) { }
+
+ PiDD& operator=(const PiDD& f) { _zbdd = f._zbdd; return *this; }
+ PiDD& operator&=(const PiDD&); // inline
+ PiDD& operator+=(const PiDD&); // inline
+ PiDD& operator-=(const PiDD&); // inline
+ PiDD& operator*=(const PiDD&); // inline
+ PiDD& operator/=(const PiDD&); // inline
+ PiDD& operator%=(const PiDD&); // inline
+ PiDD Swap(int, int) const;
+ PiDD Cofact(int, int) const;
+
+ PiDD Odd(void) const;
+ PiDD Even(void) const;
+ PiDD SwapBound(int) const;
+
+ int TopX(void) const { return PiDD_X_Lev(TopLev()); }
+ int TopY(void) const { return PiDD_Y_Lev(TopLev()); }
+ int TopLev(void) const { return BDD_LevOfVar(_zbdd.Top()); }
+ bddword Size(void) const;
+ bddword Card(void) const;
+ ZBDD GetZBDD(void) const { return _zbdd; }
+
+ void Print(void) const;
+ void Enum(void) const;
+ void Enum2(void) const;
+
+ friend PiDD operator&(const PiDD&, const PiDD&);
+ friend PiDD operator+(const PiDD&, const PiDD&);
+ friend PiDD operator-(const PiDD&, const PiDD&);
+ friend PiDD operator*(const PiDD&, const PiDD&);
+ friend PiDD operator/(const PiDD&, const PiDD&);
+ friend int operator==(const PiDD&, const PiDD&);
+};
+
+inline PiDD operator&(const PiDD& p, const PiDD& q)
+ { return PiDD(p._zbdd & q._zbdd); }
+
+inline PiDD operator+(const PiDD& p, const PiDD& q)
+ { return PiDD(p._zbdd + q._zbdd); }
+
+inline PiDD operator-(const PiDD& p, const PiDD& q)
+ { return PiDD(p._zbdd - q._zbdd); }
+
+inline PiDD operator%(const PiDD& f, const PiDD& p)
+ { return f - (f/p) * p; }
+
+inline int operator==(const PiDD& p, const PiDD& q)
+ { return p._zbdd == q._zbdd; }
+
+inline int operator!=(const PiDD& p, const PiDD& q)
+ { return !(p == q); }
+
+inline PiDD& PiDD::operator&=(const PiDD& f) { return *this = *this & f; }
+inline PiDD& PiDD::operator+=(const PiDD& f) { return *this = *this + f; }
+inline PiDD& PiDD::operator-=(const PiDD& f) { return *this = *this - f; }
+inline PiDD& PiDD::operator*=(const PiDD& f) { return *this = *this * f; }
+inline PiDD& PiDD::operator/=(const PiDD& f) { return *this = *this / f; }
+inline PiDD& PiDD::operator%=(const PiDD& f) { return *this = *this % f; }
+
+#endif // _PiDD_
+
--- /dev/null
+/************************************************
+ * ZBDD-based SOP class (SAPPORO-1.55) - Header *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ************************************************/
+
+class SOP;
+class SOPV;
+
+#ifndef _SOP_
+#define _SOP_
+
+#include "ZBDD.h"
+
+class SOP;
+extern int SOP_NewVar(void);
+extern int SOP_NewVarOfLev(int);
+
+extern SOP operator*(const SOP&, const SOP&);
+extern SOP operator/(const SOP&, const SOP&);
+extern SOP operator%(const SOP&, const SOP&);
+
+extern SOP SOP_ISOP(BDD);
+extern SOP SOP_ISOP(BDD, BDD);
+
+class SOP
+{
+ ZBDD _zbdd;
+public:
+ SOP() { _zbdd = ZBDD(); }
+ SOP(int val) { _zbdd = ZBDD(val); }
+ SOP(const SOP& f) { _zbdd = f._zbdd; }
+ SOP(const ZBDD& zbdd) { _zbdd = zbdd; }
+ ~SOP() { }
+
+ SOP& operator=(const SOP& f) { _zbdd = f._zbdd; return *this; }
+
+ SOP& operator&=(const SOP& f)
+ { _zbdd = _zbdd & f._zbdd; return *this; }
+
+ SOP& operator+=(const SOP& f)
+ { _zbdd = _zbdd + f._zbdd; return *this; }
+
+ SOP& operator-=(const SOP& f)
+ { _zbdd = _zbdd - f._zbdd; return *this; }
+
+ SOP& operator*=(const SOP&); // inline
+ SOP& operator/=(const SOP&); // inline
+ SOP& operator%=(const SOP&); // inline
+ SOP& operator<<=(int); // inline
+ SOP& operator>>=(int); // inline
+
+ SOP operator<<(int) const;
+ SOP operator>>(int) const;
+ SOP And0(int) const;
+ SOP And1(int) const;
+ SOP Factor0(int) const;
+ SOP Factor1(int) const;
+ SOP FactorD(int) const;
+
+ int Top(void) const { return (_zbdd.Top() + 1) & ~1; }
+
+ bddword Size(void) const;
+ bddword Cube(void) const;
+ bddword Lit(void) const;
+
+ int IsPolyCube(void) const;
+ int IsPolyLit(void) const;
+ SOP Divisor(void) const;
+ SOP Implicants(BDD) const;
+ SOP Support(void) const;
+ //SOP BoolDiv(SOP, int) const;
+ //SOP BoolDiv(SOP, SOP, int) const;
+ //SOP BoolDiv(BDD, int) const;
+
+ void Print(void) const;
+ int PrintPla(void) const;
+
+ ZBDD GetZBDD(void) const { return _zbdd; }
+ BDD GetBDD(void) const;
+ SOP InvISOP(void) const;
+
+ SOP Swap(int, int) const;
+
+ friend SOP operator&(const SOP&, const SOP&);
+ friend SOP operator+(const SOP&, const SOP&);
+ friend SOP operator-(const SOP&, const SOP&);
+ friend int operator==(const SOP&, const SOP&);
+};
+
+inline SOP operator&(const SOP& f, const SOP& g)
+ { return SOP(f._zbdd & g._zbdd); }
+
+inline SOP operator+(const SOP& f, const SOP& g)
+ { return SOP(f._zbdd + g._zbdd); }
+
+inline SOP operator-(const SOP& f, const SOP& g)
+ { return SOP(f._zbdd - g._zbdd); }
+
+inline int operator==(const SOP& f, const SOP& g)
+ { return f._zbdd == g._zbdd; }
+
+inline int operator!=(const SOP& f, const SOP& g)
+ { return !(f == g); }
+
+inline SOP operator%(const SOP& f, const SOP& p)
+ { return f - (f/p) * p; }
+
+inline SOP& SOP::operator*=(const SOP& f)
+ { return *this = *this * f; }
+
+inline SOP& SOP::operator/=(const SOP& f)
+ { return *this = *this / f; }
+
+inline SOP& SOP::operator%=(const SOP& f)
+ { return *this = *this - (*this/f) * f; }
+
+inline SOP& SOP::operator<<=(int n) { return *this = *this << n; }
+inline SOP& SOP::operator>>=(int n) { return *this = *this >> n; }
+
+
+
+
+class SOPV;
+extern int SOPV_NewVar(void);
+extern int SOPV_NewVarOfLev(int);
+
+extern SOPV SOPV_ISOP(BDDV);
+extern SOPV SOPV_ISOP(BDDV, BDDV);
+extern SOPV SOPV_ISOP2(BDDV);
+extern SOPV SOPV_ISOP2(BDDV, BDDV);
+
+class SOPV
+{
+ ZBDDV _v;
+
+public:
+ SOPV(void) { _v = ZBDDV(); }
+ SOPV(const SOPV& v) { _v = v._v; }
+ SOPV(const ZBDDV& zbddv) { _v = zbddv; }
+ SOPV(const SOP& f, int loc = 0) { _v = ZBDDV(f.GetZBDD(), loc); }
+ ~SOPV() { }
+
+ SOPV& operator=(const SOPV& v) { _v = v._v; return *this; }
+ SOPV operator&=(const SOPV& v) { _v = _v & v._v; return *this; }
+ SOPV operator+=(const SOPV& v) { _v = _v + v._v; return *this; }
+ SOPV operator-=(const SOPV& v) { _v = _v - v._v; return *this; }
+
+ SOPV operator<<=(int); // inline
+ SOPV operator>>=(int); // inline
+
+ SOPV operator<<(int n) const { return SOPV(_v << (n<<1)); }
+ SOPV operator>>(int n) const { return SOPV(_v >> (n<<1)); }
+
+ SOPV And0(int) const;
+ SOPV And1(int) const;
+ SOPV Factor0(int) const;
+ SOPV Factor1(int) const;
+ SOPV FactorD(int) const;
+
+ int Top(void) const { return (_v.Top() + 1) & ~1; }
+ bddword Size(void) const;
+ bddword Cube(void) const;
+ bddword Lit(void) const;
+ void Print(void) const;
+ int PrintPla(void) const;
+
+ int Last(void) const {return _v.Last(); }
+ SOPV Mask(int start, int length = 1) const
+ { return SOPV(_v.Mask(start, length)); }
+
+ SOP GetSOP(int) const;
+ ZBDDV GetZBDDV(void) const { return _v; }
+
+ SOPV Swap(int, int) const;
+
+ friend SOPV operator&(const SOPV&, const SOPV&);
+ friend SOPV operator+(const SOPV&, const SOPV&);
+ friend SOPV operator-(const SOPV&, const SOPV&);
+
+ friend int operator==(const SOPV&, const SOPV&);
+};
+
+inline SOPV operator&(const SOPV& f, const SOPV& g)
+ { return SOPV(f._v & g._v); }
+
+inline SOPV operator+(const SOPV& f, const SOPV& g)
+ { return SOPV(f._v + g._v); }
+
+inline SOPV operator-(const SOPV& f, const SOPV& g)
+ { return SOPV(f._v - g._v); }
+
+inline int operator==(const SOPV& v1, const SOPV& v2)
+ { return v1._v == v2._v; }
+
+inline int operator!=(const SOPV& v1, const SOPV& v2)
+ { return !(v1 == v2); }
+
+#endif // _SOP_
+
--- /dev/null
+/*********************************************
+ * SeqBDD+ Class (SAPPORO-1.55) - Header *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ *********************************************/
+
+class SeqBDD;
+class SeqBDDV;
+
+#ifndef _SeqBDD_
+#define _SeqBDD_
+
+#include "ZBDD.h"
+
+extern SeqBDD operator*(const SeqBDD&, const SeqBDD&);
+extern SeqBDD SeqBDD_Import(FILE *strm = stdin);
+extern SeqBDD BDD_CacheSeqBDD(char, bddword, bddword);
+extern SeqBDD SeqBDD_ID(bddword);
+//extern SeqBDD operator/(const SeqBDD&, const SeqBDD&);
+//extern SeqBDD operator%(const SeqBDD&, const SeqBDD&);
+//extern SeqBDD SeqBDD_Meet(const SeqBDD&, const SeqBDD&);
+
+class SeqBDD
+{
+ ZBDD _zbdd;
+public:
+ SeqBDD(void){ _zbdd = ZBDD(); }
+ SeqBDD(int val) { _zbdd = ZBDD(val); }
+ SeqBDD(const SeqBDD& f){ _zbdd = f._zbdd; }
+ SeqBDD(const ZBDD& zbdd){ _zbdd = zbdd; }
+ ~SeqBDD(void){ }
+
+ SeqBDD& operator=(const SeqBDD& f) { _zbdd = f._zbdd; return *this; }
+ SeqBDD operator&=(const SeqBDD& f)
+ { _zbdd = _zbdd & f._zbdd; return *this; }
+
+ SeqBDD operator+=(const SeqBDD& f)
+ { _zbdd = _zbdd + f._zbdd; return *this; }
+ SeqBDD operator-=(const SeqBDD& f)
+ { _zbdd = _zbdd - f._zbdd; return *this; }
+
+ SeqBDD operator*=(const SeqBDD&); // inline
+ // SeqBDD operator/=(const SeqBDD&);
+ // SeqBDD operator%=(const SeqBDD&);
+
+ SeqBDD OffSet(int) const;
+ SeqBDD OnSet(int) const;
+ SeqBDD OnSet0(int) const;
+ SeqBDD Push(int v) const
+ { return SeqBDD(ZBDD_ID(bddpush(_zbdd.GetID(), v))); }
+
+ int Top(void) const { return _zbdd.Top(); }
+ ZBDD GetZBDD(void) const { return _zbdd; }
+
+ bddword Size(void) const;
+ bddword Card(void) const;
+ bddword Lit(void) const;
+ bddword Len(void) const;
+ void Export(FILE *strm = stdout) const;
+ void PrintSeq(void) const;
+ void XPrint(void) const;
+ void Print(void) const;
+
+ friend SeqBDD operator&(const SeqBDD&, const SeqBDD&);
+ friend SeqBDD operator+(const SeqBDD&, const SeqBDD&);
+ friend SeqBDD operator-(const SeqBDD&, const SeqBDD&);
+ friend SeqBDD operator*(const SeqBDD&, const SeqBDD&);
+// friend SeqBDD operator/(const SeqBDD&, const SeqBDD&);
+// friend SeqBDD operator%(const SeqBDD&, const SeqBDD&);
+ friend SeqBDD BDD_CacheSeqBDD(char, bddword, bddword);
+ friend int operator==(const SeqBDD&, const SeqBDD&);
+ friend SeqBDD SeqBDD_ID(bddword);
+};
+
+inline SeqBDD operator&(const SeqBDD& f, const SeqBDD& g)
+ { return SeqBDD(f._zbdd & g._zbdd); }
+
+inline SeqBDD operator+(const SeqBDD& f, const SeqBDD& g)
+ { return SeqBDD(f._zbdd + g._zbdd); }
+
+inline SeqBDD operator-(const SeqBDD& f, const SeqBDD& g)
+ { return SeqBDD(f._zbdd - g._zbdd); }
+
+inline int operator==(const SeqBDD& f, const SeqBDD& g)
+ { return f._zbdd == g._zbdd; }
+
+inline int operator!=(const SeqBDD& f, const SeqBDD& g)
+ { return !(f == g); }
+
+inline SeqBDD SeqBDD::operator*=(const SeqBDD& f)
+ { return *this = *this * f; }
+
+#endif // _SeqBDD_
--- /dev/null
+/*********************************************
+ * ZBDD+ Manipulator (SAPPORO-1.58) - Header *
+ * (C) Shin-ichi MINATO (Nov. 22, 2013) *
+ *********************************************/
+
+class ZBDD;
+class ZBDDV;
+
+#ifndef _ZBDD_
+#define _ZBDD_
+
+#include "BDD.h"
+
+class SeqBDD;
+
+class ZBDD
+{
+ bddword _zbdd;
+
+public:
+ ZBDD(void) { _zbdd = bddempty; }
+ ZBDD(int v) { _zbdd = (v==0)? bddempty:(v>0)? bddsingle:bddnull; }
+ ZBDD(const ZBDD& f) { _zbdd = bddcopy(f._zbdd); }
+
+ ~ZBDD(void) { bddfree(_zbdd); }
+
+ ZBDD& operator=(const ZBDD& f) {
+ if(_zbdd != f._zbdd) { bddfree(_zbdd); _zbdd = bddcopy(f._zbdd); }
+ return *this;
+ }
+
+ ZBDD& operator&=(const ZBDD& f)
+ { ZBDD h; h._zbdd = bddintersec(_zbdd, f._zbdd); return *this = h; }
+
+ ZBDD& operator+=(const ZBDD& f)
+ { ZBDD h; h._zbdd = bddunion(_zbdd, f._zbdd); return *this = h; }
+
+ ZBDD& operator-=(const ZBDD& f)
+ { ZBDD h; h._zbdd = bddsubtract(_zbdd, f._zbdd); return *this = h; }
+
+ ZBDD& operator<<=(int s)
+ { ZBDD h; h._zbdd = bddlshift(_zbdd, s); return *this = h; }
+
+ ZBDD& operator>>=(int s)
+ { ZBDD h; h._zbdd = bddrshift(_zbdd, s); return *this = h; }
+
+ ZBDD& operator*=(const ZBDD&);
+ ZBDD& operator/=(const ZBDD&);
+ ZBDD& operator%=(const ZBDD&);
+
+ ZBDD operator<<(int s) const
+ { ZBDD h; h._zbdd = bddlshift(_zbdd, s); return h; }
+
+ ZBDD operator>>(int s) const
+ { ZBDD h; h._zbdd = bddrshift(_zbdd, s); return h; }
+
+ int Top(void) const { return bddtop(_zbdd); }
+
+ ZBDD OffSet(int v) const
+ { ZBDD h; h._zbdd = bddoffset(_zbdd, v); return h; }
+
+ ZBDD OnSet(int v) const
+ { ZBDD h; h._zbdd = bddonset(_zbdd, v); return h; }
+
+ ZBDD OnSet0(int v) const
+ { ZBDD h; h._zbdd = bddonset0(_zbdd, v); return h; }
+
+ ZBDD Change(int v) const
+ { ZBDD h; h._zbdd = bddchange(_zbdd, v); return h; }
+
+ bddword GetID(void) const { return _zbdd; }
+ bddword Size(void) const { return bddsize(_zbdd); }
+ bddword Card(void) const { return bddcard(_zbdd); }
+ bddword Lit(void) const { return bddlit(_zbdd); }
+ bddword Len(void) const { return bddlen(_zbdd); }
+
+ void Export(FILE *strm = stdout) const;
+ void XPrint(void) const;
+ void Print(void) const;
+ void PrintPla(void) const;
+
+ ZBDD Swap(int, int) const;
+ ZBDD Restrict(const ZBDD&) const;
+ ZBDD Permit(const ZBDD&) const;
+ ZBDD PermitSym(int) const;
+ ZBDD Support(void) const
+ { ZBDD h; h._zbdd = bddsupport(_zbdd); return h; }
+ ZBDD Always(void) const;
+
+ int SymChk(int, int) const;
+ ZBDD SymGrp(void) const;
+ ZBDD SymGrpNaive(void) const;
+
+ ZBDD SymSet(int) const;
+ int ImplyChk(int, int) const;
+ int CoImplyChk(int, int) const;
+ ZBDD ImplySet(int) const;
+ ZBDD CoImplySet(int) const;
+
+ int IsPoly(void) const;
+ ZBDD Divisor(void) const;
+
+ ZBDD ZLev(int lev, int last = 0) const;
+ void SetZSkip(void) const;
+ ZBDD Intersec(const ZBDD&) const;
+
+ friend ZBDD ZBDD_ID(bddword);
+
+ //friend class SeqBDD;
+};
+
+extern ZBDD operator*(const ZBDD&, const ZBDD&);
+extern ZBDD operator/(const ZBDD&, const ZBDD&);
+extern ZBDD ZBDD_Meet(const ZBDD&, const ZBDD&);
+extern ZBDD ZBDD_Random(int, int density = 50);
+extern ZBDD ZBDD_Import(FILE *strm = stdin);
+
+extern ZBDD ZBDD_LCM_A(char *, int);
+extern ZBDD ZBDD_LCM_C(char *, int);
+extern ZBDD ZBDD_LCM_M(char *, int);
+
+inline ZBDD ZBDD_ID(bddword zbdd)
+ { ZBDD h; h._zbdd = zbdd; return h; }
+
+inline ZBDD BDD_CacheZBDD(char op, bddword fx, bddword gx)
+ { return ZBDD_ID(bddcopy(bddrcache(op, fx, gx))); }
+
+inline ZBDD operator&(const ZBDD& f, const ZBDD& g)
+ { return ZBDD_ID(bddintersec(f.GetID(), g.GetID())); }
+
+inline ZBDD operator+(const ZBDD& f, const ZBDD& g)
+ { return ZBDD_ID(bddunion(f.GetID(), g.GetID())); }
+
+inline ZBDD operator-(const ZBDD& f, const ZBDD& g)
+ { return ZBDD_ID(bddsubtract(f.GetID(), g.GetID())); }
+
+inline ZBDD operator%(const ZBDD& f, const ZBDD& p)
+ { return f - (f/p) * p; }
+
+inline int operator==(const ZBDD& f, const ZBDD& g)
+ { return f.GetID() == g.GetID(); }
+
+inline int operator!=(const ZBDD& f, const ZBDD& g)
+ { return !(f == g); }
+
+inline ZBDD& ZBDD::operator*=(const ZBDD& f)
+ { return *this = *this * f; }
+
+inline ZBDD& ZBDD::operator/=(const ZBDD& f)
+ { return *this = *this / f; }
+
+inline ZBDD& ZBDD::operator%=(const ZBDD& f)
+ { return *this = *this % f; }
+
+
+class ZBDDV
+{
+ ZBDD _zbdd;
+
+public:
+ ZBDDV(void) { _zbdd = 0; }
+ ZBDDV(const ZBDDV& fv) { _zbdd = fv._zbdd; }
+ ZBDDV(const ZBDD& f, int location = 0);
+ ~ZBDDV(void) { }
+
+ ZBDDV& operator=(const ZBDDV& fv) { _zbdd = fv._zbdd; return *this; }
+ ZBDDV& operator&=(const ZBDDV& fv) { _zbdd &= fv._zbdd; return *this; }
+ ZBDDV& operator+=(const ZBDDV& fv) { _zbdd += fv._zbdd; return *this; }
+ ZBDDV& operator-=(const ZBDDV& fv) { _zbdd -= fv._zbdd; return *this; }
+ ZBDDV& operator<<=(int);
+ ZBDDV& operator>>=(int);
+
+ ZBDDV operator<<(int) const;
+ ZBDDV operator>>(int) const;
+
+ ZBDDV OffSet(int) const;
+ ZBDDV OnSet(int) const;
+ ZBDDV OnSet0(int) const;
+ ZBDDV Change(int) const;
+ ZBDDV Swap(int, int) const;
+
+ int Top(void) const;
+ int Last(void) const;
+ ZBDDV Mask(int start, int length = 1) const;
+ ZBDD GetZBDD(int) const;
+
+ ZBDD GetMetaZBDD(void) const { return _zbdd; }
+ bddword Size(void) const;
+ void Print(void) const;
+ void Export(FILE *strm = stdout) const;
+ int PrintPla(void) const;
+ void XPrint(void) const;
+
+ friend ZBDDV operator&(const ZBDDV&, const ZBDDV&);
+ friend ZBDDV operator+(const ZBDDV&, const ZBDDV&);
+ friend ZBDDV operator-(const ZBDDV&, const ZBDDV&);
+};
+
+extern ZBDDV ZBDDV_Import(FILE *strm = stdin);
+
+inline ZBDDV operator&(const ZBDDV& fv, const ZBDDV& gv)
+ { ZBDDV hv; hv._zbdd = fv._zbdd & gv._zbdd; return hv; }
+inline ZBDDV operator+(const ZBDDV& fv, const ZBDDV& gv)
+ { ZBDDV hv; hv._zbdd = fv._zbdd + gv._zbdd; return hv; }
+inline ZBDDV operator-(const ZBDDV& fv, const ZBDDV& gv)
+ { ZBDDV hv; hv._zbdd = fv._zbdd - gv._zbdd; return hv; }
+inline int operator==(const ZBDDV& fv, const ZBDDV& gv)
+ { return fv.GetMetaZBDD() == gv.GetMetaZBDD(); }
+inline int operator!=(const ZBDDV& fv, const ZBDDV& gv)
+ { return !(fv == gv); }
+
+inline ZBDDV& ZBDDV::operator<<=(int s)
+ { return *this = *this << s; }
+
+inline ZBDDV& ZBDDV::operator>>=(int s)
+ { return *this = *this >> s; }
+
+class ZBDD_Hash;
+class ZBDD_Hash
+{
+ struct ZBDD_Entry
+ {
+ ZBDD _key;
+ void* _ptr;
+ ZBDD_Entry(void){ _key = -1; }
+ };
+
+ bddword _amount;
+ bddword _hashSize;
+ ZBDD_Entry* _wheel;
+
+ ZBDD_Entry* GetEntry(ZBDD);
+ void Enlarge(void);
+public:
+ ZBDD_Hash(void);
+ ~ZBDD_Hash(void);
+ void Clear(void);
+ void Enter(ZBDD, void *);
+ void* Refer(ZBDD);
+ bddword Amount(void);
+};
+
+#endif // _ZBDD_
--- /dev/null
+/*****************************************
+ * ZZBDDDG - Decomposition Graph *
+ * (SAPPORO-1.02) - Header *
+ * (C) Shin-ichi MINATO (Aug. 8, 2005) *
+ *****************************************/
+
+#ifndef _ZBDDDG_
+#define _ZBDDDG_
+
+#include "ZBDD.h"
+
+#define ZBDDDG_InitSize 4
+
+#define ZBDDDG_NIL BDD_MaxNode
+
+#define ZBDDDG_C0 1
+#define ZBDDDG_P1 2
+#define ZBDDDG_LIT 3
+#define ZBDDDG_AND 4
+#define ZBDDDG_OR 5
+#define ZBDDDG_OTHER 6
+
+class ZBDDDG
+{
+ struct Node;
+ struct NodeLink
+ {
+ bddword _ndx;
+ bddword _nxt;
+ NodeLink(void){ _ndx = ZBDDDG_NIL; _nxt = ZBDDDG_NIL; }
+ };
+
+ bddword _nodeSize;
+ bddword _nodeUsed;
+ bddword _linkSize;
+ bddword _linkUsed;
+ bddword* _hashWheel;
+ Node* _nodeA;
+ NodeLink* _linkA;
+ bddword _c0;
+ bddword _c1;
+
+ bddword HashIndex(ZBDD);
+ bddword NewNdx(ZBDD, char);
+ int EnlargeNode(void);
+ bddword NewLkx(bddword);
+ int EnlargeLink(void);
+ int LinkNodes(bddword, bddword);
+ int Merge3(bddword, bddword, bddword);
+ ZBDD Func0(ZBDD, ZBDD);
+ ZBDD Func1(ZBDD, ZBDD);
+ int LinkNodesC3(bddword, bddword);
+ void Print0(bddword);
+ bddword Merge(ZBDD, bddword, bddword);
+ bddword ReferNdx(ZBDD);
+ int PhaseSweep(bddword);
+ void MarkSweep(bddword);
+ void MarkSweepR(bddword);
+ int Mark1(bddword);
+ void Mark2R(bddword);
+ int MarkChkR(bddword);
+ void Mark3R(bddword);
+ bddword Mark4R(bddword, bddword, bddword);
+ bddword Mark5R(bddword, bddword, bddword);
+ void Mark6R(bddword, bddword);
+ bddword AppendR(bddword, int, bddword, bddword);
+
+ struct Node
+ {
+ bddword _lkx;
+ ZBDD _f;
+ bddword _ndxP;
+ char _type; // NULL, C1, P1, LIT, OR, XOR, OTHER
+ char _mark;
+ Node(void);
+ Node(ZBDD, char);
+ };
+
+public:
+ ZBDDDG(void);
+ ~ZBDDDG(void);
+ void Clear(void);
+ bddword NodeUsed(void);
+ int PrintDecomp(ZBDD);
+ bddword Decomp(ZBDD);
+
+ friend class ZBDDDG_Tag;
+};
+
+class ZBDDDG_Tag
+{
+ ZBDDDG* _dg;
+ bddword _ndx;
+ bddword _lkx;
+public:
+ ZBDDDG_Tag(void);
+ int Set(ZBDDDG *, bddword);
+ bddword TopNdx(void);
+ bddword NextNdx(void);
+ char Type(void);
+ ZBDD Func(void);
+};
+
+#endif // _ZBDDDG_
+
--- /dev/null
+/*****************************************
+* BDD Package (SAPPORO-1.57) - Header *
+* (C) Shin-ichi MINATO (June 14, 2013) *
+******************************************/
+
+#ifndef bddc_h
+#define bddc_h
+
+#if (defined BDD_CPP)||(! defined B_OLDC)
+# define B_ARG(a) a /* ANSI C style */
+#else
+# define B_ARG(a) () /* K&R C style */
+#endif
+
+/***************** Internal macro for index *****************/
+#define B_VAR_WIDTH 16U /* Width of variable index */
+#define B_VAR_MASK ((1U << B_VAR_WIDTH) - 1U)
+
+/***************** Internal macro for bddp *****************/
+#ifdef B_64
+# define B_MSB_POS 39ULL
+# define B_LSB_MASK 1ULL
+#else
+# define B_MSB_POS 31U
+# define B_LSB_MASK 1U
+#endif
+#define B_MSB_MASK (B_LSB_MASK << B_MSB_POS)
+#define B_INV_MASK B_LSB_MASK /* Mask of inverter-flag */
+#define B_CST_MASK B_MSB_MASK /* Mask of constant-flag */
+#define B_VAL_MASK (B_MSB_MASK - 1U)
+ /* Mask of value-field */
+
+/***************** For stack overflow limit *****************/
+extern const int BDD_RecurLimit;
+extern int BDD_RecurCount;
+
+/***************** External typedef *****************/
+typedef unsigned int bddvar;
+#ifdef B_64
+ typedef unsigned long long bddp;
+#else
+ typedef unsigned int bddp;
+#endif
+
+/***************** External Macro *****************/
+#define bddvarmax B_VAR_MASK /* Max value of variable index */
+#define bddnull B_VAL_MASK /* Special value for null pointer */
+#define bddfalse B_CST_MASK /* bddp of constant false (0) */
+#define bddtrue (bddfalse ^ B_INV_MASK)
+ /* bddp of constant true (1) */
+#define bddempty bddfalse /* bddp of empty ZBDD (0) */
+#define bddsingle bddtrue /* bddp of single unit ZBDD (1) */
+#define bddconst(c) (((c) & B_VAL_MASK) | B_CST_MASK)
+ /* bddp of a constant valued node */
+#define bddvalmax B_VAL_MASK /* Max constant value */
+
+#ifdef BDD_CPP
+ extern "C" {
+#endif /* BDD_CPP */
+
+/***************** External operations *****************/
+
+/***************** Init. and config. ****************/
+extern int bddinit B_ARG((bddp initsize, bddp limitsize));
+extern bddvar bddnewvar B_ARG((void));
+extern bddvar bddnewvaroflev B_ARG((bddvar lev));
+extern bddvar bddlevofvar B_ARG((bddvar v));
+extern bddvar bddvaroflev B_ARG((bddvar lev));
+extern bddvar bddvarused B_ARG((void));
+
+/************** Basic logic operations *************/
+extern bddp bddprime B_ARG((bddvar v));
+extern bddvar bddtop B_ARG((bddp f));
+extern bddp bddcopy B_ARG((bddp f));
+extern bddp bddnot B_ARG((bddp f));
+extern bddp bddand B_ARG((bddp f, bddp g));
+extern bddp bddor B_ARG((bddp f, bddp g));
+extern bddp bddxor B_ARG((bddp f, bddp g));
+extern bddp bddnand B_ARG((bddp f, bddp g));
+extern bddp bddnor B_ARG((bddp f, bddp g));
+extern bddp bddxnor B_ARG((bddp f, bddp g));
+extern bddp bddat0 B_ARG((bddp f, bddvar v));
+extern bddp bddat1 B_ARG((bddp f, bddvar v));
+
+/********** Memory management and observation ***********/
+extern void bddfree B_ARG((bddp f));
+extern bddp bddused B_ARG((void));
+extern int bddgc B_ARG((void));
+extern bddp bddsize B_ARG((bddp f));
+extern bddp bddvsize B_ARG((bddp *p, int lim));
+extern void bddexport B_ARG((FILE *strm, bddp *p, int lim));
+extern int bddimport B_ARG((FILE *strm, bddp *p, int lim));
+extern void bdddump B_ARG((bddp f));
+extern void bddvdump B_ARG((bddp *p, int lim));
+extern void bddgraph B_ARG((bddp f));
+extern void bddgraph0 B_ARG((bddp f));
+extern void bddvgraph B_ARG((bddp *p, int lim));
+extern void bddvgraph0 B_ARG((bddp *p, int lim));
+
+/************** Advanced logic operations *************/
+extern bddp bddlshift B_ARG((bddp f, bddvar shift));
+extern bddp bddrshift B_ARG((bddp f, bddvar shift));
+extern bddp bddsupport B_ARG((bddp f));
+extern bddp bdduniv B_ARG((bddp f, bddp g));
+extern bddp bddexist B_ARG((bddp f, bddp g));
+extern bddp bddcofactor B_ARG((bddp f, bddp g));
+extern int bddimply B_ARG((bddp f, bddp g));
+extern bddp bddrcache B_ARG((unsigned char op, bddp f, bddp g));
+extern void bddwcache
+ B_ARG((unsigned char op, bddp f, bddp g, bddp h));
+
+/************** ZBDD operations *************/
+extern bddp bddoffset B_ARG((bddp f, bddvar v));
+extern bddp bddonset B_ARG((bddp f, bddvar v));
+extern bddp bddonset0 B_ARG((bddp f, bddvar v));
+extern bddp bddchange B_ARG((bddp f, bddvar v));
+extern bddp bddintersec B_ARG((bddp f, bddp g));
+extern bddp bddunion B_ARG((bddp f, bddp g));
+extern bddp bddsubtract B_ARG((bddp f, bddp g));
+extern bddp bddcard B_ARG((bddp f));
+extern bddp bddlit B_ARG((bddp f));
+extern bddp bddlen B_ARG((bddp f));
+extern int bddimportz B_ARG((FILE *strm, bddp *p, int lim));
+
+/************** SeqBDD operations *************/
+extern bddp bddpush B_ARG((bddp f, bddvar v));
+
+#ifdef BDD_CPP
+ }
+#endif /* BDD_CPP */
+
+#endif /* bddc_h */
--- /dev/null
+ /***************************************
+ * BDD+ Manipulator (SAPPORO-1.58) *
+ * (Basic methods) *
+ * (C) Shin-ichi MINATO (Nov. 22, 2013) *
+ ****************************************/
+
+#include "BDD.h"
+
+static const char BC_Smooth = 60;
+static const char BC_Spread = 61;
+
+extern "C"
+{
+ int rand();
+};
+
+
+//--- SBDD class for default initialization ----
+
+int BDDV_Active = 0;
+
+class SBDD
+{
+public:
+ SBDD(bddword init, bddword limit) { bddinit(init, limit); }
+};
+static SBDD BDD_Manager((bddword)256, (bddword)1024);
+
+
+//----- External constant data for BDD -------
+
+const bddword BDD_MaxNode = B_VAL_MASK >> 1U;
+const int BDD_MaxVar = bddvarmax;
+
+//-------------- class BDD --------------------
+
+bddword BDD::Size() const { return bddsize(_bdd); }
+
+void BDD::Export(FILE *strm) const
+{
+ bddword p = _bdd;
+ bddexport(strm, &p, 1);
+}
+
+void BDD::Print() const
+{
+ cout << "[ " << GetID();
+ cout << " Var:" << Top() << "(" << BDD_LevOfVar(Top()) << ")";
+ cout << " Size:" << Size() << " ]\n";
+ cout.flush();
+}
+
+BDD BDD::Swap(const int& v1, const int& v2) const
+{
+ if(v1 == v2) return *this;
+ BDD x = BDDvar(v1);
+ BDD y = BDDvar(v2);
+ BDD fx0 = At0(v1);
+ BDD fx1 = At1(v1);
+ return x & ( ~y & fx0.At1(v2) | y & fx1.At1(v2) ) |
+ ~x & ( ~y & fx0.At0(v2) | y & fx1.At0(v2) );
+}
+
+#define BDD_CACHE_CHK_RETURN(op, fx, gx) \
+ { BDD h = BDD_CacheBDD(op, fx, gx); \
+ if(h != -1) return h; \
+ BDD_RECUR_INC; }
+
+#define BDD_CACHE_ENT_RETURN(op, fx, gx, h) \
+ { BDD_RECUR_DEC; \
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h.GetID()); \
+ return h; }
+
+BDD BDD::Smooth(const int& v) const
+{
+ int t = Top();
+ if(t == 0) return *this;
+ if(BDD_LevOfVar(t) <= BDD_LevOfVar(v)) return 1;
+ bddword fx = GetID();
+ bddword gx = BDDvar(v).GetID();
+ BDD_CACHE_CHK_RETURN(BC_Smooth, fx, gx);
+ BDD x = BDDvar(t);
+ BDD h = (~x & At0(t).Smooth(v))|(x & At1(t).Smooth(v));
+ BDD_CACHE_ENT_RETURN(BC_Smooth, fx, gx, h);
+}
+
+BDD BDD::Spread(const int& k) const
+{
+ int t = Top();
+ if(t == 0) return *this;
+ if(k == 0) return *this;
+ if(k < 0) BDDerr("BDD::Spread: k < 0.",k);
+ bddword fx = GetID();
+ bddword gx = BDDvar(k).GetID();
+ BDD_CACHE_CHK_RETURN(BC_Spread, fx, gx);
+ BDD x = BDDvar(t);
+ BDD f0 = At0(t);
+ BDD f1 = At1(t);
+ BDD h = (~x & f0.Spread(k)) | (x & f1.Spread(k))
+ | (~x & f1.Spread(k-1)) | (x & f0.Spread(k-1));
+ BDD_CACHE_ENT_RETURN(BC_Spread, fx, gx, h);
+}
+
+//----- External functions for BDD -------
+
+void BDD_Init(bddword init, bddword limit)
+{
+ bddinit(init, limit);
+ BDDV_Active = 0;
+}
+
+int BDD_NewVarOfLev(int lev)
+{
+ if(lev > BDD_TopLev() + 1)
+ BDDerr("BDD_NewVarOfLev:Invald lev ", (bddword)lev);
+ return bddnewvaroflev(lev);
+}
+
+int BDD_VarUsed(void) { return bddvarused(); }
+
+bddword BDD_Used(void) { return bddused(); }
+
+void BDD_GC() { bddgc(); }
+
+BDD BDD_Import(FILE *strm)
+{
+ bddword bdd;
+ if(bddimport(strm, &bdd, 1)) return -1;
+ return BDD_ID(bdd);
+}
+
+BDD BDD_Random(int level, int density)
+{
+ if(level < 0)
+ BDDerr("BDD_Random: level < 0.",level);
+ if(level == 0) return ((rand()%100) < density)? 1: 0;
+ return (BDDvar(BDD_VarOfLev(level))
+ & BDD_Random(level-1, density)) |
+ (~BDDvar(BDD_VarOfLev(level))
+ & BDD_Random(level-1, density));
+}
+
+void BDDerr(const char* msg)
+{
+ cerr << "<ERROR> " << msg << " \n";
+ exit(1);
+}
+
+void BDDerr(const char* msg, bddword key)
+{
+ cerr << "<ERROR> " << msg << " (" << key << ")\n";
+ exit(1);
+}
+
+void BDDerr(const char* msg, const char* name)
+{
+ cerr << "<ERROR> " << msg << " (" << name << ")\n";
+ exit(1);
+}
+
+
+//----- External constant data for BDDV -------
+
+const int BDDV_SysVarTop = 20;
+const int BDDV_MaxLen = 1 << BDDV_SysVarTop;
+const int BDDV_MaxLenImport = 1000;
+
+
+//--------------- class BDDV ------------------------
+
+BDDV::BDDV(const BDD& f, int len)
+{
+ if(len < 0) BDDerr("BDDV::BDDV: len < 0.", len);
+ if(len > BDDV_MaxLen) BDDerr("BDDV::BDDV: Too large len.", len);
+ int t = f.Top();
+ if(t > 0 && BDD_LevOfVar(t) > BDD_TopLev())
+ BDDerr("BDDV::BDDV: Invalid Top Var.", t);
+ _bdd = (len == 0)? 0: f;
+ _len = (f == -1)? 1: len;
+ _lev = GetLev(len);
+}
+
+BDDV BDDV::operator<<(int shift) const
+{
+ if(!Uniform()) return (Former() << shift) || (Latter() << shift);
+ BDDV hv;
+ if((hv._bdd = _bdd << shift) == -1) return BDDV(-1);
+ hv._len = _len;
+ hv._lev = _lev;
+ return hv;
+}
+
+BDDV BDDV::operator>>(int shift) const
+{
+ if(!Uniform()) return (Former() >> shift) || (Latter() >> shift);
+ BDDV hv;
+ if((hv._bdd = _bdd >> shift) == -1) return BDDV(-1);
+ hv._len = _len;
+ hv._lev = _lev;
+ return hv;
+}
+
+BDDV BDDV::Cofact(const BDDV& fv) const
+{
+ if(_lev > 0)
+ return Former().Cofact(fv.Former()) || Latter().Cofact(fv.Latter());
+ BDDV hv;
+ if((hv._bdd = _bdd.Cofact(fv._bdd)) == -1) return BDDV(-1);
+ if(_len != fv._len) BDDerr("BDDV::Cofact: Length mismatch.");
+ hv._len = _len;
+ // hv._lev = _lev; (always zero)
+ return hv;
+}
+
+BDDV BDDV::Swap(int v1, int v2) const
+{
+ if(BDD_LevOfVar(v1) > BDD_TopLev())
+ BDDerr("BDDV::Swap: Invalid VarID.", v1);
+ if(BDD_LevOfVar(v2) > BDD_TopLev())
+ BDDerr("BDDV::Swap: Invalid VarID.", v2);
+ BDDV hv;
+ if((hv._bdd = _bdd.Swap(v1, v2)) == -1) return BDDV(-1);
+ hv._len = _len;
+ hv._lev = _lev;
+ return hv;
+}
+
+int BDDV::Top() const
+{
+ if(Uniform()) return _bdd.Top();
+ int t0 = Former().Top();
+ int t1 = Latter().Top();
+ if(BDD_LevOfVar(t0) > BDD_LevOfVar(t1)) return t0;
+ else return t1;
+}
+
+bddword BDDV::Size() const
+{
+ bddword* bddv = new bddword[_len];
+ for(int i=0; i<_len; i++) bddv[i] = GetBDD(i).GetID();
+ bddword s = bddvsize(bddv, _len);
+ delete[] bddv;
+ return s;
+}
+
+void BDDV::Export(FILE *strm) const
+{
+ bddword* bddv = new bddword[_len];
+ for(int i=0; i<_len; i++) bddv[i] = GetBDD(i).GetID();
+ bddexport(strm, bddv, _len);
+ delete[] bddv;
+}
+
+BDDV BDDV::Spread(int k) const
+{
+ if(Uniform()) return _bdd.Spread(k);
+ return Former().Spread(k) || Latter().Spread(k);
+}
+
+BDDV BDDV::Part(int start, int len) const
+{
+ if(_bdd == -1) return *this;
+ if(len == 0) return BDDV();
+
+ if(start < 0 || start + len > _len)
+ BDDerr("BDDV::Part: Illegal index.");
+
+ if(start == 0 && len == _len) return *this;
+
+ int half = 1 << (_lev-1);
+
+ if(start + len <= half) return Former().Part(start, len);
+ if(start >= half) return Latter().Part(start - half, len);
+ return Former().Part(start, half - start)
+ || Latter().Part(0, start + len - half);
+}
+
+BDD BDDV::GetBDD(int index) const
+{
+ if(index < 0 || index >= _len)
+ BDDerr("BDDV::GetBDD: Illegal index.",index);
+ if(_len == 1) return _bdd;
+ BDD f = _bdd;
+ for(int i=_lev-1; i>=0; i--)
+ if((index & (1<<i)) == 0) f = f.At0(i + 1);
+ else f = f.At1(i + 1);
+ return f;
+}
+
+void BDDV::Print() const
+{
+ for(int i=0; i<_len; i++)
+ {
+ cout << "f" << i << ": ";
+ GetBDD(i).Print();
+ }
+ cout << "Size= " << Size() << "\n\n";
+ cout.flush();
+}
+
+//----- External functions for BDD Vector -------
+
+void BDDV_Init(bddword init, bddword limit)
+{
+ bddinit(init, limit);
+ for(int i=0; i<BDDV_SysVarTop; i++) bddnewvar();
+ BDDV_Active = 1;
+}
+
+BDDV operator||(const BDDV& fv, const BDDV& gv)
+{
+ if(fv._len == 0) return gv;
+ if(gv._len == 0) return fv;
+ if(fv._len != (1 << fv._lev))
+ return BDDV(fv).Former() || (BDDV(fv).Latter() || gv);
+ if(fv._len < gv._len)
+ return (fv || BDDV(gv).Former()) || BDDV(gv).Latter();
+ BDDV hv;
+ BDD x = BDDvar(fv._lev + 1);
+ if((hv._bdd = (~x & fv._bdd)|(x & gv._bdd)) == -1) return BDDV(-1);
+ if((hv._len = fv._len + gv._len) > BDDV_MaxLen)
+ BDDerr("BDDV::operatop||: Too large len.", hv._len);
+ hv._lev = fv._lev + 1;
+ return hv;
+}
+
+BDDV BDDV_Mask1(int index, int len)
+{
+ if(len < 0) BDDerr("BDDV_Mask1: len < 0.", len);
+ if(index < 0 || index >= len)
+ BDDerr("BDDV_Mask1: Illegal index.", index);
+ return BDDV(0,index)||BDDV(1,1)||BDDV(0,len-index-1);
+}
+
+BDDV BDDV_Mask2(int index, int len)
+{
+ if(len < 0) BDDerr("BDDV_Mask2: len < 0.", len);
+ if(index < 0 || index > len)
+ BDDerr("BDDV_Mask2: Illegal index.", index);
+ return BDDV(0,index)||BDDV(1,len-index);
+}
+
+#define IMPORTHASH(x) (((x >> 1) ^ (x >> 16)) & (hashsize - 1))
+
+#ifdef B_64
+# define B_STRTOI strtoll
+#else
+# define B_STRTOI strtol
+#endif
+
+BDDV BDDV_Import(FILE *strm)
+{
+ int inv, e;
+ bddword hashsize;
+ BDD f, f0, f1;
+ char s[256];
+ bddword *hash1;
+ BDD *hash2;
+
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ if(strcmp(s, "_i") != 0) return BDDV(-1);
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ int n = strtol(s, NULL, 10);
+ while(n > BDD_TopLev()) BDD_NewVar();
+
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ if(strcmp(s, "_o") != 0) return BDDV(-1);
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ int m = strtol(s, NULL, 10);
+
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ if(strcmp(s, "_n") != 0) return BDDV(-1);
+ if(fscanf(strm, "%s", &s) == EOF) return BDDV(-1);
+ bddword n_nd = B_STRTOI(s, NULL, 10);
+
+ for(hashsize = 1; hashsize < (n_nd<<1); hashsize <<= 1)
+ ; /* empty */
+ hash1 = new bddword[hashsize];
+ if(hash1 == 0) return BDDV(-1);
+ hash2 = new BDD[hashsize];
+ if(hash2 == 0) { delete[] hash1; return BDDV(-1); }
+ for(bddword ix=0; ix<hashsize; ix++)
+ {
+ hash1[ix] = B_VAL_MASK;
+ hash2[ix] = 0;
+ }
+
+ e = 0;
+ for(bddword ix=0; ix<n_nd; ix++)
+ {
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }
+ bddword nd = B_STRTOI(s, NULL, 10);
+
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }
+ int lev = strtol(s, NULL, 10);
+ int var = bddvaroflev(lev);
+
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }
+ if(strcmp(s, "F") == 0) f0 = 0;
+ else if(strcmp(s, "T") == 0) f0 = 1;
+ else
+ {
+ bddword nd0 = B_STRTOI(s, NULL, 10);
+
+ bddword ixx = IMPORTHASH(nd0);
+ while(hash1[ixx] != nd0)
+ {
+ if(hash1[ixx] == B_VAL_MASK)
+ BDDerr("BDDV_Import(): internal error", ixx);
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ f0 = hash2[ixx];
+ }
+
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }
+ if(strcmp(s, "F") == 0) f1 = 0;
+ else if(strcmp(s, "T") == 0) f1 = 1;
+ else
+ {
+ bddword nd1 = B_STRTOI(s, NULL, 10);
+ if(nd1 & 1) { inv = 1; nd1 ^= 1; }
+ else inv = 0;
+
+ bddword ixx = IMPORTHASH(nd1);
+ while(hash1[ixx] != nd1)
+ {
+ if(hash1[ixx] == B_VAL_MASK)
+ BDDerr("BDDV_Import(): internal error", ixx);
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ f1 = (inv)? ~hash2[ixx]: hash2[ixx];
+ }
+
+ BDD x = BDDvar(var);
+ f = (x & f1) | (~x & f0);
+ if(f == -1) { e = 1; break; }
+
+ bddword ixx = IMPORTHASH(nd);
+ while(hash1[ixx] != B_VAL_MASK)
+ {
+ if(hash1[ixx] == nd)
+ BDDerr("BDDV_Import(): internal error", ixx);
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ hash1[ixx] = nd;
+ hash2[ixx] = f;
+ }
+
+ if(e)
+ {
+ delete[] hash2;
+ delete[] hash1;
+ return BDDV(-1);
+ }
+
+ BDDV v = BDDV();
+ for(int i=0; i<m; i++)
+ {
+ if(fscanf(strm, "%s", &s) == EOF)
+ {
+ delete[] hash2;
+ delete[] hash1;
+ return BDDV(-1);
+ }
+ bddword nd = B_STRTOI(s, NULL, 10);
+ if(strcmp(s, "F") == 0) v = v || BDD(0);
+ else if(strcmp(s, "T") == 0) v = v || BDD(1);
+ else
+ {
+ if(nd & 1) { inv = 1; nd ^= 1; }
+ else inv = 0;
+
+ bddword ixx = IMPORTHASH(nd);
+ while(hash1[ixx] != nd)
+ {
+ if(hash1[ixx] == B_VAL_MASK)
+ BDDerr("BDDV_Import(): internal error", ixx);
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ v = v || (inv? ~hash2[ixx]: hash2[ixx]);
+ }
+ }
+
+ delete[] hash2;
+ delete[] hash1;
+ return v;
+}
+
--- /dev/null
+/*******************************************
+ * BDD - Decomposition Graph (SAPPORO-1.02)*
+ * (C) Shin-ichi MINATO (Feb. 18, 2009) *
+ *******************************************/
+
+#include "BDDDG.h"
+
+BDDDG_Tag::BDDDG_Tag()
+{
+ _dg = 0;
+ _ndx = BDDDG_NIL;
+}
+
+int BDDDG_Tag::Set(BDDDG* dg, bddword idx)
+{
+ _dg = dg;
+ if(idx == BDDDG_NIL) return 1;
+ _ndx = BDDDG_Ndx(idx);
+ if(_ndx >= _dg->_nodeUsed) return 1;
+ _lkx = _dg->_nodeA[_ndx]._lkx;
+ return 0;
+}
+
+bddword BDDDG_Tag::TopIdx()
+{
+ _lkx = _dg->_nodeA[_ndx]._lkx;
+ if(_lkx == BDDDG_NIL) return BDDDG_NIL;
+ return _dg->_linkA[_lkx]._idx;
+}
+
+bddword BDDDG_Tag::NextIdx()
+{
+ _lkx = _dg->_linkA[_lkx]._nxt;
+ if(_lkx == BDDDG_NIL) return BDDDG_NIL;
+ return _dg->_linkA[_lkx]._idx;
+}
+
+char BDDDG_Tag::Type()
+{
+ return _dg->_nodeA[_ndx]._type;
+}
+
+BDD BDDDG_Tag::Func()
+{
+ return _dg->_nodeA[_ndx]._f;
+}
+
+BDDDG::BDDDG()
+{
+ _nodeA = 0;
+ _linkA = 0;
+ _hashWheel = 0;
+ Clear();
+}
+
+BDDDG::~BDDDG()
+{
+ delete[] _hashWheel;
+ delete[] _linkA;
+ delete[] _nodeA;
+}
+
+void BDDDG::Clear()
+{
+ delete[] _hashWheel;
+ delete[] _linkA;
+ delete[] _nodeA;
+
+ _nodeSize = BDDDG_InitSize;
+ _nodeA = new Node[_nodeSize];
+ _nodeUsed = 0;
+ _linkSize = BDDDG_InitSize;
+ _linkA = new NodeLink[_linkSize];
+ _linkUsed = 0;
+ bddword hashSize = _nodeSize << 1;
+ _hashWheel = new bddword[hashSize];
+ for(bddword i=0; i<hashSize; i++) _hashWheel[i] = BDDDG_NIL;
+ bddword cdx = NewNdx(1, BDDDG_C1);
+ _c1 = BDDDG_PackIdx(cdx, 0);
+}
+
+bddword BDDDG::HashIndex(BDD key)
+{
+ bddword id0 = key.GetID();
+ bddword id1 = (~key).GetID();
+ bddword id = (id0<id1)? id0: id1;
+ bddword hashSize = _nodeSize << 1;
+ bddword hash = (id+(id>>10)+(id>>20)) & (hashSize - 1);
+ bddword i = hash;
+ while(_hashWheel[i] != BDDDG_NIL)
+ {
+ BDD f = _nodeA[_hashWheel[i]]._f;
+ if(key == f) return i;
+ if(~key == f) return i;
+ i++;
+ i &= (hashSize -1);
+ }
+ return i;
+}
+
+bddword BDDDG::NewNdx(BDD f, char type)
+{
+ if(_nodeUsed == _nodeSize)
+ if(EnlargeNode()) return BDDDG_NIL;
+ bddword ndx = _nodeUsed++;
+ _nodeA[ndx]._f = f;
+ _nodeA[ndx]._type = type;
+ bddword i = HashIndex(f);
+ if(_hashWheel[i] != BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::NewNdx(): Duplicate node\n";
+ exit(1);
+ }
+ _hashWheel[i] = ndx;
+ return ndx;
+}
+
+
+int BDDDG::EnlargeNode()
+{
+ bddword oldHS = _nodeSize << 1;
+ Node* oldArray = _nodeA;
+ bddword* oldWheel = _hashWheel;
+
+ _nodeSize <<= 2;
+ _nodeA = new Node[_nodeSize];
+ bddword hashSize = _nodeSize << 1;
+ _hashWheel = new bddword[hashSize];
+ if(_nodeA == 0 || _hashWheel == 0)
+ {
+ cerr << "<ERROR> BDDDG::EnlargeNode(): Memory overflow (";
+ cerr << _nodeSize << ")\n";
+ return 1;
+ }
+ for(bddword i=0; i<_nodeUsed; i++)
+ {
+ _nodeA[i]._lkx = oldArray[i]._lkx;
+ _nodeA[i]._f = oldArray[i]._f;
+ _nodeA[i]._type = oldArray[i]._type;
+ _nodeA[i]._mark = oldArray[i]._mark;
+ _nodeA[i]._ndxP = oldArray[i]._ndxP;
+ _nodeA[i]._invP = oldArray[i]._invP;
+ }
+ for(bddword i=0; i<hashSize; i++) _hashWheel[i] = BDDDG_NIL;
+ for(bddword i=0; i<oldHS; i++)
+ {
+ bddword ndx = oldWheel[i];
+ if(ndx != BDDDG_NIL)
+ {
+ BDD f = _nodeA[ndx]._f;
+ _hashWheel[HashIndex(f)] = ndx;
+ }
+ }
+ delete[] oldArray;
+ delete[] oldWheel;
+ return 0;
+}
+
+bddword BDDDG::NewLkx(bddword idx)
+{
+ if(_linkUsed == _linkSize)
+ if(EnlargeLink()) return BDDDG_NIL;
+ bddword lkx = _linkUsed++;
+ _linkA[lkx]._idx = idx;
+ return lkx;
+}
+
+int BDDDG::EnlargeLink()
+{
+ NodeLink* oldArray = _linkA;
+
+ _linkSize <<= 2;
+ _linkA = new NodeLink[_linkSize];
+ if(_linkA == 0)
+ {
+ cerr << "<ERROR> BDDDG::EnlargeLink(): Memory overflow (";
+ cerr << _linkSize << ")\n";
+ return 1;
+ }
+ for(bddword i=0; i<_linkUsed; i++)
+ {
+ _linkA[i]._idx = oldArray[i]._idx;
+ _linkA[i]._nxt = oldArray[i]._nxt;
+ }
+ delete[] oldArray;
+ return 0;
+}
+
+bddword BDDDG::ReferIdx(BDD key)
+{
+ bddword i = HashIndex(key);
+ bddword ndx = _hashWheel[i];
+ if(ndx == BDDDG_NIL) return ndx;
+ return BDDDG_PackIdx(ndx, key != _nodeA[ndx]._f);
+}
+
+bddword BDDDG::NodeUsed() { return _nodeUsed; }
+
+BDDDG::Node::Node()
+{
+ _lkx = BDDDG_NIL;
+ _f = BDD(1);
+ _type = BDDDG_C1;
+ _mark = 0;
+ _ndxP = BDDDG_NIL;
+ _invP = 0;
+}
+
+BDDDG::Node::Node(BDD f, char type)
+{
+ _lkx = BDDDG_NIL;
+ _f = f;
+ _type = type;
+ _mark = 0;
+ _ndxP = BDDDG_NIL;
+ _invP = 0;
+}
+
+void BDDDG::PhaseSweep(bddword idx)
+{
+ int fin = 0;
+ int inv = 0;
+ if(idx == BDDDG_NIL) return;
+ Node* np = & _nodeA[BDDDG_Ndx(idx)];
+ bddword lkx = np->_lkx;
+
+ switch(np->_type)
+ {
+ case BDDDG_OR:
+ /* Assertion check*/
+ while(lkx != BDDDG_NIL)
+ {
+ NodeLink* lp = _linkA + lkx;
+ if(!BDDDG_Inv(lp->_idx) &&
+ _nodeA[BDDDG_Ndx(lp->_idx)]._type == BDDDG_OR)
+ {
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad structure (OR)\n";
+ exit(1);
+ }
+ lkx = lp->_nxt;
+ fin++;
+ }
+ if(fin < 2)
+ {
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad fan-in (OR)\n";
+ exit(1);
+ }
+ break;
+
+ case BDDDG_XOR:
+ /* Assertion check*/
+ while(lkx != BDDDG_NIL)
+ {
+ NodeLink* lp = _linkA + lkx;
+ if(BDDDG_Inv(lp->_idx))
+ {
+ inv++;
+ lp->_idx = BDDDG_InvReset(lp->_idx);
+ }
+ if(_nodeA[BDDDG_Ndx(lp->_idx)]._type == BDDDG_XOR)
+ {
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad structure (XOR)\n";
+ exit(1);
+ }
+ lkx = lp->_nxt;
+ fin++;
+ }
+ if(inv & 1) np->_f = ~(np->_f);
+ if(fin < 2)
+ {
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad fan-in (XOR)\n";
+ exit(1);
+ }
+ break;
+
+ case BDDDG_OTHER:
+ /* Assertion check*/
+ while(lkx != BDDDG_NIL)
+ {
+ NodeLink* lp = _linkA + lkx;
+ if(BDDDG_Inv(lp->_idx))
+ lp->_idx = BDDDG_InvReset(lp->_idx);
+ lkx = lp->_nxt;
+ fin++;
+ }
+ if(fin < 2)
+ {
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad fan-in (OTHER)\n";
+ exit(1);
+ }
+ break;
+ default:
+ cerr << "<ERROR> BDDDG::PhaseSweep(): Bad node type\n";
+ exit(1);
+ }
+}
+
+int BDDDG::LinkNodes(bddword idx, bddword idx2)
+{
+ if(idx == BDDDG_NIL || idx2 == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::LinkNodes(): Null node\n";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ bddword ndx2 = BDDDG_Ndx(idx2);
+ bddword lkx = NewLkx(idx2);
+ if(lkx == BDDDG_NIL) return 1;
+ _linkA[lkx]._nxt = _nodeA[ndx]._lkx;
+ _nodeA[ndx]._lkx = lkx;
+
+ bddword lkx2 = _linkA[lkx]._nxt;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idx3 = _linkA[lkx]._idx;
+ bddword idx4 = _linkA[lkx2]._idx;
+ BDD f = _nodeA[BDDDG_Ndx(idx3)]._f;
+ BDD f2 = _nodeA[BDDDG_Ndx(idx4)]._f;
+ if(f.Top() == f2.Top())
+ {
+ cerr << "<ERROR> BDDDG::LinkNodes(): Same VarIndex(";
+ cerr << f.Top() << ")\n";
+ exit(1);
+ }
+
+ if(f.Top() < f2.Top()) break;
+
+ _linkA[lkx]._idx = idx4;
+ _linkA[lkx2]._idx = idx3;
+
+ lkx = lkx2;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ return 0;
+}
+
+bddword BDDDG::Decomp(BDD f)
+{
+ if(f==0) return BDDDG_InvSet(_c1);
+ if(f==1) return _c1;
+
+ bddword idx = ReferIdx(f);
+ if(idx != BDDDG_NIL) return idx;
+
+ int top = f.Top();
+ BDD f0 = f.At0(top);
+ BDD f1 = f.At1(top);
+ bddword idx0 = Decomp(f0);
+ if(idx0 == BDDDG_NIL) return BDDDG_NIL;
+ bddword idx1 = Decomp(f1);
+ if(idx1 == BDDDG_NIL) return BDDDG_NIL;
+ idx = Merge(f, idx0, idx1);
+
+ return idx;
+}
+
+void BDDDG::MarkSweep(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::MarkSweep(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ _nodeA[ndx]._mark = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ _nodeA[BDDDG_Ndx(_linkA[lkx]._idx)]._mark = 0;
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+void BDDDG::MarkSweepR(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::MarkSweepR(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ _nodeA[ndx]._mark = 0;
+ _nodeA[ndx]._ndxP = BDDDG_NIL;
+ _nodeA[ndx]._invP = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ MarkSweepR(_linkA[lkx]._idx);
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+int BDDDG::Mark1(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::Mark1(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ int fin = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idx1 = _linkA[lkx]._idx;
+ if(BDDDG_Inv(idx1)) _nodeA[BDDDG_Ndx(idx1)]._mark = 2;
+ else _nodeA[BDDDG_Ndx(idx1)]._mark = 1;
+ fin++;
+ lkx = _linkA[lkx]._nxt;
+ }
+ return fin;
+}
+
+void BDDDG::Mark2R(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::Mark2R(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ _nodeA[ndx]._mark++;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ Mark2R(_linkA[lkx]._idx);
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+int BDDDG::MarkChkR(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::MarkChkR(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ if(_nodeA[ndx]._mark != 0) return 1;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(MarkChkR(_linkA[lkx]._idx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ return 0;
+}
+
+void BDDDG::Mark3R(bddword idx)
+{
+ if(idx == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::Mark3R(): Bad idx";
+ exit(1);
+ }
+ bddword ndx = BDDDG_Ndx(idx);
+ if(_nodeA[ndx]._mark == 2) return;
+
+ int cnt1 = 0; // not decided.
+ int cnt2 = 0; // shared node.
+ int cnt3 = 0; // non-shared node.
+ int cnt4 = 0; // (possibly) partly shared node.
+
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ Mark3R(idt);
+ switch(_nodeA[BDDDG_Ndx(idt)]._mark)
+ {
+ case 1:
+ cnt1++;
+ break;
+ case 2:
+ cnt2++;
+ break;
+ case 3:
+ cnt3++;
+ break;
+ case 4:
+ cnt4++;
+ break;
+ default:
+ break;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(_nodeA[ndx]._type == BDDDG_OR || _nodeA[ndx]._type == BDDDG_XOR)
+ {
+ if(cnt2 >= 2)
+ {
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ _nodeA[BDDDG_Ndx(idt)]._ndxP = ndx;
+ _nodeA[BDDDG_Ndx(idt)]._invP = (char) BDDDG_Inv(idt);
+ lkx = _linkA[lkx]._nxt;
+ }
+ _nodeA[ndx]._mark = 4;
+ return;
+ }
+ }
+
+ if(cnt1 + cnt2 + cnt4 == 0 && _nodeA[ndx]._mark == 1)
+ _nodeA[ndx]._mark = 3;
+}
+
+bddword BDDDG::Merge(BDD f, bddword idx0, bddword idx1)
+{
+ if(idx0 == BDDDG_NIL || idx1 == BDDDG_NIL)
+ {
+ cerr << "<ERROR> BDDDG::Merge(): Null node\n";
+ exit(1);
+ }
+ bddword ndx0 = BDDDG_Ndx(idx0);
+ bddword ndx1 = BDDDG_Ndx(idx1);
+
+ int top = f.Top(); // (top > 0)
+
+ // Case3-LIT ?
+ if(BDDDG_InvReset(idx0) == _c1 && BDDDG_InvReset(idx1) == _c1)
+ {
+ bddword idx = ReferIdx(f);
+ if(idx == BDDDG_NIL)
+ {
+ bddword ndx = NewNdx(BDDvar(top), BDDDG_LIT);
+ if(ndx == BDDDG_NIL) return BDDDG_NIL;
+ idx = BDDDG_PackIdx(ndx, f != BDDvar(top));
+ }
+ return idx;
+ }
+
+ // Case3-OR ?
+ if(BDDDG_InvReset(idx1) == _c1)
+ {
+ bddword idx = ReferIdx(BDDvar(top));
+ if(idx == BDDDG_NIL)
+ {
+ bddword ndx = NewNdx(BDDvar(top), BDDDG_LIT);
+ if(ndx == BDDDG_NIL) return BDDDG_NIL;
+ idx = BDDDG_PackIdx(ndx, 0);
+ }
+ bddword ndy = NewNdx(BDDDG_Inv(idx1)? ~f: f, BDDDG_OR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx1));
+ if(LinkNodes(idy, idx)) return BDDDG_NIL;
+ if(_nodeA[ndx0]._type != BDDDG_OR ||
+ BDDDG_Inv(idx0) != BDDDG_Inv(idx1) )
+ {
+ if(LinkNodes(idy, BDDDG_Inv(idx1)? BDDDG_InvAlt(idx0): idx0))
+ return BDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(LinkNodes(idy, _linkA[lkx]._idx)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ PhaseSweep(idy);
+ return idy;
+ }
+
+ if(BDDDG_InvReset(idx0) == _c1)
+ {
+ bddword idx = ReferIdx(~BDDvar(top));
+ if(idx == BDDDG_NIL)
+ {
+ bddword ndx = NewNdx(BDDvar(top), BDDDG_LIT);
+ if(ndx == BDDDG_NIL) return BDDDG_NIL;
+ idx = BDDDG_PackIdx(ndx, 1);
+ }
+ bddword ndy = NewNdx(BDDDG_Inv(idx0)? ~f: f, BDDDG_OR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx0));
+ if(LinkNodes(idy, idx)) return BDDDG_NIL;
+ if(_nodeA[ndx1]._type != BDDDG_OR ||
+ BDDDG_Inv(idx1) != BDDDG_Inv(idx0) )
+ {
+ if(LinkNodes(idy, BDDDG_Inv(idx0)? BDDDG_InvAlt(idx1): idx1))
+ return BDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(LinkNodes(idy, _linkA[lkx]._idx)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ PhaseSweep(idy);
+ return idy;
+ }
+
+ // Case3-XOR ?
+ if(ndx0 == ndx1)
+ {
+ if(idx0 == idx1) { cout << "ERROR\n"; exit(1); }
+
+ bddword idx = ReferIdx(BDDvar(top));
+ if(idx == BDDDG_NIL)
+ {
+ bddword ndx = NewNdx(BDDvar(top), BDDDG_LIT);
+ if(ndx == BDDDG_NIL) return BDDDG_NIL;
+ idx = BDDDG_PackIdx(ndx, 0);
+ }
+
+ bddword ndy = NewNdx(BDDDG_Inv(idx0)? ~f: f, BDDDG_XOR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx0));
+ if(LinkNodes(idy, idx)) return BDDDG_NIL;
+ if(_nodeA[ndx0]._type != BDDDG_XOR)
+ {
+ if(LinkNodes(idy, BDDDG_InvReset(idx0))) return BDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(LinkNodes(idy, _linkA[lkx]._idx)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ PhaseSweep(idy);
+ return idy;
+ }
+
+ // Case1-OR ?
+ if(_nodeA[ndx0]._type == BDDDG_OR && _nodeA[ndx1]._type == BDDDG_OR
+ && BDDDG_Inv(idx0) == BDDDG_Inv(idx1))
+ {
+ int fin0 = 0;
+ int fin1 = 0;
+ int fin2 = 0;
+
+ fin0 = Mark1(idx0);
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == (BDDDG_Inv(idt)? 2: 1))
+ {
+ fin2++;
+ _nodeA[BDDDG_Ndx(idt)]._mark = 3;
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin1++;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword idy0;
+ if(fin0 - fin2 > 1)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ {
+ BDD g2 = _nodeA[BDDDG_Ndx(idt)]._f;
+ g |= BDDDG_Inv(idt)? ~g2: g2;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_OR);
+ if(ndy0 == BDDDG_NIL) return BDDDG_NIL;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ if(LinkNodes(idy0, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin0 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ { idy0 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else idy0 = BDDDG_InvSet(_c1);
+
+ bddword idy1;
+ if(fin1 - fin2 > 1)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ {
+ BDD g2 = _nodeA[BDDDG_Ndx(idt)]._f;
+ g |= BDDDG_Inv(idt)? ~g2: g2;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy1 = ReferIdx(g);
+ if(idy1 == BDDDG_NIL)
+ {
+ bddword ndy1 = NewNdx(g, BDDDG_OR);
+ if(ndy1 == BDDDG_NIL) return BDDDG_NIL;
+ idy1 = BDDDG_PackIdx(ndy1, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ if(LinkNodes(idy1, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin1 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ { idy1 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else idy1 = BDDDG_InvSet(_c1);
+
+ bddword ndy = NewNdx(BDDDG_Inv(idx0)? ~f: f, BDDDG_OR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx0));
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweep(idx0);
+ if(Merge3(idy, idy0, idy1)) return BDDDG_NIL;;
+ return idy;
+ }
+ MarkSweep(idx0);
+ }
+
+ // Case1-XOR ?
+ if(_nodeA[ndx0]._type == BDDDG_XOR && _nodeA[ndx1]._type == BDDDG_XOR)
+ {
+ int fin0 = 0;
+ int fin1 = 0;
+ int fin2 = 0;
+
+ fin0 = Mark1(idx0);
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 0)
+ { fin2++; _nodeA[BDDDG_Ndx(idt)]._mark = 3; }
+ lkx = _linkA[lkx]._nxt;
+ fin1++;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword idy0;
+ if(fin0 - fin2 > 1)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ g ^= _nodeA[BDDDG_Ndx(idt)]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_XOR);
+ if(ndy0 == BDDDG_NIL) return BDDDG_NIL;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ if(LinkNodes(idy0, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin0 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ { idy0 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else idy0 = BDDDG_InvSet(_c1);
+
+ bddword idy1;
+ if(fin1 - fin2 > 1)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ g ^= _nodeA[BDDDG_Ndx(idt)]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy1 = ReferIdx(g);
+ if(idy1 == BDDDG_NIL)
+ {
+ bddword ndy1 = NewNdx(g, BDDDG_XOR);
+ if(ndy1 == BDDDG_NIL) return BDDDG_NIL;
+ idy1 = BDDDG_PackIdx(ndy1, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ if(LinkNodes(idy1, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin1 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 3)
+ { idy1 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else idy1 = BDDDG_InvSet(_c1);
+
+ if(BDDDG_Inv(idx0)) idy0 = BDDDG_InvAlt(idy0);
+ if(BDDDG_Inv(idx1)) idy1 = BDDDG_InvAlt(idy1);
+
+ bddword ndy = NewNdx(f, BDDDG_XOR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweep(idx0);
+ if(Merge3(idy, idy0, idy1)) return BDDDG_NIL;;
+ return (f == _nodeA[ndy]._f)? idy: BDDDG_InvAlt(idy);
+ }
+ MarkSweep(idx0);
+ }
+
+ // Case2-OR(a)? part 0
+ if(_nodeA[ndx1]._type == BDDDG_OR)
+ {
+ int fin1 = 0;
+ int fin2 = 0;
+ _nodeA[ndx0]._mark = 1;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 1)
+ {
+ fin2++;
+ if(BDDDG_Inv(idt)) _nodeA[BDDDG_Ndx(idt)]._mark = 2;
+ }
+ fin1++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0 &&
+ (_nodeA[ndx0]._mark == 2) == (BDDDG_Inv(idx0)!=BDDDG_Inv(idx1)))
+ {
+ bddword idy1;
+ if(fin1 > 2)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ {
+ BDD g2 = _nodeA[BDDDG_Ndx(idt)]._f;
+ g |= BDDDG_Inv(idt)? ~g2: g2;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy1 = ReferIdx(g);
+ if(idy1 == BDDDG_NIL)
+ {
+ bddword ndy1 = NewNdx(g, BDDDG_OR);
+ if(ndy1 == BDDDG_NIL) return BDDDG_NIL;
+ idy1 = BDDDG_PackIdx(ndy1, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ if(LinkNodes(idy1, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ { idy1 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword ndy = NewNdx(BDDDG_Inv(idx1)? ~f: f, BDDDG_OR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx1));
+ if(LinkNodes(idy, (_nodeA[ndx0]._mark==1)?
+ BDDDG_InvReset(idx0): BDDDG_InvSet(idx0)) )
+ return BDDDG_NIL;
+
+ _nodeA[ndx0]._mark = 0;
+ if(Merge3(idy, BDDDG_InvSet(_c1), idy1)) return BDDDG_NIL;;
+ return idy;
+ }
+ _nodeA[ndx0]._mark = 0;
+ }
+
+ // Case2-OR(a)? part 1
+ if(_nodeA[ndx0]._type == BDDDG_OR)
+ {
+ int fin0 = 0;
+ int fin2 = 0;
+ _nodeA[ndx1]._mark = 1;
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 1)
+ {
+ fin2++;
+ if(BDDDG_Inv(idt)) _nodeA[BDDDG_Ndx(idt)]._mark = 2;
+ }
+ fin0++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0 &&
+ (_nodeA[ndx1]._mark == 2) == (BDDDG_Inv(idx0)!=BDDDG_Inv(idx1)))
+ {
+ bddword idy0;
+ if(fin0 > 2)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ {
+ BDD g2 = _nodeA[BDDDG_Ndx(idt)]._f;
+ g |= BDDDG_Inv(idt)? ~g2: g2;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_OR);
+ if(ndy0 == BDDDG_NIL) return BDDDG_NIL;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ if(LinkNodes(idy0, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ { idy0 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword ndy = NewNdx(BDDDG_Inv(idx0)? ~f: f, BDDDG_OR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, BDDDG_Inv(idx0));
+ if(LinkNodes(idy, (_nodeA[ndx1]._mark==1)?
+ BDDDG_InvReset(idx1): BDDDG_InvSet(idx1)) )
+ return BDDDG_NIL;
+
+ _nodeA[ndx1]._mark = 0;
+ if(Merge3(idy, idy0, BDDDG_InvSet(_c1))) return BDDDG_NIL;;
+ return idy;
+ }
+ _nodeA[ndx1]._mark = 0;
+ }
+
+ // Case2-XOR(a)? part 0
+ if(_nodeA[ndx1]._type == BDDDG_XOR)
+ {
+ int fin1 = 0;
+ int fin2 = 0;
+ _nodeA[ndx0]._mark = 1;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 1) fin2++;
+ fin1++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword idy1;
+ if(fin1 > 2)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ g ^= _nodeA[BDDDG_Ndx(idt)]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy1 = ReferIdx(g);
+ if(idy1 == BDDDG_NIL)
+ {
+ bddword ndy1 = NewNdx(g, BDDDG_XOR);
+ if(ndy1 == BDDDG_NIL) return BDDDG_NIL;
+ idy1 = BDDDG_PackIdx(ndy1, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ if(LinkNodes(idy1, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ { idy1 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword idy0 = BDDDG_InvSet(_c1);
+
+ if(BDDDG_Inv(idx0)) idy0 = BDDDG_InvAlt(idy0);
+ if(BDDDG_Inv(idx1)) idy1 = BDDDG_InvAlt(idy1);
+
+ bddword ndy = NewNdx(f, BDDDG_XOR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ if(LinkNodes(idy, BDDDG_InvReset(idx0)))
+ return BDDDG_NIL;
+
+ _nodeA[ndx0]._mark = 0;
+ if(Merge3(idy, idy0, idy1)) return BDDDG_NIL;;
+ return (f == _nodeA[ndy]._f)? idy: BDDDG_InvAlt(idy);
+ }
+ _nodeA[ndx0]._mark = 0;
+ }
+
+ // Case2-XOR(a)? part 1
+ if(_nodeA[ndx0]._type == BDDDG_XOR)
+ {
+ int fin0 = 0;
+ int fin2 = 0;
+ _nodeA[ndx1]._mark = 1;
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 1) fin2++;
+ fin0++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword idy0;
+ if(fin0 > 2)
+ {
+ BDD g = 0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ g ^= _nodeA[BDDDG_Ndx(idt)]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_XOR);
+ if(ndy0 == BDDDG_NIL) return BDDDG_NIL;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ if(LinkNodes(idy0, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 0)
+ { idy0 = _linkA[lkx]._idx; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword idy1 = BDDDG_InvSet(_c1);
+
+ if(BDDDG_Inv(idx0)) idy0 = BDDDG_InvAlt(idy0);
+ if(BDDDG_Inv(idx1)) idy1 = BDDDG_InvAlt(idy1);
+
+ bddword ndy = NewNdx(f, BDDDG_XOR);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ if(LinkNodes(idy, BDDDG_InvReset(idx1)))
+ return BDDDG_NIL;
+
+ _nodeA[ndx1]._mark = 0;
+ if(Merge3(idy, idy0, idy1)) return BDDDG_NIL;;
+ return (f == _nodeA[ndy]._f)? idy: BDDDG_InvAlt(idy);
+ }
+ _nodeA[ndx1]._mark = 0;
+ }
+
+
+ // Case1-OTHER ?
+ if(_nodeA[ndx0]._type == BDDDG_OTHER
+ && _nodeA[ndx1]._type == BDDDG_OTHER)
+ {
+ int fin0 = 0;
+ int fin1 = 0;
+ int fin2 = 0;
+
+ fin0 = Mark1(idx0);
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark != 0)
+ { fin2++; _nodeA[BDDDG_Ndx(idt)]._mark = 3; }
+ lkx = _linkA[lkx]._nxt;
+ fin1++;
+ }
+
+ // Case1-OTHER(a) ?
+ if(fin2 > 0 && fin0 - fin2 == 1 && fin1 - fin2 == 1)
+ {
+ bddword idy0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+
+ idy0 = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idy0)]._mark != 3) break;
+ lkx = _linkA[lkx]._nxt;
+ }
+ bddword idy1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+
+ idy1 = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idy1)]._mark != 3) break;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ BDD f0 = _nodeA[ndx0]._f;
+ BDD f1 = _nodeA[ndx1]._f;
+ BDD g0 = _nodeA[BDDDG_Ndx(idy0)]._f;
+ BDD g1 = _nodeA[BDDDG_Ndx(idy1)]._f;
+
+ if(Func0(f0, g0) == Func0(f1, g1) &&
+ Func0(f0, ~g0) == Func0(f1, ~g1))
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweep(idx0);
+ if(Merge3(idy, idy0, idy1)) return BDDDG_NIL;;
+ return idy;
+ }
+
+ if(Func0(f0, g0) == Func0(f1, ~g1) &&
+ Func0(f0, ~g0) == Func0(f1, g1))
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy, idt)) return BDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweep(idx0);
+ if(Merge3(idy, idy0, BDDDG_InvAlt(idy1))) return BDDDG_NIL;;
+ return idy;
+ }
+
+ }
+ MarkSweep(idx0);
+
+ // Case1-OTHER(b) ?
+ if(fin2 > 1 && fin0 == fin2 && fin1 == fin2)
+ {
+ BDD f0 = f.At0(top);
+ BDD f1 = f.At1(top);
+ bddword idy0;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ idy0 = _linkA[lkx]._idx;
+ BDD g0 = _nodeA[BDDDG_Ndx(idy0)]._f;
+ if(Func0(f0, g0) == Func0(f1, ~g0) &&
+ Func0(f0, ~g0) == Func0(f1, g0) )
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ bddword lkx2 = _nodeA[ndx0]._lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ if(lkx != lkx2)
+ if(LinkNodes(idy, _linkA[lkx2]._idx)) return BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+
+ if(Merge3(idy, idy0, BDDDG_InvAlt(idy0))) return BDDDG_NIL;
+ return idy;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+
+ // Case2-OTHER ? part 0
+ if(_nodeA[ndx1]._type == BDDDG_OTHER)
+ {
+ Mark2R(idx0);
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idy1 = _linkA[lkx]._idx;
+ if(MarkChkR(idy1) == 0)
+ {
+ BDD f0 = _nodeA[ndx0]._f;
+ f0 = BDDDG_Inv(idx0)? ~f0: f0;
+ BDD f1 = _nodeA[ndx1]._f;
+ f1 = BDDDG_Inv(idx1)? ~f1: f1;
+ BDD g1 = _nodeA[BDDDG_Ndx(idy1)]._f;
+ BDD h = Func0(f1, g1);
+ //if(h == f0 || h == ~f0)
+ if(h == f0)
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ bddword lkx2 = _nodeA[ndx1]._lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ if(lkx != lkx2)
+ if(LinkNodes(idy, _linkA[lkx2]._idx)) return BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+
+ MarkSweepR(idx0);
+ if(Merge3(idy, BDDDG_InvAlt(_c1), idy1)) return BDDDG_NIL;
+ return idy;
+ }
+ h = Func0(f1, ~g1);
+ //if(h == f0 || h == ~f0)
+ if(h == f0)
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ bddword lkx2 = _nodeA[ndx1]._lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ if(lkx != lkx2)
+ if(LinkNodes(idy, _linkA[lkx2]._idx)) return BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+
+ MarkSweepR(idx0);
+ if(Merge3(idy, _c1, idy1)) return BDDDG_NIL;
+ return idy;
+ }
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ MarkSweepR(idx0);
+ }
+
+ // Case2-OTHER ? part 1
+ if(_nodeA[ndx0]._type == BDDDG_OTHER)
+ {
+ Mark2R(idx1);
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idy0 = _linkA[lkx]._idx;
+ if(MarkChkR(idy0) == 0)
+ {
+ BDD f0 = _nodeA[ndx0]._f;
+ f0 = BDDDG_Inv(idx0)? ~f0: f0;
+ BDD f1 = _nodeA[ndx1]._f;
+ f1 = BDDDG_Inv(idx1)? ~f1: f1;
+ BDD g0 = _nodeA[BDDDG_Ndx(idy0)]._f;
+ BDD h = Func0(f0, g0);
+ //if(h == f1 || f == ~f1)
+ if(h == f1)
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ bddword lkx2 = _nodeA[ndx0]._lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ if(lkx != lkx2)
+ if(LinkNodes(idy, _linkA[lkx2]._idx)) return BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+
+ MarkSweepR(idx1);
+ if(Merge3(idy, idy0, BDDDG_InvAlt(_c1))) return BDDDG_NIL;
+ return idy;
+ }
+ h = Func0(f0, ~g0);
+ //if(h == f1 || f == ~f1)
+ if(h == f1)
+ {
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ bddword lkx2 = _nodeA[ndx0]._lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ if(lkx != lkx2)
+ if(LinkNodes(idy, _linkA[lkx2]._idx)) return BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+
+ MarkSweepR(idx1);
+ if(Merge3(idy, idy0, _c1)) return BDDDG_NIL;
+ return idy;
+ }
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ MarkSweepR(idx1);
+ }
+
+ // Case3-OTHER?
+ MarkSweepR(idx0);
+ MarkSweepR(idx1);
+ Mark2R(idx0);
+ Mark2R(idx1);
+ Mark3R(idx0);
+ Mark3R(idx1);
+
+ bddword idx = ReferIdx(BDDvar(top));
+ if(idx == BDDDG_NIL)
+ {
+ bddword ndx = NewNdx(BDDvar(top), BDDDG_LIT);
+ if(ndx == BDDDG_NIL) return BDDDG_NIL;
+ idx = BDDDG_PackIdx(ndx, 0);
+ }
+
+ bddword ndy = NewNdx(f, BDDDG_OTHER);
+ if(ndy == BDDDG_NIL) return BDDDG_NIL;
+ bddword idy = BDDDG_PackIdx(ndy, 0);
+ if(LinkNodes(idy, idx)) return BDDDG_NIL;
+ if(LinkNodesC3(idy, idx0)) return BDDDG_NIL;
+ if(LinkNodesC3(idy, idx1)) return BDDDG_NIL;
+ PhaseSweep(idy);
+ MarkSweepR(idx0);
+ MarkSweepR(idx1);
+ return idy;
+}
+
+int BDDDG::LinkNodesC3(bddword idy, bddword idx)
+{
+ bddword ndx = BDDDG_Ndx(idx);
+ bddword lkx;
+ switch(_nodeA[ndx]._mark)
+ {
+ case 1:
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(LinkNodesC3(idy, _linkA[lkx]._idx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ break;
+ case 2:
+ if(LinkNodes(idy, idx)) return 1;
+ _nodeA[ndx]._mark = 9;
+ break;
+ case 3:
+ if(LinkNodes(idy, idx)) return 1;
+ break;
+ case 4:
+ {
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ bddword ndxP = _nodeA[BDDDG_Ndx(idt)]._ndxP;
+ if(ndxP != BDDDG_NIL && ndxP != ndx)
+ {
+ if(_nodeA[ndxP]._type == BDDDG_OR &&
+ _nodeA[ndx]._type == BDDDG_OR )
+ {
+ BDD g = 0;
+ int fin = 0;
+ bddword lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ {
+ if(_nodeA[BDDDG_Ndx(idt2)]._invP
+ != (char) BDDDG_Inv(idt2))
+ _nodeA[BDDDG_Ndx(idt2)]._ndxP = BDDDG_NIL;
+ else
+ {
+ BDD g2 = _nodeA[BDDDG_Ndx(idt2)]._f;
+ g |= BDDDG_Inv(idt2)? ~g2:g2;
+ fin++;
+ }
+ }
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_OR);
+ if(ndy0 == BDDDG_NIL) return 1;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ if(LinkNodes(idy0, idt2)) return 1;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ if(LinkNodes(idy, idy0)) return 1;
+
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ _nodeA[BDDDG_Ndx(idt2)]._mark = 9;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ _nodeA[BDDDG_Ndx(idt2)]._ndxP = BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+
+ if(_nodeA[ndxP]._type == BDDDG_XOR &&
+ _nodeA[ndx]._type == BDDDG_XOR )
+ {
+ BDD g = 0;
+ int fin = 0;
+ bddword lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ {
+ g ^= _nodeA[BDDDG_Ndx(idt2)]._f;
+ fin++;
+ }
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_XOR);
+ if(ndy0 == BDDDG_NIL) return 1;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ if(LinkNodes(idy0, idt2)) return 1;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ if(LinkNodes(idy, idy0)) return 1;
+
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ _nodeA[BDDDG_Ndx(idt2)]._mark = 9;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ lkx2 = lkx;
+ while(lkx2 != BDDDG_NIL)
+ {
+ bddword idt2 = _linkA[lkx2]._idx;
+ if(ndxP == _nodeA[BDDDG_Ndx(idt2)]._ndxP)
+ _nodeA[BDDDG_Ndx(idt2)]._ndxP = BDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+
+
+ if(_nodeA[ndx]._type == BDDDG_OR)
+ {
+ BDD g = 0;
+ int fin = 0;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ {
+ g |= _nodeA[BDDDG_Ndx(idt)]._f;
+ fin++;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_OR);
+ if(ndy0 == BDDDG_NIL) return 1;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy0, idt)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(LinkNodes(idy, idy0)) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ _nodeA[BDDDG_Ndx(idt)]._mark = 9;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+
+ if(_nodeA[ndx]._type == BDDDG_XOR)
+ {
+ BDD g = 0;
+ int fin = 0;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ {
+ g ^= _nodeA[BDDDG_Ndx(idt)]._f;
+ fin++;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword idy0 = ReferIdx(g);
+ if(idy0 == BDDDG_NIL)
+ {
+ bddword ndy0 = NewNdx(g, BDDDG_XOR);
+ if(ndy0 == BDDDG_NIL) return 1;
+ idy0 = BDDDG_PackIdx(ndy0, 0);
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ if(LinkNodes(idy0, idt)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(LinkNodes(idy, idy0)) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ bddword idt = _linkA[lkx]._idx;
+ if(_nodeA[BDDDG_Ndx(idt)]._mark == 3)
+ _nodeA[BDDDG_Ndx(idt)]._mark = 9;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ }
+
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ if(LinkNodesC3(idy, _linkA[lkx]._idx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ break;
+ case 9:
+ break;
+ default:
+ cerr << "<ERROR> BDDDG::LinkNodesC3(): wrong case (";
+ cerr << _nodeA[ndx]._mark << ")\n";
+ exit(1);
+ }
+ return 0;
+}
+
+BDD BDDDG::Func0(BDD f, BDD g)
+{
+ BDD h = f;
+ while(g != 0)
+ {
+ int top = g.Top();
+ BDD g0 = g.At0(top);
+ if(g0 != 1)
+ {
+ g = g0;
+ h = h.At0(top);
+ }
+ else
+ {
+ g = g.At1(top);
+ h = h.At1(top);
+ }
+ }
+ return h;
+}
+
+int BDDDG::Merge3(bddword idy, bddword idy0, bddword idy1)
+{
+ int top = _nodeA[BDDDG_Ndx(idy)]._f.Top();
+ BDD h0 = BDDDG_Inv(idy0)?
+ ~(_nodeA[BDDDG_Ndx(idy0)]._f): _nodeA[BDDDG_Ndx(idy0)]._f;
+ BDD h1 = BDDDG_Inv(idy1)?
+ ~(_nodeA[BDDDG_Ndx(idy1)]._f): _nodeA[BDDDG_Ndx(idy1)]._f;
+ BDD h = (~BDDvar(top) & h0) | (BDDvar(top) & h1);
+ bddword idx = ReferIdx(h);
+ if(idx == BDDDG_NIL) idx = Merge(h, idy0, idy1);
+ if(idx == BDDDG_NIL) return 1;
+ if(LinkNodes(idy, idx)) return BDDDG_NIL;
+ PhaseSweep(idy);
+ return 0;
+}
+
+int BDDDG::PrintDecomp(BDD f)
+{
+ bddword idx = Decomp(f);
+ if(idx == BDDDG_NIL) return 1;
+ Print0(idx);
+ cout << "\n";
+ return 0;
+}
+
+void BDDDG::Print0(bddword idx)
+{
+ if(BDDDG_Inv(idx)) cout << "!";
+ bddword ndx = BDDDG_Ndx(idx);
+ bddword lkx;
+ switch(_nodeA[ndx]._type)
+ {
+ case BDDDG_C1:
+ cout << "1 ";
+ break;
+ case BDDDG_LIT:
+ cout << "x" << _nodeA[ndx]._f.Top() << " ";
+ break;
+ case BDDDG_OR:
+ cout << "OR( ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._idx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << ") ";
+ break;
+ case BDDDG_XOR:
+ cout << "XOR( ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._idx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << ") ";
+ break;
+ case BDDDG_OTHER:
+ cout << "[ ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != BDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._idx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << "] ";
+ break;
+ default:
+ cerr << "<ERROR> BDDDG::Print0: wrong case (";
+ cerr << (int)_nodeA[ndx]._type << ")\n";
+ exit(1);
+ }
+}
+
--- /dev/null
+/****************************************
+ * BDD+ Manipulator (SAPPORO-1.21) *
+ * (Hash table methods) *
+ * (C) Shin-ichi MINATO (Feb. 18, 2009) *
+ ****************************************/
+
+#include "BDD.h"
+
+BDD_Hash::BDD_Hash()
+{
+ _hashSize = 16;
+ _wheel = new BDD_Entry[_hashSize];
+ _amount = 0;
+}
+
+BDD_Hash::~BDD_Hash() { delete[] _wheel; }
+
+void BDD_Hash::Clear()
+{
+ if(_hashSize != 0) delete[] _wheel;
+ _hashSize = 16;
+ _wheel = new BDD_Entry[_hashSize];
+ _amount = 0;
+}
+
+BDD_Hash::BDD_Entry* BDD_Hash::GetEntry(BDD key)
+{
+ bddword id = key.GetID();
+ bddword hash = (id+(id>>10)+(id>>20)) & (_hashSize - 1);
+ bddword i = hash;
+ while(_wheel[i]._key != -1)
+ {
+ if(key == _wheel[i]._key) return & _wheel[i];
+ i++;
+ i &= (_hashSize -1);
+ }
+ i = hash;
+ while(_wheel[i]._key != -1)
+ {
+ if(_wheel[i]._ptr == 0) break;
+ i++;
+ i &= (_hashSize -1);
+ }
+ return & _wheel[i];
+}
+
+void BDD_Hash::Enlarge()
+{
+ bddword oldSize = _hashSize;
+ BDD_Entry* oldWheel = _wheel;
+
+ _hashSize <<= 2;
+ _wheel = new BDD_Entry[_hashSize];
+ if(_wheel == 0)
+ {
+ cerr << "<ERROR> BDD_Hash::Enlarge(): Memory overflow (";
+ cerr << _hashSize << ")\n";
+ exit(1);
+ }
+ _amount = 0;
+ for(bddword i=0; i<oldSize; i++)
+ if(oldWheel[i]._ptr != 0)
+ if(oldWheel[i]._key != -1)
+ Enter(oldWheel[i]._key, oldWheel[i]._ptr);
+ delete[] oldWheel;
+}
+
+void BDD_Hash::Enter(BDD key, void* ptr)
+// ptr = 0 means deleting.
+{
+ BDD_Entry* ent = GetEntry(key);
+ if(ent -> _key == -1) _amount++;
+ else if(ent -> _ptr == 0) _amount++;
+ if(ptr == 0) _amount--;
+ ent -> _key = key;
+ ent -> _ptr = ptr;
+ if(_amount >= (_hashSize>>1)) Enlarge();
+}
+
+void* BDD_Hash::Refer(BDD key)
+// returns 0 if not found.
+{
+ BDD_Entry* ent = GetEntry(key);
+ if(ent -> _key == -1) return 0;
+ return ent -> _ptr;
+}
+
+bddword BDD_Hash::Amount() { return _amount; }
+
--- /dev/null
+/****************************************
+ * BDD+ Manipulator (SAPPORO-1.55) *
+ * (Graphic methods) *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ****************************************/
+
+#include "BDD.h"
+
+void BDD::XPrint0() const
+{
+ bddgraph0(_bdd);
+}
+
+void BDDV::XPrint0() const
+{
+ bddword* bddv = new bddword[_len];
+ for(int i=0; i<_len; i++) bddv[i] = GetBDD(i).GetID();
+ bddvgraph0(bddv, _len);
+ delete[] bddv;
+}
+
+void BDD::XPrint() const
+{
+ bddgraph(_bdd);
+}
+
+void BDDV::XPrint() const
+{
+ bddword* bddv = new bddword[_len];
+ for(int i=0; i<_len; i++) bddv[i] = GetBDD(i).GetID();
+ bddvgraph(bddv, _len);
+ delete[] bddv;
+}
+
--- /dev/null
+/******************************************
+ * Binary-to-Integer function class *
+ * (SAPPORO-1.55) - Body *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ******************************************/
+
+#include "BtoI.h"
+
+BtoI::BtoI(int n)
+{
+ int k = n;
+ if(k < 0)
+ {
+ k = -k;
+ if(k < 0) BDDerr("BtoI::BtoI(): overflow.", n);
+ }
+ while(k != 0)
+ {
+ if((k & 1) != 0) _bddv = _bddv || BDD(1);
+ else _bddv = _bddv || BDD(0);
+ k >>= 1;
+ }
+ _bddv = _bddv || BDD(0);
+ if(n < 0) *this = - (*this);
+}
+
+BtoI& BtoI::operator+=(const BtoI& fv) { return *this = *this + fv; }
+BtoI& BtoI::operator-=(const BtoI& fv) { return *this = *this - fv; }
+BtoI& BtoI::operator*=(const BtoI& fv) { return *this = *this * fv; }
+BtoI& BtoI::operator/=(const BtoI& fv) { return *this = *this / fv; }
+BtoI& BtoI::operator%=(const BtoI& fv) { return *this = *this % fv; }
+BtoI& BtoI::operator&=(const BtoI& fv) { return *this = *this & fv; }
+BtoI& BtoI::operator|=(const BtoI& fv) { return *this = *this | fv; }
+BtoI& BtoI::operator^=(const BtoI& fv) { return *this = *this ^ fv; }
+BtoI& BtoI::operator<<=(const BtoI& fv) { return *this = *this << fv; }
+BtoI& BtoI::operator>>=(const BtoI& fv) { return *this = *this >> fv; }
+
+BtoI BtoI::Shift(int power) const
+{
+ if(power == 0) return *this;
+ if(power > 0)
+ {
+ if(*this == 0) return *this;
+ return BtoI(BDDV(0, power) || _bddv);
+ }
+ int p = -power;
+ int len = Len();
+ if(p >= len) p = len-1;
+ return BtoI(_bddv.Part(p, len - p));
+}
+
+BtoI BtoI::operator<<(const BtoI& fv) const
+{
+ if(_bddv == BDDV(-1)) return *this;
+ if(fv == BtoI(BDD(-1))) return fv;
+ BtoI ffv = fv;
+ BDD sign = ffv.GetSignBDD();
+ BtoI p1 = BtoI_ITE(sign, 0, *this);
+ BtoI n1 = BtoI_ITE(sign, *this, 0);
+ BtoI p2 = BtoI_ITE(sign, 0, ffv);
+ BtoI n2 = BtoI_ITE(sign, -ffv, 0);
+
+ for(int i=0; i<ffv.Len(); i++)
+ {
+ BDD f = p2.GetBDD(i);
+ if(f != 0) p1 = BtoI_ITE(f, p1.Shift(1 << i), p1);
+ f = n2.GetBDD(i);
+ if(f != 0) n1 = BtoI_ITE(f, n1.Shift(-(1 << i)), n1);
+ }
+ return p1 | n1;
+}
+
+BtoI BtoI::Sup() const
+{
+ BDDV fv = _bddv;
+ int len = fv.Len();
+ while(len > 1)
+ {
+ if(fv.GetBDD(len-1) != fv.GetBDD(len-2))
+ break;
+ fv = fv.Part(0, --len);
+ }
+ return BtoI(fv);
+}
+
+BtoI BtoI::UpperBound() const
+{
+ if(_bddv == BDDV(-1)) return *this;
+ BDD d = GetSignBDD();
+ BDD c0 = BDD(d==1);
+ BDDV ub = c0;
+ BDD cond = c0 | ~d;
+ for(int i=Len()-2; i>=0; i--)
+ {
+ d = GetBDD(i);
+ c0 = BDD((cond & d) != 0);
+ if(c0 == -1) return BtoI(BDD(-1));
+ ub = c0 || ub;
+ cond &= ~c0 | d;
+ }
+ return BtoI(ub).Sup();
+}
+
+BtoI BtoI::UpperBound(const BDD& f) const
+{
+ if(_bddv == BDDV(-1)) return *this;
+ if(f == -1) return BtoI(BDDV(-1));
+ BDD d = GetSignBDD();
+ BDD c0 = d.Univ(f);
+ BDDV ub = c0;
+ BDD cond = c0 | ~d;
+ for(int i=Len()-2; i>=0; i--)
+ {
+ d = GetBDD(i);
+ c0 = (cond & d).Exist(f);
+ if(c0 == -1) return BtoI(BDD(-1));
+ ub = c0 || ub;
+ cond &= ~c0 | d;
+ }
+ return BtoI(ub).Sup();
+}
+
+int BtoI::GetInt() const
+{
+ if(Top() > 0)
+ {
+ if(_bddv == BDDV(-1)) return 0;
+ return At0(Top()).GetInt();
+ }
+ if(GetSignBDD() != 0) return - (- *this).GetInt();
+ int len = Len();
+ if(len > 32) len = 32; // Assuming 32-bit int.
+ int n = 0;
+ for(int i=len-2; i>=0; i--)
+ {
+ n <<= 1;
+ if(GetBDD(i) != 0) n |= 1;
+ }
+ return n;
+}
+
+static const char table[] = "0123456789ABCDEF";
+
+int BtoI::StrNum10(char* s) const
+{
+ if(*this == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ const int width = 9;
+ BtoI fv0 = *this;
+ while(fv0.Top() > 0) fv0 = fv0.At0(fv0.Top());
+ int i=0;
+ int sign = 0;
+ if(fv0.GetSignBDD() == 1)
+ {
+ sign = 1;
+ fv0 = -fv0;
+ }
+ BtoI a;
+ char s0[12];
+ if(fv0.Len() > 29)
+ {
+ BtoI fvb = BtoI(1000000000); // 10 ** width
+ while(1)
+ {
+ BtoI t = BtoI_GE(fv0, fvb);
+ if(t == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ if(t == BtoI(0)) break;
+ a = fv0 % fvb;
+ if(a == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ sprintf(s0, "%09d", a.GetInt());
+ for(int j=i-1; j>=0; j--) s[j+width] = s[j];
+ for(int j=0; j<width; j++) s[j] = s0[j];
+ i += width;
+ fv0 /= fvb;
+ }
+ }
+ sprintf(s0, "%d", fv0.GetInt());
+ int len = strlen(s0);
+ for(int j=i-1; j>=0; j--) s[j+len] = s[j];
+ for(int j=0; j<len; j++) s[j] = s0[j];
+ i += len;
+ if(sign == 1)
+ {
+ for(int j=i-1; j>=0; j--) s[j+1] = s[j];
+ s[0] = '-';
+ i++;
+ }
+ s[i] = 0;
+ return 0;
+}
+
+int BtoI::StrNum16(char* s) const
+{
+ if(*this == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ const int width = 7;
+ BtoI fv0 = *this;
+ while(fv0.Top() > 0) fv0 = fv0.At0(fv0.Top());
+ int i=0;
+ int sign = 0;
+ if(fv0.GetSignBDD() == 1)
+ {
+ sign = 1;
+ fv0 = -fv0;
+ }
+ BtoI a;
+ char s0[10];
+ if(fv0.Len() > 27)
+ {
+ BtoI fvb = BtoI(1<<(width*4));
+ while(1)
+ {
+ BtoI t = BtoI_GE(fv0, fvb);
+ if(t == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ if(t == BtoI(0)) break;
+ a = fv0 & (fvb-1);
+ if(a == BtoI(BDD(-1)))
+ {
+ sprintf(s, "0");
+ return 1;
+ }
+ sprintf(s0, "%07X", a.GetInt());
+ for(int j=i-1; j>=0; j--) s[j+width] = s[j];
+ for(int j=0; j<width; j++) s[j] = s0[j];
+ i += width;
+ fv0 >>= width*4;
+ }
+ }
+ sprintf(s0, "%X", fv0.GetInt());
+ int len = strlen(s0);
+ for(int j=i-1; j>=0; j--) s[j+len] = s[j];
+ for(int j=0; j<len; j++) s[j] = s0[j];
+ i += len;
+ if(sign == 1)
+ {
+ for(int j=i-1; j>=0; j--) s[j+1] = s[j];
+ s[0] = '-';
+ i++;
+ }
+ s[i] = 0;
+ return 0;
+}
+
+bddword BtoI::Size() const { return _bddv.Size(); }
+
+void BtoI::Print() const { _bddv.Print(); }
+
+BtoI operator+(const BtoI& a, const BtoI& b)
+{
+ if(a == 0) return b;
+ if(b == 0) return a;
+ if(a == BtoI(BDD(-1))) return a;
+ if(b == BtoI(BDD(-1))) return b;
+ BDD a0;
+ BDD b0;
+ BDD c = 0;
+ BDD c0 = 0;
+ BDDV fv;
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ for(int i=0; i<len; i++)
+ {
+ a0 = a.GetBDD(i);
+ b0 = b.GetBDD(i);
+ c0 = c;
+ fv = fv || (a0 ^ b0 ^ c0);
+ c = (a0 & b0)|(b0 & c0)|(c0 & a0);
+ }
+ if(c != c0) fv = fv || (a0 ^ b0 ^ c);
+ return BtoI(fv).Sup();
+}
+
+BtoI operator-(const BtoI& a, const BtoI& b)
+{
+ if(b == 0) return a;
+ if(b == BtoI(BDD(-1))) return b;
+ if(a == b) return 0;
+ if(a == BtoI(BDD(-1))) return a;
+ BDD a0;
+ BDD b0;
+ BDD c = 0;
+ BDD c0 = 0;
+ BDDV fv;
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ for(int i=0; i<len; i++)
+ {
+ a0 = a.GetBDD(i);
+ b0 = b.GetBDD(i);
+ c0 = c;
+ fv = fv || (a0 ^ b0 ^ c0);
+ c = (~a0 & b0)|(b0 & c0)|(c0 & ~a0);
+ }
+ if(c != c0) fv = fv || (a0 ^ b0 ^ c);
+ return BtoI(fv).Sup();
+}
+
+BtoI operator*(const BtoI& a, const BtoI& b)
+{
+ if(a == 1) return b;
+ if(b == 1) return a;
+ if(a == BtoI(BDD(-1))) return a;
+ if(b == BtoI(BDD(-1))) return b;
+ if(a == 0) return 0;
+ if(b == 0) return 0;
+ BDD sign = b.GetSignBDD();
+ BtoI a0 = BtoI_ITE(sign, -a, a);
+ BtoI b0 = BtoI_ITE(sign, -b, b);
+ BtoI s = BtoI_ITE(b.GetBDD(0), a0, 0);
+ while(b0 != 0)
+ {
+ a0 <<= 1;
+ b0 >>= 1;
+ s += BtoI_ITE(b0.GetBDD(0), a0, 0);
+ if(s == BtoI(BDD(-1))) break;
+ }
+ return s;
+}
+
+BtoI operator/(const BtoI& a, const BtoI& b)
+{
+ if(b == 1) return a;
+ if(a == BtoI(BDD(-1))) return a;
+ if(b == BtoI(BDD(-1))) return b;
+ if(a == 0) return 0;
+ if(a == b) return 1;
+ if(BtoI_EQ(b, 0) != 0)
+ BDDerr("BtoI::operator/(): Divided by 0.");
+ BDD sign = a.GetSignBDD() ^ b.GetSignBDD();
+ BtoI a0 = BtoI_ITE(a.GetSignBDD(), -a, a);
+ if(a0 == BtoI(BDD(-1))) return a0;
+ BtoI b0 = BtoI_ITE(b.GetSignBDD(), -b, b);
+ if(b0 == BtoI(BDD(-1))) return b0;
+ int len = a0.Len();
+ b0 <<= len - 2;
+ BtoI s = 0;
+ for(int i=0; i<len-1; i++)
+ {
+ s <<= 1;
+ BtoI cond = BtoI_GE(a0, b0);
+ a0 = BtoI_ITE(cond, a0 - b0, a0);
+ s += cond;
+ b0 >>= 1;
+ }
+ return BtoI_ITE(sign, -s, s);
+}
+
+BtoI operator&(const BtoI& a, const BtoI& b)
+{
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ BDDV fv;
+ for(int i=0; i<len; i++)
+ fv = fv || (a.GetBDD(i) & b.GetBDD(i));
+ return BtoI(fv).Sup();
+}
+
+BtoI operator|(const BtoI& a, const BtoI& b)
+{
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ BDDV fv;
+ for(int i=0; i<len; i++)
+ fv = fv || (a.GetBDD(i) | b.GetBDD(i));
+ return BtoI(fv).Sup();
+}
+
+BtoI operator^(const BtoI& a, const BtoI& b)
+{
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ BDDV fv;
+ for(int i=0; i<len; i++)
+ fv = fv || (a.GetBDD(i) ^ b.GetBDD(i));
+ return BtoI(fv).Sup();
+}
+
+BtoI BtoI_ITE(const BDD& f, const BtoI& a, const BtoI& b)
+{
+ if(a == b) return a;
+ int len = a.Len();
+ if(len < b.Len()) len = b.Len();
+ BDDV fv;
+ for(int i=0; i<len; i++)
+ {
+ BDD g = (f & a.GetBDD(i)) | (~f & b.GetBDD(i));
+ fv = fv || g;
+ }
+ return BtoI(fv).Sup();
+}
+
+BtoI BtoI_EQ(const BtoI& a, const BtoI& b)
+{
+ BtoI c = a - b;
+ BDD cond = 0;
+ for(int i=0; i<c.Len(); i++)
+ {
+ cond |= c.GetBDD(i);
+ if(cond == 1) break;
+ }
+ return BtoI(~cond);
+}
+
+static BtoI atoi16(char *);
+static BtoI atoi16(char* s)
+{
+ const int width = 6;
+ int p = 0;
+ int len = strlen(s);
+ char a[width + 1];
+ BtoI fv = 0;
+ while(len - p > width)
+ {
+ fv <<= BtoI(width*4);
+ strncpy(a, s+p, width);
+ fv += BtoI((int)strtol(a, 0, 16));
+ p += width;
+ }
+ if(len > width) fv <<= BtoI((len-p)*4);
+ strncpy(a, s+p, width);
+ fv += BtoI((int)strtol(a, 0, 16));
+ return fv;
+}
+
+static BtoI atoi2(char *);
+static BtoI atoi2(char* s)
+{
+ int p = 0;
+ int len = strlen(s);
+ BtoI fv = 0;
+ while(p < len)
+ {
+ fv <<= BtoI(1);
+ if(s[p] == '1') fv += 1;
+ p++;
+ }
+ return fv;
+}
+
+static BtoI atoi10(char *);
+static BtoI atoi10(char* s)
+{
+ const int width = 9;
+ int times = 1000000000; // 10 ** width
+ int p = 0;
+ int len = strlen(s);
+ char a[width + 1];
+ BtoI fv = 0;
+ while(len - p > width)
+ {
+ fv *= BtoI(times);
+ strncpy(a, s+p, width);
+ fv += BtoI((int)strtol(a, 0, 10));
+ p += width;
+ }
+ if(len > width)
+ {
+ times = 1;
+ for(int i=p; i<len; i++) times *= 10;
+ fv *= BtoI(times);
+ }
+ strncpy(a, s+p, width);
+ fv += BtoI((int)strtol(a, 0, 10));
+ return fv;
+}
+
+BtoI BtoI_atoi(char* s)
+{
+ if(s[0] == '0')
+ {
+ switch(s[1])
+ {
+ case 'x':
+ case 'X':
+ return atoi16(s+2);
+ case 'b':
+ case 'B':
+ return atoi2(s+2);
+ default:
+ ;
+ }
+ }
+ return atoi10(s);
+}
+
--- /dev/null
+/******************************************
+ * Combination-to-Integer function class *
+ * (SAPPORO-1.56) - Body *
+ * (C) Shin-ichi MINATO (June 8, 2013) *
+ ******************************************/
+
+#include "CtoI.h"
+
+static const char BC_CtoI_MULT = 40;
+static const char BC_CtoI_DIV = 41;
+static const char BC_CtoI_TV = 42;
+static const char BC_CtoI_TVI = 43;
+
+static const char BC_CtoI_RI = 44;
+static const char BC_CtoI_FPA = 45;
+static const char BC_CtoI_FPAV = 46;
+static const char BC_CtoI_FPM = 47;
+static const char BC_CtoI_FPC = 48;
+static const char BC_CtoI_MEET = 49;
+
+//----------- Macros for operation cache -----------
+#define CtoI_CACHE_CHK_RETURN(op, fx, gx) \
+ { ZBDD z = BDD_CacheZBDD(op, fx, gx); \
+ if(z != -1) return CtoI(z); \
+ BDD_RECUR_INC; }
+
+#define CtoI_CACHE_ENT_RETURN(op, fx, gx, h) \
+ { BDD_RECUR_DEC; \
+ if(h != CtoI_Null()) BDD_CacheEnt(op, fx, gx, h._zbdd.GetID()); \
+ return h; }
+
+//-------------- Public Methods -----------
+CtoI::CtoI(int n)
+{
+ if(n == 0) _zbdd = 0;
+ else if(n == 1) _zbdd = 1;
+ else if(n < 0)
+ {
+ if((n = -n) < 0) BDDerr("CtoI::CtoI(): overflow.", n);
+ *this = -CtoI(n);
+ }
+ else
+ {
+ *this = 0;
+ CtoI a = 1;
+ while(n)
+ {
+ if(n & 1) *this += a;
+ a += a;
+ n >>= 1;
+ }
+ }
+}
+
+int CtoI::TopItem() const
+{
+ int v = Top();
+ if(BDD_LevOfVar(v) <= BDD_TopLev()) return v;
+ int v0 = Factor0(v).TopItem();
+ int v1 = Factor1(v).TopItem();
+ return (BDD_LevOfVar(v0) > BDD_LevOfVar(v1))? v0: v1;
+}
+
+int CtoI::TopDigit() const
+{
+ int v = Top();
+ if(BDD_LevOfVar(v) <= BDD_TopLev()) return 0;
+ int d0 = Factor0(v).TopDigit();
+ int d1 = Factor1(v).TopDigit() + (1 << (BDDV_SysVarTop - v));
+ return (d0 > d1)? d0: d1;
+}
+
+CtoI CtoI::FilterThen(const CtoI& a) const
+{
+ if(*this == 0) return 0;
+ if(*this == CtoI_Null()) return CtoI_Null();
+ CtoI aa = a.IsBool()? a: a.NonZero();
+ if(aa == 0) return 0;
+ if(IsBool()) return CtoI_Intsec(*this, aa);
+ int v = Top();
+ return CtoI_Union(Factor0(v).FilterThen(aa),
+ Factor1(v).FilterThen(aa).AffixVar(v));
+}
+
+CtoI CtoI::FilterElse(const CtoI& a) const
+{
+ if(*this == 0) return 0;
+ if(*this == CtoI_Null()) return CtoI_Null();
+ CtoI aa = a.IsBool()? a: a.NonZero();
+ if(aa == 0) return *this;
+ if(IsBool()) return CtoI_Diff(*this, aa);
+ int v = Top();
+ return CtoI_Union(Factor0(v).FilterElse(aa),
+ Factor1(v).FilterElse(aa).AffixVar(v));
+}
+
+CtoI CtoI::FilterRestrict(const CtoI& a) const
+{
+ CtoI th = IsBool()? *this: NonZero();
+ CtoI aa = a.IsBool()? a: a.NonZero();
+ return FilterThen(CtoI(th._zbdd.Restrict(aa._zbdd)));
+}
+
+CtoI CtoI::FilterPermit(const CtoI& a) const
+{
+ CtoI th = IsBool()? *this: NonZero();
+ CtoI aa = a.IsBool()? a: a.NonZero();
+ return FilterThen(CtoI(th._zbdd.Permit(aa._zbdd)));
+}
+
+CtoI CtoI::FilterPermitSym(int n) const
+{
+ CtoI th = IsBool()? *this: NonZero();
+ return FilterThen(CtoI(th._zbdd.PermitSym(n)));
+}
+
+CtoI CtoI::NonZero() const
+{
+ if(IsBool()) return *this;
+ int v = Top();
+ return CtoI_Union(Factor0(v).NonZero(), Factor1(v).NonZero());
+}
+
+CtoI CtoI::ConstTerm() const
+{
+ if(IsBool()) return CtoI_Intsec(*this, 1);
+ int v = Top();
+ return CtoI_Union(Factor0(v).ConstTerm(),
+ Factor1(v).ConstTerm().AffixVar(v));
+}
+
+CtoI CtoI::Digit(int index) const
+{
+ if(index < 0) BDDerr("CtoI::Digit(): invalid index.", index);
+ CtoI a = *this;
+ for(int i=0; i<BDDV_SysVarTop; i++)
+ {
+ if(index == 0) break;
+ if(index & 1) a = a.Factor1(BDDV_SysVarTop - i);
+ else a = a.Factor0(BDDV_SysVarTop - i);
+ if(a == CtoI_Null()) break;
+ index >>= 1;
+ }
+ while(! a.IsBool()) a = a.Factor0(a.Top());
+ return a;
+}
+
+CtoI CtoI::EQ_Const(const CtoI& a) const
+{
+ return CtoI_Diff(NonZero(), NE_Const(a));
+}
+
+CtoI CtoI::NE_Const(const CtoI& a) const
+{
+ if(a == 0) return CtoI_NE(*this, 0);
+ return CtoI_NE(*this, a * NonZero());
+}
+
+CtoI CtoI::GT_Const(const CtoI& a) const
+{
+ if(a == 0) return CtoI_GT(*this, 0);
+ return CtoI_GT(*this, a * NonZero());
+}
+
+CtoI CtoI::GE_Const(const CtoI& a) const
+{
+ if(a == 0) return CtoI_GE(*this, 0);
+ return CtoI_GE(*this, a * NonZero());
+}
+
+CtoI CtoI::LT_Const(const CtoI& a) const
+{
+ if(a == 0) return CtoI_GT(0, *this);
+ return CtoI_GT(a * NonZero(), *this);
+}
+
+CtoI CtoI::LE_Const(const CtoI& a) const
+{
+ if(a == 0) return CtoI_GE(0, *this);
+ return CtoI_GE(a * NonZero(), *this);
+}
+
+CtoI CtoI::MaxVal() const
+{
+ if(*this == CtoI_Null()) return 0;
+ CtoI a = *this;
+ CtoI cond = NonZero();
+ CtoI c = 0;
+ while(a != 0)
+ {
+ int td = a.TopDigit();
+ CtoI d = Digit(td);
+ if(td & 1)
+ {
+ CtoI cond0 = CtoI_Diff(cond, d);
+ if(cond0 != 0) cond = cond0;
+ else c = CtoI_Union(c, CtoI(1).ShiftDigit(td));
+ }
+ else
+ {
+ CtoI cond0 = CtoI_Intsec(cond, d);
+ if(cond0 != 0)
+ {
+ cond = cond0;
+ c = CtoI_Union(c, CtoI(1).ShiftDigit(td));
+ }
+ }
+ if(td == 0) break;
+ a = CtoI_Diff(a, d.ShiftDigit(td));
+ }
+ return c;
+}
+
+CtoI CtoI::MinVal() const { return - (- *this).MaxVal(); }
+
+CtoI CtoI::TimesSysVar(int v) const
+{
+ if(v > BDDV_SysVarTop || v <= 0)
+ BDDerr("CtoI::TimesSysVar(): invalid var ID.", v);
+ if(*this == 0) return *this;
+ if(*this == CtoI_Null()) return *this;
+ CtoI a0 = Factor0(v);
+ CtoI a1 = Factor1(v);
+ if(a1 == 0) return a0.AffixVar(v);
+ return CtoI_Union(a0.AffixVar(v), a1.TimesSysVar(v-1));
+}
+
+CtoI CtoI::DivBySysVar(int v) const
+{
+ if(v > BDDV_SysVarTop || v <= 0)
+ BDDerr("CtoI::DivBySysVar(): invalid var ID.", v);
+ if(*this == 0) return *this;
+ if(*this == CtoI_Null()) return *this;
+ CtoI a0 = Factor0(v);
+ CtoI a1 = Factor1(v);
+ if(a0.IsBool()) return a1;
+ return CtoI_Union(a1, a0.AffixVar(v).DivBySysVar(v-1));
+}
+
+CtoI CtoI::ShiftDigit(int pow) const
+{
+ CtoI a = *this;
+ int v = BDDV_SysVarTop;
+ int i = (pow >= 0)? pow: -pow;
+ while(i)
+ {
+ if(i & 1)
+ {
+ if(pow > 0) a = a.TimesSysVar(v);
+ else a = a.DivBySysVar(v);
+ }
+ i >>= 1;
+ v--;
+ }
+ return a;
+}
+
+bddword CtoI::Size() const { return _zbdd.Size(); }
+
+int CtoI::GetInt() const
+{
+ if(*this == CtoI_Null()) return 0;
+ if(IsBool()) return (CtoI_Intsec(*this, 1)== 0)? 0: 1;
+ int v = Top();
+ CtoI a;
+ if((a=Factor0(v)) == CtoI_Null()) return 0;
+ int n = a.GetInt();
+ if((a=Factor1(v)) == CtoI_Null()) return 0;
+ if(v == BDDV_SysVarTop) return n - (a.GetInt() << 1);
+ return n + (a.GetInt() << (1<< (BDDV_SysVarTop - v)));
+}
+
+int CtoI::StrNum10(char* s) const
+{
+ if(*this == CtoI_Null()) { sprintf(s, "0"); return 1; }
+ if(! IsConst()) return FilterThen(1).StrNum10(s);
+ int td = TopDigit();
+ if(td & 1)
+ {
+ if((- *this).StrNum10(s)) return 1;
+ int len = strlen(s);
+ for(int i=len; i>=0; i--) s[i+1] = s[i];
+ s[0] = '-';
+ return 0;
+ }
+
+ CtoI a = *this;
+ int i=0;
+ char s0[12];
+ if(td >= 20)
+ {
+ const int width = 9;
+ CtoI shift = 1000000000; // 10 ** width
+ while(1)
+ {
+ CtoI p = a / shift;
+ if(p == 0) break;
+ CtoI q = a - p * shift;
+ if(q == CtoI_Null()) { sprintf(s, "0"); return 1; }
+ sprintf(s0, "%09d", q.GetInt());
+ for(int j=i-1; j>=0; j--) s[j+width] = s[j];
+ for(int j=0; j<width; j++) s[j] = s0[j];
+ i += width;
+ a = p;
+ }
+ }
+ sprintf(s0, "%d", a.GetInt());
+ int len = strlen(s0);
+ for(int j=i-1; j>=0; j--) s[j+len] = s[j];
+ for(int j=0; j<len; j++) s[j] = s0[j];
+ i += len;
+ s[i] = 0;
+ return 0;
+}
+
+int CtoI::StrNum16(char* s) const
+{
+ if(*this == CtoI_Null()) { sprintf(s, "0"); return 1; }
+ if(! IsConst()) return FilterThen(1).StrNum16(s);
+ int td = TopDigit();
+ if(td & 1)
+ {
+ if((- *this).StrNum16(s)) return 1;
+ int len = strlen(s);
+ for(int i=len; i>=0; i--) s[i+1] = s[i];
+ s[0] = '-';
+ return 0;
+ }
+
+ CtoI a = *this;
+ int i=0;
+ char s0[12];
+ if(td >= 20)
+ {
+ const int width = 6;
+ CtoI shift = 0x1000000; // 0x10 ** width
+ while(1)
+ {
+ CtoI p = a / shift;
+ if(p == 0) break;
+ CtoI q = a - p * shift;
+ if(q == CtoI_Null()) { sprintf(s, "0"); return 1; }
+ sprintf(s0, "%06X", q.GetInt());
+ for(int j=i-1; j>=0; j--) s[j+width] = s[j];
+ for(int j=0; j<width; j++) s[j] = s0[j];
+ i += width;
+ a = p;
+ }
+ }
+ sprintf(s0, "%X", a.GetInt());
+ int len = strlen(s0);
+ for(int j=i-1; j>=0; j--) s[j+len] = s[j];
+ for(int j=0; j<len; j++) s[j] = s0[j];
+ i += len;
+ s[i] = 0;
+ return 0;
+}
+
+static int Depth;
+static int* S_Var;
+static int PFflag;
+static int PF(CtoI);
+static int PF(CtoI a)
+{
+ if(a.IsConst())
+ {
+ if(a.TopDigit() & 1) { cout << " -"; a = -a; }
+ else if(PFflag == 1) cout << " +";
+
+ PFflag = 1;
+ int c1 = (a != 1);
+ if(c1 || Depth == 0)
+ {
+ char s[80];
+ a.StrNum10(s);
+ cout << " " << s;
+ }
+ for(int i=0; i<Depth; i++) cout << " v" << S_Var[i];
+ cout.flush();
+ 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) == 1) return 1;
+
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF(b);
+}
+
+int CtoI::PutForm() const
+{
+ if(*this == CtoI_Null()) return 1;
+
+ if(*this == 0) cout << " 0";
+ else
+ {
+ int v = TopItem();
+ Depth = 0;
+ S_Var = new int[v];
+ PFflag = 0;
+ int err = PF(*this);
+ delete[] S_Var;
+ if(err == 1)
+ {
+ cout << "...\n";
+ cout.flush();
+ return 1;
+ }
+ }
+ cout << "\n";
+ cout.flush();
+ return 0;
+}
+
+void CtoI::Print() const { _zbdd.Print(); }
+
+CtoI CtoI::CountTerms() const
+{
+ if(IsBool()) return TotalVal();
+ return NonZero().TotalVal();
+}
+
+CtoI CtoI::TotalVal() const
+{
+ if(*this == CtoI_Null()) return *this;
+ int top = Top();
+ if(top == 0) return *this;
+
+ bddword x = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_TV, x, 0);
+
+ CtoI c = Factor0(top).TotalVal();
+ if(c != CtoI_Null())
+ {
+ if(IsBool())
+ c += Factor1(top).TotalVal();
+ else
+ c += Factor1(top).TotalVal().ShiftDigit(1<<(BDDV_SysVarTop - top));
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_TV, x, 0, c);
+}
+
+CtoI CtoI::TotalValItems() const
+{
+ if(*this == CtoI_Null()) return *this;
+ int top = Top();
+ if(top == 0) return CtoI(0);
+
+ bddword x = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_TVI, x, 0);
+
+ CtoI c = Factor0(top).TotalValItems();
+ if(c != CtoI_Null())
+ {
+ CtoI a1 = Factor1(top);
+ if(IsBool())
+ c += a1.TotalValItems() + a1.TotalVal().AffixVar(top);
+ else
+ c += a1.TotalValItems().ShiftDigit(1<<(BDDV_SysVarTop - top));
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_TVI, x, 0, c);
+}
+
+CtoI CtoI::ReduceItems(const CtoI& b) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(b == CtoI_Null()) return b;
+ if(! b.IsBool()) return ReduceItems(b.NonZero());
+ int atop = Top();
+ int btop = b.Top();
+ int top = (BDD_LevOfVar(atop) > BDD_LevOfVar(btop))? atop: btop;
+ if(top == 0) return *this;
+
+ bddword ax = _zbdd.GetID();
+ bddword bx = b._zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_RI, ax, bx);
+
+ CtoI c = CtoI(0);
+ if(BDD_LevOfVar(btop) > BDD_LevOfVar(atop))
+ c = ReduceItems(b.Factor0(btop));
+ else if(!IsBool())
+ c = Factor0(atop).ReduceItems(b)
+ + Factor1(atop).ReduceItems(b).ShiftDigit(1<<(BDDV_SysVarTop - atop));
+ else if(BDD_LevOfVar(btop) == BDD_LevOfVar(atop))
+ c = Factor0(atop).ReduceItems(b) + Factor1(atop).ReduceItems(b);
+ else
+ {
+ c = Factor0(atop).ReduceItems(b.Factor0(atop))
+ + Factor1(atop).ReduceItems(b.Factor0(atop)).AffixVar(atop);
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_RI, ax, bx, c);
+}
+
+CtoI CtoI::FreqPatA(int Val) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(IsConst()) return (GetInt() >= Val)? CtoI(1): CtoI(0);
+
+ int ax = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_FPA, ax, Val);
+
+ int top = TopItem();
+ CtoI f1 = Factor1(top);
+
+ CtoI f = f1;
+ int tv = 1 << f.TopDigit();
+ CtoI f2 = f1;
+ if(tv -(tv>>1) < Val)
+ {
+ tv = 0;
+ while(f != CtoI(0))
+ {
+ int d = f.TopDigit();
+ CtoI fd = f.Digit(d);
+ if(d & 1)
+ {
+ tv -= fd.GetZBDD().Card() << d;
+ if(tv >= Val) break;
+ }
+ else
+ {
+ tv += fd.GetZBDD().Card() << d;
+ if((tv>>1) >= Val) break;
+ }
+ f -= fd.ShiftDigit(d);
+ }
+ if(tv < Val) f2 = CtoI(0);
+ }
+
+ CtoI h1 = f2.FreqPatA(Val);
+ CtoI h = CtoI_Union(h1, h1.AffixVar(top));
+ CtoI f0 = Factor0(top);
+ if(f0 != CtoI(0))
+ {
+ //CtoI f1v = f1.GE_Const(CtoI(Val));
+ f0 = f0.FilterElse(h1);
+ if(f0 != CtoI(0))
+ {
+ f1 = f1.FilterElse(h1);
+ h = CtoI_Union(h, (f0 + f1).FreqPatA(Val));
+ }
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_FPA, ax, Val, h);
+}
+
+CtoI CtoI::FreqPatA2(int Val) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(IsConst()) return (GetInt() >= Val)? CtoI(1): CtoI(0);
+
+ int ax = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_FPA, ax, Val);
+
+ int top = TopItem();
+ CtoI f1 = Factor1(top);
+
+ CtoI f = f1;
+ int tv = 1 << f.TopDigit();
+ CtoI f2 = f1;
+ if(tv -(tv>>1) < Val)
+ {
+ tv = 0;
+ while(f != CtoI(0))
+ {
+ int d = f.TopDigit();
+ CtoI fd = f.Digit(d);
+ if(d & 1)
+ {
+ tv -= fd.GetZBDD().Card() << d;
+ if(tv >= Val) break;
+ }
+ else
+ {
+ tv += fd.GetZBDD().Card() << d;
+ if((tv>>1) >= Val) break;
+ }
+ f -= fd.ShiftDigit(d);
+ }
+ if(tv < Val) f2 = CtoI(0);
+ }
+
+ int sz = f2.Size();
+ CtoI s = f2.TotalValItems().LT_Const(CtoI(Val));
+ f2 = f2.ReduceItems(s);
+ cout << (float) (sz - f2.Size())/sz << " ";
+ cout.flush();
+
+ CtoI h1 = f2.FreqPatA2(Val);
+ CtoI h = CtoI_Union(h1, h1.AffixVar(top));
+ CtoI f0 = Factor0(top);
+ if(f0 != CtoI(0))
+ {
+ //CtoI f1v = f1.GE_Const(CtoI(Val));
+ f0 = f0.FilterElse(h1);
+ if(f0 != CtoI(0))
+ {
+ f1 = f1.FilterElse(h1);
+ h = CtoI_Union(h, (f0 + f1).FreqPatA2(Val));
+ }
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_FPA, ax, Val, h);
+}
+
+CtoI CtoI::FreqPatAV(int Val) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(IsConst()) return (GetInt() >= Val)? *this: CtoI(0);
+
+ int ax = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_FPAV, ax, Val);
+
+ int top = TopItem();
+ CtoI f1 = Factor1(top);
+
+ CtoI f = f1;
+ int tv = 1 << f.TopDigit();
+ CtoI f2 = f1;
+ if(tv -(tv>>1) < Val)
+ {
+ tv = 0;
+ while(f != CtoI(0))
+ {
+ int d = f.TopDigit();
+ CtoI fd = f.Digit(d);
+ if(d & 1)
+ {
+ tv -= fd.GetZBDD().Card() << d;
+ if(tv >= Val) break;
+ }
+ else
+ {
+ tv += fd.GetZBDD().Card() << d;
+ if((tv>>1) >= Val) break;
+ }
+ f -= fd.ShiftDigit(d);
+ }
+ if(tv < Val) f2 = CtoI(0);
+ }
+
+ CtoI h1 = f2.FreqPatAV(Val);
+ CtoI h = h1.AffixVar(top);
+
+ CtoI f0 = Factor0(top);
+ if(f0 == CtoI(0)) h = CtoI_Union(h, h1);
+ else h = CtoI_Union(h, (f0 + f1).FreqPatAV(Val));
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_FPAV, ax, Val, h);
+}
+
+CtoI CtoI::FreqPatM(int Val) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(IsConst()) return (GetInt() >= Val)? CtoI(1): CtoI(0);
+
+ int ax = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_FPM, ax, Val);
+
+ int top = TopItem();
+ CtoI f1 = Factor1(top);
+
+ CtoI f = f1;
+ int tv = 1 << f.TopDigit();
+ CtoI f2 = f1;
+ if(tv -(tv>>1) < Val)
+ {
+ tv = 0;
+ while(f != CtoI(0))
+ {
+ int d = f.TopDigit();
+ CtoI fd = f.Digit(d);
+ if(d & 1)
+ {
+ tv -= fd.GetZBDD().Card() << d;
+ if(tv >= Val) break;
+ }
+ else
+ {
+ tv += fd.GetZBDD().Card() << d;
+ if((tv>>1) >= Val) break;
+ }
+ f -= fd.ShiftDigit(d);
+ }
+ if(tv < Val) f2 = CtoI(0);
+ }
+
+ CtoI h1 = f2.FreqPatM(Val);
+ CtoI h = h1.AffixVar(top);
+ CtoI f0 = Factor0(top);
+ if(f0 != CtoI(0))
+ {
+ f0 = CtoI_Diff(f0, f0.FilterPermit(h1));
+ if(f0 != CtoI(0))
+ {
+ f1 = CtoI_Diff(f1, f1.FilterPermit(h1));
+ f2 = (f0 + f1).FreqPatM(Val);
+ h = CtoI_Union(h, CtoI_Diff(f2, f2.FilterPermit(h1)));
+ }
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_FPM, ax, Val, h);
+}
+
+CtoI CtoI::FreqPatC(int Val) const
+{
+ if(*this == CtoI_Null()) return *this;
+ if(IsConst()) return (GetInt() >= Val)? CtoI(1): CtoI(0);
+
+ int ax = _zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_FPC, ax, Val);
+
+ int top = TopItem();
+ CtoI f1 = Factor1(top);
+
+ CtoI f = f1;
+ int tv = 1 << f.TopDigit();
+ CtoI f2 = f1;
+ if(tv -(tv>>1) < Val)
+ {
+ tv = 0;
+ while(f != CtoI(0))
+ {
+ int d = f.TopDigit();
+ CtoI fd = f.Digit(d);
+ if(d & 1)
+ {
+ tv -= fd.GetZBDD().Card() << d;
+ if(tv >= Val) break;
+ }
+ else
+ {
+ tv += fd.GetZBDD().Card() << d;
+ if((tv>>1) >= Val) break;
+ }
+ f -= fd.ShiftDigit(d);
+ }
+ if(tv < Val) f2 = CtoI(0);
+ }
+
+ CtoI h1 = f2.FreqPatC(Val);
+ CtoI h = h1.AffixVar(top);
+ CtoI f0 = Factor0(top);
+ if(f0 != CtoI(0))
+ {
+ h1 -= h1.FilterPermit(f0);
+ h = CtoI_Union(h, (f0 + f1).FreqPatC(Val).FilterElse(h1));
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_FPC, ax, Val, h);
+}
+
+//----------- External functions -----------
+
+CtoI operator+(const CtoI& a, const CtoI& b)
+{
+ CtoI c = CtoI_Intsec(a, b);
+ CtoI s = CtoI_Diff(CtoI_Union(a, b), c);
+ if(c == 0) return s;
+ if(s == CtoI_Null()) return s;
+ BDD_RECUR_INC;
+ CtoI h = s - c.ShiftDigit(1);
+ BDD_RECUR_DEC;
+ return h;
+}
+
+CtoI operator-(const CtoI& a, const CtoI& b)
+{
+ CtoI c = CtoI_Diff(b, a);
+ CtoI s = CtoI_Union(CtoI_Diff(a, b), c);
+ if(c == 0) return s;
+ if(s == CtoI_Null()) return s;
+ BDD_RECUR_INC;
+ CtoI h = s + c.ShiftDigit(1);
+ BDD_RECUR_DEC;
+ return h;
+}
+
+CtoI operator *(const CtoI& ac, const CtoI& bc)
+{
+ if(ac == 1) return bc;
+ if(bc == 1) return ac;
+ if(ac == CtoI_Null()) return ac;
+ if(bc == CtoI_Null()) return bc;
+ if(ac == 0) return 0;
+ if(bc == 0) return 0;
+
+ CtoI a = ac; CtoI b = bc;
+ int atop = a.Top(); int btop = b.Top();
+ if(BDD_LevOfVar(atop) < BDD_LevOfVar(btop))
+ {
+ a = bc; b = ac;
+ atop = a.Top(); btop = b.Top();
+ }
+
+ bddword ax = a._zbdd.GetID();
+ bddword bx = b._zbdd.GetID();
+ if(atop == btop && ax < bx)
+ {
+ a = bc; b = ac;
+ ax = a._zbdd.GetID(); bx = b._zbdd.GetID();
+ }
+
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_MULT, ax, bx);
+
+ CtoI a0 = a.Factor0(atop);
+ CtoI a1 = a.Factor1(atop);
+ CtoI c;
+ if(atop != btop)
+ {
+ if(BDD_LevOfVar(atop) <= BDD_TopLev())
+ c = CtoI_Union(a0*b, (a1*b).AffixVar(atop));
+ else c = a0*b + (a1*b).TimesSysVar(atop);
+ }
+ else
+ {
+ CtoI b0 = b.Factor0(atop);
+ CtoI b1 = b.Factor1(atop);
+ if(BDD_LevOfVar(atop) <= BDD_TopLev())
+ c = CtoI_Union(a0*b0, (a1*b0 + a0*b1 + a1*b1).AffixVar(atop));
+ else if(atop > 1)
+ c = a0*b0 + (a1*b0 + a0*b1).TimesSysVar(atop)
+ + (a1*b1).TimesSysVar(atop - 1);
+ else BDDerr("CtoI::operator*(): SysVar overflow.");
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_MULT, ax, bx, c);
+}
+
+CtoI operator /(const CtoI& ac, const CtoI& bc)
+{
+ if(ac == CtoI_Null()) return ac;
+ if(bc == CtoI_Null()) return bc;
+ if(ac == 0) return 0;
+ if(ac == bc) return 1;
+ if(bc == 0) BDDerr("CtoI::operator/(): Divide by zero.");
+
+ CtoI a = ac; CtoI b = bc;
+ bddword ax = a._zbdd.GetID();
+ bddword bx = b._zbdd.GetID();
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_DIV, ax, bx);
+
+ int v = b.TopItem();
+ CtoI c;
+ if(v == 0)
+ {
+ if(b.TopDigit() & 1) { a = -a; b = -b; }
+ if(b == 1) return a;
+ CtoI p = a.FilterThen(CtoI_GT(a, 0));
+ if(a != p) c = (p / b) - ((p - a)/ b);
+ else
+ {
+ int atd = a.TopDigit();
+ int btd = b.TopDigit();
+ if(atd < btd) return 0;
+ c = a.Digit(atd);
+ if(atd > btd) c = c.ShiftDigit(atd - btd - 2);
+ else
+ {
+ CtoI cond = CtoI_GE(a, c * b);
+ a = a.FilterThen(cond);
+ c = c.FilterThen(cond);
+ }
+ c += (a - c * b)/ b;
+ }
+ }
+ else
+ {
+ CtoI a0 = a.Factor0(v);
+ CtoI a1 = a.Factor1(v);
+ CtoI b0 = b.Factor0(v);
+ CtoI b1 = b.Factor1(v);
+
+ c = a1 / b1;
+ if(c != 0)
+ if(b0 != 0)
+ {
+ CtoI c0 = a0 / b0;
+ c = CtoI_ITE(CtoI_LT(c.Abs(), c0.Abs()), c, c0);
+ }
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_DIV, ax, bx, c);
+}
+
+CtoI CtoI_GT(const CtoI& ac, const CtoI& bc)
+{
+ CtoI a = ac; CtoI b = bc;
+ CtoI open = CtoI_Union(a, b).NonZero();
+ CtoI awin = 0;
+ CtoI bwin = 0;
+ CtoI awin0, bwin0;
+
+ while(open != 0)
+ {
+ int atd = a.TopDigit();
+ int btd = b.TopDigit();
+ int td = (atd > btd)? atd: btd;
+ CtoI aa = a.Digit(td);
+ CtoI bb = b.Digit(td);
+ if(td & 1)
+ {
+ awin0 = CtoI_Diff(bb, aa);
+ bwin0 = CtoI_Diff(aa, bb);
+ }
+ else
+ {
+ awin0 = CtoI_Diff(aa, bb);
+ bwin0 = CtoI_Diff(bb, aa);
+ }
+ awin = CtoI_Union(awin, awin0);
+ open = CtoI_Diff(open, awin0);
+ bwin = CtoI_Union(bwin, bwin0);
+ open = CtoI_Diff(open, bwin0);
+ if(open == CtoI_Null()) return CtoI_Null();
+ if(td == 0) break;
+ a = CtoI_Diff(a, aa.ShiftDigit(td)).FilterThen(open);
+ b = CtoI_Diff(b, bb.ShiftDigit(td)).FilterThen(open);
+ }
+ return awin;
+}
+
+CtoI CtoI_GE(const CtoI& ac, const CtoI& bc)
+{
+ CtoI a = ac; CtoI b = bc;
+ CtoI open = CtoI_Union(a, b).NonZero();
+ CtoI awin = 0;
+ CtoI bwin = 0;
+ CtoI awin0, bwin0;
+
+ while(open != 0)
+ {
+ int atd = a.TopDigit();
+ int btd = b.TopDigit();
+ int td = (atd > btd)? atd: btd;
+ CtoI aa = a.Digit(td);
+ CtoI bb = b.Digit(td);
+ if(td & 1)
+ {
+ awin0 = CtoI_Diff(bb, aa);
+ bwin0 = CtoI_Diff(aa, bb);
+ }
+ else
+ {
+ awin0 = CtoI_Diff(aa, bb);
+ bwin0 = CtoI_Diff(bb, aa);
+ }
+ awin = CtoI_Union(awin, awin0);
+ open = CtoI_Diff(open, awin0);
+ bwin = CtoI_Union(bwin, bwin0);
+ open = CtoI_Diff(open, bwin0);
+ if(open == CtoI_Null()) return CtoI_Null();
+ if(td == 0) break;
+ a = CtoI_Diff(a, aa.ShiftDigit(td)).FilterThen(open);
+ b = CtoI_Diff(b, bb.ShiftDigit(td)).FilterThen(open);
+ }
+ return CtoI_Union(awin, open);
+}
+
+static CtoI atoiX(char *, int, int);
+static CtoI atoiX(char* s, int base, int blk)
+{
+ int times = 1;
+ for(int i=0; i<blk; i++) times *= base;
+ CtoI shift = times;
+ int p = 0;
+ int len = strlen(s);
+ char *s0 = new char[blk + 1];
+ CtoI a = 0;
+ while(len - p > blk)
+ {
+ a *= shift;
+ strncpy(s0, s+p, blk);
+ a += CtoI((int)strtol(s0, 0, base));
+ p += blk;
+ }
+ if(len > blk)
+ {
+ times = 1;
+ for(int i=p; i<len; i++) times *= base;
+ a *= CtoI(times);
+ }
+ strncpy(s0, s+p, blk);
+ a += CtoI((int)strtol(s0, 0, base));
+ delete[] s0;
+ return a;
+}
+
+CtoI CtoI_atoi(char* s)
+{
+ if(s[0] == '0')
+ {
+ switch(s[1])
+ {
+ case 'x':
+ case 'X':
+ return atoiX(s+2, 16, 7);
+ case 'b':
+ case 'B':
+ return atoiX(s+2, 2, 30);
+ default:
+ ;
+ }
+ }
+ return atoiX(s, 10, 7);
+}
+
+CtoI CtoI_Meet(const CtoI& ac, const CtoI& bc)
+{
+ if(ac == CtoI_Null()) return ac;
+ if(bc == CtoI_Null()) return bc;
+ if(ac == 0) return 0;
+ if(bc == 0) return 0;
+ if(ac == 1 && bc == 1) return 1;
+
+ CtoI a = ac; CtoI b = bc;
+ int atop = ac.Top(); int btop = bc.Top();
+ if(BDD_LevOfVar(atop) < BDD_LevOfVar(btop))
+ {
+ a = bc; b = ac;
+ atop = a.Top(); btop = b.Top();
+ }
+
+ bddword ax = a._zbdd.GetID();
+ bddword bx = b._zbdd.GetID();
+ if(atop == btop && ax < bx)
+ {
+ a = bc; b = ac;
+ ax = a._zbdd.GetID(); bx = b._zbdd.GetID();
+ }
+
+ CtoI_CACHE_CHK_RETURN(BC_CtoI_MEET, ax, bx);
+
+ CtoI a0 = a.Factor0(atop);
+ CtoI a1 = a.Factor1(atop);
+ CtoI c;
+ if(atop != btop)
+ {
+ if(a.IsBool())
+ c = CtoI_Meet(a0, b) + CtoI_Meet(a1, b);
+ else c = CtoI_Meet(a0, b) + CtoI_Meet(a1, b).TimesSysVar(atop);
+ }
+ else
+ {
+ CtoI b0 = b.Factor0(atop);
+ CtoI b1 = b.Factor1(atop);
+ if(a.IsBool())
+ c = CtoI_Union(
+ CtoI_Meet(a0, b0) + CtoI_Meet(a1, b0) + CtoI_Meet(a0, b1),
+ CtoI_Meet(a1, b1).AffixVar(atop));
+ else if(atop > 1)
+ c = CtoI_Meet(a0, b0)
+ + (CtoI_Meet(a1, b0) + CtoI_Meet(a0, b1)).TimesSysVar(atop)
+ + CtoI_Meet(a1, b1).TimesSysVar(atop - 1);
+ else BDDerr("CtoI_Meet(): SysVar overflow.");
+ }
+
+ CtoI_CACHE_ENT_RETURN(BC_CtoI_MEET, ax, bx, c);
+}
+
--- /dev/null
+/****************************************
+ * CtoI Class (SAPPORO-1.55) *
+ * (Graphic methods) *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ****************************************/
+
+#include "CtoI.h"
+
+void CtoI::XPrint() const
+{
+ int len = TopDigit() + 1;
+ bddword* bddv = new bddword[len];
+ for(int i=0; i<len; i++) bddv[i] = Digit(i).GetZBDD().GetID();
+ bddvgraph(bddv, len);
+ delete[] bddv;
+}
+
+void CtoI::XPrint0() const
+{
+ int len = TopDigit() + 1;
+ bddword* bddv = new bddword[len];
+ for(int i=0; i<len; i++) bddv[i] = Digit(i).GetZBDD().GetID();
+ bddvgraph0(bddv, len);
+ delete[] bddv;
+}
+
--- /dev/null
+/*****************************************
+ * Multi-Level ZBDDV class (SAPPORO-1.41)*
+ * (Main part) *
+ * (C) Shin-ichi MINATO (Dec. 9, 2011) *
+ *****************************************/
+
+#include "MLZBDDV.h"
+
+//-------------- Class methods of MLZBDDV -----------------
+
+MLZBDDV::MLZBDDV()
+{
+ _pin = 0;
+ _out = 0;
+ _sin = 0;
+ _zbddv = ZBDDV();
+}
+
+MLZBDDV::~MLZBDDV() { }
+
+int MLZBDDV::N_pin() { return _pin; }
+int MLZBDDV::N_out() { return _out; }
+int MLZBDDV::N_sin() { return _sin; }
+
+MLZBDDV& MLZBDDV::operator=(const MLZBDDV& v)
+{
+ _pin = v._pin;
+ _out = v._out;
+ _sin = v._sin;
+ _zbddv = v._zbddv;
+ return *this;
+}
+
+MLZBDDV::MLZBDDV(ZBDDV& zbddv)
+{
+ int pin = BDD_LevOfVar(zbddv.Top());
+ int out = zbddv.Last()+1;
+ MLZBDDV v = MLZBDDV(zbddv, pin, out);
+ _pin = v._pin;
+ _out = v._out;
+ _sin = v._sin;
+ _zbddv = v._zbddv;
+}
+
+MLZBDDV::MLZBDDV(ZBDDV& zbddv, int pin, int out)
+{
+ if(zbddv == ZBDDV(-1))
+ {
+ _pin = 0;
+ _out = 0;
+ _sin = 0;
+ _zbddv = zbddv;
+ return;
+ }
+
+ _pin = pin;
+ _out = out;
+ _sin = 0;
+ _zbddv = zbddv;
+
+ /* check each output as a divisor */
+ for(int i=0; i<_out; i++)
+ {
+ _sin++;
+ int plev = _pin + _sin;
+ if(plev > BDD_TopLev()) BDD_NewVar();
+ ZBDD p = _zbddv.GetZBDD(i);
+ int pt = BDD_LevOfVar(p.Top());
+ if(p != 0)
+ {
+ for(int j=0; j<_out; j++)
+ {
+ if(i != j)
+ {
+ ZBDD f = _zbddv.GetZBDD(j);
+ int ft = BDD_LevOfVar(f.Top());
+ if(ft >= pt)
+ {
+ ZBDD q = f / p;
+ if(q != 0)
+ {
+ int v = BDD_VarOfLev(plev);
+ _zbddv -= ZBDDV(f, j);
+ f = q.Change(v) + (f % p);
+ if(f == -1) { cerr << "overflow.\n"; exit(1);}
+ _zbddv += ZBDDV(f, j);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* extract 0-level kernels */
+ for(int i=0; i<_out; i++)
+ {
+ ZBDD f = _zbddv.GetZBDD(i);
+ while(1)
+ {
+ ZBDD p = f.Divisor();
+ int pt = BDD_LevOfVar(p.Top());
+ if(p.Top() == 0) break;
+ if(p == f) break;
+ _sin++;
+ cout << _sin << " "; cout.flush();
+ int plev = _pin + _sin;
+ if(plev > BDD_TopLev()) BDD_NewVar();
+ _zbddv += ZBDDV(p, _sin-1);
+ int v = BDD_VarOfLev(plev);
+ ZBDD q = f / p;
+ _zbddv -= ZBDDV(f, i);
+ f = q.Change(v) + (f % p);
+ if(f == -1) { cerr << "overflow.\n"; exit(1);}
+ _zbddv += ZBDDV(f, i);
+ for(int j=0; j<_out; j++)
+ {
+ if(i != j)
+ {
+ ZBDD f = _zbddv.GetZBDD(j);
+ int ft = BDD_LevOfVar(f.Top());
+ if(ft >= pt)
+ {
+ ZBDD q = f / p;
+ if(q != 0)
+ {
+ _zbddv -= ZBDDV(f, j);
+ f = q.Change(v) + (f % p);
+ if(f == -1) { cerr << "overflow.\n"; exit(1);}
+ _zbddv += ZBDDV(f, j);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void MLZBDDV::Print()
+{
+ cout << "pin:" << _pin << "\n";
+ cout << "out:" << _out << "\n";
+ cout << "sin:" << _sin << "\n";
+ _zbddv.Print();
+}
+
+ZBDDV MLZBDDV::GetZBDDV()
+{
+ return _zbddv;
+}
+
--- /dev/null
+CC = g++
+DIR = ../..
+INCL = $(DIR)/include
+OPT = -O3 -I$(INCL)
+OPT64 = $(OPT) -DB_64
+
+LIB = $(DIR)/lib/BDD.a
+LIB64 = $(DIR)/lib/BDD64.a
+OBJC = $(DIR)/src/BDDc/*.o
+OBJX = $(DIR)/src/BDDXc/*.o
+OBJLCM = $(DIR)/src/BDDLCM/*.o
+
+all: BDD.o BDDX11.o BDDHASH.o ZBDD.o ZBDDX11.o \
+ ZBDDHASH.o ZBDDLCM.o MLZBDDV.o SOP.o BtoI.o \
+ CtoI.o CtoIX11.o BDDDG.o ZBDDDG.o PiDD.o SeqBDD.o
+ rm -f $(LIB)
+ ar cr $(LIB) *.o $(OBJC) $(OBJX) $(OBJLCM)
+ ranlib $(LIB)
+
+64: BDD_64.o BDDX11_64.o BDDHASH_64.o ZBDD_64.o ZBDDX11_64.o \
+ ZBDDHASH_64.o ZBDDLCM_64.o MLZBDDV_64.o SOP_64.o BtoI_64.o \
+ CtoI_64.o CtoIX11_64.o BDDDG_64.o ZBDDDG_64.o PiDD_64.o SeqBDD_64.o
+ rm -f $(LIB64)
+ ar cr $(LIB64) *.o $(OBJC) $(OBJX) $(OBJLCM)
+ ranlib $(LIB64)
+
+clean:
+ rm -f *.o *~
+
+BDD.o: BDD.cc $(INCL)/BDD.h
+ $(CC) $(OPT) -c BDD.cc
+ rm -f BDD_64.o
+
+BDD_64.o: BDD.cc $(INCL)/BDD.h
+ $(CC) $(OPT64) -c BDD.cc -o BDD_64.o
+ rm -f BDD.o
+
+BDDX11.o: BDDX11.cc $(INCL)/BDD.h
+ $(CC) $(OPT) -c BDDX11.cc
+ rm -f BDDX11_64.o
+
+BDDX11_64.o: BDDX11.cc $(INCL)/BDD.h
+ $(CC) $(OPT64) -c BDDX11.cc -o BDDX11_64.o
+ rm -f BDDX11.o
+
+BDDHASH.o: BDDHASH.cc $(INCL)/BDD.h
+ $(CC) $(OPT) -c BDDHASH.cc
+ rm -f BDDHASH_64.o
+
+BDDHASH_64.o: BDDHASH.cc $(INCL)/BDD.h
+ $(CC) $(OPT64) -c BDDHASH.cc -o BDDHASH_64.o
+ rm -f BDDHASH.o
+
+ZBDD.o: ZBDD.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c ZBDD.cc
+ rm -f ZBDD_64.o
+
+ZBDD_64.o: ZBDD.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c ZBDD.cc -o ZBDD_64.o
+ rm -f ZBDD.o
+
+ZBDDX11.o: ZBDDX11.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c ZBDDX11.cc
+ rm -f ZBDDX11_64.o
+
+ZBDDX11_64.o: ZBDDX11.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c ZBDDX11.cc -o ZBDDX11_64.o
+ rm -f ZBDDX11.o
+
+ZBDDHASH.o: ZBDDHASH.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c ZBDDHASH.cc
+ rm -f ZBDDHASH_64.o
+
+ZBDDHASH_64.o: ZBDDHASH.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c ZBDDHASH.cc -o ZBDDHASH_64.o
+ rm -f ZBDDHASH.o
+
+ZBDDLCM.o: ZBDDLCM.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c ZBDDLCM.cc
+ rm -f ZBDDLCM_64.o
+
+ZBDDLCM_64.o: ZBDDLCM.cc $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c ZBDDLCM.cc -o ZBDDLCM_64.o
+ rm -f ZBDDLCM.o
+
+MLZBDDV.o: MLZBDDV.cc $(INCL)/MLZBDDV.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c MLZBDDV.cc
+ rm -f MLZBDDV_64.o
+
+MLZBDDV_64.o: MLZBDDV.cc $(INCL)/MLZBDDV.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c MLZBDDV.cc -o MLZBDDV_64.o
+ rm -f MLZBDDV.o
+
+SOP.o: SOP.cc $(INCL)/SOP.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c SOP.cc
+ rm -f SOP_64.o
+
+SOP_64.o: SOP.cc $(INCL)/SOP.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c SOP.cc -o SOP_64.o
+ rm -f SOP.o
+
+BtoI.o: BtoI.cc $(INCL)/BtoI.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c BtoI.cc
+ rm -f BtoI_64.o
+
+BtoI_64.o: BtoI.cc $(INCL)/BtoI.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c BtoI.cc -o BtoI_64.o
+ rm -f BtoI.o
+
+CtoI.o: CtoI.cc $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c CtoI.cc
+ rm -f CtoI_64.o
+
+CtoI_64.o: CtoI.cc $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c CtoI.cc -o CtoI_64.o
+ rm -f CtoI.o
+
+CtoIX11.o: CtoIX11.cc $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c CtoIX11.cc
+ rm -f CtoIX11_64.o
+
+CtoIX11_64.o: CtoIX11.cc $(INCL)/CtoI.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c CtoIX11.cc -o CtoIX11_64.o
+ rm -f CtoIX11.o
+
+BDDDG.o: BDDDG.cc $(INCL)/BDDDG.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c BDDDG.cc
+ rm -f BDDDG_64.o
+
+BDDDG_64.o: BDDDG.cc $(INCL)/BDDDG.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c BDDDG.cc -o BDDDG_64.o
+ rm -f BDDDG.o
+
+ZBDDDG.o: ZBDDDG.cc $(INCL)/ZBDDDG.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c ZBDDDG.cc
+ rm -f ZBDDDG_64.o
+
+ZBDDDG_64.o: ZBDDDG.cc $(INCL)/ZBDDDG.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c ZBDDDG.cc -o ZBDDDG_64.o
+ rm -f ZBDDDG.o
+
+PiDD.o: PiDD.cc $(INCL)/PiDD.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c PiDD.cc
+ rm -f PiDD_64.o
+
+PiDD_64.o: PiDD.cc $(INCL)/PiDD.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c PiDD.cc -o PiDD_64.o
+ rm -f PiDD.o
+
+SeqBDD.o: SeqBDD.cc $(INCL)/SeqBDD.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT) -c SeqBDD.cc
+ rm -f SeqBDD_64.o
+
+SeqBDD_64.o: SeqBDD.cc $(INCL)/SeqBDD.h $(INCL)/ZBDD.h $(INCL)/BDD.h
+ $(CC) $(OPT64) -c SeqBDD.cc -o SeqBDD_64.o
+ rm -f SeqBDD.o
+
--- /dev/null
+/****************************************
+ * PiDD class (SAPPORO-1.55) *
+ * (Main part) *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ****************************************/
+
+#include <math.h>
+#include "PiDD.h"
+
+//----------- Internal constant data for PiDD -----------
+static const char BC_PiDD_SWAP = 80;
+static const char BC_PiDD_COFACT = 81;
+static const char BC_PiDD_MULT = 82;
+static const char BC_PiDD_DIV = 83;
+static const char BC_PiDD_ODD = 84;
+
+//----------- Macros for operation cache -----------
+#define PiDD_CACHE_CHK_RETURN(op, fx, gx) \
+ { ZBDD z = BDD_CacheZBDD(op, fx, gx); \
+ if(z != -1) return PiDD(z); \
+ BDD_RECUR_INC; }
+
+#define PiDD_CACHE_ENT_RETURN(op, fx, gx, h) \
+ { BDD_RECUR_DEC; \
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h._zbdd.GetID()); \
+ return h; }
+
+//----------- External functions for PiDD ----------
+int PiDD_TopVar = 0;
+int PiDD_VarTableSize = 16;
+int PiDD_LevOfX[PiDD_MaxVar];
+int *PiDD_XOfLev;
+
+int PiDD_NewVar()
+{
+ if(PiDD_TopVar == PiDD_MaxVar)
+ BDDerr("PiDD_NewVar: Too large var ", (bddword) PiDD_TopVar);
+
+ if(PiDD_TopVar == 0)
+ {
+ PiDD_XOfLev = new int[PiDD_VarTableSize];
+ PiDD_XOfLev[0] = 0;
+ PiDD_LevOfX[0] = 0;
+ PiDD_LevOfX[1] = 0;
+ }
+
+ for(int i=0; i<PiDD_TopVar; i++) BDD_NewVar();
+ PiDD_TopVar++;
+
+ int toplev = BDD_TopLev();
+ if(PiDD_TopVar > 1) PiDD_LevOfX[PiDD_TopVar] = toplev;
+
+ if(PiDD_VarTableSize <= toplev)
+ {
+ int size = PiDD_VarTableSize;
+ int *table = PiDD_XOfLev;
+ PiDD_VarTableSize <<= 2;
+ PiDD_XOfLev = new int[PiDD_VarTableSize];
+ for(int i=0; i<size; i++) PiDD_XOfLev[i] = table[i];
+ delete[] table;
+ }
+
+ for(int i=0; i<(PiDD_TopVar-1); i++)
+ PiDD_XOfLev[toplev - i] = PiDD_TopVar;
+
+ return PiDD_TopVar;
+}
+
+int PiDD_VarUsed() { return PiDD_TopVar; }
+
+PiDD operator*(const PiDD& p, const PiDD& q)
+{
+ if(p == 0) return 0;
+ if(q == 0) return 0;
+ if(p == 1) return q;
+ if(q == 1) return p;
+ if(p == -1) return -1;
+ if(q == -1) return -1;
+
+ bddword pz = p._zbdd.GetID();
+ bddword qz = q._zbdd.GetID();
+ PiDD_CACHE_CHK_RETURN(BC_PiDD_MULT, pz, qz);
+
+ int qx = q.TopX();
+ int qy = q.TopY();
+ int top = q._zbdd.Top();
+ PiDD q0 = PiDD(q._zbdd.OffSet(top));
+ PiDD q1 = PiDD(q._zbdd.OnSet0(top));
+
+ PiDD r = (p * q0) + (p * q1).Swap(qx, qy);
+
+ PiDD_CACHE_ENT_RETURN(BC_PiDD_MULT, pz, qz, r);
+}
+
+PiDD operator/(const PiDD& f, const PiDD& p)
+{
+ if(f == -1) return -1;
+ if(p == -1) return -1;
+ if(p == 1) return f;
+ if(p == 0) BDDerr("operator/(): Divided by zero.");
+ int fx = f.TopX(); int px = p.TopX();
+ if(fx < px) return 0;
+
+ bddword fz = f._zbdd.GetID();
+ bddword pz = p._zbdd.GetID();
+ PiDD_CACHE_CHK_RETURN(BC_PiDD_DIV, fz, pz);
+
+ int py = p.TopY();
+ int top = p._zbdd.Top();
+ PiDD p1 = PiDD(p._zbdd.OnSet0(top));
+ PiDD q = (f.Cofact(px, py) / p1).Cofact(py, py);
+ if(q != 0)
+ {
+ PiDD p0 = PiDD(p._zbdd.OffSet(top));
+ if(p0 != 0) q &= f / p0;
+ }
+
+ PiDD_CACHE_ENT_RETURN(BC_PiDD_DIV, fz, pz, q);
+}
+
+//-------------- Class methods of PiDD -----------------
+
+/*
+PiDD& PiDD::operator&=(const PiDD& f) { return *this = *this & f; }
+PiDD& PiDD::operator+=(const PiDD& f) { return *this = *this + f; }
+PiDD& PiDD::operator-=(const PiDD& f) { return *this = *this - f; }
+PiDD& PiDD::operator*=(const PiDD& f) { return *this = *this * f; }
+PiDD& PiDD::operator/=(const PiDD& f) { return *this = *this / f; }
+PiDD& PiDD::operator%=(const PiDD& f) { return *this = *this % f; }
+*/
+
+PiDD PiDD::Swap(int u, int v) const
+{
+ if(_zbdd == -1) return -1;
+ int m = PiDD_VarUsed();
+ if(u <= 0 || u > m)
+ BDDerr("PiDD::Swap(): Invalid U ", (bddword) u);
+ if(v <= 0 || v > m)
+ BDDerr("PiDD::Swap(): Invalid V ", (bddword) v);
+ if(u == v) return *this;
+ if(u < v) return Swap(v, u);
+
+ int x = TopX();
+ int y = TopY();
+
+ if(x < u)
+ return PiDD(_zbdd.Change(BDD_VarOfLev(PiDD_Lev_XY(u, v))));
+
+ bddword pz = _zbdd.GetID();
+ bddword qz = u * (PiDD_MaxVar + 1) + v;
+ PiDD_CACHE_CHK_RETURN(BC_PiDD_SWAP, pz, qz);
+
+ int top = _zbdd.Top();
+ PiDD p0 = PiDD(_zbdd.OffSet(top));
+ PiDD p1 = PiDD(_zbdd.OnSet0(top));
+
+ PiDD r = p0.Swap(u, v)
+ + p1.Swap(PiDD_U_XYU(x,y,u), v).Swap(x, PiDD_Y_YUV(y,u,v));
+
+ PiDD_CACHE_ENT_RETURN(BC_PiDD_SWAP, pz, qz, r);
+}
+
+PiDD PiDD::Cofact(int u, int v) const
+{
+ if(_zbdd == -1) return -1;
+ int m = PiDD_VarUsed();
+ if(u <= 0 || u > m)
+ BDDerr("PiDD::Cofact(): Invalid U ", (bddword) u);
+ if(v <= 0 || v > m)
+ BDDerr("PiDD::Cofact(): Invalid V ", (bddword) v);
+
+ int x = TopX();
+ if(x < u || x < v) return (u == v)? *this: 0;
+
+ int y = TopY();
+ if(x == u && y > v) return 0;
+
+ int top = _zbdd.Top();
+ PiDD p0 = PiDD(_zbdd.OffSet(top));
+ PiDD p1 = PiDD(_zbdd.OnSet0(top));
+
+ if(x == u) return (y == v)? p1: p0.Cofact(u, v);
+ if(y == v) return p0.Cofact(u, v);
+
+ bddword pz = _zbdd.GetID();
+ bddword qz = u * (PiDD_MaxVar + 1) + v;
+ PiDD_CACHE_CHK_RETURN(BC_PiDD_COFACT, pz, qz);
+
+ PiDD r = p0.Cofact(u, v);
+ if(u >= v) r += p1.Cofact(u, v).Swap(x, PiDD_Y_YUV(y, u, v));
+ else r += p1.Cofact(u, PiDD_U_XYU(x,y,v)).Swap(x, PiDD_Y_YUV(y,v,u));
+
+ PiDD_CACHE_ENT_RETURN(BC_PiDD_COFACT, pz, qz, r);
+}
+
+PiDD PiDD::Odd() const
+{
+ if(_zbdd == -1) return -1;
+
+ int x = TopX();
+ if(x == 0) return 0;
+
+ bddword pz = _zbdd.GetID();
+ PiDD_CACHE_CHK_RETURN(BC_PiDD_ODD, pz, 0);
+
+ int y = TopY();
+ int top = _zbdd.Top();
+ PiDD p0 = PiDD(_zbdd.OffSet(top));
+ PiDD p1 = PiDD(_zbdd.OnSet0(top));
+ PiDD r = p0.Odd() + p1.Even().Swap(x,y);
+
+ PiDD_CACHE_ENT_RETURN(BC_PiDD_ODD, pz, 0, r);
+}
+
+PiDD PiDD::Even() const { return *this - this->Odd(); }
+
+PiDD PiDD::SwapBound(int n) const { return PiDD(_zbdd.PermitSym(n)); }
+
+bddword PiDD::Size() const { return _zbdd.Size(); }
+bddword PiDD::Card() const { return _zbdd.Card(); }
+
+void PiDD::Print() const { _zbdd.Print(); }
+
+static int* VarMap;
+static int Flag;
+static int Depth;
+
+static void PiDD_Enum(PiDD, int);
+static void PiDD_Enum(PiDD p, int dim)
+{
+ if(p == -1) return;
+ if(p == 0) return;
+ if(p == 1)
+ {
+ if(Flag) cout << " + ";
+ else Flag = 1;
+ int d0 = 0;
+ for(int i=0; i<dim; i++) if(VarMap[i] != i + 1) d0 = i + 1;
+ if(d0 == 0) cout << "1";
+ else
+ {
+ cout << "[";
+ for(int i=0; i<d0; i++)
+ {
+ if(i > 0) cout << " ";
+ int a = VarMap[i];
+ if(a == i + 1) cout << ".";
+ else cout << a;
+ }
+ cout << "]";
+ }
+ return;
+ }
+ int x = p.TopX();
+ int y = p.TopY();
+ PiDD p1 = p.Cofact(x, y);
+ PiDD p0 = p - p1.Swap(x, y);
+ PiDD_Enum(p0, dim);
+ int t;
+ t = VarMap[x-1]; VarMap[x-1] = VarMap[y-1]; VarMap[y-1] = t;
+ PiDD_Enum(p1, dim);
+ t = VarMap[x-1]; VarMap[x-1] = VarMap[y-1]; VarMap[y-1] = t;
+}
+
+void PiDD::Enum() const
+{
+ if(*this == -1)
+ {
+ cout << "(undefined)\n";
+ cout.flush();
+ return;
+ }
+ if(*this == 0)
+ {
+ cout << "0\n";
+ cout.flush();
+ return;
+ }
+ if(*this == 1)
+ {
+ cout << "1\n";
+ cout.flush();
+ return;
+ }
+
+ Flag = 0;
+ int dim = TopX();
+ VarMap = new int[dim];
+ for(int i=0; i<dim; i++) VarMap[i] = i+1;
+ PiDD_Enum(*this, dim);
+ delete[] VarMap;
+ cout << "\n";
+ cout.flush();
+}
+
+static void PiDD_Enum2(PiDD);
+static void PiDD_Enum2(PiDD p)
+{
+ if(p == -1) return;
+ if(p == 0) return;
+ if(p == 1)
+ {
+ if(Flag) cout << " + ";
+ else Flag = 1;
+ if(Depth == 0) cout << "1";
+ else
+ {
+ for(int i=0; i<Depth; i++)
+ {
+ int a = VarMap[Depth - i - 1];
+ int x = PiDD_X_Lev(a);
+ int y = PiDD_Y_Lev(a);
+ cout << "(" << x << ":" << y << ")";
+ }
+ }
+ return;
+ }
+ int x = p.TopX();
+ int y = p.TopY();
+ PiDD p1 = p.Cofact(x, y);
+ PiDD p0 = p - p1.Swap(x, y);
+ PiDD_Enum2(p0);
+ VarMap[Depth++] = p.TopLev();
+ PiDD_Enum2(p1);
+ Depth--;
+}
+
+void PiDD::Enum2() const
+{
+ if(*this == -1)
+ {
+ cout << "(undefined)\n";
+ cout.flush();
+ return;
+ }
+ if(*this == 0)
+ {
+ cout << "0\n";
+ cout.flush();
+ return;
+ }
+ if(*this == 1)
+ {
+ cout << "1\n";
+ cout.flush();
+ return;
+ }
+
+ Flag = 0;
+ int dim = TopX();
+ VarMap = new int[dim];
+ Depth = 0;
+ PiDD_Enum2(*this);
+ delete[] VarMap;
+ cout << "\n";
+ cout.flush();
+}
+
--- /dev/null
+/****************************************
+ * ZBDD-based SOP class (SAPPORO-1.55) *
+ * (Main part) *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ****************************************/
+
+#include "SOP.h"
+
+//----------- Internal constant data for SOP -----------
+static const char BC_SOP_MULT = 30;
+static const char BC_SOP_DIV = 31;
+static const char BC_SOP_BDD = 33;
+static const char BC_ISOP1 = 34;
+static const char BC_ISOP2 = 35;
+static const char BC_SOP_IMPL = 36;
+static const char BC_SOP_SUPPORT = 37;
+
+//----------- Macros for operation cache -----------
+#define SOP_CACHE_CHK_RETURN(op, fx, gx) \
+ { ZBDD z = BDD_CacheZBDD(op, fx, gx); \
+ if(z != -1) return SOP(z); \
+ BDD_RECUR_INC; }
+
+#define SOP_CACHE_ENT_RETURN(op, fx, gx, h) \
+ { BDD_RECUR_DEC; \
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h.GetZBDD().GetID()); \
+ return h; }
+
+#define BDD_CACHE_CHK_RETURN(op, fx, gx) \
+ { BDD h = BDD_CacheBDD(op, fx, gx); \
+ if(h != -1) return h; \
+ BDD_RECUR_INC; }
+
+#define BDD_CACHE_ENT_RETURN(op, fx, gx, h) \
+ { BDD_RECUR_DEC; \
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h.GetID()); \
+ return h; }
+
+//----------- External functions for SOP ----------
+
+int SOP_NewVar() { BDD_NewVar(); return BDD_NewVar(); }
+
+int SOP_NewVarOfLev(int lev)
+{
+ if(lev & 1) BDDerr("SOP_NewVarOfLev: Invalid lev.", lev);
+ BDD_NewVarOfLev(lev - 1);
+ return BDD_NewVarOfLev(lev);
+}
+
+SOP operator*(const SOP& pc, const SOP& qc)
+{
+ if(pc == -1) return -1;
+ if(qc == -1) return -1;
+ if(pc == 0) return 0;
+ if(qc == 0) return 0;
+ if(pc == 1) return qc;
+ if(qc == 1) return pc;
+
+ SOP p = pc; SOP q = qc;
+ int top = p.Top();
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(q.Top()))
+ {
+ p = qc; q = pc;
+ top = p.Top();
+ }
+
+ bddword px = p.GetZBDD().GetID();
+ bddword qx = q.GetZBDD().GetID();
+ SOP_CACHE_CHK_RETURN(BC_SOP_MULT, px, qx);
+
+ SOP p1 = p.Factor1(top);
+ SOP p0 = p.Factor0(top);
+ SOP pD = p.FactorD(top);
+ SOP r;
+ if(top != q.Top())
+ r = (p1*q).And1(top) + (p0*q).And0(top) + (pD*q);
+ else
+ {
+ SOP q1 = q.Factor1(top);
+ SOP q0 = q.Factor0(top);
+ SOP qD = q.FactorD(top);
+
+ r = ((p1*q1)+(p1*qD)+(pD*q1)).And1(top)
+ + ((p0*q0)+(p0*qD)+(pD*q0)).And0(top)
+ + (pD*qD);
+ }
+
+ SOP_CACHE_ENT_RETURN(BC_SOP_MULT, px, qx, r);
+}
+
+SOP operator/(const SOP& fc, const SOP& pc)
+{
+ if(fc == -1) return -1;
+ if(pc == -1) return -1;
+ if(pc == 1) return fc;
+ if(fc == pc) return 1;
+ if(pc == 0) BDDerr("operator /(): Divided by zero.");
+
+ SOP f = fc; SOP p = pc;
+ int top = p.Top();
+ if(BDD_LevOfVar(f.Top()) < BDD_LevOfVar(top)) return 0;
+
+ bddword fx = f.GetZBDD().GetID();
+ bddword px = p.GetZBDD().GetID();
+ SOP_CACHE_CHK_RETURN(BC_SOP_DIV, fx, px);
+
+ SOP q = -1;
+ SOP p1 = p.Factor1(top);
+ if(p1 != 0) q = f.Factor1(top) / p1;
+ if(q != 0)
+ {
+ SOP p0 = p.Factor0(top);
+ if(p0 != 0)
+ {
+ if(q == -1) q = f.Factor0(top) / p0;
+ else q &= f.Factor0(top) / p0;
+ }
+ if(q != 0)
+ {
+ SOP pD = p.FactorD(top);
+ if(pD != 0)
+ {
+ if(q == -1) q = f.FactorD(top) / pD;
+ else q &= f.FactorD(top) / pD;
+ }
+ }
+ }
+
+ SOP_CACHE_ENT_RETURN(BC_SOP_DIV, fx, px, q);
+}
+
+//-------------- Class methods of SOP -----------------
+
+SOP SOP::operator<<(int n) const
+{
+ if(n & 1) BDDerr("SOP::operator<<: Invalid shift.", n);
+ return SOP(_zbdd << n);
+}
+
+SOP SOP::operator>>(int n) const
+{
+ if(n & 1) BDDerr("SOP::operator>>: Invalid shift.", n);
+ return SOP(_zbdd >> n);
+}
+
+SOP SOP::And0(int v) const
+{
+ if(v & 1) BDDerr("SOP::And0: VarID must be even number.", v);
+ ZBDD f = _zbdd.OffSet(v);
+ f = f.OnSet0(v-1) + f.OffSet(v-1);
+ f = f.Change(v-1);
+ return SOP(f);
+}
+
+SOP SOP::And1(int v) const
+{
+ if(v & 1) BDDerr("SOP::And1: VarID must be even number.", v);
+ ZBDD f = _zbdd.OffSet(v-1);
+ f = f.OnSet0(v) + f.OffSet(v);
+ f = f.Change(v);
+ return SOP(f);
+}
+
+SOP SOP::Factor0(int v) const
+{
+ if(v & 1) BDDerr("SOP::Factor0: VarID must be even number.", v);
+ ZBDD f = _zbdd.OnSet0(v-1);
+ return SOP(f);
+}
+
+SOP SOP::Factor1(int v) const
+{
+ if(v & 1) BDDerr("SOP::Factor1: VarID must be even number.", v);
+ ZBDD f = _zbdd.OnSet0(v);
+ return SOP(f);
+}
+
+SOP SOP::FactorD(int v) const
+{
+ if(v & 1) BDDerr("SOP::FactorD: VarID must be even number.", v);
+ ZBDD f = _zbdd.OffSet(v).OffSet(v-1);
+ return SOP(f);
+}
+
+bddword SOP::Size() const { return _zbdd.Size(); }
+bddword SOP::Cube() const { return _zbdd.Card(); }
+bddword SOP::Lit() const { return _zbdd.Lit(); }
+
+void SOP::Print() const
+{
+ cout << "[ " << _zbdd.GetID();
+ cout << " Var:" << Top() << "(" << BDD_LevOfVar(Top()) << ")";
+ cout << " Size:" << Size() << " ]\n";
+ cout.flush();
+}
+
+int SOP::PrintPla() const { return SOPV(*this).PrintPla(); }
+
+BDD SOP::GetBDD() const
+{
+ if(*this == -1) return -1;
+ if(*this == 0) return 0;
+ if(*this == 1) return 1;
+
+ bddword sx = GetZBDD().GetID();
+ BDD_CACHE_CHK_RETURN(BC_SOP_BDD, sx, 0);
+
+ int top = Top();
+ BDD x = BDDvar(top);
+ SOP p1 = Factor1(top);
+ SOP p0 = Factor0(top);
+ SOP pD = FactorD(top);
+ BDD f = (x & p1.GetBDD()) | (~x & p0.GetBDD()) | pD.GetBDD();
+
+ BDD_CACHE_ENT_RETURN(BC_SOP_BDD, sx, 0, f);
+}
+
+SOP SOP::InvISOP() const { return SOP_ISOP(~GetBDD()); }
+
+int SOP::IsPolyCube() const
+{
+ int top = Top();
+ if(top == 0) return 0;
+ SOP f1 = Factor1(top);
+ SOP f0 = Factor0(top);
+ SOP fD = FactorD(top);
+ if(f1 != 0)
+ {
+ if(f0 != 0) return 1;
+ if(fD != 0) return 1;
+ return f1.IsPolyCube();
+ }
+ if(fD != 0) return 1;
+ return f0.IsPolyCube();
+}
+
+int SOP::IsPolyLit() const
+{
+ int top = Top();
+ if(top == 0) return 0;
+ SOP fD = FactorD(top);
+ if(fD != 0) return 1;
+ SOP f0 = Factor0(top);
+ SOP f1 = Factor1(top);
+ if(f0 == 1) if(f1 == 0) return 0;
+ if(f0 == 0) if(f1 == 1) return 0;
+ return 1;
+}
+
+SOP SOP::Support() const
+{
+ if(*this == -1) return -1;
+ if(*this == 0) return 0;
+ if(*this == 1) return 0;
+
+ ZBDD fz = GetZBDD().Support();
+ SOP f = SOP(fz);
+ int t;
+ while(fz != 0)
+ {
+ t = fz.Top();
+ fz = fz.OffSet(t);
+ if(t & 1) f = f.FactorD(t).And1(t);
+ }
+
+ return f;
+}
+
+SOP SOP::Divisor() const
+{
+ if(*this == -1) return -1;
+ if(*this == 0) return 0;
+ if(IsPolyCube() == 0) return 1;
+ int top = Top();
+ SOP f = *this;
+ SOP g = Support();
+ int t;
+ while(g != 0)
+ {
+ t = g.Top();
+ g = g.FactorD(t);
+ SOP f0 = f.Factor0(t);
+ SOP f1 = f.Factor1(t);
+ if(f0.IsPolyCube() == 1) f = f0;
+ else if(f1.IsPolyCube() == 1) f = f1;
+ }
+ return f;
+}
+
+SOP SOP::Swap(int v1, int v2) const
+{
+ if(v1 & 1) BDDerr("SOP::Swap: VarID must be even number.", v1);
+ if(v2 & 1) BDDerr("SOP::Swap: VarID must be even number.", v2);
+ ZBDD z = GetZBDD();
+ z = z.Swap(v1, v2);
+ z = z.Swap(v1-1, v2-1);
+ return SOP(z);
+}
+
+SOP SOP::Implicants(BDD f) const
+{
+ if(*this == 0) return 0;
+ if(f == 0) return 0;
+ if(f == 1) return *this;
+ if(*this == 1) return 0;
+
+ bddword fx = GetZBDD().GetID();
+ bddword gx = f.GetID();
+ SOP_CACHE_CHK_RETURN(BC_SOP_IMPL, fx, gx);
+
+ int top = Top();
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(f.Top())) top = f.Top();
+
+ BDD f0 = f.At0(top);
+ BDD f1 = f.At1(top);
+ SOP imp = Factor0(top).Implicants(f0).And0(top)
+ + Factor1(top).Implicants(f1).And1(top);
+ SOP pD = FactorD(top);
+ if(pD != 0) imp += pD.Implicants(f0 & f1);
+
+ SOP_CACHE_ENT_RETURN(BC_SOP_IMPL, fx, gx, imp);
+}
+
+
+//----------- External functions for SOP ----------
+
+int SOPV_NewVar() { BDD_NewVar(); return BDD_NewVar(); }
+
+int SOPV_NewVarOfLev(int lev)
+{
+ BDD_NewVarOfLev(lev - 1);
+ return BDD_NewVarOfLev(lev);
+}
+
+//-------------- Class methods of SOPV -----------------
+
+SOPV SOPV::operator<<=(int n) { return *this = *this << n; }
+SOPV SOPV::operator>>=(int n) { return *this = *this >> n; }
+
+SOPV SOPV::And0(int v) const
+{
+ if(v & 1) BDDerr("SOPV::And0: VarID must be even number.", v);
+ ZBDDV f = _v.OffSet(v);
+ f = f.OnSet0(v-1) + f.OffSet(v-1);
+ f = f.Change(v-1);
+ return SOPV(f);
+}
+
+SOPV SOPV::And1(int v) const
+{
+ if(v & 1) BDDerr("SOPV::And1: VarID must be even number.", v);
+ ZBDDV f = _v.OffSet(v-1);
+ f = f.OnSet0(v) + f.OffSet(v);
+ f = f.Change(v);
+ return SOPV(f);
+}
+
+SOPV SOPV::Factor0(int v) const
+{
+ if(v & 1) BDDerr("SOPV::Factor0: VarID must be even number.", v);
+ ZBDDV f = _v.OnSet0(v-1);
+ return SOPV(f);
+}
+
+SOPV SOPV::Factor1(int v) const
+{
+ if(v & 1) BDDerr("SOPV::Factor1: VarID must be even number.", v);
+ ZBDDV f = _v.OnSet0(v);
+ return SOPV(f);
+}
+
+SOPV SOPV::FactorD(int v) const
+{
+ if(v & 1) BDDerr("SOPV::FactorD: VarID must be even number.", v);
+ ZBDDV f = _v.OffSet(v).OffSet(v-1);
+ return SOPV(f);
+}
+
+bddword SOPV::Size() const { return _v.Size(); }
+
+SOP SOPV::GetSOP(int index) const { return SOP(_v.GetZBDD(index)); }
+
+SOPV SOPV::Swap(int v1, int v2) const
+{
+ if(v1 & 1) BDDerr("SOPV::Swap: VarID must be even number.", v1);
+ if(v2 & 1) BDDerr("SOPV::Swap: VarID must be even number.", v2);
+ ZBDDV z = GetZBDDV();
+ z = z.Swap(v1, v2);
+ z = z.Swap(v1-1, v2-1);
+ return SOPV(z);
+}
+
+bddword SOPV::Cube() const
+{
+ SOPV v = *this;
+ SOP sum = 0;
+ while(v != SOPV())
+ {
+ if(v == SOPV(-1)) return 0;
+ int last = v.Last();
+ sum += v.GetSOP(last);
+ v -= v.Mask(last);
+ }
+ return sum.Cube();
+}
+
+bddword SOPV::Lit() const
+{
+ SOPV v = *this;
+ SOP sum = 0;
+ while(v != SOPV())
+ {
+ if(v == SOPV(-1)) return 0;
+ int last = v.Last();
+ SOP f = v.GetSOP(last);
+ sum += f;
+ v -= v.Mask(last);
+ }
+ return sum.Lit();
+}
+
+void SOPV::Print() const
+{
+ int len = this -> Last() + 1;
+ for(int i=0; i<len; i++)
+ {
+ cout << "f" << i << ": ";
+ GetSOP(i).Print();
+ }
+ cout << "Size= " << Size() << "\n";
+ cout << "Cube= " << Cube() << "\n";
+ cout << "Lit= " << Lit() << "\n\n";
+ cout.flush();
+}
+
+static int Len;
+static char* Array;
+static int SOPV_PLA(const SOPV &, int);
+static int SOPV_PLA(const SOPV& v, int tlev)
+{
+ if(v == SOPV(-1)) return 1;
+ if(v == SOPV()) return 0;
+ SOPV vv = v;
+ if(tlev == 0)
+ {
+ cout << Array << " ";
+ for(int i=0; i<Len; i++)
+ if(vv.GetSOP(i) == 0) cout << "~";
+ else cout << "1";
+ cout << "\n";
+ cout.flush();
+ return 0;
+ }
+ else
+ {
+ Array[tlev/2-1] = '1';
+ if(SOPV_PLA(vv.Factor1(BDD_VarOfLev(tlev)), tlev-2) == 1)
+ return 1;
+ Array[tlev/2-1] = '0';
+ if(SOPV_PLA(vv.Factor0(BDD_VarOfLev(tlev)), tlev-2) == 1)
+ return 1;
+ Array[tlev/2-1] = '-';
+ return SOPV_PLA(vv.FactorD(BDD_VarOfLev(tlev)), tlev-2);
+ }
+}
+
+int SOPV::PrintPla() const
+{
+ if(*this == SOPV(-1)) return 1;
+ int tlev = BDD_LevOfVar(Top());
+ Len = Last() + 1;
+ cout << ".i " << tlev/2 << "\n";
+ cout << ".o " << Len << "\n";
+ if(tlev > 0)
+ {
+ Array = new char[tlev/2 + 1];
+ Array[tlev/2] = 0;
+ int err = SOPV_PLA(*this, tlev);
+ delete[] Array;
+ if(err == 1) return 1;
+ }
+ else
+ {
+ for(int i=0; i<Len; i++)
+ if(GetSOP(i) == 0) cout << "0";
+ else cout << "1";
+ cout << "\n";
+ }
+ cout << ".e\n";
+ cout.flush();
+ return 0;
+}
+
+//--------- Advanced external functions for SOP/SOPV ---------
+
+struct BCpair
+{
+ BDD _f;
+ SOP _cs;
+ BCpair() { _f = 0; _cs = 0; }
+ BCpair(const BDD& f, const SOP& cs) { _f = f; _cs = cs; }
+ BCpair(const BCpair& p) { _f = p._f; _cs = p._cs; }
+};
+
+static BCpair ISOP(BDD, BDD);
+BCpair ISOP(BDD s, BDD r)
+{
+ if(s == -1) return BCpair(-1, -1);
+ if(r == -1) return BCpair(-1, -1);
+ if(r == 1) return BCpair(0, 0);
+ if(s == 1) return BCpair(1, 1);
+
+ bddword sx = s.GetID();
+ bddword rx = r.GetID();
+ BDD f = BDD_CacheBDD(BC_ISOP1, sx, rx);
+ ZBDD z = BDD_CacheZBDD(BC_ISOP2, sx, rx);
+ if(f != -1) if(z != -1) return BCpair(f, SOP(z));
+ BDD_RECUR_INC;
+
+ int top = s.Top();
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(r.Top())) top = r.Top();
+
+ BDD s0 = s.At0(top);
+ BDD r0 = r.At0(top);
+ BDD s1 = s.At1(top);
+ BDD r1 = r.At1(top);
+
+ BCpair bc1 = ISOP(s1, r1 | s0);
+ SOP c1 = bc1._cs.And1(top);
+
+ BCpair bc0 = ISOP(s0, r0 | s1);
+ SOP c0 = bc0._cs.And0(top);
+
+ BDD sD = (s0 & s1);
+ BCpair bcD = ISOP(sD, ~sD |( (r0|bc0._f) & (r1|bc1._f) ));
+ SOP cD = bcD._cs;
+
+ BDD x = BDDvar(top);
+ f = (~x & bc0._f)|(x & bc1._f)| bcD._f;
+ SOP cs = c1 + c0 + cD;
+
+ BDD_RECUR_DEC;
+ if(f == -1) return BCpair(-1, -1);
+ if(cs == -1) return BCpair(-1, -1);
+ BDD_CacheEnt(BC_ISOP1, sx, rx, f.GetID());
+ BDD_CacheEnt(BC_ISOP2, sx, rx, cs.GetZBDD().GetID());
+ return BCpair(f, cs);
+}
+
+SOP SOP_ISOP(BDD f) { return ISOP(f, ~f)._cs; }
+
+SOP SOP_ISOP(BDD on, BDD dc)
+{
+ return ISOP(on | dc, ~on |dc)._cs;
+}
+
+SOPV SOPV_ISOP(BDDV v) { return SOPV_ISOP(v, BDDV(0, v.Len())); }
+
+SOPV SOPV_ISOP(BDDV on, BDDV dc)
+{
+ int len = on.Len();
+ if(len != dc.Len()) BDDerr("SOPV_ISOP(): Len mismatch.");
+ int top = on.Top();
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(dc.Top())) top = dc.Top();
+ SOPV csv(0, 0);
+ for(int i=0; i<len; i++)
+ {
+ SOP cs = SOP_ISOP(on.GetBDD(i), dc.GetBDD(i));
+ csv += SOPV(cs, i);
+ }
+ return csv;
+}
+
+SOPV SOPV_ISOP2(BDDV v) { return SOPV_ISOP2(v, BDDV(0, v.Len())); }
+
+SOPV SOPV_ISOP2(BDDV on, BDDV dc)
+{
+ int len = on.Len();
+ if(len != dc.Len()) BDDerr("SOPV_ISOP2(): Len mismatch,");
+ int top = on.Top();
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(dc.Top())) top = dc.Top();
+ SOPV csv;
+ SOPV phase;
+ for(int i=0; i<len; i++)
+ {
+ SOP cs1 = SOP_ISOP(on.GetBDD(i), dc.GetBDD(i));
+ if(cs1 == -1) return SOPV(-1);
+ SOP cs2 = SOP_ISOP(~on.GetBDD(i), dc.GetBDD(i));
+ if(cs2 == -1) return SOPV(-1);
+ int lit1 = (csv + SOPV(cs1, i)).Lit();
+ int lit2 = (csv + SOPV(cs2, i)).Lit();
+
+ if(lit1 <= lit2)
+ {
+ csv += SOPV(cs1, i);
+ phase += SOPV(0, i+len);
+ }
+ else
+ {
+ csv += SOPV(cs2, i);
+ phase += SOPV(1, i+len);
+ }
+ }
+ return csv + phase;
+}
+
--- /dev/null
+/****************************************\r
+ * SeqBDD Class (SAPPORO-1.55) *\r
+ * (Main part) *\r
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *\r
+ ****************************************/\r
+\r
+#include "SeqBDD.h"\r
+\r
+//------------ Internal constant data for SeqBDD ----------\r
+static const char BC_SeqBDD_MULT = 70;\r
+\r
+//----------- Macros for operation cache -----------\r
+#define SeqBDD_CACHE_CHK_RETURN(op, fx, gx) \\r
+ { ZBDD z = BDD_CacheZBDD(op, fx, gx); \\r
+ if(z != -1) return SeqBDD(z); \\r
+ BDD_RECUR_INC; }\r
+\r
+#define SeqBDD_CACHE_ENT_RETURN(op, fx, gx, h) \\r
+ { BDD_RECUR_DEC; \\r
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h.GetZBDD().GetID()); \\r
+ return h; }\r
+\r
+// class SeqBDD ---------------------------------------------\r
+\r
+SeqBDD SeqBDD::OffSet(int v) const\r
+{\r
+ ZBDD f = _zbdd;\r
+ ZBDD h = 0;\r
+ int top = f.Top();\r
+ while(BDD_LevOfVar(v) < BDD_LevOfVar(top))\r
+ {\r
+ h += f.OnSet(top);\r
+ f = f.OffSet(top);\r
+ top = f.Top();\r
+ }\r
+ return SeqBDD(h + f.OffSet(v));\r
+}\r
+\r
+SeqBDD SeqBDD::OnSet(int v) const\r
+{\r
+ ZBDD f = _zbdd;\r
+ int top = f.Top();\r
+ while(BDD_LevOfVar(v) < BDD_LevOfVar(top))\r
+ {\r
+ f = f.OffSet(top);\r
+ top = f.Top();\r
+ }\r
+ return SeqBDD(f.OnSet(v));\r
+}\r
+\r
+SeqBDD SeqBDD::OnSet0(int v) const\r
+{\r
+ ZBDD f = _zbdd;\r
+ int top = f.Top();\r
+ while(BDD_LevOfVar(v) < BDD_LevOfVar(top))\r
+ {\r
+ f = f.OffSet(top);\r
+ top = f.Top();\r
+ }\r
+ return SeqBDD(f.OnSet0(v));\r
+}\r
+\r
+bddword SeqBDD::Size() const { return _zbdd.Size(); }\r
+bddword SeqBDD::Card() const { return _zbdd.Card(); }\r
+bddword SeqBDD::Lit() const { return _zbdd.Lit(); }\r
+bddword SeqBDD::Len() const { return _zbdd.Len(); }\r
+\r
+void SeqBDD::Export(FILE *strm) const { _zbdd.Export(strm); }\r
+\r
+void SeqBDD::Print() const { GetZBDD().Print(); }\r
+\r
+SeqBDD operator*(const SeqBDD& f, const SeqBDD& g)\r
+{\r
+ if(f == -1) return -1;\r
+ if(g == -1) return -1;\r
+ if(f == 0) return 0;\r
+ if(g == 0) return 0;\r
+ if(f == 1) return g;\r
+ if(g == 1) return f;\r
+\r
+ int ftop = f.Top();\r
+ bddword fx = f.GetZBDD().GetID();\r
+ bddword gx = g.GetZBDD().GetID();\r
+\r
+ SeqBDD_CACHE_CHK_RETURN(BC_SeqBDD_MULT, fx, gx);\r
+\r
+ SeqBDD f1 = f.OnSet0(ftop);\r
+ SeqBDD f0 = f.OffSet(ftop);\r
+ SeqBDD h = f1 * g;\r
+ h = h.Push(ftop) + (f0 * g);\r
+\r
+ SeqBDD_CACHE_ENT_RETURN(BC_SeqBDD_MULT, fx, gx, h);\r
+}\r
+\r
+static int* Seq;\r
+static bddword Index;\r
+static int Flag;\r
+\r
+static void SeqBDD_PrintSeq(SeqBDD);\r
+static void SeqBDD_PrintSeq(SeqBDD f)\r
+{\r
+ if((f & 1)== 1)\r
+ {\r
+ if(Flag > 0) cout << "+ ";\r
+ if(Index == 0) cout << "e ";\r
+ else for(int i=0; i<Index; i++) cout << Seq[i] << " ";\r
+ Flag = 1;\r
+ cout.flush();\r
+ f -= 1;\r
+ }\r
+ if(f == 0) return;\r
+ int top = f.Top();\r
+ SeqBDD f1 = f.OnSet0(top);\r
+ Seq[Index] = BDD_LevOfVar(top);\r
+ Index++;\r
+ SeqBDD_PrintSeq(f1);\r
+ Index--;\r
+ SeqBDD f0 = f.OffSet(top);\r
+ SeqBDD_PrintSeq(f0);\r
+}\r
+\r
+void SeqBDD::PrintSeq() const\r
+{\r
+ if(*this == -1)\r
+ {\r
+ cout << "(undefined)\n";\r
+ cout.flush();\r
+ return;\r
+ }\r
+ if(*this == 0)\r
+ {\r
+ cout << "(empty)\n";\r
+ cout.flush();\r
+ return;\r
+ }\r
+ bddword len = Len();\r
+ Seq = new int[len];\r
+ Index = 0;\r
+ Flag = 0;\r
+ SeqBDD_PrintSeq(*this);\r
+ delete[] Seq;\r
+ cout << "\n";\r
+ cout.flush();\r
+}\r
--- /dev/null
+/****************************************\r
+ * ZBDD+ Manipulator (SAPPORO-1.58) *\r
+ * (Main part) *\r
+ * (C) Shin-ichi MINATO (Nov. 22, 2013) *\r
+ ****************************************/\r
+\r
+#include "ZBDD.h"\r
+\r
+#define BDD_CPP\r
+#include "bddc.h"\r
+\r
+static const char BC_ZBDD_MULT = 20;\r
+static const char BC_ZBDD_DIV = 21;\r
+static const char BC_ZBDD_RSTR = 22;\r
+static const char BC_ZBDD_PERMIT = 23;\r
+static const char BC_ZBDD_PERMITSYM = 24;\r
+static const char BC_ZBDD_SYMCHK = 25;\r
+static const char BC_ZBDD_ALWAYS = 26;\r
+static const char BC_ZBDD_SYMSET = 27;\r
+static const char BC_ZBDD_COIMPSET = 28;\r
+static const char BC_ZBDD_MEET = 29;\r
+\r
+static const char BC_ZBDD_ZSkip = 65;\r
+static const char BC_ZBDD_INTERSEC = 66;\r
+\r
+extern "C"\r
+{\r
+ int rand();\r
+};\r
+\r
+// class ZBDD ---------------------------------------------\r
+\r
+void ZBDD::Export(FILE *strm) const\r
+{\r
+ bddword p = _zbdd;\r
+ bddexport(strm, &p, 1);\r
+}\r
+\r
+void ZBDD::Print() const\r
+{\r
+ cout << "[ " << GetID();\r
+ cout << " Var:" << Top() << "(" << BDD_LevOfVar(Top()) << ")";\r
+ cout << " Size:" << Size() << " Card:";\r
+ cout << Card() << " Lit:" << Lit() << " Len:" << Len() << " ]\n";\r
+ cout.flush();\r
+}\r
+\r
+void ZBDD::PrintPla() const { ZBDDV(*this).PrintPla(); }\r
+\r
+#define ZBDD_CACHE_CHK_RETURN(op, fx, gx) \\r
+ { ZBDD h = BDD_CacheZBDD(op, fx, gx); \\r
+ if(h != -1) return h; \\r
+ BDD_RECUR_INC; }\r
+\r
+#define ZBDD_CACHE_ENT_RETURN(op, fx, gx, h) \\r
+ { BDD_RECUR_DEC; \\r
+ if(h != -1) BDD_CacheEnt(op, fx, gx, h.GetID()); \\r
+ return h; }\r
+\r
+ZBDD ZBDD::Swap(int v1, int v2) const\r
+{\r
+ if(v1 == v2) return *this;\r
+ ZBDD f00 = this->OffSet(v1).OffSet(v2);\r
+ ZBDD f11 = this->OnSet(v1).OnSet(v2);\r
+ ZBDD h = *this - f00 - f11;\r
+ return h.Change(v1).Change(v2) + f00 + f11;\r
+}\r
+\r
+ZBDD ZBDD::Restrict(const ZBDD& g) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(g == -1) return -1;\r
+ if(*this == 0) return 0;\r
+ if(g == 0) return 0;\r
+ if(*this == g) return g;\r
+ if((g & 1) == 1) return *this;\r
+ ZBDD f = *this - 1;\r
+\r
+ int top = f.Top();\r
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(g.Top())) top = g.Top();\r
+\r
+ bddword fx = f.GetID();\r
+ bddword gx = g.GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_RSTR, fx, gx);\r
+\r
+ ZBDD f1 = f.OnSet0(top);\r
+ ZBDD f0 = f.OffSet(top);\r
+ ZBDD g1 = g.OnSet0(top);\r
+ ZBDD g0 = g.OffSet(top);\r
+ ZBDD h = f1.Restrict(g1 + g0).Change(top) + f0.Restrict(g0);\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_RSTR, fx, gx, h);\r
+}\r
+\r
+ZBDD ZBDD::Permit(const ZBDD& g) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(g == -1) return -1;\r
+ if(*this == 0) return 0;\r
+ if(g == 0) return 0;\r
+ if(*this == g) return *this;\r
+ if(g == 1) return *this & 1;\r
+ if(*this == 1) return 1;\r
+\r
+ int top = Top();\r
+ if(BDD_LevOfVar(top) < BDD_LevOfVar(g.Top())) top = g.Top();\r
+\r
+ bddword fx = GetID();\r
+ bddword gx = g.GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_PERMIT, fx, gx);\r
+\r
+ ZBDD f1 = OnSet0(top);\r
+ ZBDD f0 = OffSet(top);\r
+ ZBDD g1 = g.OnSet0(top);\r
+ ZBDD g0 = g.OffSet(top);\r
+ ZBDD h = f1.Permit(g1).Change(top) + f0.Permit(g0 + g1);\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_PERMIT, fx, gx, h);\r
+}\r
+\r
+ZBDD ZBDD::PermitSym(int n) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(*this == 0) return 0;\r
+ if(*this == 1) return 1;\r
+ if(n < 1) return *this & 1;\r
+\r
+ int top = Top();\r
+\r
+ bddword fx = GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_PERMITSYM, fx, n);\r
+\r
+ ZBDD f1 = OnSet0(top);\r
+ ZBDD f0 = OffSet(top);\r
+ ZBDD h = f1.PermitSym(n - 1).Change(top) + f0.PermitSym(n);\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_PERMITSYM, fx, n, h);\r
+}\r
+\r
+ZBDD ZBDD::Always() const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(*this == 0 || *this == 1) return 0;\r
+\r
+ bddword fx = GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_ALWAYS, fx, 0);\r
+\r
+ int t = Top();\r
+ ZBDD f1 = OnSet0(t);\r
+ ZBDD f0 = OffSet(t);\r
+ ZBDD h = f1.Always();\r
+ if(f0 == 0) h += ZBDD(1).Change(t);\r
+ else if(h != 0) h &= f0.Always();\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_ALWAYS, fx, 0, h);\r
+}\r
+\r
+int ZBDD::SymChk(int v1, int v2) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v1 <= 0) BDDerr("ZBDD::SymChk(): invalid v1.", v1);\r
+ if(v2 <= 0) BDDerr("ZBDD::SymChk(): invalid v2.", v2);\r
+ if(*this == 0 || *this == 1) return 1;\r
+ if(v1 == v2) return 1;\r
+ if(v1 < v2) { int tmp = v1; v1 = v2; v2 = tmp; }\r
+\r
+ ZBDD S = ZBDD(1).Change(v1) + ZBDD(1).Change(v2);\r
+ bddword fx = GetID();\r
+ bddword gx = S.GetID();\r
+ int Y = BDD_CacheInt(BC_ZBDD_SYMCHK, fx, gx);\r
+ if(Y != -1) return Y;\r
+ BDD_RECUR_INC;\r
+\r
+ int t = Top();\r
+ if(BDD_LevOfVar(t) > BDD_LevOfVar(v1))\r
+ {\r
+ Y = OnSet0(t).SymChk(v1, v2);\r
+ if(Y == 1) Y = OffSet(t).SymChk(v1, v2);\r
+ }\r
+ else\r
+ {\r
+ ZBDD f0 = OffSet(v1);\r
+ ZBDD f1 = OnSet0(v1);\r
+ int t0 = f0.Top();\r
+ int t1 = f1.Top();\r
+ int t2 = (BDD_LevOfVar(t0) > BDD_LevOfVar(t1))? t0: t1;\r
+ if(BDD_LevOfVar(t2) <= BDD_LevOfVar(v2))\r
+ Y = (f0.OnSet0(v2) == f1.OffSet(v2));\r
+ else\r
+ {\r
+ ZBDD g0 = f0.OffSet(t2) + f1.OffSet(t2).Change(t2);\r
+ ZBDD g1 = f0.OnSet0(t2) + f1.OnSet0(t2).Change(t2);\r
+ Y = g1.SymChk(t2, v2);\r
+ if(Y == 1) Y = g0.SymChk(t2, v2);\r
+ }\r
+ }\r
+\r
+ BDD_RECUR_DEC;\r
+ if(Y != -1) BDD_CacheEnt(BC_ZBDD_SYMCHK, fx, gx, Y);\r
+ return Y;\r
+}\r
+\r
+ZBDD ZBDD::SymGrp() const\r
+{\r
+ ZBDD h = 0;\r
+ ZBDD g = Support();\r
+ while(g != 0)\r
+ {\r
+ int t = g.Top();\r
+ ZBDD hh = ZBDD(1).Change(t);\r
+ g = g.OffSet(t);\r
+\r
+ ZBDD g2 = g;\r
+ while(g2 != 0)\r
+ {\r
+ int t2 = g2.Top();\r
+ g2 = g2.OffSet(t2);\r
+ int y = SymChk(t, t2);\r
+ if(y == -1) return -1;\r
+ if(y)\r
+ {\r
+ hh = hh.Change(t2);\r
+ g = g.OffSet(t2);\r
+ }\r
+ }\r
+ if(hh.OnSet0(t) != 1) h += hh;\r
+ }\r
+ return h;\r
+}\r
+\r
+ZBDD ZBDD::SymGrpNaive() const\r
+{\r
+ ZBDD h = 0;\r
+ ZBDD g = Support();\r
+ while(g != 0)\r
+ {\r
+ int t = g.Top();\r
+ ZBDD hh = ZBDD(1).Change(t);\r
+ g = g.OffSet(t);\r
+ ZBDD f0 = OffSet(t);\r
+ ZBDD f1 = OnSet0(t);\r
+\r
+ ZBDD g2 = g;\r
+ while(g2 != 0)\r
+ {\r
+ int t2 = g2.Top();\r
+ g2 = g2.OffSet(t2);\r
+ if(f0.OnSet0(t2) == f1.OffSet(t2))\r
+ {\r
+ hh = hh.Change(t2);\r
+ g = g.OffSet(t2);\r
+ }\r
+ }\r
+ h += hh;\r
+ }\r
+ return h;\r
+}\r
+\r
+static ZBDD ZBDD_SymSet(const ZBDD&, const ZBDD&);\r
+static ZBDD ZBDD_SymSet(const ZBDD& f0, const ZBDD& f1)\r
+{\r
+ if(f0 == -1) return -1;\r
+ if(f1 == -1) return -1;\r
+ if(f1 == 0) return 0;\r
+ if(f1 == 1 && (f0 == 0 || f0 == 1)) return 0;\r
+\r
+ bddword fx = f0.GetID();\r
+ bddword gx = f1.GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_SYMSET, fx, gx);\r
+\r
+ int t0 = f0.Top();\r
+ int t1 = f1.Top();\r
+ int t = (BDD_LevOfVar(t0) > BDD_LevOfVar(t1))? t0: t1;\r
+\r
+ ZBDD f00 = f0.OffSet(t);\r
+ ZBDD f01 = f0.OnSet0(t);\r
+ ZBDD f10 = f1.OffSet(t);\r
+ ZBDD f11 = f1.OnSet0(t);\r
+ \r
+ ZBDD h;\r
+ if(f11 == 0) h = ZBDD_SymSet(f00, f10) - f01.Support();\r
+ else if(f10 == 0) h = ZBDD_SymSet(f01, f11) - f00.Support();\r
+ else\r
+ {\r
+ h = ZBDD_SymSet(f01, f11);\r
+ if(h != 0) h &= ZBDD_SymSet(f00, f10);\r
+ }\r
+ if(f10 == f01) h += ZBDD(1).Change(t);\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_SYMSET, fx, gx, h);\r
+}\r
+\r
+ZBDD ZBDD::SymSet(int v) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v <= 0) BDDerr("ZBDD::SymSet(): invalid v.", v);\r
+ ZBDD f0 = OffSet(v);\r
+ ZBDD f1 = OnSet0(v);\r
+ return ZBDD_SymSet(f0, f1);\r
+}\r
+\r
+int ZBDD::ImplyChk(int v1, int v2) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v1 <= 0) BDDerr("ZBDD::IndImplyChk(): invalid v1.", v1);\r
+ if(v2 <= 0) BDDerr("ZBDD::IndImplyChk(): invalid v2.", v2);\r
+ if(v1 == v2) return 1;\r
+ if(*this == 0 || *this == 1) return 1;\r
+\r
+ ZBDD f10 = OnSet0(v1).OffSet(v2);\r
+ if(f10 == -1) return -1;\r
+ return (f10 == 0);\r
+}\r
+\r
+ZBDD ZBDD::ImplySet(int v) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v <= 0) BDDerr("ZBDD::ImplySet(): invalid v.", v);\r
+ ZBDD f1 = OnSet0(v);\r
+ if(f1 == 0) return Support();\r
+ return f1.Always();\r
+}\r
+\r
+int ZBDD::CoImplyChk(int v1, int v2) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v1 <= 0) BDDerr("ZBDD::IndImplyChk(): invalid v1.", v1);\r
+ if(v2 <= 0) BDDerr("ZBDD::IndImplyChk(): invalid v2.", v2);\r
+ if(v1 == v2) return 1;\r
+ if(*this == 0 || *this == 1) return 1;\r
+\r
+ ZBDD f10 = OnSet0(v1).OffSet(v2);\r
+ if(f10 == 0) return 1;\r
+\r
+ ZBDD f01 = OffSet(v1).OnSet0(v2);\r
+ ZBDD chk = f10 - f01;\r
+ if(chk == -1) return -1;\r
+ return (chk == 0) ;\r
+}\r
+\r
+static ZBDD ZBDD_CoImplySet(const ZBDD&, const ZBDD&);\r
+static ZBDD ZBDD_CoImplySet(const ZBDD& f0, const ZBDD& f1)\r
+{\r
+ if(f0 == -1) return -1;\r
+ if(f1 == -1) return -1;\r
+ if(f1 == 0) return 0;\r
+ if(f1 == 1 && (f0 == 0 || f0 == 1)) return 0;\r
+\r
+ bddword fx = f0.GetID();\r
+ bddword gx = f1.GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_COIMPSET, fx, gx);\r
+\r
+ int t0 = f0.Top();\r
+ int t1 = f1.Top();\r
+ int t = (BDD_LevOfVar(t0) > BDD_LevOfVar(t1))? t0: t1;\r
+\r
+ ZBDD f00 = f0.OffSet(t);\r
+ ZBDD f01 = f0.OnSet0(t);\r
+ ZBDD f10 = f1.OffSet(t);\r
+ ZBDD f11 = f1.OnSet0(t);\r
+ \r
+ ZBDD h;\r
+ if(f11 == 0) h = ZBDD_CoImplySet(f00, f10);\r
+ else if(f10 == 0) h = ZBDD_CoImplySet(f01, f11);\r
+ else\r
+ {\r
+ h = ZBDD_CoImplySet(f01, f11);\r
+ if(h != 0) h &= ZBDD_CoImplySet(f00, f10);\r
+ }\r
+ if(f10 - f01 == 0) h += ZBDD(1).Change(t);\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_COIMPSET, fx, gx, h);\r
+}\r
+\r
+ZBDD ZBDD::CoImplySet(int v) const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(v <= 0) BDDerr("ZBDD::CoImplySet(): invalid v.", v);\r
+ ZBDD f0 = OffSet(v);\r
+ ZBDD f1 = OnSet0(v);\r
+ if(f1 == 0) return Support();\r
+ return ZBDD_CoImplySet(f0, f1);\r
+}\r
+\r
+int ZBDD::IsPoly() const\r
+{\r
+ int top = Top();\r
+ if(top == 0) return 0;\r
+ ZBDD f1 = OnSet0(top);\r
+ ZBDD f0 = OffSet(top);\r
+ if(f0 != 0) return 1;\r
+ return f1.IsPoly();\r
+}\r
+\r
+ZBDD ZBDD::Divisor() const\r
+{\r
+ if(*this == -1) return -1;\r
+ if(*this == 0) return 0;\r
+ if(! IsPoly()) return 1;\r
+ ZBDD f = *this;\r
+ ZBDD g = Support();\r
+ int t;\r
+ while(g != 0)\r
+ {\r
+ t = g.Top();\r
+ g = g.OffSet(t);\r
+ ZBDD f1 = f.OnSet0(t);\r
+ if(f1.IsPoly()) f = f1;\r
+ }\r
+ return f;\r
+}\r
+\r
+\r
+//--------- External functions for ZBDD ------------\r
+\r
+ZBDD operator*(const ZBDD& fc, const ZBDD& gc)\r
+{\r
+ if(fc == -1) return -1;\r
+ if(gc == -1) return -1;\r
+ if(fc == 0) return 0;\r
+ if(gc == 0) return 0;\r
+ if(fc == 1) return gc;\r
+ if(gc == 1) return fc;\r
+\r
+ ZBDD f = fc; ZBDD g = gc;\r
+ int ftop = f.Top(); int gtop = g.Top();\r
+ if(BDD_LevOfVar(ftop) < BDD_LevOfVar(gtop))\r
+ {\r
+ f = gc; g = fc;\r
+ ftop = f.Top(); gtop = g.Top();\r
+ }\r
+\r
+ bddword fx = f.GetID();\r
+ bddword gx = g.GetID();\r
+ if(ftop == gtop && fx < gx)\r
+ {\r
+ f = gc; g = fc;\r
+ fx = f.GetID(); gx = g.GetID();\r
+ }\r
+\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_MULT, fx, gx);\r
+\r
+ ZBDD f1 = f.OnSet0(ftop);\r
+ ZBDD f0 = f.OffSet(ftop);\r
+ ZBDD h;\r
+ if(ftop != gtop)\r
+ {\r
+ h = f1 * g;\r
+ h = h.Change(ftop) + (f0 * g);\r
+ }\r
+ else\r
+ {\r
+ ZBDD g1 = g.OnSet0(ftop);\r
+ ZBDD g0 = g.OffSet(ftop);\r
+ h = (f1 * g1)+(f1 * g0)+(f0 * g1);\r
+ h = h.Change(ftop) + (f0 * g0);\r
+ }\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_MULT, fx, gx, h);\r
+}\r
+\r
+ZBDD operator/(const ZBDD& f, const ZBDD& p)\r
+{\r
+ if(f == -1) return -1;\r
+ if(p == -1) return -1;\r
+ if(p == 1) return f;\r
+ if(f == p) return 1;\r
+ if(p == 0) BDDerr("operator /(): Divided by zero.");\r
+ int top = p.Top();\r
+ if(BDD_LevOfVar(f.Top()) < BDD_LevOfVar(top)) return 0;\r
+\r
+ bddword fx = f.GetID();\r
+ bddword px = p.GetID();\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_DIV, fx, px);\r
+ \r
+ ZBDD q = f.OnSet0(top) / p.OnSet0(top);\r
+ if(q != 0)\r
+ {\r
+ ZBDD p0 = p.OffSet(top);\r
+ if(p0 != 0) q &= f.OffSet(top) / p0;\r
+ }\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_DIV, fx, px, q);\r
+}\r
+\r
+ZBDD ZBDD_Meet(const ZBDD& fc, const ZBDD& gc)\r
+{\r
+ if(fc == -1) return -1;\r
+ if(gc == -1) return -1;\r
+ if(fc == 0) return 0;\r
+ if(gc == 0) return 0;\r
+ if(fc == 1) return 1;\r
+ if(gc == 1) return 1;\r
+\r
+ ZBDD f = fc; ZBDD g = gc;\r
+ int ftop = f.Top();\r
+ int gtop = g.Top();\r
+ if(BDD_LevOfVar(ftop) < BDD_LevOfVar(gtop))\r
+ {\r
+ f = gc; g = fc;\r
+ ftop = f.Top(); gtop = g.Top();\r
+ }\r
+\r
+ bddword fx = f.GetID();\r
+ bddword gx = g.GetID();\r
+ if(ftop == gtop && fx < gx)\r
+ {\r
+ f = gc; g = fc;\r
+ fx = f.GetID(); gx = g.GetID();\r
+ }\r
+\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_MEET, fx, gx);\r
+\r
+ ZBDD f1 = f.OnSet0(ftop);\r
+ ZBDD f0 = f.OffSet(ftop);\r
+ ZBDD h;\r
+ if(ftop != gtop)\r
+ {\r
+ h = ZBDD_Meet(f0, g) + ZBDD_Meet(f1, g);\r
+ }\r
+ else\r
+ {\r
+ ZBDD g1 = g.OnSet0(ftop);\r
+ ZBDD g0 = g.OffSet(ftop);\r
+ h = ZBDD_Meet(f1, g1);\r
+ h = h.Change(ftop) + ZBDD_Meet(f0, g0)\r
+ + ZBDD_Meet(f1, g0) + ZBDD_Meet(f0, g1);\r
+ }\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_MEET, fx, gx, h);\r
+}\r
+\r
+ZBDD ZBDD_Random(int lev, int density)\r
+{\r
+ if(lev < 0) BDDerr("ZBDD_Random(): lev < 0.", lev);\r
+ if(lev == 0) return ((rand()%100) < density)? 1: 0;\r
+ return ZBDD_Random(lev-1, density) +\r
+ ZBDD_Random(lev-1, density).Change(BDD_VarOfLev(lev));\r
+}\r
+\r
+ZBDD ZBDD_Import(FILE *strm)\r
+{\r
+ bddword zbdd;\r
+ if(bddimportz(strm, &zbdd, 1)) return -1;\r
+ return ZBDD_ID(zbdd);\r
+}\r
+\r
+\r
+// class ZBDDV ---------------------------------------------\r
+\r
+ZBDDV::ZBDDV(const ZBDD& f, int location)\r
+{\r
+ if(location < 0) BDDerr("ZBDDV::ZBDDV(): location < 0.", location);\r
+ if(location >= BDDV_MaxLen)\r
+ BDDerr("ZBDDV::ZBDDV(): Too large location.", location);\r
+ if(BDD_LevOfVar(f.Top()) > BDD_TopLev())\r
+ BDDerr("ZBDDV::ZBDDV(): Invalid top var.", f.Top());\r
+ _zbdd = f;\r
+ int var = 1;\r
+ for(int i=location; i>0; i>>=1)\r
+ {\r
+ if((i & 1)!= 0) _zbdd = _zbdd.Change(var);\r
+ var++;\r
+ }\r
+}\r
+\r
+ZBDDV ZBDDV::operator<<(int shift) const\r
+{\r
+ ZBDDV fv1 = *this;\r
+ ZBDDV fv2;\r
+ while(fv1 != ZBDDV())\r
+ {\r
+ if(fv1 == ZBDDV(-1)) return fv1;\r
+ int last = fv1.Last();\r
+ fv2 += ZBDDV(fv1.GetZBDD(last) << shift, last);\r
+ fv1 -= fv1.Mask(last);\r
+ }\r
+ return fv2;\r
+}\r
+\r
+ZBDDV ZBDDV::operator>>(int shift) const\r
+{\r
+ ZBDDV fv1 = *this;\r
+ ZBDDV fv2;\r
+ while(fv1 != ZBDDV())\r
+ {\r
+ if(fv1 == ZBDDV(-1)) return fv1;\r
+ int last = fv1.Last();\r
+ fv2 += ZBDDV(fv1.GetZBDD(last) >> shift, last);\r
+ fv1 -= fv1.Mask(last);\r
+ }\r
+ return fv2;\r
+}\r
+\r
+ZBDDV ZBDDV::OffSet(int v) const\r
+{\r
+ if(BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("ZBDDV::OffSet(): Invalid VarID.", v);\r
+ ZBDDV tmp;\r
+ tmp._zbdd = _zbdd.OffSet(v);\r
+ return tmp;\r
+}\r
+\r
+ZBDDV ZBDDV::OnSet(int v) const\r
+{\r
+ if(BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("ZBDDV::OnSet(): Invalid VarID.", v);\r
+ ZBDDV tmp;\r
+ tmp._zbdd = _zbdd.OnSet(v);\r
+ return tmp;\r
+}\r
+\r
+ZBDDV ZBDDV::OnSet0(int v) const\r
+{\r
+ if(BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("ZBDDV::OnSet0(): Invalid VarID.", v);\r
+ ZBDDV tmp;\r
+ tmp._zbdd = _zbdd.OnSet0(v);\r
+ return tmp;\r
+}\r
+\r
+ZBDDV ZBDDV::Change(int v) const\r
+{\r
+ if(BDD_LevOfVar(v) > BDD_TopLev())\r
+ BDDerr("ZBDDV::Change(): Invalid VarID.", v);\r
+ ZBDDV tmp;\r
+ tmp._zbdd = _zbdd.Change(v);\r
+ return tmp;\r
+}\r
+\r
+ZBDDV ZBDDV::Swap(int v1, int v2) const\r
+{\r
+ if(BDD_LevOfVar(v1) > BDD_TopLev())\r
+ BDDerr("ZBDDV::Swap(): Invalid VarID.", v1);\r
+ if(BDD_LevOfVar(v1) > BDD_TopLev())\r
+ BDDerr("ZBDDV::Swap(): Invalid VarID.", v2);\r
+ ZBDDV tmp;\r
+ tmp._zbdd = _zbdd.Swap(v1, v2);\r
+ return tmp;\r
+}\r
+\r
+int ZBDDV::Top() const\r
+{\r
+ ZBDDV fv1 = *this;\r
+ if(fv1 == ZBDDV(-1)) return 0;\r
+ int top = 0;\r
+ while(fv1 != ZBDDV())\r
+ {\r
+ int last = fv1.Last();\r
+ int t = fv1.GetZBDD(last).Top();\r
+ if(BDD_LevOfVar(t) > BDD_LevOfVar(top)) top = t;\r
+ fv1 -= fv1.Mask(last);\r
+ }\r
+ return top;\r
+}\r
+\r
+int ZBDDV::Last() const\r
+{\r
+ int last = 0;\r
+ ZBDD f = _zbdd;\r
+ while(BDD_LevOfVar(f.Top()) > BDD_TopLev())\r
+ {\r
+ int t = f.Top();\r
+ last += 1 << (t - 1);\r
+ f = f.OnSet0(t);\r
+ }\r
+ return last;\r
+}\r
+\r
+ZBDDV ZBDDV::Mask(int start, int len) const\r
+{\r
+ if(start < 0 || start >= BDDV_MaxLen)\r
+ BDDerr("ZBDDV::Mask(): Illegal start index.", start);\r
+ if(len <= 0 || start+len > BDDV_MaxLen)\r
+ BDDerr("ZBDDV::Mask(): Illegal len.", len);\r
+ ZBDDV tmp;\r
+ for(int i=start; i<start+len; i++)\r
+ tmp += ZBDDV(this -> GetZBDD(i), i);\r
+ return tmp;\r
+}\r
+\r
+ZBDD ZBDDV::GetZBDD(int index) const\r
+{\r
+ if(index < 0 || index >= BDDV_MaxLen)\r
+ BDDerr("ZBDDV::GetZBDD(): Illegal index.",index);\r
+ int level = 0;\r
+ for(int i=1; i<=index; i<<=1) level++;\r
+\r
+ ZBDD f = _zbdd;\r
+ while(BDD_LevOfVar(f.Top()) > BDD_TopLev() + level)\r
+ f = f.OffSet(f.Top());\r
+ while(level > 0)\r
+ {\r
+ if(f == 0) return f;\r
+ if((index & (1<<level-1)) != 0) f = f.OnSet0(level);\r
+ else f = f.OffSet(level);\r
+ level--;\r
+ }\r
+ return f;\r
+}\r
+\r
+bddword ZBDDV::Size() const\r
+{\r
+ int len = this -> Last() + 1;\r
+ bddword* bddv = new bddword[len];\r
+ for(int i=0; i<len; i++) bddv[i] = GetZBDD(i).GetID(); \r
+ bddword s = bddvsize(bddv, len);\r
+ delete[] bddv;\r
+ return s;\r
+}\r
+\r
+void ZBDDV::Print() const\r
+{\r
+ int len = this -> Last() + 1;\r
+ for(int i=0; i<len; i++)\r
+ {\r
+ cout << "f" << i << ": ";\r
+ GetZBDD(i).Print();\r
+ }\r
+ cout << "Size= " << Size() << "\n\n";\r
+ cout.flush();\r
+}\r
+\r
+void ZBDDV::Export(FILE *strm) const\r
+{\r
+ int len = this -> Last() + 1;\r
+ bddword* bddv = new bddword[len];\r
+ for(int i=0; i<len; i++) bddv[i] = GetZBDD(i).GetID(); \r
+ bddexport(strm, bddv, len);\r
+ delete[] bddv;\r
+}\r
+\r
+static int Len;\r
+static char* Cube;\r
+static int ZBDDV_PLA(const ZBDDV&, int);\r
+static int ZBDDV_PLA(const ZBDDV& fv, int tlev)\r
+{\r
+ if(fv == ZBDDV(-1)) return 1;\r
+ if(fv == ZBDDV()) return 0;\r
+ if(tlev == 0)\r
+ {\r
+ cout << Cube << " ";\r
+ for(int i=0; i<Len; i++)\r
+ if(fv.GetZBDD(i) == 0) cout << "~";\r
+ else cout << "1";\r
+ cout << "\n";\r
+ cout.flush();\r
+ return 0;\r
+ }\r
+ Cube[tlev-1] = '1';\r
+ if(ZBDDV_PLA(fv.OnSet0(BDD_VarOfLev(tlev)), tlev-1) == 1)\r
+ return 1;\r
+ Cube[tlev-1] = '0';\r
+ return ZBDDV_PLA(fv.OffSet(BDD_VarOfLev(tlev)), tlev-1);\r
+}\r
+\r
+int ZBDDV::PrintPla() const\r
+{\r
+ if(*this == ZBDDV(-1)) return 1;\r
+ int tlev = BDD_LevOfVar(Top());\r
+ Len = Last() + 1;\r
+ cout << ".i " << tlev << "\n";\r
+ cout << ".o " << Len << "\n";\r
+ if(tlev == 0)\r
+ {\r
+ for(int i=0; i<Len; i++)\r
+ if(GetZBDD(i) == 0) cout << "0";\r
+ else cout << "1";\r
+ cout << "\n";\r
+ }\r
+ else\r
+ {\r
+ Cube = new char[tlev + 1];\r
+ Cube[tlev] = 0;\r
+ int err = ZBDDV_PLA(*this, tlev);\r
+ delete[] Cube;\r
+ if(err == 1) return 1;\r
+ }\r
+ cout << ".e\n";\r
+ cout.flush();\r
+ return 0;\r
+}\r
+\r
+/*\r
+ZBDDV operator&(const ZBDDV& fv1, const ZBDDV& fv2)\r
+{\r
+ ZBDDV tmp;\r
+ tmp._zbdd = fv1._zbdd & fv2._zbdd;\r
+ return tmp;\r
+}\r
+\r
+ZBDDV operator+(const ZBDDV& fv1, const ZBDDV& fv2)\r
+{\r
+ ZBDDV tmp;\r
+ tmp._zbdd = fv1._zbdd + fv2._zbdd;\r
+ return tmp;\r
+}\r
+\r
+ZBDDV operator-(const ZBDDV& fv1, const ZBDDV& fv2)\r
+{\r
+ ZBDDV tmp;\r
+ tmp._zbdd = fv1._zbdd - fv2._zbdd;\r
+ return tmp;\r
+}\r
+\r
+int operator==(const ZBDDV& fv1, const ZBDDV& fv2)\r
+{ return fv1._zbdd == fv2._zbdd; }\r
+\r
+int operator!=(const ZBDDV& fv1, const ZBDDV& fv2)\r
+{ return !(fv1 == fv2); }\r
+\r
+*/\r
+\r
+#define IMPORTHASH(x) (((x >> 1) ^ (x >> 16)) & (hashsize - 1))\r
+\r
+#ifdef B_64\r
+# define B_STRTOI strtoll\r
+#else\r
+# define B_STRTOI strtol\r
+#endif\r
+\r
+ZBDDV ZBDDV_Import(FILE *strm)\r
+{\r
+ int inv, e;\r
+ bddword hashsize;\r
+ ZBDD f, f0, f1;\r
+ char s[256];\r
+ bddword *hash1;\r
+ ZBDD *hash2;\r
+\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ if(strcmp(s, "_i") != 0) return ZBDDV(-1);\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ int n = strtol(s, NULL, 10);\r
+ while(n > BDD_TopLev()) BDD_NewVar();\r
+\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ if(strcmp(s, "_o") != 0) return ZBDDV(-1);\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ int m = strtol(s, NULL, 10);\r
+\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ if(strcmp(s, "_n") != 0) return ZBDDV(-1);\r
+ if(fscanf(strm, "%s", &s) == EOF) return ZBDDV(-1);\r
+ bddword n_nd = B_STRTOI(s, NULL, 10);\r
+\r
+ for(hashsize = 1; hashsize < (n_nd<<1); hashsize <<= 1)\r
+ ; /* empty */\r
+ hash1 = new bddword[hashsize];\r
+ if(hash1 == 0) return ZBDDV(-1);\r
+ hash2 = new ZBDD[hashsize];\r
+ if(hash2 == 0) { delete[] hash1; return ZBDDV(-1); }\r
+ for(bddword ix=0; ix<hashsize; ix++)\r
+ {\r
+ hash1[ix] = B_VAL_MASK;\r
+ hash2[ix] = 0;\r
+ }\r
+\r
+ e = 0;\r
+ for(bddword ix=0; ix<n_nd; ix++)\r
+ {\r
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }\r
+ bddword nd = B_STRTOI(s, NULL, 10);\r
+ \r
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }\r
+ int lev = strtol(s, NULL, 10);\r
+ int var = bddvaroflev(lev);\r
+\r
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }\r
+ if(strcmp(s, "F") == 0) f0 = 0;\r
+ else if(strcmp(s, "T") == 0) f0 = 1;\r
+ else\r
+ {\r
+ bddword nd0 = B_STRTOI(s, NULL, 10);\r
+\r
+ bddword ixx = IMPORTHASH(nd0);\r
+ while(hash1[ixx] != nd0)\r
+ {\r
+ if(hash1[ixx] == B_VAL_MASK)\r
+ BDDerr("ZBDDV_Import(): internal error", ixx);\r
+ ixx++;\r
+ ixx &= (hashsize-1);\r
+ }\r
+ f0 = hash2[ixx];\r
+ }\r
+\r
+ if(fscanf(strm, "%s", &s) == EOF) { e = 1; break; }\r
+ if(strcmp(s, "F") == 0) f1 = 0;\r
+ else if(strcmp(s, "T") == 0) f1 = 1;\r
+ else\r
+ {\r
+ bddword nd1 = B_STRTOI(s, NULL, 10);\r
+ if(nd1 & 1) { inv = 1; nd1 ^= 1; }\r
+ else inv = 0;\r
+ \r
+ bddword ixx = IMPORTHASH(nd1);\r
+ while(hash1[ixx] != nd1)\r
+ {\r
+ if(hash1[ixx] == B_VAL_MASK)\r
+ BDDerr("ZBDDV_Import(): internal error", ixx);\r
+ ixx++;\r
+ ixx &= (hashsize-1);\r
+ }\r
+ f1 = (inv)? (hash2[ixx] + 1): hash2[ixx];\r
+ }\r
+\r
+ f = f1.Change(var) + f0;\r
+ if(f == -1) { e = 1; break; }\r
+\r
+ bddword ixx = IMPORTHASH(nd);\r
+ while(hash1[ixx] != B_VAL_MASK)\r
+ {\r
+ if(hash1[ixx] == nd)\r
+ BDDerr("ZBDDV_Import(): internal error", ixx);\r
+ ixx++;\r
+ ixx &= (hashsize-1);\r
+ }\r
+ hash1[ixx] = nd;\r
+ hash2[ixx] = f;\r
+ }\r
+\r
+ if(e)\r
+ {\r
+ delete[] hash2;\r
+ delete[] hash1;\r
+ return ZBDDV(-1);\r
+ }\r
+\r
+ ZBDDV v = ZBDDV();\r
+ for(int i=0; i<m; i++)\r
+ {\r
+ if(fscanf(strm, "%s", &s) == EOF)\r
+ {\r
+ delete[] hash2;\r
+ delete[] hash1;\r
+ return ZBDDV(-1);\r
+ }\r
+ bddword nd = B_STRTOI(s, NULL, 10);\r
+ if(strcmp(s, "F") == 0) v += ZBDDV(0, i);\r
+ else if(strcmp(s, "T") == 0) v += ZBDDV(1, i);\r
+ else\r
+ {\r
+ if(nd & 1) { inv = 1; nd ^= 1; }\r
+ else inv = 0;\r
+ \r
+ bddword ixx = IMPORTHASH(nd);\r
+ while(hash1[ixx] != nd)\r
+ {\r
+ if(hash1[ixx] == B_VAL_MASK)\r
+ BDDerr("ZBDDV_Import(): internal error", ixx);\r
+ ixx++;\r
+ ixx &= (hashsize-1);\r
+ }\r
+ v += ZBDDV((inv? (hash2[ixx] + 1): hash2[ixx]), i);\r
+ }\r
+ }\r
+\r
+ delete[] hash2;\r
+ delete[] hash1;\r
+ return v;\r
+}\r
+\r
+#define ZLevNum(n) \\r
+ (n-((n&2)?(n&1)? (n<512)?(n<64)?(n<16)?4:8:(n<128)?32:(n<256)?64:128:(n<4096)?(n<1024)?256:(n<2048)?512:1024:(n<8192)?2048:(n<32768)?4096:8192 \\r
+ : (n<512)?(n<64)?4:(n<256)?16:32:(n<4096)?(n<1024)?64:128:(n<32768)?512:1024 \\r
+ :(n&1)? (n<512)?(n<16)?4:8:(n<2048)?(n<1024)?16:32:(n<32768)?64:128 \\r
+ : (n<1024)?4:(n<32768)?8:16 \\r
+ ))\r
+\r
+ZBDD ZBDD::ZLev(int lev, int last) const\r
+{\r
+ if(lev <= 0) return *this & 1;\r
+ ZBDD f = *this;\r
+ ZBDD u = *this & 1;\r
+ int ftop = Top();\r
+ int flev = BDD_LevOfVar(ftop);\r
+ while(flev > lev)\r
+ {\r
+ if(flev - lev >= 5)\r
+ {\r
+ int n = ZLevNum(flev);\r
+ if(flev >= 66)\r
+ {\r
+ if(n < lev || ((flev & 3) < 3 && ZLevNum(flev - 3) >= lev))\r
+ n = flev - 1;\r
+ }\r
+ else if(flev >= 18)\r
+ {\r
+ if(n < lev || ((flev & 1) < 1 && ZLevNum(flev - 1) >= lev))\r
+ n = flev - 1;\r
+ }\r
+ else if(n < lev) n = flev - 1;\r
+\r
+ if(n < flev - 1)\r
+ {\r
+ bddword fx = f.GetID();\r
+ ZBDD g = BDD_CacheZBDD(BC_ZBDD_ZSkip, fx, fx);\r
+ if(g != -1)\r
+ {\r
+ int gtop = g.Top();\r
+ int glev = BDD_LevOfVar(gtop);\r
+ if(glev >= lev)\r
+ {\r
+ f = g;\r
+ ftop = gtop;\r
+ flev = glev;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ u = f;\r
+ f = f.OffSet(ftop);\r
+ ftop = f.Top();\r
+ flev = BDD_LevOfVar(ftop);\r
+ }\r
+ return (last == 0 || lev == flev)? f: u;\r
+}\r
+\r
+void ZBDD::SetZSkip() const\r
+{\r
+ int t = Top();\r
+ int lev = BDD_LevOfVar(t);\r
+ if(lev <= 4) return;\r
+ bddword fx = GetID();\r
+ ZBDD g = BDD_CacheZBDD(BC_ZBDD_ZSkip, fx, fx);\r
+ if(g != -1) return;\r
+ ZBDD f0 = OffSet(t);\r
+ f0.SetZSkip();\r
+ g = ZLev(ZLevNum(lev), 1);\r
+ if(g == *this) g = f0;\r
+ bddword gx = g.GetID();\r
+ BDD_CacheEnt(BC_ZBDD_ZSkip, fx, fx, gx);\r
+ OnSet0(t).SetZSkip();\r
+}\r
+\r
+ZBDD ZBDD::Intersec(const ZBDD& g) const\r
+{\r
+ if(g == 0) return 0;\r
+ if(g == 1) return *this & 1;\r
+ int ftop = Top();\r
+ if(ftop == 0) return *this & g;\r
+ int gtop = g.Top();\r
+\r
+ bddword fx = GetID();\r
+ bddword gx = g.GetID();\r
+ if(fx < gx) { fx = g.GetID(); gx = GetID(); }\r
+ ZBDD_CACHE_CHK_RETURN(BC_ZBDD_INTERSEC, fx, gx);\r
+\r
+ int flev = BDD_LevOfVar(ftop);\r
+ int glev = BDD_LevOfVar(gtop);\r
+ ZBDD h;\r
+ if(flev > glev) h = ZLev(glev).Intersec(g);\r
+ else if(flev < glev) h = Intersec(g.OffSet(gtop));\r
+ else\r
+ {\r
+ h = OnSet0(ftop).Intersec(g.OnSet0(ftop)).Change(ftop)\r
+ + OffSet(ftop).Intersec(g.OffSet(ftop));\r
+ }\r
+\r
+ ZBDD_CACHE_ENT_RETURN(BC_ZBDD_INTERSEC, fx, gx, h);\r
+}\r
+\r
--- /dev/null
+/**********************************************
+ * ZBDDDG - Decomposition Graph (SAPPORO-1.21)*
+ * (C) Shin-ichi MINATO (Feb. 18, 2009) *
+ **********************************************/
+
+#include "ZBDDDG.h"
+
+ZBDDDG_Tag::ZBDDDG_Tag()
+{
+ _dg = 0;
+ _ndx = ZBDDDG_NIL;
+}
+
+int ZBDDDG_Tag::Set(ZBDDDG* dg, bddword ndx)
+{
+ _dg = dg;
+ _ndx = ndx;
+ if(_ndx >= _dg->_nodeUsed) return 1;
+ _lkx = _dg->_nodeA[_ndx]._lkx;
+ return 0;
+}
+
+bddword ZBDDDG_Tag::TopNdx()
+{
+ _lkx = _dg->_nodeA[_ndx]._lkx;
+ if(_lkx == ZBDDDG_NIL) return ZBDDDG_NIL;
+ return _dg->_linkA[_lkx]._ndx;
+}
+
+bddword ZBDDDG_Tag::NextNdx()
+{
+ _lkx = _dg->_linkA[_lkx]._nxt;
+ if(_lkx == ZBDDDG_NIL) return ZBDDDG_NIL;
+ return _dg->_linkA[_lkx]._ndx;
+}
+
+char ZBDDDG_Tag::Type()
+{
+ return _dg->_nodeA[_ndx]._type;
+}
+
+ZBDD ZBDDDG_Tag::Func()
+{
+ return _dg->_nodeA[_ndx]._f;
+}
+
+ZBDDDG::ZBDDDG()
+{
+ _nodeA = 0;
+ _linkA = 0;
+ _hashWheel = 0;
+ Clear();
+}
+
+ZBDDDG::~ZBDDDG()
+{
+ delete[] _hashWheel;
+ delete[] _linkA;
+ delete[] _nodeA;
+}
+
+void ZBDDDG::Clear()
+{
+ delete[] _hashWheel;
+ delete[] _linkA;
+ delete[] _nodeA;
+
+ _nodeSize = ZBDDDG_InitSize;
+ _nodeA = new Node[_nodeSize];
+ _nodeUsed = 0;
+ _linkSize = ZBDDDG_InitSize;
+ _linkA = new NodeLink[_linkSize];
+ _linkUsed = 0;
+ bddword hashSize = _nodeSize << 1;
+ _hashWheel = new bddword[hashSize];
+ for(bddword i=0; i<hashSize; i++) _hashWheel[i] = ZBDDDG_NIL;
+ _c0 = NewNdx(0, ZBDDDG_C0);
+ _c1 = NewNdx(1, ZBDDDG_P1);
+ LinkNodes(_c1, _c0);
+}
+
+bddword ZBDDDG::HashIndex(ZBDD key)
+{
+ bddword id = key.GetID();
+ bddword hashSize = _nodeSize << 1;
+ bddword hash = (id+(id>>10)+(id>>20)) & (hashSize - 1);
+ bddword i = hash;
+ while(_hashWheel[i] != ZBDDDG_NIL)
+ {
+ ZBDD f = _nodeA[_hashWheel[i]]._f;
+ if(key == f) return i;
+ i++;
+ i &= (hashSize -1);
+ }
+ return i;
+}
+
+bddword ZBDDDG::NewNdx(ZBDD f, char type)
+{
+ if(_nodeUsed == _nodeSize)
+ if(EnlargeNode()) return ZBDDDG_NIL;
+ bddword ndx = _nodeUsed++;
+ _nodeA[ndx]._f = f;
+ _nodeA[ndx]._type = type;
+ bddword i = HashIndex(f);
+ if(_hashWheel[i] != ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::NewNdx(): Duplicate node\n";
+ exit(1);
+ }
+ _hashWheel[i] = ndx;
+ return ndx;
+}
+
+int ZBDDDG::EnlargeNode()
+{
+ bddword oldHS = _nodeSize << 1;
+ Node* oldArray = _nodeA;
+ bddword* oldWheel = _hashWheel;
+
+ _nodeSize <<= 2;
+ _nodeA = new Node[_nodeSize];
+ bddword hashSize = _nodeSize << 1;
+ _hashWheel = new bddword[hashSize];
+ if(_nodeA == 0 || _hashWheel == 0)
+ {
+ cerr << "<ERROR> ZBDDDG::EnlargeNode(): Memory overflow (";
+ cerr << _nodeSize << ")\n";
+ return 1;
+ }
+ for(bddword i=0; i<_nodeUsed; i++)
+ {
+ _nodeA[i]._lkx = oldArray[i]._lkx;
+ _nodeA[i]._f = oldArray[i]._f;
+ _nodeA[i]._type = oldArray[i]._type;
+ _nodeA[i]._mark = oldArray[i]._mark;
+ _nodeA[i]._ndxP = oldArray[i]._ndxP;
+ }
+ for(bddword i=0; i<hashSize; i++) _hashWheel[i] = ZBDDDG_NIL;
+ for(bddword i=0; i<oldHS; i++)
+ {
+ bddword ndx = oldWheel[i];
+ if(ndx != ZBDDDG_NIL)
+ {
+ ZBDD f = _nodeA[ndx]._f;
+ _hashWheel[HashIndex(f)] = ndx;
+ }
+ }
+ delete[] oldArray;
+ delete[] oldWheel;
+ return 0;
+}
+
+bddword ZBDDDG::NewLkx(bddword ndx)
+{
+ if(_linkUsed == _linkSize)
+ if(EnlargeLink()) return ZBDDDG_NIL;
+ bddword lkx = _linkUsed++;
+ _linkA[lkx]._ndx = ndx;
+ return lkx;
+}
+
+int ZBDDDG::EnlargeLink()
+{
+ NodeLink* oldArray = _linkA;
+
+ _linkSize <<= 2;
+ _linkA = new NodeLink[_linkSize];
+ if(_linkA == 0)
+ {
+ cerr << "<ERROR> ZBDDDG::EnlargeLink(): Memory overflow (";
+ cerr << _linkSize << ")\n";
+ return 1;
+ }
+ for(bddword i=0; i<_linkUsed; i++)
+ {
+ _linkA[i]._ndx = oldArray[i]._ndx;
+ _linkA[i]._nxt = oldArray[i]._nxt;
+ }
+ delete[] oldArray;
+ return 0;
+}
+
+bddword ZBDDDG::ReferNdx(ZBDD key)
+{
+ return _hashWheel[HashIndex(key)];
+}
+
+bddword ZBDDDG::NodeUsed() { return _nodeUsed; }
+
+ZBDDDG::Node::Node()
+{
+ _lkx = ZBDDDG_NIL;
+ _f = ZBDD(1);
+ _type = ZBDDDG_C0;
+ _mark = 0;
+ _ndxP = ZBDDDG_NIL;
+}
+
+ZBDDDG::Node::Node(ZBDD f, char type)
+{
+ _lkx = ZBDDDG_NIL;
+ _f = f;
+ _type = type;
+ _mark = 0;
+ _ndxP = ZBDDDG_NIL;
+}
+
+int ZBDDDG::PhaseSweep(bddword ndx)
+{
+ int fin = 0;
+ int inv = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+
+ switch(_nodeA[ndx]._type)
+ {
+ case ZBDDDG_P1:
+ /* Assertion check*/
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(_nodeA[_linkA[lkx]._ndx]._type == ZBDDDG_P1)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad structure (P1)\n";
+ exit(1);
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin++;
+ }
+ if(fin != 1)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad fan-in (P1)\n";
+ exit(1);
+ }
+ break;
+ case ZBDDDG_AND:
+ /* Assertion check*/
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(_nodeA[_linkA[lkx]._ndx]._type == ZBDDDG_AND)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad structure (AND)\n";
+ exit(1);
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin++;
+ }
+ if(fin < 2)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad fan-in (AND)\n";
+ exit(1);
+ }
+ break;
+
+ case ZBDDDG_OR:
+ /* Assertion check*/
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(_nodeA[_linkA[lkx]._ndx]._type == ZBDDDG_OR ||
+ _nodeA[_linkA[lkx]._ndx]._type == ZBDDDG_P1)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad structure (OR)\n";
+ exit(1);
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin++;
+ }
+ if(fin < 2)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad fan-in (OR)\n";
+// exit(1);
+ }
+ if((_nodeA[ndx]._f & 1) == 1)
+ {
+ lkx = _nodeA[ndx]._lkx;
+ int chk = 0;
+ while(lkx != ZBDDDG_NIL)
+ {
+ ZBDD f1 = _nodeA[_linkA[lkx]._ndx]._f;
+ if((f1 & 1) == 1)
+ {
+ chk = 1;
+ break;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(chk == 0)
+ {
+ ZBDD f0 = _nodeA[ndx]._f - 1;
+ bddword ndx0 = ReferNdx(f0);
+ if(ndx0 == ZBDDDG_NIL)
+ {
+ ndx0 = NewNdx(_nodeA[ndx]._f - 1, ZBDDDG_OR);
+ if(ndx0 == ZBDDDG_NIL) return 1;
+ _nodeA[ndx0]._lkx = _nodeA[ndx]._lkx;
+ }
+ _nodeA[ndx]._lkx = ZBDDDG_NIL;
+ _nodeA[ndx]._type = ZBDDDG_P1;
+ if(LinkNodes(ndx, ndx0)) return 1;
+ }
+ }
+ break;
+
+ case ZBDDDG_OTHER:
+ /* Assertion check*/
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(_nodeA[_linkA[lkx]._ndx]._type == ZBDDDG_P1)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad structure (OTHER)\n";
+ exit(1);
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin++;
+ }
+ if(fin < 2)
+ {
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad fan-in (OTHER)\n";
+ exit(1);
+ }
+
+ if((_nodeA[ndx]._f & 1) == 1)
+ {
+ lkx = _nodeA[ndx]._lkx;
+ int chk = 0;
+ while(lkx != ZBDDDG_NIL)
+ {
+ ZBDD f1 = _nodeA[_linkA[lkx]._ndx]._f;
+ if((f1 & 1) == 1 && (Func1(_nodeA[ndx]._f, f1) & 1) == 1)
+ {
+ chk = 1;
+ break;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(chk == 0)
+ {
+ ZBDD f0 = _nodeA[ndx]._f - 1;
+ bddword ndx0 = ReferNdx(f0);
+ if(ndx0 == ZBDDDG_NIL)
+ {
+ ndx0 = NewNdx(_nodeA[ndx]._f - 1, ZBDDDG_OTHER);
+ if(ndx0 == ZBDDDG_NIL) return 1;
+ _nodeA[ndx0]._lkx = _nodeA[ndx]._lkx;
+ }
+ _nodeA[ndx]._lkx = ZBDDDG_NIL;
+ _nodeA[ndx]._type = ZBDDDG_P1;
+ if(LinkNodes(ndx, ndx0)) return 1;
+ }
+ }
+
+ break;
+ default:
+ cerr << "<ERROR> ZBDDDG::PhaseSweep(): Bad node type\n";
+ exit(1);
+ }
+ return 0;
+}
+
+int ZBDDDG::LinkNodes(bddword ndx, bddword ndx2)
+{
+ if(ndx == ZBDDDG_NIL || ndx2 == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::LinkNodes(): Null node\n";
+ exit(1);
+ }
+ bddword lkx = NewLkx(ndx2);
+ if(lkx == ZBDDDG_NIL) return 1;
+ _linkA[lkx]._nxt = _nodeA[ndx]._lkx;
+ _nodeA[ndx]._lkx = lkx;
+
+ bddword lkx2 = _linkA[lkx]._nxt;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndx3 = _linkA[lkx]._ndx;
+ bddword ndx4 = _linkA[lkx2]._ndx;
+ ZBDD f = _nodeA[ndx3]._f;
+ ZBDD f2 = _nodeA[ndx4]._f;
+ if(f.Top() == f2.Top())
+ {
+ cerr << "<ERROR> ZBDDDG::LinkNodes(): Same VarIndex(";
+ cerr << f.Top() << ")\n";
+ exit(1);
+ }
+
+ if(f.Top() < f2.Top()) break;
+
+ _linkA[lkx]._ndx = ndx4;
+ _linkA[lkx2]._ndx = ndx3;
+
+ lkx = lkx2;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ return 0;
+}
+
+bddword ZBDDDG::Decomp(ZBDD f)
+{
+ if(f == 0) return _c0;
+ if(f == 1) return _c1;
+
+ bddword ndx = ReferNdx(f);
+ if(ndx != ZBDDDG_NIL) return ndx;
+
+ int top = f.Top();
+ ZBDD f0 = f.OffSet(top);
+ ZBDD f1 = f.OnSet0(top);
+ bddword ndx0 = Decomp(f0);
+ if(ndx0 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ bddword ndx1 = Decomp(f1);
+ if(ndx1 == ZBDDDG_NIL) return ZBDDDG_NIL;
+//PrintDecomp(f0);
+//PrintDecomp(f1);
+ ndx = Merge(f, ndx0, ndx1);
+//PrintDecomp(f); cout << "\n";
+
+ return ndx;
+}
+
+void ZBDDDG::MarkSweep(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::MarkSweep(): Bad ndx";
+ exit(1);
+ }
+ _nodeA[ndx]._mark = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ _nodeA[_linkA[lkx]._ndx]._mark = 0;
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+void ZBDDDG::MarkSweepR(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::MarkSweepR(): Bad ndx";
+ exit(1);
+ }
+ _nodeA[ndx]._mark = 0;
+ _nodeA[ndx]._ndxP = ZBDDDG_NIL;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ MarkSweepR(_linkA[lkx]._ndx);
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+int ZBDDDG::Mark1(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark1(): Bad ndx";
+ exit(1);
+ }
+ int fin = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndx1 = _linkA[lkx]._ndx;
+ _nodeA[ndx1]._mark = 1;
+ fin++;
+ lkx = _linkA[lkx]._nxt;
+ }
+ return fin;
+}
+
+void ZBDDDG::Mark2R(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark2R(): Bad ndx";
+ exit(1);
+ }
+ _nodeA[ndx]._mark++;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ Mark2R(_linkA[lkx]._ndx);
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+int ZBDDDG::MarkChkR(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::MarkChkR(): Bad ndx";
+ exit(1);
+ }
+ if(_nodeA[ndx]._mark != 0) return 1;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(MarkChkR(_linkA[lkx]._ndx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ return 0;
+}
+
+void ZBDDDG::Mark3R(bddword ndx)
+{
+ if(ndx == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark3R(): Bad ndx";
+ exit(1);
+ }
+ if(_nodeA[ndx]._mark == 2) return;
+
+ int cnt1 = 0; // not decided.
+ int cnt2 = 0; // shared node.
+ int cnt3 = 0; // non-shared node.
+ int cnt4 = 0; // (possibly) partly shared node.
+
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ Mark3R(ndt);
+ switch(_nodeA[ndt]._mark)
+ {
+ case 1:
+ if(_nodeA[ndt]._type != ZBDDDG_P1) cnt1++;
+ else
+ {
+ if(_nodeA[_linkA[_nodeA[ndt]._lkx]._ndx]._mark == 2)
+ cnt2++;
+ else cnt1++;
+ }
+ break;
+ case 2:
+ cnt2++;
+ break;
+ case 3:
+ cnt3++;
+ break;
+ case 4:
+ cnt4++;
+ break;
+ default:
+ break;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(_nodeA[ndx]._type == ZBDDDG_AND || _nodeA[ndx]._type == ZBDDDG_OR)
+ {
+ if(cnt2 >= 1)
+ {
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ _nodeA[ndt]._ndxP = ndx;
+ lkx = _linkA[lkx]._nxt;
+ }
+ _nodeA[ndx]._mark = 4;
+ return;
+ }
+ }
+
+ if(cnt1 + cnt2 + cnt4 == 0 && _nodeA[ndx]._mark == 1)
+ _nodeA[ndx]._mark = 3;
+}
+
+bddword ZBDDDG::Mark4R(bddword ndx0, bddword ndx1, bddword ndy0)
+{
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark4R(): Bad ndx";
+ exit(1);
+ }
+ if(_nodeA[ndy0]._mark == 1) return ZBDDDG_NIL;
+ if(ndx0 != ndy0 && MarkChkR(ndy0) == 0)
+ {
+ if(Func1(_nodeA[ndx0]._f, _nodeA[ndy0]._f) == _nodeA[ndx1]._f)
+ {
+ _nodeA[ndy0]._mark = 3; // hit at this node.
+ return ndy0;
+ }
+ }
+ bddword lkx = _nodeA[ndy0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ bddword ndh = Mark4R(ndx0, ndx1, ndt);
+ if(ndh != ZBDDDG_NIL)
+ {
+ _nodeA[ndy0]._mark = 2; // hit at a sub-node.
+ return ndh;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ return ZBDDDG_NIL;
+}
+
+bddword ZBDDDG::Mark5R(bddword ndx0, bddword ndx1, bddword ndy0)
+{
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark5R(): Bad ndx";
+ exit(1);
+ }
+ if(ndx0 != ndy0)
+ {
+ Mark6R(ndx0, ndy0);
+ int fin1 = 0;
+ int fin2 = 0;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(MarkChkR(ndt) != 0) _nodeA[ndt]._mark = 1;
+ else fin2++;
+ fin1++;
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin2 > 0 && fin1 - fin2 > 0)
+ {
+ ZBDD f1 = 1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1) f1 *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(Func1(_nodeA[ndx0]._f, _nodeA[ndy0]._f) == f1)
+ {
+ _nodeA[ndy0]._mark = 3; // hit at this node.
+ return ndy0;
+ }
+ }
+ MarkSweepR(ndx0);
+ MarkSweep(ndx1);
+ }
+ bddword lkx = _nodeA[ndy0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ bddword ndh = Mark5R(ndx0, ndx1, ndt);
+ if(ndh != ZBDDDG_NIL)
+ {
+ _nodeA[ndy0]._mark = 2; // hit at a sub-node.
+ return ndh;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ return ZBDDDG_NIL;
+}
+
+void ZBDDDG::Mark6R(bddword ndx, bddword ndy)
+{
+ if(ndx == ZBDDDG_NIL || ndy == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Mark6R(): Bad ndx";
+ exit(1);
+ }
+ if(ndx == ndy) return;
+ _nodeA[ndx]._mark++;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ Mark6R(_linkA[lkx]._ndx, ndy);
+ lkx = _linkA[lkx]._nxt;
+ }
+}
+
+bddword ZBDDDG::Merge(ZBDD f, bddword ndx0, bddword ndx1)
+{
+ if(ndx0 == ZBDDDG_NIL || ndx1 == ZBDDDG_NIL)
+ {
+ cerr << "<ERROR> ZBDDDG::Merge(): Null node\n";
+ exit(1);
+ }
+
+//cout << "[Merge]\n";
+ int top = f.Top(); // (top > 0)
+
+ // [LIT] ?
+ if(ndx0 == _c0 && ndx1 == _c1)
+ {
+//cout << "[LIT]\n";
+ bddword ndy = ReferNdx(f);
+ if(ndy == ZBDDDG_NIL)
+ ndy = NewNdx(f, ZBDDDG_LIT);
+ return ndy;
+ }
+
+ // [AND] P0==1, P1==1 ?
+ if(ndx0 == ndx1 && ndx0 != _c1)
+ {
+//cout << "[AND] P0==1, P1==1\n";
+ bddword ndx = Decomp(ZBDD(1).Change(top) + 1);
+ if(ndx == ZBDDDG_NIL) return ZBDDDG_NIL;
+ bddword ndy = NewNdx(f, ZBDDDG_AND);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ if(_nodeA[ndx1]._type != ZBDDDG_AND)
+ {
+ if(LinkNodes(ndy, ndx1)) return ZBDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodes(ndy, _linkA[lkx]._ndx)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ return ndy;
+ }
+
+ // [AND] P0==0, P1==1 ?
+ if(ndx0 == _c0)
+ {
+//cout << "[AND] P0==0, P1==1\n";
+ bddword ndx = Decomp(ZBDD(1).Change(top));
+ if(ndx == ZBDDDG_NIL) return ZBDDDG_NIL;
+ bddword ndy = NewNdx(f, ZBDDDG_AND);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ if(_nodeA[ndx1]._type != ZBDDDG_AND)
+ {
+ if(LinkNodes(ndy, ndx1)) return ZBDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodes(ndy, _linkA[lkx]._ndx)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ return ndy;
+ }
+
+ // [OR] P0==0, P1==1 ?
+ if(ndx1 == _c1 && _nodeA[ndx0]._type != ZBDDDG_P1)
+ {
+//cout << "[OR] P0==0, P1==1\n";
+ bddword ndx = Decomp(ZBDD(1).Change(top));
+ if(ndx == ZBDDDG_NIL) return ZBDDDG_NIL;
+ bddword ndy = NewNdx(f, ZBDDDG_OR);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ if(_nodeA[ndx0]._type != ZBDDDG_OR)
+ {
+ if(LinkNodes(ndy, ndx0)) return ZBDDDG_NIL;
+ }
+ else
+ {
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodes(ndy, _linkA[lkx]._ndx)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ return ndy;
+ }
+
+ // [AND] General or P0==1 or P1==1 ?
+ if(_nodeA[ndx0]._type == ZBDDDG_AND &&
+ _nodeA[ndx1]._type == ZBDDDG_AND)
+ {
+//cout << "[AND] general\n";
+ int fin0 = 0;
+ int fin1 = 0;
+ int fin2 = 0;
+
+ fin0 = Mark1(ndx0);
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1)
+ {
+ fin2++;
+ _nodeA[ndt]._mark = 3;
+ }
+ lkx = _linkA[lkx]._nxt;
+ fin1++;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword ndy0;
+ if(fin0 - fin2 > 1)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_AND);
+ if(ndy0 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3)
+ if(LinkNodes(ndy0, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin0 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3)
+ { ndy0 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else ndy0 = _c1;
+
+ bddword ndy1;
+ if(fin1 - fin2 > 1)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy1 = ReferNdx(g);
+ if(ndy1 == ZBDDDG_NIL)
+ {
+ ndy1 = NewNdx(g, ZBDDDG_AND);
+ if(ndy1 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3)
+ if(LinkNodes(ndy1, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin1 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark != 3)
+ { ndy1 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else ndy1 = _c1;
+
+ bddword ndy = NewNdx(f, ZBDDDG_AND);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3)
+ if(LinkNodes(ndy, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweep(ndx0);
+ if(Merge3(ndy, ndy0, ndy1)) return ZBDDDG_NIL;;
+ return ndy;
+ }
+ MarkSweep(ndx0);
+ }
+
+ // [AND] P1==1 (special) ?
+ if(_nodeA[ndx0]._type == ZBDDDG_AND)
+ {
+//cout << "[AND] P1==1(special)\n";
+ int fin0 = 0;
+ int fin2 = 0;
+ _nodeA[ndx1]._mark = 1;
+ bddword lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1) fin2++;
+ fin0++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword ndy0;
+ if(fin0 > 2)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_AND);
+ if(ndy0 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ if(LinkNodes(ndy0, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx0]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ { ndy0 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword ndy = NewNdx(f, ZBDDDG_AND);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx1)) return ZBDDDG_NIL;
+
+ _nodeA[ndx1]._mark = 0;
+ if(Merge3(ndy, ndy0, _c1)) return ZBDDDG_NIL;;
+ return ndy;
+ }
+ _nodeA[ndx1]._mark = 0;
+ }
+
+ // [AND] P0==1 (special) ?
+ if(_nodeA[ndx1]._type == ZBDDDG_AND)
+ {
+//cout << "[AND] P0==1(special)\n";
+ int fin1 = 0;
+ int fin2 = 0;
+ _nodeA[ndx0]._mark = 1;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1) fin2++;
+ fin1++;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(fin2 > 0)
+ {
+ bddword ndy1;
+ if(fin1 > 2)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy1 = ReferNdx(g);
+ if(ndy1 == ZBDDDG_NIL)
+ {
+ ndy1 = NewNdx(g, ZBDDDG_AND);
+ if(ndy1 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ if(LinkNodes(ndy1, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ { ndy1 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword ndy = NewNdx(f, ZBDDDG_AND);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx0)) return ZBDDDG_NIL;
+
+ _nodeA[ndx0]._mark = 0;
+ if(Merge3(ndy, _c1, ndy1)) return ZBDDDG_NIL;;
+ return ndy;
+ }
+ _nodeA[ndx0]._mark = 0;
+ }
+
+ // [OR] general or P0==0 ?
+ bddword ndx00 = ndx0;
+ if(_nodeA[ndx00]._type == ZBDDDG_P1)
+ ndx00 = _linkA[_nodeA[ndx00]._lkx]._ndx;
+
+ if(_nodeA[ndx00]._type == ZBDDDG_OR)
+ {
+//cout << "[OR] (general)\n";
+ int fin0 = 0;
+ int fin2 = 0;
+ Mark2R(ndx1);
+ bddword lkx = _nodeA[ndx00]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(MarkChkR(ndt) != 0) _nodeA[ndt]._mark = 1;
+ else fin2++;
+ fin0++;
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin2 > 0)
+ {
+ bddword ndy0;
+ if(fin0 - fin2 > 1)
+ {
+ ZBDD g = 0;
+ lkx = _nodeA[ndx00]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1) g += _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_OR);
+ if(ndy0 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx00]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1)
+ if(LinkNodes(ndy0, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else if(fin0 - fin2 == 1)
+ {
+ lkx = _nodeA[ndx00]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1)
+ { ndy0 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else ndy0 = _c0;
+
+ if((f & 1) == 1)
+ {
+ ZBDD g0 = _nodeA[ndy0]._f + 1;
+ bddword ndy00 = ReferNdx(g0);
+ if(ndy00 == ZBDDDG_NIL)
+ {
+ ndy00 = NewNdx(g0, ZBDDDG_P1);
+ if(ndy00 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy00, ndy0)) return ZBDDDG_NIL;
+ }
+ ndy0 = ndy00;
+ }
+
+ bddword ndy = NewNdx(f, ZBDDDG_OR);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx00]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ if(LinkNodes(ndy, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ MarkSweepR(ndx1);
+ MarkSweep(ndx00);
+ if(Merge3(ndy, ndy0, ndx1)) return ZBDDDG_NIL;
+ return ndy;
+ }
+
+ MarkSweepR(ndx1);
+ MarkSweep(ndx00);
+ }
+
+ // [OR] P0==0 (special) ?
+ if(_nodeA[ndx00]._type != ZBDDDG_OR)
+ {
+//cout << "[OR] P0==0 (special)\n";
+ Mark2R(ndx1);
+ if(MarkChkR(ndx00) == 0)
+ {
+ bddword ndy = NewNdx(f, ZBDDDG_OR);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx00)) return ZBDDDG_NIL;
+
+ MarkSweepR(ndx1);
+ if(Merge3(ndy, _c0, ndx1)) return ZBDDDG_NIL;;
+ return ndy;
+ }
+ MarkSweepR(ndx1);
+ }
+
+ // [OTHER] P1==1 ?
+ if(_nodeA[ndx00]._type == ZBDDDG_OTHER)
+ {
+//cout << "[OTHER] P1==1\n";
+ Mark2R(ndx1);
+ bddword ndh = Mark4R(ndx0, ndx1, ndx0);
+ if(ndh != ZBDDDG_NIL)
+ {
+ bddword ndy = AppendR(ndx0, top, ndh, _c1);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ MarkSweepR(ndx0);
+ MarkSweepR(ndx1);
+ return ndy;
+ }
+ MarkSweepR(ndx0);
+ MarkSweepR(ndx1);
+ }
+
+ // [OTHER] general ?
+ if(_nodeA[ndx00]._type == ZBDDDG_OTHER &&
+ _nodeA[ndx1]._type == ZBDDDG_AND)
+ {
+//cout << "[OTHER] general\n";
+ bddword ndh = Mark5R(ndx0, ndx1, ndx0);
+ if(ndh != ZBDDDG_NIL)
+ {
+ bddword ndy1 = _c1;
+ int fin1 = 0;
+ int fin2 = 0;
+ ZBDD g = 1;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ fin1++;
+ if(_nodeA[ndt]._mark == 0)
+ {
+ fin2++;
+ g *= _nodeA[ndt]._f;
+ ndy1 = ndt;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin2 >= 2)
+ {
+ ndy1 = ReferNdx(g);
+ if(ndy1 == ZBDDDG_NIL)
+ {
+ ndy1 = NewNdx(g, ZBDDDG_AND);
+ if(ndy1 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ if(LinkNodes(ndy1, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+
+ ZBDD f0 = _nodeA[ndx0]._f;
+ if(Func1(f0, ndh) - f0 == 0)
+ {
+ ZBDD g0 = _nodeA[ndh]._f + 1;
+ bddword ndh0 = ReferNdx(g0);
+ if(ndh0 == ZBDDDG_NIL)
+ {
+ ndh0 = NewNdx(g0, ZBDDDG_P1);
+ if(ndh0 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndh0, ndh)) return ZBDDDG_NIL;
+ }
+ ndh = ndh0;
+ }
+
+ bddword ndy = AppendR(ndx0, top, ndh, ndy1);
+ MarkSweepR(ndx0);
+ MarkSweep(ndx1);
+ return ndy;
+ }
+ MarkSweepR(ndx0);
+ MarkSweep(ndx1);
+ }
+
+ // [P1] ?
+ if(_nodeA[ndx0]._type == ZBDDDG_P1)
+ {
+//cout << "[P1]\n";
+ bddword ndy = NewNdx(f, ZBDDDG_P1);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ bddword ndy0 = ReferNdx(f - 1);
+ if(ndy0 == ZBDDDG_NIL)
+ ndy0 = Merge(f - 1, _linkA[_nodeA[ndx0]._lkx]._ndx, ndx1);
+ if(LinkNodes(ndy, ndy0)) return ZBDDDG_NIL;
+ return ndy;
+ }
+
+ // [OTHER] P0==0 ?
+ if(_nodeA[ndx0]._type == ZBDDDG_OTHER
+ && _nodeA[ndx1]._type == ZBDDDG_AND)
+ {
+//cout << "[OTHER] P0==0\n";
+ Mark2R(ndx0);
+
+ int fin1 = 0;
+ int fin2 = 0;
+ bddword lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(MarkChkR(ndt) != 0) _nodeA[ndt]._mark = 1;
+ else fin2++;
+ fin1++;
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin2 > 0 && fin1 - fin2 > 0)
+ {
+ bddword ndy1;
+ if(fin2 >= 2)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy1 = ReferNdx(g);
+ if(ndy1 == ZBDDDG_NIL)
+ {
+ ndy1 = NewNdx(g, ZBDDDG_AND);
+ if(ndy1 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ if(LinkNodes(ndy1, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else // fin2 == 1
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 0)
+ { ndy1 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ bddword ndy2;
+ if(fin1 - fin2 >= 2)
+ {
+ ZBDD g = 1;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1) g *= _nodeA[ndt]._f;
+ lkx = _linkA[lkx]._nxt;
+ }
+ ndy2 = ReferNdx(g);
+ if(ndy2 == ZBDDDG_NIL)
+ {
+ ndy2 = NewNdx(g, ZBDDDG_AND);
+ if(ndy2 == ZBDDDG_NIL) return ZBDDDG_NIL;
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1)
+ if(LinkNodes(ndy2, ndt)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+ else // fin1 - fin2 == 1
+ {
+ lkx = _nodeA[ndx1]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 1)
+ { ndy2 = ndt; break; }
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+
+ MarkSweepR(ndx0);
+ MarkSweepR(ndy2);
+ Mark2R(ndx0);
+ Mark2R(ndy2);
+ Mark3R(ndx0);
+ Mark3R(ndy2);
+
+ bddword ndy = NewNdx(f, ZBDDDG_OTHER);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodesC3(ndy, ndx0)) return ZBDDDG_NIL;
+ if(LinkNodesC3(ndy, ndy2)) return ZBDDDG_NIL;
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ MarkSweepR(ndx0);
+ MarkSweepR(ndy2);
+ if(Merge3(ndy, _c0, ndy1)) return ZBDDDG_NIL;;
+ return ndy;
+ }
+ MarkSweepR(ndx0);
+ }
+
+ // [OTHER] P1==1, P0==0 ?
+//cout << "[OTHER] (default)\n";
+ MarkSweepR(ndx0);
+ MarkSweepR(ndx1);
+ Mark2R(ndx0);
+ Mark2R(ndx1);
+ Mark3R(ndx0);
+ Mark3R(ndx1);
+ bddword ndx = Decomp(ZBDD(1).Change(top));
+ if(ndx == ZBDDDG_NIL) return ZBDDDG_NIL;
+
+ bddword ndy = NewNdx(f, ZBDDDG_OTHER);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ if(LinkNodesC3(ndy, ndx0)) return ZBDDDG_NIL;
+ if(LinkNodesC3(ndy, ndx1)) return ZBDDDG_NIL;
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ MarkSweepR(ndx0);
+ MarkSweepR(ndx1);
+ return ndy;
+}
+
+bddword ZBDDDG::AppendR(bddword ndx, int top, bddword ndy0, bddword ndy1)
+{
+ ZBDD f = _nodeA[ndx]._f;
+ ZBDD h = _nodeA[ndy0]._f;
+ ZBDD g = f + Func1(f, h) * _nodeA[ndy1]._f.Change(top);
+ bddword ndy = ReferNdx(g);
+ if(ndy != ZBDDDG_NIL) return ndy;
+ ndy = NewNdx(g, _nodeA[ndx]._type);
+ if(ndy == ZBDDDG_NIL) return ZBDDDG_NIL;
+ int hit = 0;
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark <= 1)
+ {
+ if(LinkNodes(ndy, ndt)) return ZBDDDG_NIL;
+ }
+ else if(_nodeA[ndt]._mark == 2)
+ {
+ bddword ndr = AppendR(ndt, top, ndy0, ndy1);
+ if(ndr == ZBDDDG_NIL) return ZBDDDG_NIL;
+ if(LinkNodes(ndy, ndr)) return ZBDDDG_NIL;
+ }
+ else hit = 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(hit)
+ {
+ if(Merge3(ndy, ndy0, ndy1)) return ZBDDDG_NIL;
+ }
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ return ndy;
+}
+
+int ZBDDDG::LinkNodesC3(bddword ndy, bddword ndx)
+{
+ bddword lkx;
+ switch(_nodeA[ndx]._mark)
+ {
+ case 1:
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodesC3(ndy, _linkA[lkx]._ndx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ break;
+ case 2:
+ if(_nodeA[ndx]._type == ZBDDDG_P1)
+ {
+ if(LinkNodesC3(ndy, _linkA[_nodeA[ndx]._lkx]._ndx)) return 1;
+ break;
+ }
+ if(LinkNodes(ndy, ndx)) return 1;
+ _nodeA[ndx]._mark = 9;
+ break;
+ case 3:
+ if(_nodeA[ndx]._type == ZBDDDG_P1)
+ {
+ if(LinkNodesC3(ndy, _linkA[_nodeA[ndx]._lkx]._ndx)) return 1;
+ break;
+ }
+ if(LinkNodes(ndy, ndx)) return 1;
+ break;
+ case 4:
+ {
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ bddword ndxP = _nodeA[ndt]._ndxP;
+ if(ndxP != ZBDDDG_NIL && ndxP != ndx)
+ {
+ if(_nodeA[ndxP]._type == ZBDDDG_AND &&
+ _nodeA[ndx]._type == ZBDDDG_AND )
+ {
+ ZBDD g = 1;
+ int fin = 0;
+ bddword lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ {
+ g *= _nodeA[ndt2]._f;
+ fin++;
+ }
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_AND);
+ if(ndy0 == ZBDDDG_NIL) return 1;
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ {
+ if(LinkNodes(ndy0, ndt2)) return 1;
+ }
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ if(LinkNodes(ndy, ndy0)) return 1;
+
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ _nodeA[ndt2]._mark = 9;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ _nodeA[ndt2]._ndxP = ZBDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+
+ if(_nodeA[ndxP]._type == ZBDDDG_OR &&
+ _nodeA[ndx]._type == ZBDDDG_OR )
+ {
+ ZBDD g = 0;
+ int fin = 0;
+ bddword lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ {
+ g += _nodeA[ndt2]._f;
+ fin++;
+ }
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_OR);
+ if(ndy0 == ZBDDDG_NIL) return 1;
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ if(LinkNodes(ndy0, ndt2)) return 1;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ if(LinkNodes(ndy, ndy0)) return 1;
+
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ _nodeA[ndt2]._mark = 9;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ lkx2 = lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ bddword ndt2 = _linkA[lkx2]._ndx;
+ if(ndxP == _nodeA[ndt2]._ndxP)
+ _nodeA[ndt2]._ndxP = ZBDDDG_NIL;
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+
+ if(_nodeA[ndx]._type == ZBDDDG_AND)
+ {
+ ZBDD g = 1;
+ int fin = 0;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3)
+ {
+ g *= _nodeA[ndt]._f;
+ fin++;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_AND);
+ if(ndy0 == ZBDDDG_NIL) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3)
+ if(LinkNodes(ndy0, ndt)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(LinkNodes(ndy, ndy0)) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3) _nodeA[ndt]._mark = 9;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+
+
+ if(_nodeA[ndx]._type == ZBDDDG_OR)
+ {
+ ZBDD g = 0;
+ int fin = 0;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3)
+ {
+ g += _nodeA[ndt]._f;
+ fin++;
+ }
+ lkx = _linkA[lkx]._nxt;
+ }
+ if(fin >= 2)
+ {
+ bddword ndy0 = ReferNdx(g);
+ if(ndy0 == ZBDDDG_NIL)
+ {
+ ndy0 = NewNdx(g, ZBDDDG_OR);
+ if(ndy0 == ZBDDDG_NIL) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3)
+ if(LinkNodes(ndy0, ndt)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ if(LinkNodes(ndy, ndy0)) return 1;
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ bddword ndt = _linkA[lkx]._ndx;
+ if(_nodeA[ndt]._mark == 3) _nodeA[ndt]._mark = 9;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ }
+
+ }
+
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodesC3(ndy, _linkA[lkx]._ndx)) return 1;
+ lkx = _linkA[lkx]._nxt;
+ }
+ break;
+ case 9:
+ break;
+ default:
+ cerr << "<ERROR> ZBDDDG::LinkNodesC3(): wrong case (";
+ cerr << _nodeA[ndx]._mark << ")\n";
+ exit(1);
+ }
+ return 0;
+}
+
+ZBDD ZBDDDG::Func0(ZBDD f, ZBDD g)
+{
+ if(g == 1)
+ {
+ cerr << "<ERROR> ZBDDDG::Func0: g == 1";
+ exit(1);
+ }
+ ZBDD h = f;
+ while(g != 0)
+ {
+ int top = g.Top();
+ ZBDD g0 = g.OffSet(top);
+ if(g0 != 1)
+ {
+ g = g0;
+ h = h.OffSet(top);
+ }
+ else
+ {
+ g = g.OnSet0(top);
+ h = h.OnSet0(top);
+ }
+ }
+ return h;
+}
+
+ZBDD ZBDDDG::Func1(ZBDD f, ZBDD g)
+{
+ if(g == 0)
+ {
+ cerr << "<ERROR> ZBDDDG::Func1: g == 0";
+ exit(1);
+ }
+ ZBDD h = f;
+ while(g != 1)
+ {
+ int top = g.Top();
+ g = g.OnSet0(top);
+ h = h.OnSet0(top);
+ }
+ return h;
+}
+
+int ZBDDDG::Merge3(bddword ndy, bddword ndy0, bddword ndy1)
+{
+//cout << "[Merge3]\n";
+ int top = _nodeA[ndy]._f.Top();
+ ZBDD h0 = _nodeA[ndy0]._f;
+ ZBDD h1 = _nodeA[ndy1]._f;
+ ZBDD h = h0 + h1.Change(top);
+ bddword ndx = ReferNdx(h);
+ if(ndx == ZBDDDG_NIL) ndx = Merge(h, ndy0, ndy1);
+ if(ndx == ZBDDDG_NIL) return 1;
+ switch(_nodeA[ndy]._type)
+ {
+ case ZBDDDG_AND:
+ if(_nodeA[ndx]._type == ZBDDDG_AND)
+ {
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodes(ndy, _linkA[lkx]._ndx)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ break;
+ case ZBDDDG_OR:
+ if(_nodeA[ndx]._type == ZBDDDG_P1)
+ ndx = _linkA[_nodeA[ndx]._lkx]._ndx;
+ if(_nodeA[ndx]._type == ZBDDDG_OR)
+ {
+ bddword lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ if(LinkNodes(ndy, _linkA[lkx]._ndx)) return ZBDDDG_NIL;
+ lkx = _linkA[lkx]._nxt;
+ }
+ }
+ else if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ break;
+ case ZBDDDG_OTHER:
+ if(_nodeA[ndx]._type == ZBDDDG_P1)
+ ndx = _linkA[_nodeA[ndx]._lkx]._ndx;
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ break;
+ default:
+ if(LinkNodes(ndy, ndx)) return ZBDDDG_NIL;
+ break;
+ }
+ if(PhaseSweep(ndy)) return ZBDDDG_NIL;
+ return 0;
+}
+
+int ZBDDDG::PrintDecomp(ZBDD f)
+{
+ bddword ndx = Decomp(f);
+ if(ndx == ZBDDDG_NIL) return 1;
+ Print0(ndx);
+ cout << "\n";
+ return 0;
+}
+
+void ZBDDDG::Print0(bddword ndx)
+{
+ bddword lkx, lkx2;
+ bddword ndx2;
+ switch(_nodeA[ndx]._type)
+ {
+ case ZBDDDG_C0:
+ cout << "0 ";
+ break;
+ case ZBDDDG_P1:
+ cout << "OR( ";
+ lkx = _nodeA[ndx]._lkx;
+ ndx2 = _linkA[lkx]._ndx;
+ if(_nodeA[ndx2]._type != ZBDDDG_OR)
+ Print0(ndx2);
+ else
+ {
+ lkx2 = _nodeA[ndx2]._lkx;
+ while(lkx2 != ZBDDDG_NIL)
+ {
+ Print0(_linkA[lkx2]._ndx);
+ lkx2 = _linkA[lkx2]._nxt;
+ }
+ }
+ cout << "1 ) ";
+ break;
+ case ZBDDDG_LIT:
+ cout << "x" << _nodeA[ndx]._f.Top() << " ";
+ break;
+ case ZBDDDG_AND:
+ cout << "AND( ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._ndx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << ") ";
+ break;
+ case ZBDDDG_OR:
+ cout << "OR( ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._ndx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << ") ";
+ break;
+ case ZBDDDG_OTHER:
+ cout << "[ ";
+ lkx = _nodeA[ndx]._lkx;
+ while(lkx != ZBDDDG_NIL)
+ {
+ Print0(_linkA[lkx]._ndx);
+ lkx = _linkA[lkx]._nxt;
+ }
+ cout << "] ";
+ break;
+ default:
+ cerr << "<ERROR> ZBDDDG::Print0: wrong case (";
+ cerr << (int)_nodeA[ndx]._type << ")\n";
+ exit(1);
+ }
+}
+
--- /dev/null
+/****************************************
+ * ZBDD+ Manipulator (SAPPORO-1.21) *
+ * (Hash table methods) *
+ * (C) Shin-ichi MINATO (Feb. 18, 2009) *
+ ****************************************/
+
+#include "ZBDD.h"
+
+ZBDD_Hash::ZBDD_Hash()
+{
+ _hashSize = 16;
+ _wheel = new ZBDD_Entry[_hashSize];
+ _amount = 0;
+}
+
+ZBDD_Hash::~ZBDD_Hash() { delete[] _wheel; }
+
+void ZBDD_Hash::Clear()
+{
+ if(_hashSize != 0) delete[] _wheel;
+ _hashSize = 16;
+ _wheel = new ZBDD_Entry[_hashSize];
+ _amount = 0;
+}
+
+ZBDD_Hash::ZBDD_Entry* ZBDD_Hash::GetEntry(ZBDD key)
+{
+ bddword id = key.GetID();
+ bddword hash = (id+(id>>10)+(id>>20)) & (_hashSize - 1);
+ bddword i = hash;
+ while(_wheel[i]._key != -1)
+ {
+ if(key == _wheel[i]._key) return & _wheel[i];
+ i++;
+ i &= (_hashSize -1);
+ }
+ i = hash;
+ while(_wheel[i]._key != -1)
+ {
+ if(_wheel[i]._ptr == 0) break;
+ i++;
+ i &= (_hashSize -1);
+ }
+ return & _wheel[i];
+}
+
+void ZBDD_Hash::Enlarge()
+{
+ bddword oldSize = _hashSize;
+ ZBDD_Entry* oldWheel = _wheel;
+
+ _hashSize <<= 2;
+ _wheel = new ZBDD_Entry[_hashSize];
+ if(_wheel == 0)
+ {
+ cerr << "<ERROR> ZBDD_Hash::Enlarge(): Memory overflow (";
+ cerr << _hashSize << ")\n";
+ exit(1);
+ }
+ _amount = 0;
+ for(bddword i=0; i<oldSize; i++)
+ if(oldWheel[i]._ptr != 0)
+ if(oldWheel[i]._key != -1)
+ Enter(oldWheel[i]._key, oldWheel[i]._ptr);
+ delete[] oldWheel;
+}
+
+void ZBDD_Hash::Enter(ZBDD key, void* ptr)
+// ptr = 0 means deleting.
+{
+ ZBDD_Entry* ent = GetEntry(key);
+ if(ent -> _key == -1) _amount++;
+ else if(ent -> _ptr == 0) _amount++;
+ if(ptr == 0) _amount--;
+ ent -> _key = key;
+ ent -> _ptr = ptr;
+ if(_amount >= (_hashSize>>1)) Enlarge();
+}
+
+void* ZBDD_Hash::Refer(ZBDD key)
+// returns 0 if not found.
+{
+ ZBDD_Entry* ent = GetEntry(key);
+ if(ent -> _key == -1) return 0;
+ return ent -> _ptr;
+}
+
+bddword ZBDD_Hash::Amount() { return _amount; }
+
--- /dev/null
+/****************************************
+ * BDD+ Manipulator (SAPPORO-1.21) *
+ * (LCM interface) *
+ * (C) Shin-ichi MINATO (Feb. 18, 2009) *
+ ****************************************/
+
+#include "ZBDD.h"
+
+#define BDD_CPP
+#include "bddc.h"
+
+extern "C"
+{
+ /***************** Init. and config. ****************/
+ extern void bddlcm1 B_ARG((char *fname, int th, int param));
+ extern bddp bddlcm2 B_ARG(());
+ extern void bddfree B_ARG((bddp f));
+}
+
+extern int LCM_Eend;
+
+ZBDD ZBDD_LCM_A(char *fname, int th)
+{
+ bddlcm1(fname, th, 0);
+ while(LCM_Eend > BDDV_UserTopLev()) BDD_NewVar();
+ bddword z = bddlcm2();
+ ZBDD h = ZBDD_ID(z);
+ bddfree(z);
+ return h;
+}
+
+ZBDD ZBDD_LCM_C(char *fname, int th)
+{
+ bddlcm1(fname, th, 1);
+ while(LCM_Eend > BDDV_UserTopLev()) BDD_NewVar();
+ bddword z = bddlcm2();
+ ZBDD h = ZBDD_ID(z);
+ bddfree(z);
+ return h;
+}
+
+ZBDD ZBDD_LCM_M(char *fname, int th)
+{
+ bddlcm1(fname, th, 2);
+ while(LCM_Eend > BDDV_UserTopLev()) BDD_NewVar();
+ bddword z = bddlcm2();
+ ZBDD h = ZBDD_ID(z);
+ bddfree(z);
+ return h;
+}
+
--- /dev/null
+/****************************************
+ * ZBDD+ Manipulator (SAPPORO-1.55) *
+ * (Graphic methods) *
+ * (C) Shin-ichi MINATO (Dec. 11, 2012) *
+ ****************************************/
+
+#include "ZBDD.h"
+
+void ZBDD::XPrint() const
+{
+ bddgraph(_zbdd);
+}
+
+void ZBDDV::XPrint() const
+{
+ int len = Last() + 1;
+ bddword* bddv = new bddword[len];
+ for(int i=0; i<len; i++) bddv[i] = GetZBDD(i).GetID();
+ bddvgraph(bddv, len);
+ delete[] bddv;
+}
+
+/*
+void ZBDD::XPrint0()
+{
+ bddgraph0(_zbdd);
+}
+
+void ZBDDV::XPrint0()
+{
+ int len = Last() + 1;
+ bddword* bddv = new bddword[len];
+ for(int i=0; i<len; i++) bddv[i] = GetZBDD(i).GetID();
+ bddvgraph0(bddv, len);
+ delete[] bddv;
+}
+*/
--- /dev/null
+/*
+ array-based simple heap (fixex size)
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _aheap_c_
+#define _aheap_c_
+
+#include"aheap.h"
+
+QSORT_TYPE (AHEAP_KEY, AHEAP_KEY)
+QSORT_TYPE (AHEAP_ID, AHEAP_ID)
+AHEAP INIT_AHEAP = {TYPE_AHEAP,NULL,0,0};
+
+/* allocate memory */
+void AHEAP_alloc (AHEAP *H, AHEAP_ID num){
+ AHEAP_ID i;
+#ifdef ERROR_CHECK
+ if ( num<0 ) error_num ("size is out of range", num, EXIT);
+#endif
+ *H = INIT_AHEAP;
+ if ( num>0 ) malloc2 (H->v, num*2, "AHEAP_alloc: H->v", EXIT);
+ H->end = num;
+ ARY_FILL (H->v, 0, num*2, AHEAP_KEYHUGE);
+ for (i=0 ; i<num-1 ; i=i*2+1);
+ H->base = i - num + 1;
+}
+
+/* termination */
+void AHEAP_end (AHEAP *H){
+ free2 (H->v);
+ *H = INIT_AHEAP;
+}
+
+/* return the index of the leaf having the minimum key among the descendants
+ of the given node i. If several leaves with the smallest key are there,
+ return the minimum index among them if f=0, maximum index if f=1, and
+ random choice if f=2 */
+/* random choice version. choose one child to go down randomly for each node,
+ thus it is not uniformly random */
+AHEAP_ID AHEAP_findmin_node (AHEAP *H, AHEAP_ID i, int f){
+ if ( H->end <= 0 ) return (-1);
+ while ( i < H->end-1 ){
+ if ( H->v[i*2+1] == H->v[i] )
+ if ( H->v[i*2+2] == H->v[i] )
+ if ( f == 2 ) i = i*2 + 1 + rand()%2;
+ else i = i*2+1+f;
+ else i = i*2+1;
+ else i = i*2+2;
+ }
+ return (AHEAP_IDX(*H, i) );
+}
+AHEAP_ID AHEAP_findmin_head (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 0) ); }
+AHEAP_ID AHEAP_findmin_tail (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 1) ); }
+AHEAP_ID AHEAP_findmin_rnd (AHEAP *H){ return (AHEAP_findmin_node (H, 0, 2) ); }
+
+/* return the index of the leaf having smaller value than a among the
+ descendants of the given node i. If several leaves with the smallest key
+ are there, return the minimum index among them if f=0, maximum index if f=1,
+ and random choice if f=2 */
+AHEAP_ID AHEAP_findlow_node (AHEAP *H, AHEAP_KEY a, AHEAP_ID i, int f){
+ if ( H->end == 0 ) return (-1);
+ if ( H->v[0] > a ) return (-1);
+ while ( i < H->end-1 ){
+ if ( f == 2 ) {
+ if ( H->v[i*2+1] <= a )
+ if ( H->v[i*2+2] <= a ) i = i*2 + 1 + rand()%2;
+ else i = i*2+1;
+ else i = i*2+2;
+ } else if ( H->v[i*2+1] <= a ) i = i*2+1+f; else i = i*2+2-f;
+ }
+ return (AHEAP_IDX(*H, i) );
+}
+AHEAP_ID AHEAP_findlow_head (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 0) ); }
+AHEAP_ID AHEAP_findlow_tail (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 1) ); }
+AHEAP_ID AHEAP_findlow_rnd (AHEAP *H, AHEAP_KEY a){ return (AHEAP_findlow_node (H, a, 0, 2) ); }
+
+/* return the index of the leaf having smaller value than a next/previous to
+ leaf i. return -1 if such a leaf does not exist */
+AHEAP_ID AHEAP_findlow_nxt (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ if ( H->end == 0 ) return (-1);
+ for (i=AHEAP_LEAF(*H,i); i>0 ; i=(i-1)/2){
+ /* i is the child of smaller index, and the key of the sibling of i is less than a */
+ if ( i%2 == 1 && H->v[i+1] <= a ) return (AHEAP_findlow_node (H, a, i+1, 0) );
+ }
+ return (-1);
+}
+AHEAP_ID AHEAP_findlow_prv (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ if ( H->end == 0 ) return (-1);
+ for (i=AHEAP_LEAF(*H,i); i>0 ; i=(i-1)/2){
+ /* i is the child of larger index, and the key of the sibling of i is less than a */
+ if ( i%2 == 0 && H->v[i-1] <= a ) return (AHEAP_findlow_node (H, a, i-1, 1) );
+ }
+ return (-1);
+}
+
+/* change the key of node i to a /Add a to the key of node i, and update heap H */
+void AHEAP_chg (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ i = AHEAP_LEAF (*H, i);
+ H->v[i] = a;
+ AHEAP_update (H, i);
+}
+void AHEAP_add (AHEAP *H, AHEAP_ID i, AHEAP_KEY a){
+ i = AHEAP_LEAF (*H, i);
+ H->v[i] += a;
+ AHEAP_update (H, i);
+}
+
+/* update the ancestor of node i */
+void AHEAP_update (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID j;
+ AHEAP_KEY a = H->v[i];
+ while ( i>0 ){
+ j = i - 1 + (i%2)*2; /* j = the sibling of i */
+ i = (i-1) / 2;
+ if ( H->v[j] < a ) a = H->v[j];
+ if ( a == H->v[i] ) break;
+ H->v[i] = a;
+ }
+}
+
+/* find the leaf with the minimum key value among the leaves having index
+ smaller/larger than i, or between i and j */
+AHEAP_ID AHEAP_upper_min (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID fi=0, j = AHEAP_LEAF (*H, H->end - 1);
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == 0 ) return (AHEAP_findmin_head (H) );
+ i = AHEAP_LEAF (*H, i-1);
+ while ( i != j ){
+ if ( i%2 ){ /* if i is the child with smaller index */
+ if ( fm > H->v[i+1] ){
+ fm = H->v[i+1];
+ fi = i+1;
+ }
+ }
+ i = (i-1)/2;
+ if ( j == i ) break; /* stop if the right pointer and the left pointer are the same */
+ j = (j-1)/2;
+ }
+ while ( fi < H->end-1 ) fi = fi*2 + (H->v[fi*2+1]<=fm?1:2);
+ return ( AHEAP_IDX(*H, fi) );
+}
+AHEAP_ID AHEAP_lower_min (AHEAP *H, AHEAP_ID i){
+ AHEAP_ID fi=0, j = AHEAP_LEAF (*H, 0);
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == H->end-1 ) return (AHEAP_findmin_head (H) );
+ i = AHEAP_LEAF (*H, i+1);
+ while ( i != j ){
+ if ( i%2 == 0 ){ /* if i is the child of larger index */
+ if ( fm > H->v[i-1] ){
+ fm = H->v[i-1];
+ fi = i-1;
+ }
+ }
+ j = (j-1)/2;
+ if ( j == i ) break; /* stop if the right pointer and the left pointer are the same */
+ i = (i-1)/2;
+ }
+ while ( fi < H->end-1 ) fi = fi*2 + (H->v[fi*2+1]<=fm?1:2);
+ return (AHEAP_IDX(*H, fi) );
+}
+
+/* find the index having the minimum among given two indices */
+AHEAP_ID AHEAP_interval_min (AHEAP *H, AHEAP_ID i, AHEAP_ID j){
+ AHEAP_ID fi=0;
+ AHEAP_KEY fm = AHEAP_KEYHUGE;
+ if ( i == 0 ) return (AHEAP_lower_min (H, j) );
+ if ( j == H->end-1 ) return (AHEAP_upper_min (H, i) );
+ i = AHEAP_LEAF (*H, i-1);
+ j = AHEAP_LEAF (*H, j+1);
+ while ( i != j && i != j-1 ){
+ if ( i%2 ){ /* if i is the child of smaller index */
+ if ( fm > H->v[i+1] ){
+ fm = H->v[i+1];
+ fi = i+1;
+ }
+ }
+ i = (i-1)/2;
+ if ( j == i || j == i+1 ) break; /* stop if the right pointer and the left pointer are the same */
+ if ( j%2 == 0 ){ /* if j is the child of larger index */
+ if ( fm > H->v[j-1] ){
+ fm = H->v[j-1];
+ fi = j-1;
+ }
+ }
+ j = (j-1)/2;
+ }
+ while ( fi < H->end-1 )
+ fi = fi*2 + (H->v[fi*2+1] <= fm?1:2);
+ return (AHEAP_IDX(*H, fi) );
+}
+
+/* print heap keys according to the structure of the heap */
+void AHEAP_print (AHEAP *H){
+ AHEAP_ID i, j=1;
+ while ( j<=H->end*2-1 ){
+ FLOOP (i, j-1, MIN(j, H->end)*2-1) printf (AHEAP_KEYF ",", H->v[i] );
+ printf ("\n");
+ j = j*2;
+ }
+}
+
+#endif
--- /dev/null
+/*
+ array-based simple heap (fixed size)
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* bench mark
+ PentiumIII 500MHz, Memory 256MB Linux
+ values 0-1,000,000 : set & del & get 1,000,000 times
+ 2.55sec
+
+ # rotation == 1/5 per 1 set/del
+
+ *** simple array ***
+ value 0-1,000,000 set & set & set 1,000,000 times,
+ 0.88sec
+ */
+
+#ifndef _aheap_h_
+#define _aheap_h_
+
+#include"stdlib2.h"
+
+#ifndef AHEAP_KEY
+ #ifdef AHEAP_KEY_DOUBLE
+ #define AHEAP_KEY double
+ #define AHEAP_KEYHUGE DOUBLEHUGE
+ #define AHEAP_KEYF "%f"
+ #elif defined(AHEAP_KEY_WEIGHT)
+ #define AHEAP_KEY WEIGHT
+ #define AHEAP_KEYHUGE WEIGHTHUGE
+ #define AHEAP_KEYF WEIGHTF
+ #else
+#define AHEAP_KEY int
+ #define AHEAP_KEYHUGE INTHUGE
+ #define AHEAP_KEYF "%d"
+ #endif
+#endif
+
+#ifndef AHEAP_ID
+ #define AHEAP_ID int
+ #define AHEAP_ID_END INTHUGE
+ #define AHEAP_IDF "%d"
+#endif
+
+#define AHEAP_IDX(H,i) (((i)+1-(H).base)%(H).end)
+#define AHEAP_LEAF(H,i) (((i)+(H).base)%(H).end+(H).end-1)
+#define AHEAP_H(H,i) (H).v[(((i)+(H).base)%(H).end+(H).end-1)]
+
+typedef struct {
+ unsigned char type;
+ AHEAP_KEY *v; /* array for heap key */
+ int end; /* the number of maximum elements */
+ int base; /* the constant for set 0 to the leftmost leaf */
+} AHEAP;
+
+QSORT_TYPE_HEADER (AHEAP_KEY, AHEAP_KEY)
+QSORT_TYPE_HEADER (AHEAP_ID, AHEAP_ID)
+extern AHEAP INIT_AHEAP;
+
+/* initialization. allocate memory for H and fill it by +infinity */
+void AHEAP_alloc (AHEAP *H, int num);
+void AHEAP_end (AHEAP *H);
+
+/* return the index of the leaf having the minimum key among the descendants
+ of the given node i. If several leaves with the smallest key are there,
+ return the minimum index among them if f=0, maximum index if f=1, and
+ random choice if f=2 */
+AHEAP_ID AHEAP_findmin_node (AHEAP *H, AHEAP_ID i, int f);
+AHEAP_ID AHEAP_findmin_head (AHEAP *H);
+AHEAP_ID AHEAP_findmin_tail (AHEAP *H);
+AHEAP_ID AHEAP_findmin_rnd (AHEAP *H);
+
+/* return the index of the leaf having smaller value than a among the
+ descendants of the given node i. If several leaves with the smallest key
+ are there, return the minimum index among them if f=0, maximum index if f=1,
+ and random choice if f=2 */
+AHEAP_ID AHEAP_findlow_node (AHEAP *H, AHEAP_KEY a, AHEAP_ID i, int f);
+AHEAP_ID AHEAP_findlow_head (AHEAP *H, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_tail (AHEAP *H, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_rnd (AHEAP *H, AHEAP_KEY a);
+
+/* return the index of the leaf having smaller value than a next/previous to
+ leaf i. return -1 if such a leaf does not exist */
+AHEAP_ID AHEAP_findlow_nxt (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+AHEAP_ID AHEAP_findlow_prv (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+
+/* change the key of node i to a /Add a to the key of node i, and update heap H */
+void AHEAP_chg (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+void AHEAP_add (AHEAP *H, AHEAP_ID i, AHEAP_KEY a);
+
+/* update the ancestor of node i */
+void AHEAP_update (AHEAP *H, AHEAP_ID i);
+
+/* find the leaf with the minimum key value among the leaves having index
+ smaller/larger than i, or between i and j */
+AHEAP_ID AHEAP_upper_min (AHEAP *H, AHEAP_ID i);
+AHEAP_ID AHEAP_lower_min (AHEAP *H, AHEAP_ID i);
+AHEAP_ID AHEAP_interval_min (AHEAP *H, AHEAP_ID i, AHEAP_ID j);
+
+/* print heap keys according to the structure of the heap */
+void AHEAP_print (AHEAP *H);
+
+#endif
--- /dev/null
+/*
+ blocked memory allocation library
+ 12/Mar/2002 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _base_c_
+#define _base_c_
+
+#include"base.h"
+
+BASE INIT_BASE = {TYPE_BASE,NULL,0,0,0,0,-1,NULL};
+
+/* initialization, and allocate memory for header */
+void BASE_alloc (BASE *B, int unit, int block_siz){
+ *B = INIT_BASE;
+ B->dellist = B;
+ B->unit = unit;
+ B->block_siz = block_siz;
+ B->num = block_siz;
+ B->block_num = -1;
+ calloc2 (B->base, 20, "BASE_alloc: B->base", EXIT);
+ B->block_end = 20;
+}
+
+/* termination */
+void BASE_end (BASE *B){
+ int i;
+ FLOOP (i, 0, B->block_end) free2 (B->base[i]);
+ free2 (B->base);
+ *B = INIT_BASE;
+}
+
+/* return pointer to the cell corresponding to the given index */
+void *BASE_pnt (BASE *B, size_t i){
+ return ( B->base[i/BASE_BLOCK] + (i%BASE_BLOCK)*B->unit);
+}
+/* return index corresponding to the given pointer */
+size_t BASE_index (BASE *B, void *x){
+ size_t i;
+ FLOOP (i, 0, (size_t)(B->block_end+1)){
+ if ( ((char*)x)>= B->base[i] && ((char*)x)<=B->base[i]+B->unit*BASE_BLOCK )
+ return ( i*BASE_BLOCK + ((size_t)(((char *)x) - B->base[i])) / B->unit);
+ }
+ return (0);
+}
+
+/* increment the current memory block pointer and (re)allcate memory if necessary */
+void *BASE_get_memory (BASE *B, int i){
+ B->num += i;
+ if ( B->num >= B->block_siz ){ /* if reach to the end of base array */
+ B->num = i; /* allocate one more base array, and increment the counter */
+ B->block_num++;
+ reallocx(B->base, B->block_end, B->block_num, NULL, "BASE:block", EXIT0);
+ if ( B->base[B->block_num] == NULL )
+ malloc2 (B->base[B->block_num], B->block_siz*B->unit, "BASE_new: base", EXIT0);
+ return (B->base[B->block_num]);
+ }
+ return (B->base[B->block_num] + (B->num-i)*B->unit);
+}
+
+
+/* allocate new cell */
+void *BASE_new (BASE *B){
+ char *x;
+
+ /* use deleted cell if it exists */
+ if ( B->dellist != ((void *)B) ){
+ x = (char *)B->dellist; /* return the deleted cell */
+ B->dellist = (void *)(*((char **)x)); /* increment the head of the list */
+ } else {
+ /* take a new cell from the base array if no deleted one exists */
+ x = (char *)BASE_get_memory (B, 1);
+ }
+ return (x);
+}
+
+/* delete one cell. (add to the deleted list) */
+void BASE_del (BASE *B, void *x){
+ *((void **)x) = B->dellist;
+ B->dellist = x;
+}
+
+#endif
+
+
--- /dev/null
+/*
+ blocked memory allocation library
+ 12/Mar/2002 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+
+#ifndef _base_h_
+#define _base_h_
+
+#include"stdlib2.h"
+
+/* structure for base array */
+#define BASE_UNIT 16
+#define BASE_BLOCK 65536
+
+typedef struct {
+ unsigned char type;
+ char **base;
+ int block_siz; // size of one block of memory
+ int block_num; // currently using block
+ int unit; // size of one unit memory
+ int num; // current position in a block
+ int block_end; // current end of the block
+ void *dellist;
+} BASE;
+
+extern BASE INIT_BASE;
+
+/* initialization, and allocate memory for header */
+void BASE_alloc (BASE *B, int unit, int block_siz);
+
+/* termination */
+void BASE_end (BASE *B);
+
+/* return pointer to the cell corresponding to the given index */
+void *BASE_pnt (BASE *B, size_t i);
+
+/* return index corresponding to the given pointer */
+size_t BASE_index (BASE *B, void *x);
+
+/* increment the current memory block pointer and (re)allcate memory if necessary */
+void *BASE_get_memory (BASE *B, int i);
+
+/* allocate new cell */
+void *BASE_new (BASE *B);
+
+/* delete one cell. (add to the deleted list) */
+void BASE_del (BASE *B, void *x);
+
+
+#endif
+
--- /dev/null
+/* itemset search input/output common routines
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* routines for itemset mining */
+
+#ifndef _itemset_c_
+#define _itemset_c_
+
+#include"itemset.h"
+#include"queue.c"
+#include"aheap.c"
+
+/* flush the write buffer, available for multi-core mode */
+void ITEMSET_flush (ITEMSET *I, FILE2 *fp){
+ if ( !(I->flag&ITEMSET_MULTI_OUTPUT) || (fp->buf-fp->buf_org) > FILE2_BUFSIZ/2 ){
+ SPIN_LOCK(I->multi_core, I->lock_output);
+ FILE2_flush (fp);
+ SPIN_UNLOCK(I->multi_core, I->lock_output);
+ }
+}
+
+/* Output information about ITEMSET structure. flag&1: print frequency constraint */
+void ITEMSET_print (ITEMSET *I, int flag){
+ if ( I->lb>0 || I->ub<INTHUGE ){
+ if ( I->lb > 0 ) print_err ("%d <= ", I->lb);
+ print_err ("itemsets ");
+ if ( I->ub < INTHUGE ) print_err (" <= %d\n", I->ub);
+ print_err ("\n");
+ }
+ if ( flag&1 ){
+ if ( I->frq_lb > -WEIGHTHUGE ) print_err (WEIGHTF" <=", I->frq_lb);
+ print_err (" frequency ");
+ if ( I->frq_ub < WEIGHTHUGE ) print_err (" <="WEIGHTF, I->frq_ub);
+ print_err ("\n");
+ }
+}
+
+/* ITEMSET initialization */
+void ITEMSET_init (ITEMSET *I){
+ I->flag = 0;
+ I->iters = I->iters2 = I->iters3 = 0;
+ I->solutions = I->solutions2 = I->max_solutions = I->outputs = I->outputs2 = 0;
+ I->topk.end = 0;
+ I->item_max = I->item_max_org = 0;
+ I->ub = I->len_ub = I->gap_ub = INTHUGE;
+ I->lb = I->len_lb = I->gap_lb = 0;
+ I->frq = I->pfrq = I->total_weight = 0;
+ I->ratio = I->prob = 0.0;
+ I->posi_ub = I->nega_ub = I->frq_ub = WEIGHTHUGE;
+ I->posi_lb = I->nega_lb = I->frq_lb = I->setrule_lb = -WEIGHTHUGE;
+ I->dir = 0;
+ I->target = INTHUGE;
+ I->prob_ub = I->ratio_ub = I->rposi_ub = 1;
+ I->prob_lb = I->ratio_lb = I->rposi_lb = 0;
+ I->itemflag = NULL;
+ I->perm = NULL;
+ I->item_frq = NULL;
+ I->sc = NULL;
+ I->X = NULL;
+ I->fp = NULL;
+ I->topk = INIT_AHEAP;
+ I->itemset = I->add = INIT_QUEUE;
+ I->set_weight = NULL;
+ I->set_occ = NULL;
+
+ I->multi_iters = I->multi_iters2 = I->multi_iters3 = NULL;
+ I->multi_outputs = I->multi_outputs2 = NULL;
+ I->multi_solutions = I->multi_solutions2 = NULL;
+ I->multi_fp = NULL;
+ I->multi_core = 0;
+}
+
+
+/* second initialization
+ topk.end>0 => initialize heap for topk mining */
+/* all pointers will be set to 0, but not for */
+/* if topK mining, set topk.end to "K" */
+void ITEMSET_init2 (ITEMSET *I, char *fname, PERM *perm, QUEUE_INT item_max, size_t item_max_org){
+ LONG i;
+ size_t siz = (I->flag&ITEMSET_USE_ORG)?item_max_org+2: item_max+2;
+ I->prob = I->ratio = 1.0;
+ I->frq = 0;
+ I->perm = perm;
+ if ( I->topk.end>0 ){
+ AHEAP_alloc (&I->topk, I->topk.end);
+ FLOOP (i, 0, I->topk.end) AHEAP_chg (&I->topk, (AHEAP_ID)i, -WEIGHTHUGE);
+ I->frq_lb = -WEIGHTHUGE;
+ } else I->topk.v = NULL;
+ QUEUE_alloc (&I->itemset, (QUEUE_ID)siz); I->itemset.end = (QUEUE_ID)siz;
+ if ( I->flag&ITEMSET_ADD ) QUEUE_alloc (&I->add, (QUEUE_ID)siz);
+ calloc2 (I->sc, siz+2, "ITEMSET_init2: sc", goto ERR);
+ if ( I->flag&ITEMSET_SET_RULE ){
+ calloc2 (I->set_weight, siz, "ITEMSET_init2: set_weight", goto ERR);
+ if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) )
+ calloc2 (I->set_occ, siz, "ITEMSET_init2: set_weight", goto ERR);
+ }
+ I->iters = I->iters2 = I->solutions = 0;
+ I->item_max = item_max;
+ I->item_max_org = (QUEUE_INT)item_max_org;
+ if ( fname ){ fopen2 (I->fp, fname, "w", "ITEMSET_init2", goto ERR);}
+ else I->fp = 0;
+ if ( I->flag&ITEMSET_ITEMFRQ )
+ malloc2 (I->item_frq, item_max+2, "ITEMSET_init2: item_frqs", goto ERR);
+ if ( I->flag&ITEMSET_RULE ){
+ calloc2 (I->itemflag, item_max+2, "ITEMSET_init2: item_flag", goto ERR);
+ }
+ I->total_weight = 1;
+
+ calloc2 (I->multi_iters, I->multi_core+1, "ITEMSET_init2: multi_iters", goto ERR);
+ calloc2 (I->multi_iters2, I->multi_core+1, "ITEMSET_init2: multi_iters2", goto ERR);
+ calloc2 (I->multi_iters3, I->multi_core+1, "ITEMSET_init2: multi_iters3", goto ERR);
+ calloc2 (I->multi_outputs, I->multi_core+1, "ITEMSET_init2: multi_outputs", goto ERR);
+ calloc2 (I->multi_outputs2, I->multi_core+1, "ITEMSET_init2: multi_outputs2", goto ERR);
+ calloc2 (I->multi_solutions, I->multi_core+1, "ITEMSET_init2: multi_solutions", goto ERR);
+ calloc2 (I->multi_solutions2, I->multi_core+1, "ITEMSET_init2: multi_solutions2", goto ERR);
+ calloc2 (I->multi_fp, I->multi_core+1, "ITEMSET_init2: multi_fp", goto ERR);
+
+ FLOOP (i, 0, MAX(I->multi_core,1))
+ FILE2_open_ (I->multi_fp[i], I->fp, "ITEMSET_init2: multi_fp[i]", goto ERR);
+#ifdef MULTI_CORE
+ if ( I->multi_core > 0 ){
+ pthread_spin_init (&I->lock_counter, PTHREAD_PROCESS_PRIVATE);
+ pthread_spin_init (&I->lock_sc, PTHREAD_PROCESS_PRIVATE);
+ pthread_spin_init (&I->lock_output, PTHREAD_PROCESS_PRIVATE);
+ }
+#endif
+ return;
+ ERR:;
+ ITEMSET_end (I);
+ EXIT;
+}
+
+/* sum the counters computed by each thread */
+void ITEMSET_merge_counters (ITEMSET *I){
+ int i;
+ FLOOP (i, 0, MAX(I->multi_core,1)){
+ I->iters += I->multi_iters[i];
+ I->iters2 += I->multi_iters2[i];
+ I->iters3 += I->multi_iters3[i];
+ I->outputs += I->multi_outputs[i];
+ I->outputs2 += I->multi_outputs2[i];
+ I->solutions += I->multi_solutions[i];
+ I->solutions2 += I->multi_solutions2[i];
+ FILE2_flush ( &I->multi_fp[i]);
+ }
+}
+
+/*******************************************************************/
+/* termination of ITEMSET */
+/*******************************************************************/
+void ITEMSET_end (ITEMSET *I){
+ int i;
+ QUEUE_end (&I->itemset);
+ QUEUE_end (&I->add);
+ AHEAP_end (&I->topk);
+ fclose2 ( I->fp);
+ mfree (I->sc, I->item_frq, I->itemflag, I->perm, I->set_weight, I->set_occ);
+
+ if ( I->multi_fp )
+ FLOOP (i, 0, MAX(I->multi_core,1)) free2 (I->multi_fp[i].buf);
+ mfree (I->multi_fp, I->multi_iters, I->multi_iters2, I->multi_iters3);
+ mfree (I->multi_outputs, I->multi_outputs2, I->multi_solutions, I->multi_solutions2);
+#ifdef MULTI_CORE
+ if ( I->multi_core>0 ){
+ pthread_spin_destroy(&I->lock_counter);
+ pthread_spin_destroy(&I->lock_sc);
+ pthread_spin_destroy(&I->lock_output);
+ }
+#endif
+ ITEMSET_init (I);
+}
+
+/*******************************************************************/
+/* output at the termination of the algorithm */
+/* print #of itemsets of size k, for each k */
+/*******************************************************************/
+void ITEMSET_last_output (ITEMSET *I){
+ QUEUE_ID i;
+ unsigned long long n=0, nn=0;
+
+ ITEMSET_merge_counters (I);
+ if ( I->topk.end > 0 ){
+ i = AHEAP_findmin_head (&I->topk);
+ fprint_WEIGHT (stdout, AHEAP_H (I->topk, i));
+ printf ("\n");
+ return;
+ }
+ FLOOP (i, 0, I->itemset.end+1){
+ n += I->sc[i];
+ if ( I->sc[i] != 0 ) nn = i;
+ }
+ if ( !(I->flag&SHOW_MESSAGE) ) return;
+ if ( n!=0 ){
+ printf ("%llu\n", n);
+ FLOOP (i, 0, nn+1) printf ("%llu\n", I->sc[i]);
+ }
+ print_err ("iters=%lld", I->iters);
+ if ( I->flag&ITEMSET_ITERS2 ) print_err (", iters2=%lld", I->iters2);
+ print_err ("\n");
+}
+
+/* output frequency, coverage */
+void ITEMSET_output_frequency (ITEMSET *I, int core_id){
+ FILE2 *fp = &I->multi_fp[core_id];
+ if ( I->flag&(ITEMSET_FREQ+ITEMSET_PRE_FREQ) ){
+ if ( I->flag&ITEMSET_FREQ ) FILE2_putc (fp, ' ');
+ FILE2_print_WEIGHT (fp, I->frq, 4, '(');
+ FILE2_putc (fp, ')');
+ if ( I->flag&ITEMSET_PRE_FREQ ) FILE2_putc (fp, ' ');
+ }
+ if ( I->flag&ITEMSET_OUTPUT_POSINEGA ){ // output positive sum, negative sum in the occurrence
+ FILE2_putc (fp, ' ');
+ FILE2_print_WEIGHT (fp, I->pfrq, 4, '(');
+ FILE2_print_WEIGHT (fp, I->pfrq-I->frq, 4, ',');
+ FILE2_print_WEIGHT (fp, I->pfrq/(2*I->pfrq-I->frq), 4, ',');
+ FILE2_putc (fp, ')');
+ }
+}
+
+#ifdef _trsact_h_
+void ITEMSET_output_occ (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID i;
+ QUEUE_INT *x;
+ FILE2 *fp = &I->multi_fp[core_id];
+ TRSACT *TT = (TRSACT *)(I->X);
+ VEC_ID j, ee = TT->rows_org;
+ int flag = I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT);
+
+ i=0; MQUE_FLOOP_ (*occ, x, TT->occ_unit){
+ if ( (I->flag&ITEMSET_RM_DUP_TRSACT)==0 || *x != ee ){
+ FILE2_print_int (fp, TT->trperm? TT->trperm[*x]: *x,' ');
+ if (flag == ITEMSET_MULTI_OCC_PRINT ){
+ FLOOP (j, 1, (VEC_ID)(TT->occ_unit/sizeof(QUEUE_INT)))
+ FILE2_print_int (fp, *(x+j), ' ');
+ } else if ( flag == (ITEMSET_MULTI_OCC_PRINT+ITEMSET_TRSACT_ID) ){
+ FILE2_print_int (fp, *(x+1), ' ');
+ }
+ }
+ ee = *x;
+ if ( (++i)%256==0 ) ITEMSET_flush (I, fp);
+ }
+ FILE2_putc (fp, '\n');
+}
+#endif
+
+/* output an itemset to the output file */
+void ITEMSET_output_itemset (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID i;
+ QUEUE_INT e;
+ FILE2 *fp = &I->multi_fp[core_id];
+
+ I->multi_outputs[core_id]++;
+ if ( (I->flag&SHOW_PROGRESS ) && (I->iters%(ITEMSET_INTERVAL) == 0) )
+ print_err ("---- %lld solutions in %lld candidates\n", I->solutions, I->outputs);
+ if ( I->itemset.t < I->lb || I->itemset.t > I->ub ) return;
+ if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
+ if ( (I->flag&ITEMSET_IGNORE_BOUND)==0 && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;
+
+ I->multi_solutions[core_id]++;
+ if ( I->max_solutions>0 && I->solutions > I->max_solutions ){
+ ITEMSET_last_output (I);
+ ERROR_MES = "reached to maximum number of solutions";
+ EXIT;
+ }
+ if ( I->topk.v ){
+ e = AHEAP_findmin_head (&(I->topk));
+ if ( I->frq > AHEAP_H (I->topk, e) ){
+ AHEAP_chg (&(I->topk), e, I->frq);
+ e = AHEAP_findmin_head (&(I->topk));
+ I->frq_lb = AHEAP_H (I->topk, e);
+ }
+ } else if ( I->fp ){
+ if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
+ if ( (I->flag & ITEMSET_NOT_ITEMSET) == 0 ){
+#ifdef _agraph_h_
+ if ( I->flag&ITEMSET_OUTPUT_EDGE ){
+ ARY_FLOOP (I->itemset, i, e){
+ FILE2_print_int (fp, AGRAPH_INC_FROM(*((AGRAPH *)(I->X)),e,I->dir), '(' );
+ FILE2_print_int (fp, AGRAPH_INC_TO(*((AGRAPH *)(I->X)),e,I->dir), ',');
+ FILE2_putc (fp, ')');
+ if ( i<I->itemset.t-1 ) FILE2_putc (fp, ' ');
+ if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
+ }
+ goto NEXT;
+ }
+#endif
+ ARY_FLOOP (I->itemset, i, e){
+ FILE2_print_int (fp, I->perm? I->perm[e]: e, i==0? 0: ' ');
+ if ( (i+1)%256==0 ) ITEMSET_flush (I, fp);
+ }
+#ifdef _agraph_h_
+ NEXT:;
+#endif
+ }
+ if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency (I, core_id);
+ if ( ((I->flag & ITEMSET_NOT_ITEMSET) == 0) || (I->flag&ITEMSET_FREQ) || (I->flag&ITEMSET_PRE_FREQ) ) FILE2_putc (fp, '\n');
+
+#ifdef _trsact_h_
+ if (I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT)) ITEMSET_output_occ (I, occ, core_id);
+#endif
+ }
+ I->sc[I->itemset.t]++;
+ ITEMSET_flush (I, fp);
+}
+
+/* output itemsets with adding all combination of "add"
+ at the first call, i has to be "add->t" */
+void ITEMSET_solution_iter (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID t=I->add.t;
+ if ( I->itemset.t > I->ub ) return;
+ ITEMSET_output_itemset (I, occ, core_id);
+if ( ERROR_MES ) return;
+ BLOOP (I->add.t, I->add.t, 0){
+ ARY_INS (I->itemset, I->add.v[I->add.t]);
+ ITEMSET_solution_iter (I, occ, core_id);
+if ( ERROR_MES ) return;
+ I->itemset.t--;
+ }
+ I->add.t = t;
+}
+
+void ITEMSET_solution (ITEMSET *I, QUEUE *occ, int core_id){
+ QUEUE_ID i;
+ LONG s;
+ if ( I->itemset.t > I->ub ) return;
+ if ( I->flag & ITEMSET_ALL ){
+ if ( I->fp || I->topk.v ) ITEMSET_solution_iter (I, occ, core_id);
+ else {
+ s=1; FLOOP (i, 0, I->add.t+1){
+ I->sc[I->itemset.t+i] += s;
+ s = s*(I->add.t-i)/(i+1);
+ }
+ }
+ } else {
+ FLOOP (i, 0, I->add.t) ARY_INS (I->itemset, I->add.v[i]);
+ ITEMSET_output_itemset (I, occ, core_id);
+ I->itemset.t -= I->add.t;
+ }
+}
+
+/*************************************************************************/
+/* ourput a rule */
+/*************************************************************************/
+void ITEMSET_output_rule (ITEMSET *I, QUEUE *occ, double p1, double p2, size_t item, int core_id){
+ FILE2 *fp = &I->multi_fp[core_id];
+ if ( fp->fp && !(I->topk.v) ){
+ FILE2_print_real (fp, p1, 4, '(');
+ FILE2_print_real (fp, p2, 4, ',');
+ FILE2_putc (fp, ')');
+ FILE2_print_int (fp, I->perm[item], ' ');
+ FILE2_puts (fp, " <= ");
+ }
+ if ( I->flag & ITEMSET_RULE ) ITEMSET_output_itemset (I, occ, core_id);
+ else ITEMSET_solution (I, occ, core_id);
+}
+/*************************************************************************/
+/* check all rules for a pair of itemset and item */
+/*************************************************************************/
+void ITEMSET_check_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, size_t item, int core_id){
+ double p = w[item]/I->frq, pp, ff;
+// printf ("[ratio] %f, p=%f, (%f/ %f), %d(%d) <= ", I->ratio_lb, p, w[item], I->frq, I->perm[item], I->itemflag[item]);
+ if ( I->itemflag[item]==1 ) return;
+ if ( w[item] <= -WEIGHTHUGE ) p = 0;
+ pp = p; ff = I->item_frq[item];
+ if ( I->flag & ITEMSET_RULE_SUPP ){ pp = w[item]; ff *= I->total_weight; }
+
+ if ( I->flag & (ITEMSET_RULE_FRQ+ITEMSET_RULE_INFRQ)){
+ if ( (I->flag & ITEMSET_RULE_FRQ) && p < I->ratio_lb ) return;
+ if ( (I->flag & ITEMSET_RULE_INFRQ) && p > I->ratio_ub ) return;
+ ITEMSET_output_rule (I, occ, pp, ff, item, core_id);
+ } else if ( I->flag & (ITEMSET_RULE_RFRQ+ITEMSET_RULE_RINFRQ) ){
+ if ( (I->flag & ITEMSET_RULE_RFRQ) && (1-p) > I->ratio_lb * (1-I->item_frq[item]) ) return;
+ if ( (I->flag & ITEMSET_RULE_RINFRQ) && p > I->ratio_ub * I->item_frq[item] ) return;
+ ITEMSET_output_rule (I, occ, pp, ff, item, core_id);
+ }
+}
+
+/*************************************************************************/
+/* check all rules for an itemset and all items */
+/*************************************************************************/
+void ITEMSET_check_all_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, QUEUE *jump, WEIGHT total, int core_id){
+ QUEUE_ID i, t;
+ QUEUE_INT e, f=0, *x;
+ WEIGHT d = I->frq/total;
+
+ // checking out of range for itemset size and (posi/nega) frequency
+ if ( I->itemset.t+I->add.t < I->lb || I->itemset.t>I->ub || (!(I->flag&ITEMSET_ALL) && I->itemset.t+I->add.t>I->ub)) return;
+ if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->frq < I->frq_lb || I->frq > I->frq_ub) ) return;
+ if ( !(I->flag&ITEMSET_IGNORE_BOUND) && (I->pfrq < I->posi_lb || I->pfrq > I->posi_ub || (I->frq - I->pfrq) > I->nega_ub || (I->frq - I->pfrq) < I->nega_lb) ) return;
+
+ if ( I->flag&ITEMSET_SET_RULE ){ // itemset->itemset rule for sequence mining
+ FLOOP (i, 0, I->itemset.t-1){
+ if ( I->frq/I->set_weight[i] >= I->setrule_lb && I->fp ){
+ I->sc[i]++;
+ if ( I->flag&ITEMSET_PRE_FREQ ) ITEMSET_output_frequency (I, core_id);
+ FLOOP (t, 0, I->itemset.t){
+ FILE2_print_int (&I->multi_fp[core_id], I->itemset.v[t], t?' ':0);
+ if ( t == i ){
+ FILE2_putc (&I->multi_fp[core_id], ' ');
+ FILE2_putc (&I->multi_fp[core_id], '=');
+ FILE2_putc (&I->multi_fp[core_id], '>');
+ }
+ }
+ if ( !(I->flag&ITEMSET_PRE_FREQ) ) ITEMSET_output_frequency ( I, core_id);
+ FILE2_putc (&I->multi_fp[core_id], ' ');
+ FILE2_print_real (&I->multi_fp[core_id], I->frq/I->set_weight[i], 4, '(');
+ FILE2_putc (&I->multi_fp[core_id], ')');
+ FILE2_putc (&I->multi_fp[core_id], '\n');
+#ifdef _trsact_h_
+ if ( I->flag&(ITEMSET_TRSACT_ID+ITEMSET_MULTI_OCC_PRINT) )
+ ITEMSET_output_occ (I, I->set_occ[i], core_id);
+#endif
+ ITEMSET_flush (I, &I->multi_fp[core_id]);
+ }
+ }
+ }
+ // constraint of relational frequency
+ if ( ((I->flag&ITEMSET_RFRQ)==0 || d >= I->prob_lb * I->prob )
+ && ((I->flag&ITEMSET_RINFRQ)==0 || d <= I->prob * I->prob_ub) ){
+ if ( I->flag&ITEMSET_RULE ){ // rule mining routines
+ if ( I->itemset.t == 0 ) return;
+ if ( I->target < I->item_max ){
+ ITEMSET_check_rule (I, w, occ, I->target, core_id); if (ERROR_MES) return;
+ } else {
+ if ( I->flag & (ITEMSET_RULE_FRQ + ITEMSET_RULE_RFRQ) ){
+ if ( I->add.t>0 ){
+// if ( I->itemflag[I->add.v[0]] ) // for POSI_EQUISUPP (occ_w[e] may not be 100%, in the case)
+ f = I->add.v[I->add.t-1]; t = I->add.t; I->add.t--;
+ FLOOP (i, 0, t){
+ e = I->add.v[i];
+ I->add.v[i] = f;
+ ITEMSET_check_rule (I, w, occ, e, core_id); if (ERROR_MES) return;
+ I->add.v[i] = e;
+ }
+ I->add.t++;
+ }
+ MQUE_FLOOP (*jump, x)
+ ITEMSET_check_rule (I, w, occ, *x, core_id); if (ERROR_MES) return;
+ } else {
+ if ( I->flag & (ITEMSET_RULE_INFRQ + ITEMSET_RULE_RINFRQ) ){
+// ARY_FLOOP ( *jump, i, e ) I->itemflag[e]--;
+ FLOOP (i, 0, I->item_max){
+ if ( I->itemflag[i] != 1 ){
+ ITEMSET_check_rule (I, w, occ, i, core_id); if (ERROR_MES) return;
+ }
+ }
+// ARY_FLOOP ( *jump, i, e ) I->itemflag[e]++;
+// }
+// ARY_FLOOP ( *jump, i, e ) ITEMSET_check_rule (I, w, occ, e);
+ }
+ }
+ }
+ } else { // usual mining (not rule mining)
+ if ( I->fp && (I->flag&(ITEMSET_RFRQ+ITEMSET_RINFRQ))){
+ FILE2_print_real (&I->multi_fp[core_id], d, 4, '[');
+ FILE2_print_real (&I->multi_fp[core_id], I->prob, 4, ',');
+ FILE2_putc (&I->multi_fp[core_id], ']');
+ }
+ ITEMSET_solution (I, occ, core_id);
+ }
+ }
+}
+
+#endif
--- /dev/null
+/* itemset search input/output common routines
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/* routines for itemset mining */
+
+#ifndef _itemset_h_
+#define _itemset_h_
+
+#include"stdlib2.h"
+#include"queue.h"
+#define AHEAP_KEY_WEIGHT
+#include"aheap.h"
+
+
+typedef struct {
+ int a;
+ QUEUE itemset; // current operating itemset
+ QUEUE add; // for equisupport (hypercube decomposition)
+ int ub, lb; // upper/lower bounds for the itemset size
+ WEIGHT frq, pfrq, frq_ub, frq_lb; // upper/lower bounds for the frequency
+ WEIGHT rposi_lb, rposi_ub, posi_lb, posi_ub, nega_ub, nega_lb; // upper/lower bounds for the sum of positive/negative weights
+ WEIGHT setrule_lb; // frequency lower bound for set rule
+ double ratio, prob; // confidence and independent probability of the current pattern
+ double ratio_ub, ratio_lb, prob_ub, prob_lb; // upper/lower bounds for confidence and independent probability
+ QUEUE_INT target; // target item for rule mining
+ char *itemflag; // 1 if it is include in the pattern (and 2 if included in add)
+ WEIGHT *item_frq; // frequency of each item
+ WEIGHT total_weight; // total weight of the input database
+ int len_ub, len_lb; // upper/lower bounds for the length of the pattern
+ int gap_ub, gap_lb; // upper/lower bounds for the gaps in the pattern
+ LONG *sc; // #itemsets classified by the sizes
+ QUEUE_INT item_max, item_max_org; // (original) maximum item
+ AHEAP topk; // heap for topk mining. valid if topk->h is not NULL
+ int flag; // flag for various functions
+ PERM *perm; // permutation array for output itemset: item => original item
+ FILE *fp; // file pointer to the output file
+ LONG iters, iters2, iters3; //iterations
+ LONG solutions, solutions2; // number of solutions output
+ LONG outputs, outputs2; // #calls of ITEMSET_output_itemset or ITEMSET_solusion
+ LONG max_solutions; // maximum solutions to be output
+ void *X; // pointer to the original data
+ int dir; // direction flag for AGRAPH & SGRAPH
+
+ int multi_core; // number of processors
+ LONG *multi_iters, *multi_iters2, *multi_iters3; //iterations
+ LONG *multi_solutions, *multi_solutions2; // number of solutions output
+ LONG *multi_outputs, *multi_outputs2; // #calls of ITEMSET_output_itemset or ITEMSET_solusion
+ FILE2 *multi_fp; // output file2 pointer for multi-core mode
+ WEIGHT *set_weight; // the frequency of each prefix of current itemset
+ QUEUE **set_occ; // the occurrence of each prefix of current itemset
+
+#ifdef MULTI_CORE
+ pthread_spinlock_t lock_counter; // couneter locker for jump counter
+ pthread_spinlock_t lock_sc; // couneter locker for
+ pthread_spinlock_t lock_output; // couneter locker for output
+#endif
+} ITEMSET;
+
+/* parameters for ITEMSET.flag */
+
+#define ITEMSET_ITERS2 4 // output #iters2
+#define ITEMSET_PRE_FREQ 8 // output frequency preceding to each itemset
+#define ITEMSET_FREQ 16 // output frequency following to each itemset
+#define ITEMSET_ALL 32 // concat all combinations of "add" to each itemset
+
+#define ITEMSET_TRSACT_ID 64 // output transaction ID's in occurrences
+#define ITEMSET_OUTPUT_EDGE 128 // output itemset as edge set (refer AGRAPH)
+#define ITEMSET_IGNORE_BOUND 256 // ignore constraint for frequency
+#define ITEMSET_RM_DUP_TRSACT 512 // remove duplicated transaction ID's
+#define ITEMSET_MULTI_OCC_PRINT 1024 //print each component of occ
+ // TRSACT_ID+MULTI_OCC_PRINT means print first two components of occ
+#define ITEMSET_NOT_ITEMSET 2048 // do not print itemset to the output file
+#define ITEMSET_RULE_SUPP 4096 // output confidence and item frquency by abusolute value
+#define ITEMSET_OUTPUT_POSINEGA 8192 // output negative/positive frequencies
+#define ITEMSET_MULTI_OUTPUT 16384 // for multi-core mode
+#define ITEMSET_USE_ORG 32768 // use item_max_org to the size of use
+#define ITEMSET_ITEMFRQ 65536 // allocate item_frq
+#define ITEMSET_ADD 131072 // allocate add
+
+#define ITEMSET_RULE_FRQ 262144
+#define ITEMSET_RULE_INFRQ 524288
+#define ITEMSET_RULE_RFRQ 1048576
+#define ITEMSET_RULE_RINFRQ 2097152
+#define ITEMSET_RFRQ 4194304
+#define ITEMSET_RINFRQ 8388608
+#define ITEMSET_POSI_RATIO 16777216
+#define ITEMSET_SET_RULE 134217728
+
+//#define ITEMSET_RULE (ITEMSET_RULE_FRQ + ITEMSET_RULE_INFRQ + ITEMSET_RULE_RFRQ + ITEMSET_RULE_RINFRQ + ITEMSET_RFRQ + ITEMSET_RINFRQ + ITEMSET_SET_RULE) // for check any rule is true
+#define ITEMSET_RULE (ITEMSET_RULE_FRQ + ITEMSET_RULE_INFRQ + ITEMSET_RULE_RFRQ + ITEMSET_RULE_RINFRQ + ITEMSET_SET_RULE) // for check any rule is true
+
+#ifndef ITEMSET_INTERVAL
+#define ITEMSET_INTERVAL 500000
+#endif
+
+/* Output information about ITEMSET structure. flag&1: print frequency constraint */
+void ITEMSET_print ( ITEMSET *II, int flag);
+
+/* topk.end>0 => initialize heap for topk mining */
+/* all pointers will be set to 0, but not for */
+/* if topK mining, set topk.end to "K" */
+void ITEMSET_init (ITEMSET *I);
+void ITEMSET_init2 (ITEMSET *I, char *fname, PERM *perm, QUEUE_INT item_max, size_t item_max_org);
+void ITEMSET_end (ITEMSET *I);
+
+/* sum the counters computed by each thread */
+void ITEMSET_merge_counters (ITEMSET *I);
+
+/*******************************************************************/
+/* output at the termination of the algorithm */
+/* print #of itemsets of size k, for each k */
+/*******************************************************************/
+void ITEMSET_last_output (ITEMSET *I);
+
+/* output frequency, coverage */
+void ITEMSET_output_frequency (ITEMSET *I, int core_id);
+
+/* output an itemset to the output file */
+void ITEMSET_output_itemset (ITEMSET *I, QUEUE *occ, int core_id);
+
+/* output itemsets with adding all combination of "add"
+ at the first call, i has to be "add->t" */
+void ITEMSET_solution (ITEMSET *I, QUEUE *occ, int core_id);
+
+/*************************************************************************/
+/* ourput a rule */
+/*************************************************************************/
+void ITEMSET_output_rule (ITEMSET *I, QUEUE *occ, double p1, double p2, size_t item, int core_id);
+
+/*************************************************************************/
+/* check all rules for a pair of itemset and item */
+/*************************************************************************/
+void ITEMSET_check_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, size_t item, int core_id);
+
+/*************************************************************************/
+/* check all rules for an itemset and all items */
+/*************************************************************************/
+void ITEMSET_check_all_rule (ITEMSET *I, WEIGHT *w, QUEUE *occ, QUEUE *jump, WEIGHT total, int core_id);
+
+#endif
+
+
+
+
--- /dev/null
+/#define _lcm_c_/a #include "CtoI.h" //ZDD \
+
+/void LCM (/c CtoI LCM (PROBLEM *PP, int item, QUEUE *occ, WEIGHT frq, WEIGHT pfrq){ //ZDD \
+ int ii, xx; //ZDD \
+ CtoI F, G; //ZDD \
+ F = CtoI(0); //ZDD
+
+/ITEMSET_check_all_rule (/a \ F = (II->flag & ITEMSET_PRE_FREQ)? CtoI((int)II->frq): CtoI(1); //ZDD \
+ for(ii=0; ii<II->add.t; ii++) { //ZDD \
+ xx = II->add.v[ii]; //ZDD \
+ G = F.AffixVar(BDD_VarOfLev(xx+1)); //ZDD \
+ if(PP->problem & PROBLEM_FREQSET) { //ZDD \
+ F = CtoI_Union(F, G); //ZDD \
+ } //ZDD \
+ else F = G; //ZDD \
+ } //ZDD
+
+/LCM (PP, e/c \ G = LCM (PP, e, &TT->OQ[e], PP->occ_w2[e], PP->occ_pw2[e]); // recursive call //ZDD \
+ F = CtoI_Union(F, G); //ZDD
+
+/END:;/a \ if(item < II->item_max) { //ZDD \
+ xx = item; //ZDD \
+ F = F.AffixVar(BDD_VarOfLev(xx+1)); //ZDD \
+ } //ZDD
+
+/PP->itemcand.s = js;/a \ return F; //ZDD
+/int LCM_main/c extern PROBLEM LCM_PP; //ZDD \
+PROBLEM LCM_PP; //ZDD \
+extern CtoI CtoI_Lcm2(); //ZDD \
+ \
+int CtoI_LcmItems() { //ZDD \
+ if( ERROR_MES ) return -1; //ZDD \
+ return LCM_PP.II.item_max; //ZDD \
+} //ZDD \
+ \
+int CtoI_LcmPerm(int k) { //ZDD \
+ if( ERROR_MES ) return -1; //ZDD \
+ return LCM_PP.II.perm[k]; //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmA ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 0); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmC ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 1); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmM ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 2); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmAV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 10); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmCV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 11); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmMV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 12); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+int CtoI_Lcm1 ( char *fname1, char *fname2, int th, int param ) { //ZDD
+
+/PROBLEM PP/d
+
+/ITEMSET \*II = &PP\./c \ ITEMSET *II = &LCM_PP.II; //ZDD
+
+/TRSACT \*TT = &PP\./c \ TRSACT *TT = &LCM_PP.TT; //ZDD
+
+/SGRAPH \*SG = &PP\./c \ SGRAPH *SG = &LCM_PP.SG; //ZDD
+
+/PROBLEM_init (/c \ ERROR_MES = 0; //ZDD \
+ PROBLEM_init ( &LCM_PP ); //ZDD
+
+/LCM_read_param (argc/c \ switch(param) //ZDD \
+ { //ZDD \
+ case 12: //ZDD \
+ LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD \
+ LCM_PP.TT.flag |= TRSACT_UNION; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ break; //ZDD \
+ case 11: //ZDD \
+ LCM_PP.problem |= PROBLEM_CLOSED; //ZDD \
+ LCM_PP.TT.flag |= TRSACT_INTSEC; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ break; //ZDD \
+ case 10: //ZDD \
+ LCM_PP.problem |= PROBLEM_FREQSET; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ II->flag |= ITEMSET_ALL; //ZDD \
+ break; //ZDD \
+ case 2: //ZDD \
+ LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD \
+ LCM_PP.TT.flag |= TRSACT_UNION; //ZDD \
+ break; //ZDD \
+ case 1: //ZDD \
+ LCM_PP.problem |= PROBLEM_CLOSED; //ZDD \
+ LCM_PP.TT.flag |= TRSACT_INTSEC; //ZDD \
+ break; //ZDD \
+ case 0: //ZDD \
+ default: //ZDD \
+ LCM_PP.problem |= PROBLEM_FREQSET; //ZDD \
+ II->flag |= ITEMSET_ALL; //ZDD \
+ } //ZDD \
+ LCM_PP.trsact_fname = fname1; //ZDD \
+ LCM_PP.trsact_pfname = fname2; //ZDD \
+ II->frq_lb = (WEIGHT)th; //ZDD
+
+/PROBLEM_init2 (/c \ PROBLEM_init2 ( &LCM_PP, PROBLEM_PRINT_SHRINK + PROBLEM_PRINT_FRQ ); //ZDD
+
+/LCM_init (&PP)/c \ LCM_init(&LCM_PP); //ZDD \
+ } //ZDD \
+ return 0; //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_Lcm2 () { //ZDD \
+ CtoI F, G; //ZDD \
+ if ( ERROR_MES ) { //ZDD \
+ PROBLEM_end( &LCM_PP ); //ZDD \
+ return CtoI(-1); //ZDD \
+ } //ZDD \
+ else //ZDD \
+ { //ZDD \
+ F = CtoI(0); //ZDD
+
+/if ( ERROR_MES ) return;/c if ( ERROR_MES ) return CtoI(-1); //ZDD
+/LCM (&PP, TT->T\.clms/c \ if ( !ERROR_MES ) G = LCM (&LCM_PP, LCM_PP.TT.T.clms, &LCM_PP.oo, LCM_PP.TT.total_w_org, LCM_PP.TT.total_pw_org); //ZDD \
+ else G = CtoI(0); //ZDD \
+ F = CtoI_Union(F, G); //ZDD
+
+/ITEMSET_last/c \ ITEMSET_last_output (&LCM_PP.II); //ZDD
+
+/TT->sc = NULL/c \ LCM_PP.TT.sc = NULL; //ZDD
+
+/PROBLEM_end (&PP)/c \ PROBLEM_end (&LCM_PP); //ZDD
+
+/return (ERR/c \ return F; //ZDD
+
--- /dev/null
+/* Linear time Closed itemset Miner for Frequent Itemset Mining problems */
+/* 2004/4/10 Takeaki Uno, e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about LCM for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+
+#ifndef _lcm_c_
+#define _lcm_c_
+
+#define WEIGHT_DOUBLE
+#define TRSACT_DEFAULT_WEIGHT 1
+
+#define LCM_UNCONST 16777216 // use the complement graph of the constraint graph
+#define LCM_POSI_EQUISUPP 33554432 // an item will be dealt as "equisupp" when "positive"-frequency is equal to the positive-frequency of the current itemset
+
+#define ERROR_RET
+
+#include"trsact.c"
+#include"sgraph.c"
+#include"problem.c"
+
+void LCM_error (){
+ ERROR_MES = "command explanation";
+ print_err ("LCM: [FCMfQIq] [options] input-filename support [output-filename]\n\
+F:frequent itemset mining, C:closed frequent itemset mining\n\
+M:maximal frequent itemset mining, P:positive-closed itemset mining\n\
+f:output frequency following to each output itemset\n\
+A:output positive/negative frequency, and their ratio\n\
+Q:output frequency and coverages preceding to itemsets\n\
+q:no output to standard output, V:show progress of computation\n\
+I:output ID's of transactions including each pattern\n\
+i:do not output itemset to the output file (only rules)\n\
+s:output confidence and item frequency by absolute values\n\
+t:transpose the input database (item i will be i-th transaction, and i-th transaction will be item i)\n\
+[options]\n\
+-K [num]:output [num] most frequent itemsets\n\
+-l,-u [num]:output itemsets with size at least/most [num]\n\
+-U [num]:upper bound for support(maximum support)\n\
+-w [filename]:read weights of transactions from the file\n\
+-c,-C [filename]:read item constraint/un-constraint file\n\
+-S [num]:stop aftre outputting [num] solutions\n\
+-i [num]: find association rule for item [num]\n\
+-a,-A [ratio]: find association rules of confidence at least/most [ratio]\n\
+-r,-R [ratio]: find association rules of relational confidence at least/most [ratio]\n\
+-f,F [ratio]: output itemsets with frequency no less/greater than [ratio] times the frequency given by product of the probability of each item appearance\n\
+-p,-P [num]: output itemset only if (frequency)/(abusolute frequency) is no less/no greater than [num]\n\
+-n,-N [num]: output itemset only if its negative frequency is no less/no greater than [num] (negative frequency is the sum of weights of transactions having negative weights)\n\
+-o,-O [num]: output itemset only if its positive frequency is no less/no greater than [num] (positive frequency is the sum of weights of transactions having positive weights)\n\
+-m,-M [filename]:read/write item permutation from/to file [filename]\n\
+if the 1st letter of input-filename is '-', be considered as 'parameter list'\n");
+ EXIT;
+}
+
+/***********************************************************************/
+/* read parameters given by command line */
+/***********************************************************************/
+void LCM_read_param (int argc, char *argv[], PROBLEM *PP){
+ ITEMSET *II = &PP->II;
+ int c=1, f=0;
+ if ( argc < c+3 ){ LCM_error (); return; }
+
+ if ( !strchr (argv[c], 'q') ){ II->flag |= SHOW_MESSAGE; PP->TT.flag |= SHOW_MESSAGE; }
+ if ( strchr (argv[c], 'f') ) II->flag |= ITEMSET_FREQ;
+ if ( strchr (argv[c], 'Q') ) II->flag |= ITEMSET_PRE_FREQ;
+ if ( strchr (argv[c], 'A') ) II->flag |= ITEMSET_OUTPUT_POSINEGA;
+ if ( strchr (argv[c], 'C') ){ PP->problem |= PROBLEM_CLOSED; PP->TT.flag |= TRSACT_INTSEC; }
+ else if ( strchr (argv[c], 'F') ){ PP->problem |= PROBLEM_FREQSET; II->flag |= ITEMSET_ALL; }
+ else if ( strchr (argv[c], 'M') ){ PP->problem |= PROBLEM_MAXIMAL; PP->TT.flag |= TRSACT_UNION; }
+ else error ("one of F, C, M has to be given", EXIT);
+ if ( strchr (argv[c], 'P') ) PP->problem |= LCM_POSI_EQUISUPP;
+ if ( strchr (argv[c], 'V') ) II->flag |= SHOW_PROGRESS;
+ if ( strchr (argv[c], 'I') ) II->flag |= ITEMSET_TRSACT_ID;
+ if ( strchr (argv[c], 'i') ) II->flag |= ITEMSET_NOT_ITEMSET;
+ if ( strchr (argv[c], 's') ) II->flag |= ITEMSET_RULE_SUPP;
+ if ( strchr (argv[c], 't') ) PP->TT.flag |= LOAD_TPOSE;
+ c++;
+
+ while ( argv[c][0] == '-' ){
+ switch (argv[c][1]){
+ case 'K': if ( PP->problem & PROBLEM_MAXIMAL )
+ error ("M command and -K option can not be given simltaneously", EXIT);
+ II->topk.end = atoi (argv[c+1]);
+ break; case 'm': PP->trsact_pfname = argv[c+1];
+ break; case 'M': PP->trsact_pfname = argv[c+1]; PP->TT.flag |= TRSACT_WRITE_PERM;
+ break; case 'l': II->lb = atoi (argv[c+1]);
+ break; case 'u': II->ub = atoi(argv[c+1]);
+ break; case 'U': II->frq_ub = (WEIGHT)atof(argv[c+1]);
+ break; case 'w': PP->trsact_wfname = argv[c+1];
+ break; case 'c': PP->sgraph_fname = argv[c+1];
+ break; case 'C': PP->sgraph_fname = argv[c+1]; PP->problem |= LCM_UNCONST;
+ break; case 'S': II->max_solutions = atoi(argv[c+1]);
+ break; case 'f': II->prob_lb = atof(argv[c+1]); II->flag |= ITEMSET_RFRQ; f++;
+ break; case 'F': II->prob_ub = atof(argv[c+1]); II->flag |= ITEMSET_RINFRQ; f++;
+ break; case 'i': II->target = atoi(argv[c+1]);
+ break; case 'a': II->ratio_lb = atof(argv[c+1]); II->flag |= ITEMSET_RULE_FRQ; f|=1;
+ break; case 'A': II->ratio_ub = atof(argv[c+1]); II->flag |= ITEMSET_RULE_INFRQ; f|=1;
+ break; case 'r': II->ratio_lb = atof(argv[c+1]); II->flag |= ITEMSET_RULE_RFRQ; f|=2;
+ break; case 'R': II->ratio_ub = atof(argv[c+1]); II->flag |= ITEMSET_RULE_RINFRQ; f|=2;
+ break; case 'P': II->flag |= ITEMSET_POSI_RATIO; II->flag |= ITEMSET_IGNORE_BOUND; II->rposi_ub = atof(argv[c+1]); f|=4;
+ break; case 'p': II->flag |= ITEMSET_POSI_RATIO; II->flag |= ITEMSET_IGNORE_BOUND; II->rposi_lb = atof(argv[c+1]); f|=4;
+ break; case 'n': II->nega_lb = atof(argv[c+1]);
+ break; case 'N': II->nega_ub = atof(argv[c+1]);
+ break; case 'o': II->posi_lb = atof(argv[c+1]);
+ break; case 'O': II->posi_ub = atof(argv[c+1]);
+ break; default: goto NEXT;
+ }
+ c += 2;
+ if ( argc < c+2 ){ LCM_error (); return; }
+ }
+
+ NEXT:;
+ if ( (f&3)==3 || (f&5)==5 || (f&6)==6 ) error ("-f, -F, -a, -A, -p, -P, -r and -R can not specified simultaneously", EXIT);
+ if ( f && (II->flag & ITEMSET_PRE_FREQ) ) BITRM (II->flag, ITEMSET_PRE_FREQ);
+
+ if ( ( PP->problem & PROBLEM_CLOSED ) && PP->sgraph_fname )
+ error ("closed itemset mining does not work with item constraints", EXIT);
+
+ if ( (PP->problem & PROBLEM_FREQSET) && (II->flag & (ITEMSET_RULE + ITEMSET_RFRQ + ITEMSET_RINFRQ)) ){
+ PP->problem |= PROBLEM_CLOSED; BITRM (PP->problem, PROBLEM_FREQSET);
+ BITRM (II->flag, ITEMSET_ALL);
+ }
+ PP->trsact_fname = argv[c];
+ if ( II->topk.end==0 ) II->frq_lb = (WEIGHT)atof(argv[c+1]);
+ if ( argc>c+2 ) PP->output_fname = argv[c+2];
+}
+
+/*********************************************************************/
+/* add an item to itemset, and update data */
+/*********************************************************************/
+void LCM_add_item (PROBLEM *PP, QUEUE *Q, QUEUE_INT item){
+ QUEUE_INT *x;
+ ARY_INS (*Q, item);
+ PP->II.itemflag[item] = 1;
+ if ( PP->sgraph_fname )
+ MQUE_MLOOP (PP->SG.edge.v[item], x, item) PP->itemary[*x]++;
+}
+
+/*********************************************************************/
+/* delete an item from itemset, and update data */
+/*********************************************************************/
+void LCM_del_item (PROBLEM *PP, QUEUE *Q){
+ QUEUE_INT *x, item = Q->v[--Q->t];
+ PP->II.itemflag[item] = 0;
+ if ( PP->sgraph_fname )
+ MQUE_MLOOP (PP->SG.edge.v[item], x, item) PP->itemary[*x]--;
+}
+
+/* remove unnecessary transactions which do not include all posi_closed items */
+/* scan of each transaction is up to item */
+void LCM_reduce_occ_by_posi_equisupp (PROBLEM *PP, QUEUE *occ, QUEUE_INT item, QUEUE_INT full){
+ QUEUE_ID ii=0;
+ TRSACT *TT = &PP->TT;
+ ITEMSET *II = &PP->II;
+ QUEUE_INT *x, *y, *z, cnt;
+
+ MQUE_FLOOP (*occ, x){
+ if ( TT->w[*x]>= 0 ) continue;
+ cnt = 0;
+ MQUE_MLOOP (TT->T.v[*x], y, item) if ( II->itemflag[*y] == 2 ) cnt++;
+ if ( cnt==full ) occ->v[ii++] = *x;
+ else {
+ II->frq -= TT->w[*x];
+ MQUE_MLOOP (TT->T.v[*x], z, item) PP->occ_w[*z] -= TT->w[*x];
+ }
+ }
+ occ->t = ii;
+ MQUE_FLOOP (PP->itemcand, x){
+ if ( II->itemflag[*x] == 2 ) II->itemflag[*x] = 1;
+ }
+}
+
+/*************************************************************************/
+/* ppc check and maximality check */
+/* INPUT: O:occurrence, jump:items, th:support, frq:frequency, add:itemset
+ OUTPUT: maximum item i s.t. frq(i)=frq
+ OPERATION: remove infrequent items from jump, and
+ insert items i to "add" s.t. frq(i)=frq */
+/*************************************************************************/
+/* functions
+ 1. when closed itemset mining or maximal frequent itemset mining, find all items
+ included in all transactions in occ (checked by pfrq, occ_w
+ if there is such an item with index>item, ppc condition is violated, and return non-negative value
+ 2. when constraint graph is given, set the frequency (occ_w) of the items which can
+ not be added to itemset to infrequent number.
+ 3. count the size of reduced database
+ 4. call LCM_reduce_occ_posi
+ */
+QUEUE_INT LCM_maximality_check (PROBLEM *PP, QUEUE *occ, QUEUE_INT item, QUEUE_INT *fmax, QUEUE_INT *cnt){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ QUEUE_INT m = TT->T.clms, full=0, *x;
+ WEIGHT w=-WEIGHTHUGE;
+ *fmax = TT->T.clms; *cnt=0;
+
+ MQUE_FLOOP (TT->jump, x){
+ if ( II->itemflag[*x] == 1) continue;
+//QUEUE_perm_print (&II->itemset, II->perm);
+ if ( PP->sgraph_fname && ( (((PP->problem & LCM_UNCONST)==0) && (PP->itemary[*x]>0) ) ||
+ ((PP->problem & LCM_UNCONST) && (PP->itemary[*x]<II->itemset.t ))) ){
+ // e can not be added by item constraint
+// PP->occ_pw[e] = PP->occ_w[e] = II->frq_lb -1;
+ II->itemflag[*x] = 3;
+ } else if ( ISEQUAL(PP->occ_pw[*x],II->pfrq) && ( ISEQUAL(PP->occ_w[*x],II->frq) || (PP->problem & LCM_POSI_EQUISUPP) ) ){ // check e is included in all transactions in occ
+ if ( *x<item ){
+ if ( !PP->sgraph_fname ){ // add item as "equisupport"
+ LCM_add_item (PP, &II->add, *x);
+ if ( (PP->problem&LCM_POSI_EQUISUPP) && (II->flag&ITEMSET_RULE) ) II->itemflag[*x] = 0; // in POSI_EQUISUPP, occ_w[*x] is not equal to II->frq, thus we have to deal it in the rule mining
+ }
+ if ( !ISEQUAL(PP->occ_w[*x],II->frq) ){ full++; II->itemflag[*x] = 2; }
+ } else m = *x; // an item in prefix can be added without going to another closed itemset
+ } else {
+ if ( *x<item ) (*cnt)++;
+ II->itemflag[*x] = PP->occ_pw[*x] < PP->th? 3: 0; // mark item by freq/infreq
+ if ( PP->occ_w[*x] > w ){
+ *fmax = *x;
+ w = PP->occ_w[*x];
+ }
+ }
+ }
+ if ( full && (PP->problem & LCM_POSI_EQUISUPP) && m<item ) // m<item always holds in frequent itemset mining
+ LCM_reduce_occ_by_posi_equisupp (PP, occ, item, full);
+ return (m);
+}
+
+/***************************************************************/
+/* iteration of LCM ver. 5 */
+/* INPUT: item:tail of the current solution, t_new,buf:head of the list of
+ ID and buffer memory of new transactions */
+/*************************************************************************/
+void LCM (PROBLEM *PP, int item, QUEUE *occ, WEIGHT frq, WEIGHT pfrq){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ int bnum = TT->buf.num, bblock = TT->buf.block_num;
+ int wnum = TT->wbuf.num, wblock = TT->wbuf.block_num;
+ VEC_ID new_t = TT->new_t;
+ QUEUE_INT cnt, f, *x, m, e, imax = PP->clms? item: TT->T.clms;
+ QUEUE_ID js = PP->itemcand.s, qt = II->add.t, i;
+ WEIGHT rposi=0.0;
+
+//TRSACT_print (TT, occ, NULL);
+//printf ("itemset: %f ::::", II->frq); QUEUE_print__ ( &II->itemset);
+//QUEUE_print__ ( occ );
+//printf ("itemset: %f ::::", II->frq); QUEUE_perm_print ( &II->itemset, II->perm);
+//printf ("add:"); QUEUE_perm_print ( &II->add, II->perm);
+//for (i=0 ; i<II->imax ; i++ ) printf ("%d(%d) ", II->perm[i], II->itemflag[i]); printf ("\n");
+
+ II->iters++;
+ PP->itemcand.s = PP->itemcand.t;
+// if ( II->flag&ITEMSET_POSI_RATIO && pfrq!=0 ) II->frq /= (pfrq+pfrq-II->frq);
+ if ( II->flag&ITEMSET_POSI_RATIO && pfrq!=0 ) rposi = pfrq / (pfrq+pfrq-II->frq);
+ TRSACT_delivery (TT, &TT->jump, PP->occ_w, PP->occ_pw, occ, imax);
+ // if the itemset is empty, set frq to the original #trsactions, and compute item_frq's
+ if ( II->itemset.t == 0 ){
+ if ( TT->total_w_org != 0.0 )
+ FLOOP (i, 0, TT->T.clms) II->item_frq[i] = PP->occ_w[i]/TT->total_w_org;
+ }
+
+ II->frq = frq; II->pfrq = pfrq;
+ m = LCM_maximality_check (PP, occ, item, &f, &cnt);
+// printf ("add: "); QUEUE_print__ ( &II->add);
+ if ( !(PP->problem & PROBLEM_FREQSET) && m<TT->T.clms ){ // ppc check
+ MQUE_FLOOP (TT->jump, x) TT->OQ[*x].end = 0;
+ goto END;
+ }
+ if ( !(PP->problem&PROBLEM_MAXIMAL) || f>=TT->T.clms || PP->occ_w[f]<II->frq_lb ){
+ if ( !(II->flag & ITEMSET_POSI_RATIO) || (rposi<=II->rposi_ub && rposi>=II->rposi_lb) ){
+ II->prob = 1.0;
+ MQUE_FLOOP (II->itemset, x) II->prob *= II->item_frq[*x];
+ MQUE_FLOOP (II->add, x) II->prob *= II->item_frq[*x];
+ ITEMSET_check_all_rule (II, PP->occ_w, occ, &TT->jump, TT->total_pw_org, 0); // if (ERROR_MES) return;
+ }
+ }
+ // select freqeut (and addible) items with smaller indices
+ MQUE_FLOOP (TT->jump, x){
+ TT->OQ[*x].end = 0; // in the case of freqset mining, automatically done by rightmost sweep;
+ if ( *x<item && II->itemflag[*x] == 0 ){
+ ARY_INS (PP->itemcand, *x);
+ PP->occ_w2[*x] = PP->occ_w[*x];
+ if ( TT->flag & TRSACT_NEGATIVE ) PP->occ_pw2[*x] = PP->occ_pw[*x];
+ }
+ }
+
+ if ( QUEUE_LENGTH_(PP->itemcand)==0 || II->itemset.t >= II->ub ) goto END;
+ qsort_QUEUE_INT (PP->itemcand.v+PP->itemcand.s, PP->itemcand.t-PP->itemcand.s, -1);
+//QUEUE_print__ (&PP->itemcand);
+ qsort_QUEUE_INT (II->add.v+qt, II->add.t-qt, -1);
+
+// database reduction
+ if ( cnt>2 && (II->flag & ITEMSET_TRSACT_ID)==0 && II->itemset.t >0){
+ TRSACT_find_same (TT, occ, item);
+ TRSACT_merge_trsact (TT, &TT->OQ[TT->T.clms], item);
+ TRSACT_reduce_occ (TT, occ);
+ }
+// occurrence deliver
+ TRSACT_deliv (TT, occ, item);
+
+// loop for recursive calls
+ cnt = QUEUE_LENGTH_ (PP->itemcand); f=0; // for showing progress
+ while ( QUEUE_LENGTH_ (PP->itemcand) > 0 ){
+ e = QUEUE_ext_tail_ (&PP->itemcand);
+ if ( PP->occ_pw2[e] >= MAX(II->frq_lb, II->posi_lb) ){ // if the item is frequent
+ LCM_add_item (PP, &II->itemset, e);
+ LCM (PP, e, &TT->OQ[e], PP->occ_w2[e], PP->occ_pw2[e]); // recursive call
+if ( ERROR_MES ) return;
+ LCM_del_item (PP, &II->itemset);
+ }
+ TT->OQ[e].end = TT->OQ[e].t = 0; // clear the occurrences, for the further delivery
+ PP->occ_w[e] = PP->occ_pw[e] = -WEIGHTHUGE; // unnecessary?
+
+ if ( (II->flag & SHOW_PROGRESS) && (II->itemset.t == 0 ) ){
+ f++; print_err ("%d/%d (%lld iterations)\n", f, cnt, II->iters);
+ }
+ }
+
+ TT->new_t = new_t;
+ TT->buf.num = bnum, TT->buf.block_num = bblock;
+ TT->wbuf.num = wnum, TT->wbuf.block_num = wblock;
+
+ END:;
+ while ( II->add.t > qt ) LCM_del_item (PP, &II->add);
+ PP->itemcand.t = PP->itemcand.s;
+ PP->itemcand.s = js;
+}
+
+/*************************************************************************/
+/* initialization of LCM main routine */
+/*************************************************************************/
+void LCM_init (PROBLEM *PP){
+ ITEMSET *II = &PP->II;
+ TRSACT *TT = &PP->TT;
+ SGRAPH *SG = &PP->SG;
+ PERM *sperm = NULL, *tmp=NULL;
+ QUEUE_INT i;
+
+ II->X = TT;
+ II->flag |= ITEMSET_ITEMFRQ + ITEMSET_ADD;
+ PP->clms = ((PP->problem&PROBLEM_FREQSET)&&(II->flag&ITEMSET_RULE)==0);
+ PROBLEM_alloc (PP, TT->T.clms, TT->T.t, 0, TT->perm, PROBLEM_ITEMCAND +(PP->sgraph_fname?PROBLEM_ITEMARY:0) +((TT->flag&TRSACT_NEGATIVE)?PROBLEM_OCC_PW: PROBLEM_OCC_W) +((PP->problem&PROBLEM_FREQSET)?0:PROBLEM_OCC_W2));
+ PP->th = (II->flag&ITEMSET_RULE)? ((II->flag&ITEMSET_RULE_INFRQ)? -WEIGHTHUGE: II->frq_lb * II->ratio_lb ): II->frq_lb; // threshold for database reduction
+ if ( TT->flag&TRSACT_SHRINK ) PP->oo = QUEUE_dup_ (&TT->OQ[TT->T.clms]); // preserve occ
+ else { QUEUE_alloc (&PP->oo, TT->T.t); ARY_INIT_PERM(PP->oo.v, TT->T.t); PP->oo.t = TT->T.t; }
+ TT->perm = NULL;
+ TT->OQ[TT->T.clms].t = 0;
+ print_mes (PP->TT.flag, "separated at %d\n", PP->TT.sep);
+ if ( !(TT->sc) ) calloc2 (TT->sc, TT->T.clms+2, "LCM_init: item_flag", return);
+ free2 (II->itemflag); II->itemflag = TT->sc; // II->itemflag and TT->sc shares the same memory
+ II->frq = TT->total_w_org; II->pfrq = TT->total_pw_org;
+
+ if ( PP->sgraph_fname ){
+ if ( SG->edge.t < TT->T.clms )
+ print_mes (PP->problem, "#nodes in constraint graph is smaller than #items\n");
+ if ( TT->perm ){
+ malloc2 (sperm, SG->edge.t, "LCM_init: sperm", EXIT);
+ ARY_INIT_PERM (sperm, SG->edge.t);
+ FLOOP (i, 0, MIN(TT->T.t, SG->edge.t)) sperm[i] = TT->perm[i];
+ ARY_INV_PERM (tmp, sperm, SG->edge.t, "LCM_init:INV_PERM", {free(sperm);EXIT;});
+ SGRAPH_replace_index (SG, sperm, tmp);
+ mfree (tmp, sperm);
+ SG->perm = NULL;
+ }
+
+ SG->edge.flag |= LOAD_INCSORT +LOAD_RM_DUP;
+ SETFAMILY_sort (&SG->edge);
+ }
+ II->total_weight = TT->total_w;
+}
+
+/*************************************************************************/
+/* main of LCM ver. 5 */
+/*************************************************************************/
+int LCM_main (int argc, char *argv[]){
+ PROBLEM PP;
+ ITEMSET *II = &PP.II;
+ TRSACT *TT = &PP.TT;
+ SGRAPH *SG = &PP.SG;
+
+ PROBLEM_init (&PP);
+ LCM_read_param (argc, argv, &PP);
+if ( ERROR_MES ) return (1);
+ TT->flag |= LOAD_PERM +TRSACT_FRQSORT +LOAD_DECSORT +LOAD_RM_DUP +TRSACT_MAKE_NEW +TRSACT_DELIV_SC +TRSACT_ALLOC_OCC + ((II->flag & ITEMSET_TRSACT_ID)?0: TRSACT_SHRINK) ;
+ if ( II->flag&ITEMSET_RULE ) TT->w_lb = -WEIGHTHUGE; else TT->w_lb = II->frq_lb;
+ SG->flag = LOAD_EDGE;
+ PROBLEM_init2 (&PP, PROBLEM_PRINT_SHRINK + PROBLEM_PRINT_FRQ);
+ if ( !ERROR_MES ){
+ LCM_init (&PP);
+ if ( !ERROR_MES ) LCM (&PP, TT->T.clms, &PP.oo, TT->total_w_org, TT->total_pw_org);
+ ITEMSET_last_output (II);
+ }
+
+ TT->sc = NULL;
+ PROBLEM_end (&PP);
+ return (ERROR_MES?1:0);
+}
+
+/*******************************************************************************/
+#ifndef _NO_MAIN_
+#define _NO_MAIN_
+int main (int argc, char *argv[]){
+ return (LCM_main (argc, argv));
+}
+#endif
+/*******************************************************************************/
+
+#endif
+
+
--- /dev/null
+CC = g++
+DIR = ../..
+INCL = $(DIR)/include
+OPT = -O3 -D_NO_MAIN_ -I$(INCL)
+OPT64 = $(OPT) -DB_64
+
+all: lcm-vsop.o
+
+64: lcm-vsop_64.o
+
+clean:
+ rm -f *.o *.a *~
+
+lcm-vsop.o: lcm-vsop.cc
+ $(CC) $(OPT) -c lcm-vsop.cc
+ rm -f lcm-vsop_64.o
+
+lcm-vsop_64.o: lcm-vsop.cc
+ $(CC) $(OPT64) -c lcm-vsop.cc -o lcm-vsop_64.o
+ rm -f lcm-vsop.o
+
+lcm-vsop.cc: lcm.c problem.c itemset.c trsact.c base.c \
+ queue.c stdlib2.c aheap.c sgraph.c vec.c lcm-vsop.sed \
+ aheap.h base.h itemset.h problem.h queue.h \
+ sgraph.h stdlib2.h trsact.h vec.h
+ sed -f lcm-vsop.sed < lcm.c > lcm-vsop.cc
+
--- /dev/null
+/* Common problem input/output routines /structure
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/***************************************************/
+
+#ifndef _problem_c_
+#define _problem_c_
+
+#include"problem.h"
+
+#include"stdlib2.c"
+#include"queue.c"
+#include"itemset.c"
+
+void PROBLEM_error (){
+ ERROR_MES = "command explanation";
+ EXIT;
+}
+
+/*************************************************************************/
+/* PROBLEM and ITEMSET initialization */
+/*************************************************************************/
+void PROBLEM_init (PROBLEM *P){
+ P->start_time = clock();
+ RAND_INIT;
+ P->problem = 0;
+ P->prog = 0;
+ P->prog2 = 0;
+ P->input_fname = P->output_fname = P->weight_fname = NULL;
+ P->table_fname = P->position_fname = NULL;
+
+ P->sgraph_fname = P->sgraph2_fname = NULL;
+ P->sgraph_wfname = P->sgraph2_wfname = NULL;
+ P->agraph_fname = P->agraph2_fname = NULL;
+ P->trsact_fname = P->trsact2_fname = NULL;
+ P->trsact_fname2 = P->trsact2_fname2 = NULL;
+ P->trsact_wfname = P->trsact2_wfname = NULL;
+ P->trsact_wfname2 = P->trsact2_wfname2 = NULL;
+ P->trsact_pfname = P->trsact2_pfname = NULL;
+ P->seq_fname = P->seq2_fname = NULL;
+ P->fstar_fname = P->fstar2_fname = NULL;
+ P->mat_fname = P->mat2_fname = NULL;
+ P->smat_fname = P->smat2_fname = NULL;
+ P->setfamily_fname = P->setfamily2_fname = NULL;
+ P->setfamily_wfname = P->setfamily2_wfname = NULL;
+
+ P->root = 0;
+ P->dir = P->edge_dir = 0;
+ P->th = P->th2 = P->th3 = 0;
+ P->ratio = P->ratio2 = 0;
+ P->num = P->siz = P->dim = P->len = 0;
+ P->rows = 0;
+ P->clms = 0;
+
+ ITEMSET_init (&P->II);
+ ITEMSET_init (&P->II2);
+
+ P->vf = P->dep = NULL;
+ P->ff = INIT_QUEUE;
+
+ P->shift = NULL;
+ P->occ_w = P->occ_pw = P->occ_w2 = P->occ_pw2 = NULL;
+
+ P->itemjump = P->itemcand = P->vecjump = P->veccand = INIT_QUEUE; // for delivery
+ P->OQ = P->OQ2 = P->VQ = P->VQ2 = NULL; // for delivery
+ P->itemary = NULL;
+ P->itemmark = P->itemflag = P->vecmark = P->vecflag = NULL; // mark for vector
+ P->occ_t = P->vecary = NULL;
+ P->oo = INIT_QUEUE;
+
+ P->pat = NULL;
+ P->plen = P->perr = 0;
+
+#ifdef _alist_h_
+ P->occ = INIT_MALIST;
+#endif
+
+#ifdef _trsact_h_
+ TRSACT_init (&P->TT);
+ TRSACT_init (&P->TT2);
+#endif
+#ifdef _sgraph_h_
+ P->SG = INIT_SGRAPH;
+ P->SG2 = INIT_SGRAPH;
+#endif
+#ifdef _agraph_h_
+ P->AG = INIT_AGRAPH;
+ P->AG2 = INIT_AGRAPH;
+#endif
+#ifdef _seq_h_
+ SEQ_init (&P->SS);
+ SEQ_init (&P->SS2);
+#endif
+#ifdef _fstar_h_
+ P->FS = INIT_FSTAR;
+ P->FS2 = INIT_FSTAR;
+#endif
+
+#ifdef _vec_h_
+ P->MM = INIT_MAT;
+ P->MM2 = INIT_MAT;
+ P->SM = INIT_SMAT;
+ P->SM2 = INIT_SMAT;
+ P->FF = INIT_SETFAMILY;
+ P->FF2 = INIT_SETFAMILY;
+#endif
+}
+
+/*************************************************************************/
+/* PROBLEM initialization */
+/* all pointers are set to NULL, but don't touch filenames */
+/* load_flag, flag to give TRSACT_load */
+/* II->item_max will be item_max when do not load problem */
+/* II-> */
+/*************************************************************************/
+void PROBLEM_init2 (PROBLEM *P, int flag){
+ int f=0;
+/******************************/
+#ifdef _trsact_h_
+ if ( P->trsact_fname ){
+ TRSACT_load (&P->TT, P->trsact_fname, P->trsact_fname2, P->trsact_wfname, P->trsact_wfname2, P->trsact_pfname); if (ERROR_MES) goto ERR;
+ if ( P->TT.flag & SHOW_MESSAGE ){
+ print_err ("trsact: %s", P->trsact_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %d", P->TT.rows_org, P->TT.clms_org, P->TT.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT.T.t, P->TT.T.clms, P->TT.T.eles);
+ if ( P->trsact_wfname ) print_err (" ,weightfile %s", P->trsact_wfname);
+ if ( P->trsact_wfname2 ) print_err (" ,2nd-weightfile %s", P->trsact_wfname2);
+ if ( P->trsact_pfname ) print_err (" ,item-order-file %s", P->trsact_pfname);
+ print_err ("\n");
+ }
+ }
+ if ( P->trsact2_fname ){
+ TRSACT_load (&P->TT2, P->trsact2_fname, P->trsact2_fname2, P->trsact2_wfname, P->trsact2_wfname2, P->trsact2_pfname); if (ERROR_MES) goto ERR;
+ if ( P->TT2.flag & SHOW_MESSAGE ){
+ print_err ("trsact2: %s", P->trsact2_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact2_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %zd", P->TT2.rows_org, P->TT2.clms_org, P->TT2.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT2.T.t, P->TT2.T.clms, P->TT2.T.eles);
+ if ( P->trsact2_wfname ) print_err (" ,weightfile2 %s", P->trsact2_wfname);
+ if ( P->trsact2_wfname2 ) print_err (" ,2nd-weightfile2 %s", P->trsact2_wfname2);
+ if ( P->trsact2_pfname ) print_err (" ,item-order-file2 %s", P->trsact2_pfname);
+ print_err ("\n");
+ }
+ }
+#endif
+#ifdef _sgraph_h_
+ if ( P->sgraph_fname ){
+ SGRAPH_load (&P->SG, P->sgraph_fname, P->sgraph_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->SG.flag, "sgraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->sgraph_fname, SGRAPH_NODE_NUM(P->SG), P->SG.edge.eles/2, P->SG.in.eles);
+ }
+ if ( P->sgraph2_fname ){
+ SGRAPH_load (&P->SG, P->sgraph2_fname, P->sgraph2_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->SG2.flag, "sgraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->sgraph2_fname, SGRAPH_NODE_NUM(P->SG2), P->SG2.edge.eles/2, P->SG2.in.eles);
+ }
+#endif
+#ifdef _agraph_h_
+ if ( P->agraph_fname ){
+ AGRAPH_load (&P->AG, P->agraph_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->AG.flag, "agraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->agraph_fname, P->AG.node_num, P->AG.edge_num, P->AG.arc_num);
+ }
+ if ( P->agraph2_fname ){
+ AGRAPH_load (&P->AG2, P->agraph_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->AG2.flag, "agraph: %s ,#nodes %d ,#edges %zd ,#arcs %zd\n", P->agraph2_fname, P->AG2.node_num, P->AG2.edge_num, P->AG2.arc_num);
+ }
+#endif
+#ifdef _fstar_h_
+ if ( P->fstar_fname ){
+ FSTAR_load (&P->FS, P->fstar_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->FS.flag, "agraph: %s ,#nodes %d(%d,%d) ,#edges %zd\n", P->fstar_fname, P->FS.node_num, P->FS.in_node_num, P->FS.out_node_num, P->FS.edge_num);
+ }
+ if ( P->fstar2_fname ){
+ FSTAR_load (&P->FS2, P->fstar2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->FS2.flag, "agraph2: %s ,#nodes %d(%d,%d) ,#edges %zd\n", P->fstar2_fname, P->FS2.node_num, P->FS2.in_node_num, P->FS2.out_node_num, P->FS2.edge_num);
+ }
+
+#endif
+#ifdef _vec_h_
+ if ( P->mat_fname ){
+ MAT_load (&P->MM, P->mat_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->MM.flag, "mat: %s ,#rows %d ,#clms %d\n", P->mat_fname, P->MM.t, P->MM.clms);
+ }
+ if ( P->mat2_fname ){
+ MAT_load (&P->MM2, P->mat2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->MM2.flag, "mat2: %s ,#rows %d ,#clms %d\n", P->mat2_fname, P->MM2.t, P->MM2.clms);
+ }
+ if ( P->smat_fname ){
+ SMAT_load (&P->SM, P->smat_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->SM.flag, "smat: %s ,#rows %d ,#clms %d ,#eles %zd\n", P->smat_fname, P->SM.t, P->SM.clms, P->SM.eles);
+ }
+ if ( P->smat2_fname ){
+ SMAT_load (&P->SM2, P->smat2_fname); if (ERROR_MES) goto ERR;
+ print_mes (P->SM2.flag, "smat2: %s ,#rows %d ,#clms %d ,#eles %zd\n", P->smat2_fname, P->SM2.t, P->SM2.clms, P->SM2.eles);
+ }
+ if ( P->setfamily_fname ){
+ SETFAMILY_load (&P->FF, P->setfamily_fname, P->setfamily_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->FF.flag, "setfamily: %s ,#rows %d ,#clms %d ,#eles %zd", P->setfamily_fname, P->FF.t, P->FF.clms, P->FF.eles);
+ if ( P->setfamily_wfname ) print_mes (P->FF.flag, " ,weightfile %s", P->setfamily_wfname);
+ print_mes (P->FF.flag, "\n");
+ }
+ if ( P->setfamily2_fname ){
+ SETFAMILY_load (&P->FF2, P->setfamily2_fname, P->setfamily2_wfname); if (ERROR_MES) goto ERR;
+ print_mes (P->FF2.flag, "setfamily2: %s ,#rows %d ,#clms %d ,#eles %zd", P->setfamily2_fname, P->FF2.t, P->FF2.clms, P->FF2.eles);
+ if ( P->setfamily2_wfname ) print_mes (P->FF2.flag, " ,weightfile %s", P->setfamily2_wfname);
+ print_mes (P->FF2.flag, "\n");
+ }
+#endif
+ if (P->input_fname){ f=1; print_err (" input: %s", P->input_fname); }
+ if (P->weight_fname){ f=1; print_err (" weight: %s", P->weight_fname); }
+ if (P->output_fname){ f=1; print_err (" output to: %s",P->output_fname); }
+ if ( f )print_err ("\n");
+
+/******************************/
+
+ if ( flag&SHOW_MESSAGE ){
+ ITEMSET_print (&P->II, (flag&PROBLEM_PRINT_FRQ)? 1: 0);
+ if ( flag&PROBLEM_PRINT_DENSE ){
+ print_err ("density threshold");
+ fprint_real (stderr, P->dense);
+ print_err ("\n");
+ }
+ }
+
+ if ( !ERROR_MES ) return;
+ ERR:;
+ PROBLEM_end (P);
+ EXIT;
+}
+
+/* termination of problem */
+void PROBLEM_end (PROBLEM *P){
+ ITEMSET *II = &P->II;
+
+#ifdef _trsact_h_
+ TRSACT_end (&P->TT);
+ TRSACT_end (&P->TT2);
+#endif
+#ifdef _sgraph_h_
+ SGRAPH_end (&P->SG);
+ SGRAPH_end (&P->SG2);
+#endif
+#ifdef _agraph_h_
+ AGRAPH_end (&P->AG);
+ AGRAPH_end (&P->AG2);
+#endif
+#ifdef _seq_h_
+ SEQ_end (&P->SS);
+ SEQ_end (&P->SS2);
+#endif
+#ifdef _fstar_h_
+ FSTAR_end (&P->FS);
+ FSTAR_end (&P->FS2);
+#endif
+#ifdef _vec_h_
+ MAT_end (&P->MM);
+ MAT_end (&P->MM2);
+ SMAT_end (&P->SM);
+ SMAT_end (&P->SM2);
+ SETFAMILY_end (&P->FF);
+ SETFAMILY_end (&P->FF2);
+#endif
+
+/******************************/
+
+ mfree (P->vf, P->dep);
+ QUEUE_end (&P->ff);
+
+ ITEMSET_end (II);
+ ITEMSET_end (&P->II2);
+
+ if ( P->occ_pw2 != P->occ_pw && P->occ_pw2 != P->occ_w2 ) free2 (P->occ_pw2);
+ if ( P->occ_w2 != P->occ_w ) free2 (P->occ_w2);
+ if ( P->occ_pw != P->occ_w ) free2 (P->occ_pw);
+ mfree (P->shift, P->occ_t, P->occ_w);
+
+ if ( P->OQ ) free2 (P->OQ[0].v);
+ if ( P->OQ2 ) free2 (P->OQ2[0].v);
+ if ( P->VQ ) free2 (P->VQ[0].v);
+ if ( P->VQ2 ) free2 (P->VQ2[0].v);
+ mfree (P->OQ, P->OQ2, P->VQ, P->VQ2);
+
+
+ mfree (P->itemary, P->itemflag, P->itemmark, P->vecary, P->vecflag, P->vecmark);
+ QUEUE_end (&P->itemcand);
+ QUEUE_end (&P->itemjump);
+
+ QUEUE_end (&P->veccand);
+ QUEUE_end (&P->vecjump);
+ QUEUE_end (&P->oo);
+
+
+#ifdef _alist_h_
+ MALIST_end (&P->occ);
+#endif
+
+#ifdef _undo_h_
+ ALISTundo_end ();
+#endif
+
+ P->end_time = clock();
+ if ( print_time_flag )
+ print_err ("computation_time= %3f\n", ((double)(P->end_time - P->start_time))/CLOCKS_PER_SEC);
+
+ PROBLEM_init (P);
+}
+
+/* allocate arrays and structures */
+void PROBLEM_alloc (PROBLEM *P, QUEUE_ID siz, QUEUE_ID siz2, size_t siz3, PERM *perm, int f){
+#ifdef _alist_h_
+ ALIST_ID i;
+#endif
+
+ if ( f&PROBLEM_SHIFT ) calloc2 (P->shift, siz+2, "PROBLEM_alloc: shift", goto ERR);
+ if ( f&PROBLEM_OCC_T ) calloc2 (P->occ_t, siz+2, "PROBLEM_alloc:occ_t", goto ERR);
+ if ( f&(PROBLEM_OCC_W+PROBLEM_OCC_PW) ) calloc2 (P->occ_w, siz+2, "PROBLEM_alloc:occ_w", goto ERR);
+ if ( f&PROBLEM_OCC_PW ){
+ calloc2 (P->occ_pw, siz+2, "PROBLEM_alloc:occ_pw", goto ERR);
+ } else P->occ_pw = P->occ_w;
+ if ( f&PROBLEM_OCC_W2 ){
+ calloc2 (P->occ_w2, siz+2, "PROBLEM_alloc:occ_w", goto ERR);
+ if ( f&PROBLEM_OCC_PW ){
+ calloc2 (P->occ_pw2, siz+2, "PROBLEM_alloc:occ_pw", goto ERR);
+ } else P->occ_pw2 = P->occ_w2;
+ } else { P->occ_w2 = P->occ_w; P->occ_pw2 = P->occ_pw; }
+
+ if ( f&PROBLEM_ITEMFLAG ) calloc2 (P->itemflag, siz+2, "PROBLEM_alloc:itemflag", goto ERR);
+ if ( f&PROBLEM_ITEMMARK ) calloc2 (P->itemmark, siz+2, "PROBLEM_alloc:itemmark", goto ERR);
+ if ( f&PROBLEM_ITEMARY ) calloc2(P->itemary, siz+2,"PROBLEM_alloc:itemary", goto ERR);
+ if ( f&PROBLEM_ITEMJUMP ) QUEUE_alloc (&P->itemjump, siz+2);
+ if ( f&PROBLEM_ITEMCAND ) QUEUE_alloc (&P->itemcand, siz+2);
+
+ if ( f&PROBLEM_VECFLAG ) calloc2 (P->vecflag, siz+2, "PROBLEM_alloc:vecflag", goto ERR);
+ if ( f&PROBLEM_VECMARK ) calloc2 (P->vecmark, siz2+2, "PROBLEM_alloc:vecmark", goto ERR);
+ if ( f&PROBLEM_VECARY ) calloc2 (P->vecary, siz2+2, "PROBLEM_alloc:vecary", goto ERR);
+ if ( f&PROBLEM_VECJUMP ) QUEUE_alloc (&P->vecjump, siz2+2);
+ if ( f&PROBLEM_VECCAND ) QUEUE_alloc (&P->veccand, siz2+2);
+
+#ifdef _alist_h_
+ if ( f&PROBLEM_OCC3){
+ MALIST_alloc (&P->occ, siz, siz2+2); // element=>
+if ( ERROR_MES ) goto ERR;
+ if ( f&PROBLEM_OCC2 )
+ FLOOP (i, 0, siz) MALIST_ins_tail (&P->occ, (f&PROBLEM_OCC1)?siz: 0, i, 0);
+ }
+#endif
+
+ ITEMSET_init2 (&P->II, P->output_fname, perm, siz, siz3);
+ if ( P->II.target<siz && P->II.perm ) P->II.target = P->II.perm[P->II.target];
+
+#ifdef _undo_h_
+ ALISTundo_init ();
+#endif
+
+ return;
+ ERR:;
+ PROBLEM_end (P);
+ EXIT;
+}
+
+#endif
+
+
--- /dev/null
+/* Common problem input/output routines /structure
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/***************************************************/
+
+#ifndef _problem_h_
+#define _problem_h_
+
+#include"stdlib2.h"
+#include"queue.h"
+#include"itemset.h"
+
+#define PROBLEM_FREQSET 1
+#define PROBLEM_MAXIMAL 2
+#define PROBLEM_CLOSED 4
+#define PROBLEM_EX_MAXIMAL 8
+#define PROBLEM_EX_CLOSED 16
+
+/***** parameters for PROBLEM initialization, given to flag *****/
+
+#define PROBLEM_PRINT_DENSE 4 // print density threshold
+#define PROBLEM_PRINT_SHRINK 8 // print properties of shrinked database
+#define PROBLEM_PRINT_FRQ 16 // print density threshold
+#define PROBLEM_NORMALIZE 32 // print density threshold
+
+#define PROBLEM_ITEMARY 128 // alloc itemary
+#define PROBLEM_ITEMJUMP 256 // alloc itemjump
+#define PROBLEM_ITEMFLAG 512 // alloc itemflag
+#define PROBLEM_ITEMMARK 1024 // alloc itemmark
+#define PROBLEM_ITEMCAND 2048 // alloc itemcand
+#define PROBLEM_VECARY 4096 // alloc itemary
+#define PROBLEM_VECJUMP 8192 // alloc vecjump
+#define PROBLEM_VECFLAG 16384 // alloc vecflag
+#define PROBLEM_VECMARK 32768 // alloc vecmark
+#define PROBLEM_VECCAND 65536 // alloc veccand
+//4194304
+#define PROBLEM_OCC_T 524288 // alloc occ_t
+#define PROBLEM_SHIFT 1048576 // allocate shift
+#define PROBLEM_OCC_W 2097152 // weight/positive-weight sum for items
+#define PROBLEM_OCC_PW 4194304 // weight/positive-weight sum for items
+#define PROBLEM_OCC_W2 8388608 // weight/positive-weight sum for items
+
+#define PROBLEM_OCC1 16 // alloc occ
+#define PROBLEM_OCC2 32 // alloc occ and ins all to list 0
+#define PROBLEM_OCC3 48 // alloc occ and ins all to list "siz"
+
+typedef struct {
+ clock_t start_time, end_time;
+ int problem;
+ LONG prog;
+ int prog2;
+ double dense;
+ char *input_fname;
+ char *output_fname;
+ char *weight_fname;
+ char *table_fname, *table2_fname;
+ char *position_fname, *position2_fname;
+
+ char *sgraph_fname, *sgraph2_fname;
+ char *sgraph_wfname, *sgraph2_wfname;
+ char *agraph_fname, *agraph2_fname;
+ char *trsact_fname, *trsact_fname2, *trsact_wfname, *trsact_wfname2, *trsact_pfname;
+ char *trsact2_fname, *trsact2_fname2, *trsact2_wfname, *trsact2_wfname2, *trsact2_pfname;
+ char *seq_fname, *seq2_fname;
+ char *fstar_fname, *fstar2_fname;
+ char *mat_fname, *mat2_fname;
+ char *smat_fname, *smat2_fname;
+ char *setfamily_fname, *setfamily2_fname;
+ char *setfamily_wfname, *setfamily2_wfname;
+
+ ITEMSET II, II2;
+ QUEUE ff; // for agraph search
+ int *vf, *dep; // for agraph search
+
+ int root, dir, edge_dir;
+ double th, th2, th3; // thresholds
+ double ratio, ratio2; // ratio
+ int num, siz, dim, len;
+ QUEUE_INT clms;
+ VEC_ID rows;
+
+ QUEUE_ID **shift;
+ QUEUE itemjump, itemcand, vecjump, veccand, *OQ, *OQ2, *VQ, *VQ2; // for delivery
+ QUEUE_INT *itemary;
+ int *itemmark, *itemflag, *vecmark, *vecflag; // mark for vector
+ VEC_ID *vecary, *occ_t;
+ WEIGHT *occ_w, *occ_pw, *occ_w2, *occ_pw2;
+ QUEUE oo;
+
+ char *pat; // pattern string
+ int plen, perr; // pattern length and #error allowed
+
+#ifdef _alist_h_
+ MALIST occ;
+#endif
+
+#ifdef _sgraph_h_
+ SGRAPH SG, SG2;
+#endif
+
+#ifdef _agraph_h_
+ AGRAPH AG, AG2;
+#endif
+
+#ifdef _trsact_h_
+ TRSACT TT, TT2;
+#endif
+
+#ifdef _seq_h_
+ SEQ SS, SS2;
+#endif
+
+#ifdef _fstar_h_
+ FSTAR FS, FS2;
+#endif
+
+#ifdef _vec_h_
+ MAT MM, MM2;
+ SMAT SM, SM2;
+ SETFAMILY FF, FF2;
+#endif
+
+} PROBLEM;
+
+
+/***** print filename information ****/
+void PROBLEM_print (PROBLEM *P);
+
+/***** print usage of the program *****/
+void PROBLEM_error ();
+
+/***** read parameters given by command line *****/
+void PROBLEM_read_param (int argc, char *argv[], PROBLEM *P);
+
+/***** PROBLEM and ITEMSET initialization *****/
+/* all pointers are set to NULL, but don't touch filenames */
+void PROBLEM_init (PROBLEM *P);
+
+/***** PROBLEM initialization: load the files given by filenames ******/
+void PROBLEM_init2 (PROBLEM *P, int flag);
+
+/***** allocate memory according to flag *****/
+void PROBLEM_alloc (PROBLEM *PP, QUEUE_ID siz, QUEUE_ID siz2, size_t siz3, PERM *p, int f);
+
+/* termination of problem */
+void PROBLEM_end (PROBLEM *PP);
+
+
+#endif
+
+
--- /dev/null
+/* Library of queue: spped priority implementation
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _queue_c_
+#define _queue_c_
+
+
+#include"queue.h"
+#include"stdlib2.c"
+
+QSORT_TYPE(QUEUE_INT, QUEUE_INT)
+QSORT_TYPE(QUEUE_ID, QUEUE_ID)
+QUEUE INIT_QUEUE = {TYPE_QUEUE,NULL,0,0,0};
+QUEUE_INT *common_QUEUE_INTp;
+
+/* initialization, not fill the memory by 0 */
+void QUEUE_alloc (QUEUE *Q, QUEUE_ID siz){
+ *Q = INIT_QUEUE;
+ Q->end = siz+1;
+ malloc2 (Q->v, siz+1, "QUEUE_alloc: Q->v", EXIT);
+}
+
+/* termination processing */
+void QUEUE_end (QUEUE *Q){
+ free2 (Q->v);
+ *Q = INIT_QUEUE;
+}
+
+
+/* tranpose the matrix ; counting/transpose/memory_allocate */
+void QUEUE_delivery(QUEUE *OQ, VEC_ID *c, QUEUE *jump, QUEUE *Q, QUEUE *occ, VEC_ID t, QUEUE_INT M){ VEC_ID i, e;
+ QUEUE_INT *x;
+ FLOOP(i, 0, occ? occ->t: t){
+ e = occ? occ->v[i]: i;
+ if ( c ){
+ if ( jump ){ MLOOP (x, Q[e].v, M){ if ( c[*x]==0 ) ARY_INS (*jump, *x); c[*x]++; }
+ } else { MLOOP (x, Q[e].v, M){ c[*x]++; }}
+ } else {
+ if ( jump ){ MLOOP (x, Q[e].v, M){ if ( OQ[*x].t==0 ) ARY_INS (*jump, *x); ARY_INS (OQ[*x], e); }
+ } else MLOOP (x, Q[e].v, M){ ARY_INS (OQ[*x], e); }
+ }
+ }
+}
+
+/* sort a QUEUE with WEIGHT, with already allocated memory */
+void QUEUE_perm_WEIGHT (QUEUE *Q, WEIGHT *w, PERM *invperm, int flag){
+ WEIGHT y;
+ if ( w ){
+ qsort_perm__QUEUE_INT (Q->v, Q->t, invperm, flag);
+ ARY_INVPERMUTE_ (w, invperm, y, Q->t);
+ }
+ qsort_QUEUE_INT (Q->v, Q->t, flag);
+}
+
+/* remove (or unify) the consecutive same ID's in a QUEUE (duplication delete, if sorted) */
+void QUEUE_rm_dup_WEIGHT (QUEUE *Q, WEIGHT *w){
+ VEC_ID j, jj=0;
+ if ( w ){
+ FLOOP (j, 1, Q->t){
+ if ( Q->v[j-1] != Q->v[j] ){
+ Q->v[++jj] = Q->v[j];
+ w[jj] = w[j];
+ } else w[jj] += w[j];
+ }
+ } else FLOOP (j, 1, Q->t){
+ if ( Q->v[j-1] != Q->v[j] ) Q->v[++jj] = Q->v[j];
+ }
+ if ( Q->t>0 ) Q->t = jj+1;
+}
+
+/***********************************************************************/
+/* duplicate occ's in jump, ( copy occ's to allocated QUEUE array) */
+/* Q[i].end := original item, clear each original occ */
+/* buffer size is multiplied by u */
+/*******************************************************/
+void QUEUE_occ_dup (QUEUE *jump, QUEUE **QQ, QUEUE *Q, WEIGHT **ww, WEIGHT *w, WEIGHT **ppw, WEIGHT *pw, int u){
+ QUEUE_ID i, l=QUEUE_LENGTH_(*jump);
+ size_t cnt=0;
+ QUEUE_INT e, *x;
+ char *buf;
+ int unit = sizeof(*Q) + (w?sizeof(*w):0) + (pw?sizeof(*pw):0);
+
+ ENMAX (u, sizeof(*x));
+ MQUE_FLOOP (*jump, x) cnt += Q[*x].t;
+ if ( cnt == 0 ){ *QQ=NULL; return; }
+ malloc2 (buf, l*unit + (cnt+l)*u, "QUEUE_occ_dup: buf", EXIT);
+ *QQ = (QUEUE*)buf; buf += sizeof(*Q) *l;
+ if ( w ){ *ww = (WEIGHT *)buf; buf += sizeof(*w)*l; }
+ if ( pw ){ *ppw = (WEIGHT *)buf; buf += sizeof(*pw)*l; }
+ ARY_FLOOP (*jump, i, e){
+ (*QQ)[i].end = e;
+ (*QQ)[i].v = (QUEUE_INT *)buf;
+ (*QQ)[i].t = Q[e].t;
+ memcpy (buf, Q[e].v, (Q[e].t+1)*u);
+ buf += (Q[e].t+1) *u;
+ if ( w ) (*ww)[i] = w[e];
+ if ( pw ) (*ppw)[i] = pw[e];
+ }
+}
+
+
+/* return the position of the first element having value e. return -1 if no such element exists */
+LONG QUEUE_ele (QUEUE *Q, QUEUE_INT e){
+ QUEUE_INT *x;
+ MQUE_FLOOP (*Q, x)
+ if ( *x == e ) return (x - Q->v);
+ return (-1);
+}
+
+/* insert an element to the tail */
+void QUEUE_ins_ (QUEUE *Q, QUEUE_INT e){
+ Q->v[Q->t] = e;
+ Q->t++;
+}
+void QUEUE_ins (QUEUE *Q, QUEUE_INT e){
+ Q->v[Q->t] = e;
+ QUEUE_INCREMENT (*Q, Q->t);
+ if (Q->s == Q->t ) error_num ("QUEUE_ins: overflow", Q->s, EXIT);
+}
+
+/* insert an element to the head */
+void QUEUE_ins_head_ (QUEUE *Q, QUEUE_INT e){
+ Q->s--;
+ Q->v[Q->s] = e;
+}
+void QUEUE_ins_head (QUEUE *Q, QUEUE_INT e){
+ QUEUE_DECREMENT(*Q,Q->s);
+ Q->v[Q->s] = e;
+ if (Q->s == Q->t ) error_num ("QUEUE_ins_head: underflow", Q->s, EXIT);
+}
+
+/* extract an element from the head, without checking underflow */
+QUEUE_INT QUEUE_ext_ (QUEUE *Q){
+ (Q->s)++;
+ return (Q->v[Q->s-1]);
+}
+QUEUE_INT QUEUE_ext (QUEUE *Q){
+ QUEUE_INT e;
+ if (Q->s == Q->t ) error_num ("QUEUE_ext: empty queue", Q->s, EXIT0);
+ e = Q->v[Q->s];
+ QUEUE_INCREMENT(*Q,Q->s);
+ return ( e);
+}
+
+/* extract an element from the tail, without checking underflow */
+QUEUE_INT QUEUE_ext_tail_ (QUEUE *Q){
+ (Q->t)--;
+ return (Q->v[Q->t]);
+}
+QUEUE_INT QUEUE_ext_tail (QUEUE *Q){
+ if ( Q->s == Q->t ) error_num ("QUEUE_ext_tail: empty queue", Q->s, EXIT0);
+ QUEUE_DECREMENT(*Q,Q->t);
+ return (Q->v[Q->t]);
+}
+
+/* remove the j-th element and replace it by the tail */
+void QUEUE_rm_ (QUEUE *Q, QUEUE_ID j){
+ Q->t--;
+ Q->v[j] = Q->v[Q->t];
+}
+void QUEUE_rm (QUEUE *Q, QUEUE_ID j){
+ if ( Q->s <= Q->t ){
+ if ( j < Q->s || j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ } else if ( j < Q->s && j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ QUEUE_DECREMENT(*Q,Q->t);
+ Q->v[j] = Q->v[Q->t];
+}
+
+/* remove the j-th element and replace it by the head */
+void QUEUE_rm_head_ (QUEUE *Q, QUEUE_ID j){
+ Q->v[j] = Q->v[Q->s];
+ Q->s++;
+}
+void QUEUE_rm_head (QUEUE *Q, QUEUE_ID j){
+ if ( Q->s <= Q->t ){
+ if ( j < Q->s || j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ } else if ( j < Q->s && j >= Q->t ) error ("QUEUE_rm: j is out of queue", EXIT);
+ Q->v[j] = Q->v[Q->s];
+ QUEUE_INCREMENT(*Q,Q->s);
+}
+
+/* remove the j-th element and shift the following elements to fill the gap */
+int QUEUE_rm_ele_ (QUEUE *Q, QUEUE_INT e){
+ QUEUE_ID i;
+ QUEUE_F_LOOP (*Q, i){
+ if ( Q->v[i] == e ){
+ memcpy ( &(Q->v[i]), &(Q->v[i+1]), (Q->t-i-1)*sizeof(QUEUE_INT));
+ Q->t--;
+ return (1);
+ }
+ }
+ return (0);
+}
+/* insert e to the position determined by the increasing order of elements */
+void QUEUE_ins_ele_ (QUEUE *Q, QUEUE_INT e){
+ QUEUE_ID i;
+ QUEUE_INT ee;
+ QUEUE_BE_LOOP_ (*Q, i, ee){
+ if ( ee<e ) break;
+ Q->v[i+1] = ee;
+ }
+ Q->v[i+1] = e;
+ Q->t++;
+}
+
+/* Append Q2 to the tail of Q1. Q2 will not be deleted */
+void QUEUE_concat_ (QUEUE *Q1, QUEUE *Q2){
+ memcpy ( &(Q1->v[Q1->t]), &(Q2->v[Q2->s]), (Q2->t-Q2->s)*sizeof(QUEUE_INT));
+ Q1->t += Q2->t-Q2->s;
+}
+void QUEUE_concat (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID e = Q2->s;
+ while ( e != Q2->t){
+ QUEUE_ins (Q1, Q2->v[e]);
+ QUEUE_INCREMENT(*Q2,e);
+ }
+}
+/* Append Q2 to the tail of Q1. Q2 will be deleted */
+void QUEUE_append_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_concat_ (Q1, Q2);
+ QUEUE_RMALL (*Q2);
+}
+void QUEUE_append (QUEUE *Q1, QUEUE *Q2){ // more improvement can be
+ while ( Q2->s != Q2->t )
+ QUEUE_ins (Q1, QUEUE_ext(Q2));
+}
+
+/* Append from j to jj th elements to the tail of Q1. Q2 will not be deleted */
+void QUEUE_subconcat_ (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj){
+ for ( ; j<=jj ; j++){
+ Q1->v[Q1->t] = Q2->v[j];
+ Q1->t++;
+ }
+}
+void QUEUE_subconcat (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj){
+ while (1){
+ QUEUE_ins (Q1, Q2->v[j]);
+ if ( j == jj ) break;
+ QUEUE_INCREMENT(*Q2,j);
+ }
+}
+
+/* initialize Q1 by length of Q2, and copy Q2 to Q1 */
+void QUEUE_store_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_alloc (Q1, QUEUE_LENGTH(*Q2));
+ QUEUE_concat_ (Q1, Q2);
+}
+void QUEUE_store (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_alloc (Q1, QUEUE_LENGTH(*Q2));
+ QUEUE_concat (Q1, Q2);
+}
+/* copy Q2 to Q1 and delete Q2 */
+void QUEUE_restore_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat_ (Q1, Q2);
+ QUEUE_end (Q2);
+}
+void QUEUE_restore (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat (Q1, Q2);
+ QUEUE_end (Q2);
+}
+
+/* copy Q2 to Q1 */
+void QUEUE_cpy_ (QUEUE *Q1, QUEUE *Q2){
+ Q1->s = Q1->t = 0;
+ QUEUE_concat_ (Q1, Q2);
+}
+void QUEUE_cpy (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_RMALL (*Q1);
+ QUEUE_concat (Q1, Q2);
+}
+/* copy l elements of Q2 starting from s2 to the s1th position of Q1.
+ size of Q1 is not increasing */
+void QUEUE_subcpy_ (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l){
+ memcpy ( &(Q1->v[s1]), &(Q2->v[s2]), (l-s2)*sizeof(QUEUE_INT));
+}
+void QUEUE_subcpy (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l){
+ for ( ; s2!=l ; QUEUE_INCREMENT(*Q1,s1),QUEUE_INCREMENT(*Q2,s2) )
+ Q1->v[s1] = Q2->v[s2];
+ Q1->v[s1] = Q2->v[s2];
+}
+
+/* duplicate Q2 to Q1. The memory size will be the length of Q2 */
+QUEUE QUEUE_dup_ (QUEUE *Q){
+ QUEUE QQ;
+ QUEUE_alloc (&QQ, QUEUE_LENGTH_(*Q));
+ QUEUE_cpy_ (&QQ, Q);
+ return (QQ);
+}
+
+/* merge Q1 and Q2 by insert all elements of Q2 to Q1 with deleting duplications. Both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_merge_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->t-1, j=Q2->t-1, t=i+j-Q2->s+1;
+ QUEUE_INT ei, ej;
+ if ( i+1 == Q1->s || j+1 == Q2->s ){
+ QUEUE_concat_ (Q1, Q2);
+ return;
+ }
+ Q1->t = t+1;
+ ei = Q1->v[i];
+ ej = Q2->v[j];
+ while (1){
+ if ( ei > ej ){
+ Q1->v[t] = ei;
+ if ( i == Q1->s ){
+ QUEUE_subcpy_ (Q1, Q1->s, Q2, Q2->s, j);
+ return;
+ }
+ i--;
+ ei = Q1->v[i];
+ } else {
+ Q1->v[t] = ej;
+ if ( j == Q2->s ) return;
+ j--;
+ ej = Q2->v[j];
+ }
+ t--;
+ }
+}
+void QUEUE_merge (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->t, j=Q2->t;
+ QUEUE_INT ei, ej;
+ QUEUE_ID t = (Q1->t + QUEUE_LENGTH(*Q2)-1) % Q1->end;
+ if ( QUEUE_LENGTH(*Q1) + QUEUE_LENGTH(*Q2) >= Q1->end ){
+ printf ("QUEUE_merge: overflow Q1->end="QUEUE_INTF", Q1length="QUEUE_INTF", Q2length="QUEUE_INTF"\n", Q1->end, QUEUE_LENGTH(*Q1), QUEUE_LENGTH(*Q2));
+ exit (1);
+ }
+ if ( i == Q1->s || j == Q2->s ){
+ QUEUE_concat (Q1, Q2);
+ return;
+ }
+
+ Q1->t = t;
+ QUEUE_DECREMENT(*Q1,i);
+ QUEUE_DECREMENT(*Q2,j);
+ ei = Q1->v[i];
+ ej = Q2->v[j];
+ while (1){
+ if ( ei > ej ){
+ Q1->v[t] = ei;
+ if ( i == Q1->s ){
+ QUEUE_subcpy (Q1, Q1->s, Q2, Q2->s, (j+Q2->end-Q2->s)%Q2->end);
+ return;
+ }
+ QUEUE_DECREMENT(*Q1,i);
+ ei = Q1->v[i];
+ } else {
+ Q1->v[t] = ej;
+ if ( j == Q2->s ) return;
+ QUEUE_DECREMENT(*Q2,j);
+ ej = Q2->v[j];
+ }
+ QUEUE_DECREMENT(*Q1,t);
+ }
+}
+
+/* delete all elements of Q1 included in Q2.
+ both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_minus_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t){
+ if (Q1->v[i] > Q2->v[i2] ) i2++;
+ else {
+ if (Q1->v[i] < Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ ii++;
+ }
+ i++;
+ }
+ }
+ while ( i != Q1->t ){
+ Q1->v[ii] = Q1->v[i];
+ i++;
+ ii++;
+ }
+ Q1->t = ii;
+}
+void QUEUE_minus (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t ){
+ if ( Q1->v[i] > Q2->v[i2] ) QUEUE_INCREMENT (*Q2, i2);
+ else {
+ if ( Q1->v[i] < Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ QUEUE_INCREMENT (*Q1, i);
+ }
+ }
+ while ( i != Q1->t ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, i);
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ Q1->t = ii;
+}
+
+/* Delete all elements of Q1 which are not included in Q2.
+ both Q1 and Q2 have to be sorted in increasing order */
+QUEUE_ID QUEUE_intsec_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, c=0;
+ while ( i != Q1->t ){
+ if ( Q1->v[i] > Q2->v[i2] ){
+ if ( ++i2 == Q2->t ) break;
+ } else {
+ if ( Q1->v[i] == Q2->v[i2] ) c++;
+ i++;
+ }
+ }
+ return (c);
+}
+void QUEUE_and_ (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t ){
+ if ( Q1->v[i] > Q2->v[i2] ){
+ if ( ++i2 == Q2->t ) break;
+ } else {
+ if ( Q1->v[i] == Q2->v[i2] ) Q1->v[ii++] = Q1->v[i];
+ i++;
+ }
+ }
+ Q1->t = ii;
+}
+void QUEUE_and (QUEUE *Q1, QUEUE *Q2){
+ QUEUE_ID i=Q1->s, i2 = Q2->s, ii=Q1->s;
+ while ( i != Q1->t && i2 != Q2->t){
+ if ( Q1->v[i] > Q2->v[i2] ) QUEUE_INCREMENT (*Q2, i2);
+ else {
+ if ( Q1->v[i] == Q2->v[i2] ){
+ Q1->v[ii] = Q1->v[i];
+ QUEUE_INCREMENT (*Q1, ii);
+ }
+ QUEUE_INCREMENT (*Q1, i);
+ }
+ }
+ Q1->t = ii;
+}
+
+/* insertion sort */
+void QUEUE_sort (QUEUE *Q){
+ QUEUE_ID i = Q->s, j, jj;
+ QUEUE_INT e;
+ if ( i== Q->t ) return;
+ QUEUE_INCREMENT(*Q,i);
+ for ( ; i!=Q->t ; QUEUE_INCREMENT(*Q,i) ){
+ e=Q->v[i];
+ j=i;
+ while (1){
+ jj = j;
+ QUEUE_DECREMENT(*Q,j);
+ if ( Q->v[j] <= e ) { Q->v[jj] = e; break; }
+ Q->v[jj] = Q->v[j];
+ if ( j == Q->s) { Q->v[j] = e; break; }
+ }
+ }
+}
+
+
+/* print a queue */
+void QUEUE_print (QUEUE *Q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+/* permutation version */
+void QUEUE_perm_print (QUEUE *Q, QUEUE_ID *q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", q[Q->v[i]]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+void QUEUE_printn (QUEUE *Q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ", Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+}
+void QUEUE_perm_printn (QUEUE *Q, QUEUE_ID *q){
+ QUEUE_ID i;
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ",q[Q->v[i]]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+}
+void QUEUE_print_ (QUEUE *Q){
+ QUEUE_ID i;
+ printf("s="QUEUE_IDF",t="QUEUE_INTF": ", Q->s, Q->t);
+ for ( i=Q->s ; i!=Q->t ; ){
+ printf (QUEUE_INTF" ",Q->v[i]);
+ QUEUE_INCREMENT(*Q,i);
+ }
+ printf ("\n");
+}
+
+void QUEUE_print__ (QUEUE *Q){
+ QUEUE_ID i;
+ printf("s="QUEUE_IDF",t="QUEUE_IDF": ", Q->s, Q->t);
+ for ( i=Q->s ; i!=Q->t ; i++ ) printf (QUEUE_INTF" ",Q->v[i]);
+ printf ("\n");
+}
+
+#endif
--- /dev/null
+/* Library of queue: spped priority implementation
+ 12/Apr/2001 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _queue_h_
+#define _queue_h_
+
+#include"stdlib2.h"
+
+#ifndef QUEUE_INT
+ #ifdef QUEUE_INT_LONG
+ #define QUEUE_INT LONG // define the type before if change is needed
+ #define QUEUE_INTHUGE LONGHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_INTF "%lld"
+ #else
+ #define QUEUE_INT int // define the type before if change is needed
+ #define QUEUE_INTHUGE INTHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_INTF "%d"
+ #endif
+#endif
+
+#ifndef QUEUE_ID
+ #ifdef QUEUE_ID_LONG
+ #define QUEUE_ID LONG // define the type before if change is needed
+ #define QUEUE_IDHUGE LONGHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_IDF "%lld"
+ #else
+ #define QUEUE_ID int // define the type before if change is needed
+ #define QUEUE_IDHUGE INTHUGE // comment out if QUEUE_INT is "short"
+ #define QUEUE_IDF "%d"
+ #endif
+#endif
+#define SWAP_QUEUE_INT(a,b) (common_QUEUE_INT=a,a=b,b=common_QUEUE_INT)
+#define SWAP_QUEUE_ID(a,b) (common_QUEUE_ID=a,a=b,b=common_QUEUE_ID)
+
+typedef struct {
+ unsigned char type; // type of the structure
+ QUEUE_INT *v; // pointer to the array
+ QUEUE_ID end; // the length of the array
+ QUEUE_ID t; // end position+1
+ QUEUE_ID s; // start position
+} QUEUE;
+
+/* QUEUE stores at most end-1 elements. Overflow occurs after inserting end-1 elements */
+
+#define QUEUE_INCREMENT(Q,i) ((i)=((i)>=(Q).end-1)?0:(i)+1)
+#define QUEUE_DECREMENT(Q,i) ((i)=(i)==0?(Q).end-1:(i)-1)
+#define QUEUE_LENGTH(Q) (((Q).t-(Q).s+(Q).end)%(Q).end)
+#define QUEUE_LENGTH_(Q) ((Q).t-(Q).s)
+
+/* macro for loop w.r.t., QUEUE */
+#define QUEUE_F_LOOP(Q,i) for((i)=(Q).s;(i)!=(Q).t;((i)=((i)>=(Q).end-1)?0:(i)+1))
+#define QUEUE_F_LOOP_(Q,i) for((i)=(Q).s;(i)<(Q).t;(i)++)
+#define QUEUE_FE_LOOP(Q,i,x) for((i)=(Q).s,x=(Q).v[i];(i)!=(Q).t;((i)=((i)>=(Q).end-1)?0:(i)+1),x=(Q).v[i])
+#define QUEUE_FE_LOOP_(Q,i,x) for((i)=(Q).s,x=(Q).v[i];(i)<(Q).t;(i)++,x=(Q).v[i])
+#define QUEUE_B_LOOP(Q,i) for((i)=(Q).t==0?(Q).end-1:(Q).t-1;(i)!=(Q).s;(i)=(i)==0?(Q).end-1:(i)-1)
+#define QUEUE_B_LOOP_(Q,i) for((i)=(Q).t-1;(i)>=(Q).s;(i)--)
+#define QUEUE_BE_LOOP(Q,i,x) for((i)=(Q).t==0?(Q).end-1:(Q).t-1,x=(Q).v[i];(i)!=(Q).s;(i)=(i)==0?(Q).end-1:(i)-1,x=(Q).v[i])
+#define QUEUE_BE_LOOP_(Q,i,x) for((i)=(Q).t-1;((i)>=(Q).s)?((x=(Q).v[i])||1):0;(i)--)
+
+#define QUEUE_RMALL(Q) ((Q).t=(Q).s)
+#define QUEUE_RMALL_(Q) ((Q).t=0)
+#define QUEUE_HEAD(Q) ((Q).v[(Q).s])
+#define QUEUE_TAIL_(Q) ((Q).v[(Q).t-1])
+
+extern QUEUE INIT_QUEUE;
+extern QUEUE_INT common_QUEUE_INT, *common_QUEUE_INTp;
+QSORT_TYPE_HEADER(QUEUE_INT, QUEUE_INT)
+QSORT_TYPE_HEADER(QUEUE_ID, QUEUE_ID)
+
+
+/* initialization, not fill the memory by 0 */
+void QUEUE_alloc (QUEUE *Q, QUEUE_ID siz);
+
+/* termination processing */
+void QUEUE_end (QUEUE *Q);
+
+/* delivery: transpose that matrinx (transaction database) Q. Each row of the
+ transposed matrix is called occurrence.
+
+variables to be set.
+OQ:array for occurrences, c: for counting frequency, jump: list of items with non-empty OQ
+if c!=NULL, count the frequency and set to c, and set occurrences to OQ, otherwise.
+if jump==NULL, then the list of non-empty item will not be generated
+Q:matrix, of an array of QUEUE, occ: list of rows of Q to be scaned, t; maximum ID of the
+ row to be scaned; if occ==NULL, occ will be ignored, otherwise t will be ignored.
+ M: end mark of each QUEUE. */
+void QUEUE_delivery(QUEUE *OQ, VEC_ID *c, QUEUE *jump, QUEUE *Q, QUEUE *occ, VEC_ID t, QUEUE_INT M);
+/* sort a QUEUE with WEIGHT, with already allocated memory (size have to no less than the size of QUEUE) */
+void QUEUE_perm_WEIGHT (QUEUE *Q, WEIGHT *w, PERM *invperm, int flag);
+
+/* remove (or unify) the consecutive same ID's in a QUEUE (duplication delete, if sorted) */
+void QUEUE_rm_dup_WEIGHT (QUEUE *Q, WEIGHT *w);
+
+/***********************************************************************/
+/* duplicate occ's in jump, ( copy occ's to allocated QUEUE array) */
+/* Q[i].end := original item, clear each original occ */
+/* buffer size is multiplied by u */
+/*******************************************************/
+
+
+void QUEUE_occ_dup (QUEUE *jump, QUEUE **QQ, QUEUE *Q, WEIGHT **ww, WEIGHT *w, WEIGHT **ppw, WEIGHT *pw, int u);
+
+/* return the position of the first element having value e. return -1 if no such element exists */
+LONG QUEUE_ele (QUEUE *Q, QUEUE_INT e);
+
+/* insert an element to the tail/head */
+void QUEUE_ins_ (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins_head_ (QUEUE *Q, QUEUE_INT e);
+void QUEUE_ins_head (QUEUE *Q, QUEUE_INT e);
+
+/* extract an element from the head/tail, without checking the underflow */
+QUEUE_INT QUEUE_ext_ (QUEUE *Q);
+QUEUE_INT QUEUE_ext (QUEUE *Q);
+QUEUE_INT QUEUE_ext_tail_ (QUEUE *Q);
+QUEUE_INT QUEUE_ext_tail (QUEUE *Q);
+
+/* remove the j-th element and replace it by the tail/head or shift */
+void QUEUE_rm_ (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm_head_ (QUEUE *Q, QUEUE_ID j);
+void QUEUE_rm_head (QUEUE *Q, QUEUE_ID j);
+int QUEUE_rm_ele_ (QUEUE *Q, QUEUE_INT e);
+
+/* Append Q2 to the tail of Q1. Q2 will (not) be deleted */
+void QUEUE_append_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_append (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_concat_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_concat (QUEUE *Q1, QUEUE *Q2);
+
+/* Append from j to jj th elements to the tail of Q1. Q2 will not be deleted */
+void QUEUE_subconcat_ (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj);
+void QUEUE_subconcat (QUEUE *Q1, QUEUE *Q2, QUEUE_ID j, QUEUE_ID jj);
+
+/* initialize Q1 by length of Q2, and copy Q2 to Q1 */
+void QUEUE_store_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_store (QUEUE *Q1, QUEUE *Q2);
+/* copy Q2 to Q1 and delete Q2 */
+void QUEUE_restore_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_restore (QUEUE *Q1, QUEUE *Q2);
+
+/* copy Q2 to Q1 */
+void QUEUE_cpy_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_cpy (QUEUE *Q1, QUEUE *Q2);
+QUEUE QUEUE_dup_ (QUEUE *Q);
+/* copy l elements of Q2 starting from s2 to the s1th position of Q1.
+ size of Q1 is not increasing */
+void QUEUE_subcpy_ (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l);
+void QUEUE_subcpy (QUEUE *Q1, QUEUE_ID s1, QUEUE *Q2, QUEUE_ID s2, QUEUE_ID l);
+
+/* merge/minum/intersection of Q1 and Q2, and set Q1 to it.
+ Both Q1 and Q2 have to be sorted in increasing order */
+void QUEUE_merge_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_merge (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_minus_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_minus (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_and_ (QUEUE *Q1, QUEUE *Q2);
+void QUEUE_and (QUEUE *Q1, QUEUE *Q2);
+
+/* insertion sort */
+void QUEUE_sort (QUEUE *Q);
+
+ /* print */
+void QUEUE_print (QUEUE *Q);
+void QUEUE_print_ (QUEUE *Q);
+
+
+#endif
--- /dev/null
+######################################################################\r
+LCM: Linear time Closed itemset Minor\r
+ Coded by Takeaki Uno, e-mail:uno@nii.jp, \r
+ homepage: http://research.nii.ac.jp/~uno/index.html\r
+######################################################################\r
+\r
+** This program is available for only academic use, basically. **\r
+** Anyone can modify this program, but he/she has to write down **\r
+** the change of the modification on the top of the source code. **\r
+** Neither contact nor appointment to Takeaki Uno is needed. **\r
+** If one wants to re-distribute this code, do not forget to **\r
+** refer the newest code, and show the link to homepage **\r
+** of Takeaki Uno, to notify the news about codes for the users. **\r
+** For the commercial use, please make a contact to Takeaki Uno. **\r
+\r
+1. Problem Definition\r
+2. Usage\r
+3. Input File Format\r
+4. Use General Names for Variables and Other Formats\r
+5. Batch Files for Simple use\r
+6. Output Format\r
+7. Performance\r
+8. Algorithms and Implementation Issue\r
+9. Introductions to Frequent Itemset Mining\r
+10. Acknowledgments \r
+11. References\r
+\r
+################################\r
+#### Problem Definition ####\r
+################################\r
+\r
+Let I be a set of items. An itemset is a subset of I. Let D be a transaction \r
+database such that each record (called transaction) is an itemset. Frequency\r
+of an itemset is the number of transactions including the itemset. For a\r
+given number t (called support), an itemset is said to be frequent\r
+if its frequency is no less than t. A frequent itemset is called maximal\r
+if it is included in no other frequent itemset, and called closed if it\r
+is included in no other itemset of the same frequency. The task of\r
+this program, LCM, is to enumerate (output, or count) all frequent\r
+itemsets, all maximal frequent itemsets, or all frequent closed itemsets\r
+in a given transaction database for given a support.\r
+\r
+\r
+\r
+#####################\r
+#### Usage ####\r
+#####################\r
+\r
+ ==== How to Compile ====\r
+\r
+Unzip the file into arbitrary directory, and execute "make".\r
+Then you can see "lcm" (or lcm.exe) in the same directory.\r
+In the case of ver. 2xx and 3, you see fim_all, fim_closed, and fim_maximal.\r
+\r
+\r
+ ==== Command Line Options for ver.2xx and ver.3 ====\r
+\r
+The parameter format follows the FIMI implementations.\r
+(http://fimi.cs.helsinki.fi/) \r
+To enumerate frequent itemsets, execute fim_all. For frequent closed itemsets, \r
+execute fim_closed, and for maximal frequent itemsets, execute fim_maximal.\r
+The first parameter is the input file name, the second is minimum support, \r
+and the third is the output file name. We can omit the third parameter, \r
+then no output file will be generated, and the program counts the number of \r
+solutions.\r
+\r
+Example)\r
+% fim_closed input-filename support [output-filename]\r
+\r
+\r
+ ==== Command Line Options for ver.4, and ver.5 ====\r
+\r
+To execute LCM, just type lcm and give some parameters as follows.\r
+\r
+% lcm FCMfQIVq [options] input-filename support [output-filename]\r
+\r
+"%" is not needed to type. It is a symbol to represent command line.\r
+To see a simple explanation, just execute "lcm" without parameters.\r
+\r
+"input-filename" is the filename of the input transaction database.\r
+The 1st letter of input-filename must not be '-'. Otherwise it is \r
+regarded as an option. The input file format is written below. "support"\r
+is the support, which is for given the threshold of frequency.\r
+"output-filename" is the name of file to write the itemsets the program\r
+finds. You can omit the output file to see only the number of frequent\r
+itemsets in the database.\r
+\r
+The first parameter is given to the program to indicate the task.\r
+ F: enumerate frequent itemsets,\r
+ C: enumerate closed frequent itemsets\r
+ M: enumerate maximal frequent itemsets\r
+\r
+For example, if you want to enumerate maximal frequent itemset, type \r
+"M" in the first parameter. Additionally, we can give the following\r
+commands, to specify the output style: \r
+\r
+ q: no output to standard output (including messages w.r.t. input data)\r
+ i: do not output itemset to the output file (only rules are written)\r
+ f: output the frequency on the end of each itemset found,\r
+ Q: output the frequency on the head of each itemset found,\r
+ A: output positive/negative frequency, and (frequency)/(absolute\r
+ frequency); positive/negative frequency is the sum of weights of\r
+ the occurrence which have positive/negative weights, respectively.\r
+ Absolute frequency is the sum of absolute value of the weights of \r
+ the occurrences.\r
+ s: output confidence and item frequency by absolute values; in default, \r
+ they are written by ratio, but by this command they are written by \r
+ #transactions/sum of the transaction weights\r
+ I: output ID's of transactions including each itemset; ID of a\r
+ transaction is given by the number of line in which the transaction\r
+ is written. The ID starts from 0.\r
+ V: show the progress of computation\r
+ t: transpose the database so that item i will be transaction i, thus\r
+ if item i is included in j-th transaction, then item j will be\r
+ included in i-th transaction.\r
+\r
+The output format is explained below. The following options are to\r
+restrict the itemset to be found. We can type them between the first \r
+parameter and the second parameter. Of course the option can be nothing.\r
+\r
+ -l,-u [num]: enumerate itemsets with size at least/most [num] \r
+ -U [num]: enumerate itemsets with frequency at most [num]\r
+ -w [filename]: read weights of transactions from the file (ver. 4 and 5)\r
+ the frequency of itemset will be the sum of weights of the transactions\r
+ which include the itemset.\r
+ -c [filename]: read constraints graph between items (ver. 5.2)\r
+ -C [filename]: read un-constraint graph between items (ver. 5.2)\r
+\r
+Following options are only for ver. 5.x.\r
+\r
+ -m,-M [filename]:read/write item permutation from/to file [filename]\r
+ -K [num]: output the frequency of [num]-th largest frequent(closed/maximal)\r
+ itemsets (only for ver.5). Notice that it outputs only the frequency,\r
+ thus no itemset will be output\r
+ -S [num]: stop after outputting [num] solutions\r
+ -f,-F [ratio]: output itemsets with frequency [ratio] times smaller/larger\r
+ than that in the case of independence; let p be the product of \r
+ (frequency of i)/(#transactions) for all item i in the itemset.\r
+ -i [num]: find association rule for item [num]; output all rules of the form\r
+ {1,3,5} => [num]. The criteria to output a rule can be given by other\r
+ options.\r
+ -a,-A [ratio]: find association rules of confidence at least [ratio]; an\r
+ association rule of {1,3,5} => 2 will be output if the frequency of\r
+ {1,3,5,2} is no less/no more than the frequency of {1,3,5} times [ratio].\r
+ -r,-R [ratio]: find association rules of relational confidence at least\r
+ [ratio]; an association rule of {1,3,5} => 2 will be output if the\r
+ frequency of {1,3,5,2} is no less/no more than the frequency of {1,3,5}\r
+ times (frequency of {2}/(#transactions in the database)) times [ratio].\r
+ -p,-P [num]: output pattern itemset only if (frequency) / (abusolute\r
+ frequency) is no less/no greater than [num]. Absolute frequency is the\r
+ sum of absolute weights of the occurrences of the pattern itemset.\r
+ -n,-N [num]: output pattern itemset only if its negative frequency is\r
+ no less/no greater than [num]. Negative frequency is the sum of\r
+ weights of the occurrences which have negative weights\r
+ -o,-O [num]: output pattern itemset only if its positive frequency is\r
+ no less/no greater than [num]. Positive frequency is the sum of\r
+ weights of the occurrences which have positive weights\r
+\r
+-l, -u, and -U specify the upper/lower bound for itemset/frequency.\r
+itemsets exceed the upper/lower bound will be not output.\r
+When we give -S option and a number X, the program will terminate\r
+if it finds X solutions, even if there are more solutions.\r
+\r
+If we specify "-w" and filename, then LCM reads the file as a weight \r
+database of transactions. Each i-th line of the file is regarded as\r
+the weight of i-th transaction. With transaction weights, LCM finds\r
+the itemsets such that the sum of weights of the transaction including\r
+the itemset is no less than the support. The weights can be real numbers.\r
+For version 5, we can give negative weights.\r
+\r
+"-c" and "-C" options (only for ver 5): "-c" option is for giving item\r
+constraints. An item constraint is given between two items which can not\r
+be included in frequent itemsets together with. In the other words, if\r
+an item constraint is given for items 1 and 2, then {1,2} can not be\r
+included in any frequent itemset. The set of item constraints forms an\r
+undirected graph. Thus, LCM inputs item constraints by a graph. The\r
+filename following to "-c" is regarded as a graph file. The format of the\r
+graph file is written below. Conversely, "-C" option is for giving\r
+"un-constraint" item pairs. In precise, when we give "-C" option, \r
+the item constraint between items 1 and 2 means that {1,2} can be included \r
+in frequent itemsets. That is, if no item constraint is given for \r
+items 1 and 2, the pair {1,2} can not be included in any frequent itemset.\r
+The un-constraints of "-C" option are also given by graph, of the same\r
+format to "-c" option.\r
+\r
+If we specify "-w" and filename, then LCM reads the file as a weight \r
+database of transactions. Each i-th line of the file is regarded as\r
+the weight of i-th transaction. With transaction weights, LCM finds\r
+the itemsets such that the sum of weights of the transaction including\r
+the itemset is no less than the support. The weights can be real numbers.\r
+For version 5, we can give minus weights.\r
+\r
+When we give -K option, LCM computes the frequency of the [num]-th largest\r
+frequent(closed/maximal) itemsets, and output it to the standard output\r
+(print it to the command line). By giving the output frequency to LCM, \r
+we can enumerate top-[num] frequent itemsets (closed, or maximal).\r
+\r
+\r
+Examples)\r
+\r
+- To find all frequent itemsets in "test.dat" for support 4, and size of\r
+ no less than 3. Output frequencies of each itemsets found. Do not output \r
+ to file. Show progress, and stop if 1,000,000 solutions will be found.\r
+\r
+% lcm FfV -l 3 -S 1000000 test.dat 4\r
+\r
+- To find closed itemsets in "test.dat" with frequency at least 6, and\r
+ sizes from 5 to 10. Output itemsets to "out.dat".\r
+\r
+% lcm C -l 5 -u 10 test.dat 6 out.dat\r
+\r
+- To find maximal frequent itemsets in "test.dat" with weight file\r
+ "weight.dat" with frequency at least 8, output to "out.dat" with\r
+ transaction IDs, and no output for standard output.\r
+ \r
+% lcm MqI -w weight.dat test.dat 8 out.dat\r
+\r
+- To specify item constraint file g.grh, for "test.dat" with frequency\r
+ at least 3, and output out.dat.\r
+\r
+% lcm F -c g.grh test.dat 8 out.dat\r
+\r
+When -m,-M [filename] options are given, LCM reads/writes item permutation\r
+from/to the file of [filename]. LCM internally permute the items for the \r
+efficient computation, and this option is to enforce the permutation to\r
+a specified one, or to know the permutation. The file format is just a list\r
+of indices, for example, if 0,1,2,3 will be 2,1,0,3 then the file is \r
+\r
+2\r
+1\r
+0\r
+3\r
+[EOF]\r
+For the items whose permutation is not written in the file, LCM determine\r
+its internal indices.\r
+\r
+-f and -F options are for finding itemsets with high relational frequency.\r
+For each item i, let us consider (frequency of {i}) / (#transactions in D)\r
+as the appearance probability that item i is included in a transaction.\r
+If the appearance probability of each item is independent to each other,\r
+the frequency of an itemset S is expected to be the product of these\r
+appearance probabilities of its items times (#transactions in D). We here\r
+define the relational frequency of S by\r
+(frequency of S) / (expected frequency of S).\r
+When we give -f [num] option, LCM outputs frequent itemsets with relational \r
+frequency no less than [num]. Similarly, frequent itemsets with relational \r
+frequency no greater than [num] is output when -F [num] option is given.\r
+\r
+The remaining options are for the association rule mining. An association\r
+rule is a pair of an itemset S and an item x with the form "S => x".\r
+The confidence of the rule is the ratio of transactions including x,\r
+in the set of transactions including S. If the confidence is high, \r
+we can say that a transaction including S may include x with high\r
+probability. The remaining options are for enumerating all such association\r
+rules with higher or lower confidence \r
+\r
+-a [ratio] and -A [ratio] options are for specifying the threshold value \r
+for the confidence. When -a option and [ratio] are given, LCM finds all \r
+association rules with confidence at least [ratio]. Conversely, association\r
+rules with confidence at most [ratio] are found when we give -A option.\r
+\r
+-r [ratio] and -R [ratio] options are also for specifying the threshold, but\r
+the threshold values changes according to the frequency of each item.\r
+Precisely, when we give -R and [ratio], an association rule S => x is\r
+output if its confidence is no greater than\r
+ [ratio] * (frequency of {x}/#transactions),\r
+thus it is output only if the confidence is small compared to the frequency\r
+of x in the database. Conversely, when we give -r and [ratio], an association\r
+rule S => x is output if (1 - its confidence) is no greater than [ratio] *\r
+(1- frequency of {x}).\r
+\r
+When -i [num] option is given, LCM finds only the rules of the form\r
+ S => [num] ([num] is an item).\r
+\r
+The following options are valid only when some transactions have negative\r
+weights. -p,-P [num] options restrict the output pattern itemsets\r
+to those satisfy (frequency) / (abusolute frequency) is no less/no greater\r
+than [num]. Here, absolute frequency is the sum of absolute weights of \r
+the occurrences of the pattern itemset.\r
+\r
+-n,-N [num] options give bound for negative weights. If these options are\r
+given, LCMseq outputs a pattern itemset only if its negative frequency\r
+is no less/no greater than [num]. Here negative frequency is the sum of\r
+weights of the occurrences which have negative weights.\r
+\r
+Similarly, -o,-O [num] options let the LCMseq output a pattern itemset\r
+only if its positive frequency is no less/no greater than [num].\r
+Positive frequency is the sum of weights of the occurrences which have\r
+positive weights.\r
+\r
+\r
+Examples)\r
+- To find all association rule "A => b" such that frequency of A is no less \r
+than 200, and the confidence is no less than 0.9. The input file is\r
+ "test.dat" and the output file is "out".\r
+\r
+% lcm C -a 0.9 test.dat 200 out\r
+\r
+- To find all association rule "A => b" such that frequency of A is no less \r
+than 200, and the confidence is no greater than\r
+ 0.1 * (frequency of {x}/#transactions). The item b is specified as item 5.\r
+The input file is "test.dat" and the output file is "out".\r
+\r
+% lcm C -R 0.1 -i 5 test.dat 200 out\r
+\r
+\r
+###############################\r
+#### Input File Format ####\r
+###############################\r
+\r
+Each line (row) of the input file is a transaction. The items included in \r
+a transaction are listed in a line. The items must be numbers begin from 1.\r
+They can not be minus. The item numbers do not have to be continuous, but\r
+notice that the program takes memory linear in the maximum item number.\r
+The separator of numbers can be any non-numeric letter, such as \r
+"," " " ":" "a", etc.\r
+\r
+Example) ( "[EOF]" is the end of file )\r
+0 1 2\r
+1\r
+2 3 4\r
+4,1 2 3\r
+2,1\r
+[EOF]\r
+\r
+The file format of item constraints (or complement) graphs is as follows.\r
+The ith row (line) of the file corresponds to node i-1. The first line\r
+corresponds to the node 0, and the 10th line corresponds to node 9. The\r
+node larger than i-1 and adjacent to i-1 is listed in the i-th line.\r
+The nodes are written by numbers. Separator to the number can be ",",\r
+but the graph load routine accepts any letter for the separator but\r
+not a number, +, and -. If the edge set is {(0,1),(0,2),(1,1),(1,3),(2,3)},\r
+the file will be \r
+===========\r
+ 1,2\r
+ 1 3\r
+ 3\r
+ \r
+ [EOF]\r
+=========\r
+where "[EOF]" is a symbol for the end of file.\r
+\r
+\r
+#################################################################\r
+#### Use General Names for Variables and Other Formats ####\r
+#################################################################\r
+\r
+We can transform variable names in general strings to numbers so that we\r
+can input the data to the program, by some script files. \r
+\r
+-- sortout < input-file > output-file\r
+Sort the file in the lexicographical order. It is used to sort the output file.\r
+\r
+-- transnum.pl table-file [separator] < input-file > output-file\r
+Read file from standard input, and give a unique number to each name written\r
+by general strings (such as ABC, ttt), and transform every string name to \r
+a number, and output it to standard output. The mapping from string names to\r
+numbers is output to table-file. The default character for the separator of \r
+the string names is " "(space). It can be changed by giving a character for\r
+the option [separator]. For example, A,B is a string name, if the separator \r
+is space, but if we set the separator to ",", it is regarded as two names \r
+A and B. This is executed by "transnum.pl table-file "," < input-file...".\r
+\r
+-- untransnum.pl table-file < input-file > output-file\r
+According to the table-file output by transnum.pl, un-transform numbers to \r
+string names. The output of the program is composed of numbers, thus \r
+it is used if we want to transform to the original string names.\r
+It reads file from standard output, and output to the standard output.\r
+\r
+-- appendnum.pl < input-file > output-file\r
+When we want to distinct the same words in different columns, use this \r
+script. This append column number to each words, so we can distinct them.\r
+Then, by using transnum.pl, we transform the strings to numbers.\r
+\r
+-- transpose.pl < input-file > output-file\r
+Transpose the file. In the other words, consider the file as an adjacency\r
+matrix, and output the transposed matrix, or exchange the positions of\r
+items and transactions. For an input file, output the file in which \r
+the i-th line corresponds to item i, and includes the numbers j\r
+such that i is included in the j-th line of the input file.\r
+\r
+-- 01conv.pl [separator] < input-file > output-file\r
+Transform the transaction database written in the style of 01 matrix\r
+to our input style. The file has to be a list of 0 and 1, separated by\r
+[separator]. If [separator] is omitted, the default separator " " is \r
+used.\r
+\r
+\r
+#########################################\r
+#### Batch Files for Simple use ####\r
+#########################################\r
+\r
+For general string names, we have several batch files scripts for basic usages\r
+"exec_lcm", "exec_lcm_", "sep_lcm", or "sep_lcm_". For example, when a database\r
+with "general item names" is, \r
+\r
+dog pig cat\r
+cat mouse\r
+cat mouse dog pig\r
+cow horse\r
+horse mouse dog\r
+[EOF]\r
+\r
+All these replace strings in the input database by numbers, execute LCM,\r
+and replace the numbers in the output file by the original strings.\r
+The usage of the scripts are\r
+\r
+% exec_lcm [FCMfQIVq] input-filename support output-filename [options]\r
+\r
+You have to specify F, C or M, and output filename. The separator of the\r
+items is " " (blank, space). If you want to use other character as a\r
+separator, use "sep_lcm". The usage is \r
+\r
+% sep_lcm separator [FCMfQIVq] input-filename support output-filename [options]\r
+\r
+Almost same as "exec_lcm" but you have to specify separator at the fourth \r
+parameter. "exec_lcm_" and "sep_lcm_" are both for the aim to distinct \r
+the same items in the different columns. For example, it is used to the\r
+database such that different items are there in different columns, but \r
+some special symbols, such as "- is for missing data", are used commonly.\r
+An example is;\r
+\r
+A true small\r
+- true big\r
+- false middle\r
+B - -\r
+C - middle\r
+A true -\r
+[EOF]\r
+\r
+In the output file, the items are followed by "." and numbers where \r
+the numbers are the column number. For example, "dog.0" means the item\r
+"dog" on the 0th(first) column.\r
+\r
+The usage of them are the same as "exec_lcm" and "sep_lcm", respectively.\r
+All these scripts use files of the names "__tmp1__", "__tmp2__", and\r
+"__tmp3__". The files of these names will be deleted after the execution.\r
+\r
+Example)\r
+\r
+% exec_lcm F test2.dat 10 out.dat -w weight.dat -l 2\r
+\r
+% sep_lcm_ "," C test3.dat 3 out.dat -U 5\r
+\r
+\r
+#############################\r
+#### Output Format ####\r
+#############################\r
+\r
+When the program is executed, the program prints out the #items,\r
+#transactions, and other features of the input database to standard\r
+error. After the termination of the enumeration, it outputs the total\r
+number of itemsets found (frequent/closed/maximal itemsets), and the \r
+numbers of itemsets of each size. For example, if there are 4 frequent\r
+itemsets of size 1, 2 frequent itemsets of size 3, and 1 frequent itemset\r
+of size 3, then the output to standard output will be,\r
+\r
+9 <= total #frequent itemsets\r
+1 <= #frequent itemsets of size 0 (empty set), it is always frequent\r
+4 <= #frequent itemsets of size 1\r
+3 <= #frequent itemsets of size 2\r
+1 <= #frequent itemsets of size 3\r
+\r
+If "q" is given in the first parameter, these do not appear in the\r
+standard output.\r
+\r
+If output-filename was given, then the itemsets found are written to \r
+the output file. Each line of the output file is the list of items \r
+included in an itemset found, separated by " ". If "f" is given in \r
+the first parameter, the frequency follows each itemset, for example,\r
+\r
+1 5 10 2 4 (22)\r
+\r
+which means itemset {1,2,4,5,10} is included in 22 transactions. When "Q"\r
+option is given, the output will be \r
+\r
+(22) 1 5 10 2 4\r
+\r
+The output itemsets are not sorted. If you want to sort it, use the script\r
+"sortout.pl". The usage is just,\r
+\r
+% sortout.pl < input-file > output-file\r
+\r
+"input-file" is the name of file to which LCM outputs, and the sorted output\r
+will be written in the file of the name "output-file".\r
+The items of each itemset will be sorted in the increasing order of\r
+items, and all the itemsets (lines) will be also sorted, by the\r
+lexicographical order (considered as a string).\r
+(Actually, you can specify separator like sortout.pl ",").\r
+\r
+An association rule S => x, for example {1,2,3} => 5 is output in the form \r
+\r
+[xxx yyy] 5 <= 1 2 3\r
+\r
+where xxx is the confidence of the rule, and yyy is\r
+ (frequency of y)/#transactions in D.\r
+\r
+\r
+###########################\r
+#### Performance #### \r
+###########################\r
+\r
+The performance of LCM is stable, for both computation time and memory use.\r
+The initialization and preprocess time of LCM is linear in the size of \r
+input database. The computation time for finding frequent itemsets depends\r
+on the number of itemsets found, and the minimum support.\r
+When the minimum support is large and the number of the itemsets found is\r
+small, the computation time for each itemset is relatively large. However, \r
+computation time per itemset decreases as the increase of the itemsets found,\r
+and roughly speaking when the size of output file is equal to the input\r
+database size, it will be constant, such as 1/1,000,000 sec (by PC with \r
+CPU of 2GHz.)\r
+\r
+Memory usage of LCM is very stable. It is an advantage compared to other \r
+implementations. The memory usage of LCM is always linear in the size of\r
+the input database. Approximately LCM uses integers at most three times\r
+as much as the database size, which is the sum of the number of items of\r
+each transaction. The memory usage of the other implementations increases \r
+as the increase of the number of frequent itemsets, but that of LCM does not.\r
+\r
+\r
+######################################\r
+#### Solving Other Problems ####\r
+######################################\r
+\r
+- Enumerating Maximal Bipartite Cliques in a Bipartite Graph -\r
+\r
+Enumerating all maximal bipartite cliques in a bipartite graph is\r
+equivalent to enumerating all closed itemsets. LCM can be used for\r
+this task. For a bipartite graph of two vertex sets A and B, construct\r
+the database such that each line is the list of vertices incident to\r
+a vertex in A. Then, by executing \r
+\r
+% lcm CI input-filename 1 output-filename\r
+\r
+you can enumerate maximal bipartite cliques.\r
+\r
+\r
+- Enumerating Maximal Bipartite Cliques in a Graph -\r
+\r
+By transforming the graph, we can enumerate bipartite cliques in graphs.\r
+For a given G=(V,E), we construct a graph G'=(V+V', E') where V' is a \r
+copy of V. If an edge (v,u) is in E, then, in E', vertex v of V and \r
+vertex u in V' are connected by an edge, and vertex u of V and vertex \r
+v in V' are connected by an edge. Then, G' is a bipartite graph, and \r
+a bipartite clique in G' is a bipartite clique in G, and vice versa.\r
+Thus, giving G' to LCM, we can enumerate all maximal bipartite cliques\r
+in general graphs.\r
+\r
+\r
+- Enumerating Maximal Directed Bipartite Cliques in a directed Graph -\r
+\r
+For a directed graph G=(V,A), a directed bipartite clique is vertex sets\r
+B and C such that for any pair of a vertex b in B and c in C, there is \r
+an arc from b to c. In a similar way to the above, we construct a \r
+directed graph G'=(V+V', A') where V' is a copy of V. If an arc (v,u) is\r
+in A, then, in A', there is an edge connecting vertex v of V and vertex u\r
+in V' in A'. Then, G' is a bipartite graph, and a bipartite clique in G' \r
+is a directed bipartite clique in G, and vice versa. Thus, giving G' to LCM,\r
+we can enumerate all maximal bipartite cliques in general graphs.\r
+\r
+\r
+- Finding Pairs of Transactions Having Large Intersection -\r
+\r
+Suppose that we want to see which pair of transactions having many common \r
+items, i.e., for a threshold t, we want to find all pairs of transactions\r
+A and B such that at least t items are included in both A and B.\r
+For the sake, execute lcm with -l 2 and -u 2, for example,\r
+\r
+lcm F -l 2 -u 2 test.dat 20\r
+\r
+then we can find all pairs of transactions having at least 20 common items.\r
+\r
+\r
+- Mining "itemset" sets.\r
+Consider a data base each whose record is a set of itemset (transaction\r
+database). a set S of itemsets is included in a record R if and only if \r
+each itemset of S is included in some itemset in R. Note that an itemset\r
+of R may include more than one itemsets of S. Here the problem is to enumerate\r
+all sets of itemsets included in no less than theta records of the given\r
+database. When we give a restriction of the size of itemsets in a pattern S\r
+to be enumerated, say at most some small k, we can tract the problem by\r
+using LCM. Transform each record of the database to an itemset by\r
+\r
+ listing all the itemsets included in at least one itemsets in the record,\r
+ and regarding each itemset listed as an item.\r
+\r
+For example, an itemset {A,B,C} is considered as an item "{A,B,C}".\r
+A frequent itemset in the database obtained corresponds to a frequent \r
+set of itemsets. They correspond to each other one-to-one. Moreover, \r
+by enumerating closed itemsets, we can ignore unnecessary patterns\r
+automatically. If a frequent itemset includes a item {A,B,C}, corresponding\r
+to an itemset {A,B,C} in the original problem, then without changing the\r
+frequency we can add any item corresponding to a subset of {A,B,C} to the\r
+itemset. A closed itemset always includes such subsets, thus a closed \r
+itemset is given by a set of itemsets such that any two itemsets does \r
+not satisfy the inclusion relation. Thus, we can discard unnecessary \r
+patterns automatically.\r
+\r
+\r
+########################################################\r
+#### Introductions to Frequent Itemset Mining ####\r
+########################################################\r
+\r
+Let D be a database such that each record is transaction data. Here\r
+transaction data is a set of items. Thus, the database is a set of\r
+subsets of items. Such a database is called a "transaction database".\r
+\r
+For example, let us see the following database of\r
+transactions:\r
+\r
+ transaction A: 1,2,5,6,7\r
+ transaction B: 2,3,4,5\r
+ transaction C: 1,2,7,8,9\r
+ transaction D: 1,7,9\r
+ transaction E: 2,7,9\r
+ transaction E: 2,7,9\r
+ transaction F: 2\r
+\r
+Transaction A is a set of items 1, 2, 5, 6, and 7, and the\r
+others are so on. Now we consider a problem of finding sets of items\r
+which are included in many transactions, since such sets give some\r
+interesting structures of the database. Since "many transactions" is\r
+not well-defined, we introduce a number called "minimum support" or simply\r
+"support", and consider that itemsets included in at least "minimum support"\r
+transactions are included in many transactions. We call such itemsets \r
+"frequent itemsets", and the number of transactions including an itemset \r
+"frequency" of the itemset. For the above transaction database, by setting\r
+minimum support to 3, frequent itemsets are\r
+\r
+ {}, {1}, {2}, {7}, {9}, {1,7}, {1,9}, {2,7}, {2,9}, {7,9}, and {2,7,9}.\r
+ \r
+Note that the first itemset is the empty set, and it is considered as a \r
+frequent itemset. If the support is large, #frequent itemsets is small.\r
+The number of frequent itemsets increases as the decrease of the support.\r
+\r
+A popular usage of the frequent itemset mining is to find an interesting \r
+knowledge from database. In this sense, large support usually gives trivial\r
+frequent itemset, which are not interesting. In the other hand. when we\r
+set minimum support to a small number, the number of frequent itemsets \r
+will be so huge. Dealing with a large huge of itemsets is itself a hard \r
+task. Thus, next we consider how to decrease the number of itemsets to be\r
+found, without missing interesting knowledge.\r
+\r
+One approach to this task is to find only maximal frequent itemsets, \r
+which are included in no other frequent itemset. For example, the maximal\r
+frequent itemsets in the above database are \r
+\r
+ {1,7}, {1,9}, and {2,7,9}.\r
+\r
+The idea is that any frequent itemset is included in at least one maximal\r
+frequent itemset, at least we can get the itemset from maximal frequent\r
+itemsets. However, we can not know how much frequent they are.\r
+For example, {2,7} can be obtained from {2,7,9}, but we can not know \r
+whether {2,7} is more frequent than {2,7,9} or not. In this sense we \r
+miss how much interesting each frequent itemset is.\r
+\r
+Using closed itemsets, we can avoid this problem. An itemset is closed\r
+if it is included in no other itemset of the same frequency. For example,\r
+in the above database, the closed itemsets are\r
+\r
+ {}, {2}, {2,5}, {7,9}, {1,7,9}, {2,7,9}, {1,2,7,9}, {2,3,4,5},\r
+ {1,2,7,8,9}, and {1,2,5,6,7,9}.\r
+ \r
+Closed itemset is a maximal frequent itemset if the support is \r
+equal to its frequency. Thus, the set of closed itemsets is the collection\r
+of maximal frequent itemsets for all possible supports. Any non-closed \r
+itemset is dominated by a closed itemset, thus we lose nothing about \r
+the frequency.\r
+\r
+\r
+###################################################\r
+#### Algorithms and Implementation Issue #### \r
+###################################################\r
+\r
+The basic idea of the algorithm is depth first search. Let D be a transaction\r
+database, t be the minimum support, 1,...,n be items, T1,...,Tm be the\r
+transactions in D. D(I) denotes the set of transactions including I. We denote\r
+the largest item of an itemset I by tail(I). LCM first computes the frequency of\r
+each itemset composed of one item. If an itemset {i} is frequent, then \r
+enumerate frequent itemsets obtained by adding one item to {i}. In this way,\r
+recursively, LCM enumerates all frequent itemsets. To avoid duplications,\r
+LCM adds items j to {i} only if j>i. This algorithm is written as follows:\r
+\r
+ FrequentItemsetMining (D:database, I:itemset )\r
+ Output I\r
+ For each item j > tail(I), \r
+ if (I \cup j) is frequent, then FrequentItemsetMining (D, I\cup{j})\r
+\r
+By calling FrequentItemsetMining (D, emptyset), we can enumerate \r
+all frequent itemsets. \r
+\r
+However, a straightforward implementation of this algorithm is very slow,\r
+since computing frequency of (I\cup{j}) takes long time. To be fast, we use \r
+conditional database and occurrence deliver as follows.\r
+\r
+ ==== Conditional database of itemset I ===\r
+Conditional database of itemset I, denoted by D(I), is given by the\r
+database obtained by\r
+\r
+ 1. D(I) := all transactions including I\r
+ 2. remove all unnecessary items from each transaction of D(I)\r
+ 3. merge the identical transactions into one.\r
+ (do for all such identical transactions)\r
+\r
+Here unnecessary item is an item satisfying \r
+ (a) included in less than t transactions of D(I), \r
+ (b) included in all transactions in D(I), or\r
+ (c) less than the largest item in I.\r
+Then, the frequency of itemset I plus J is the same, in D and D(I),\r
+thus LCM uses D(I) instead of D in the recursive call with respect to I.\r
+This technique is quite common in implementations of frequent itemset mining.\r
+\r
+Constructing D(I) possibly takes much memory, when the recursion is deep.\r
+Thus, LCM uses a slight modification.\r
+\r
+ 1. D(I) := IDs of all transactions including I\r
+ 2. If there are transactions T1,...,Tk become the same after deleting\r
+ unnecessary items, make a new transaction equal to it, and replace the\r
+ IDs of T1,...,Tk by the ID of new transaction\r
+\r
+After terminating the recursive call with respect to I, we delete the \r
+transactions generated in the process. By this, we can bound the memory\r
+usage for the transactions by twice the database size. From this, LCM\r
+allocates the memory in the initialization, and never do again in the\r
+main routine. Thus the memory usage is very stable, and is very fast\r
+since computation time for memory allocation is not small in the\r
+frequent itemset mining implementations.\r
+\r
+ === occurrence deliver ===\r
+Let T be a transaction database (subset family), a collection of subsets of\r
+E = {1,...,n}, and T(S) be the set of transactions (subsets) in T including \r
+a subset S.\r
+We suppose that each transaction is sorted. The occurrence deliver computes\r
+T(i) for all i>j, for a given j, in time linear in the sum of their sizes.\r
+First, for each i for which we compute T(i), we give an empty bucket. Then,\r
+for each transaction t in T, we scan it in decreasing order of items until \r
+we meet the item less than j, and for each item i>j, insert t to the bucket\r
+of i. After scanning all the transactions, the bucket of i is T(i).\r
+When we have T(S) and want to compute T(S\cup {i}) for all i>tail(S), \r
+we can do in the same way by setting T:=T(S), and j:=tail(S). For the check\r
+whether the current itemset is a maximal frequent itemset of not, we also\r
+use the occurrence deliver. If there is no item i such that S\cup {i} is\r
+frequent, then the frequent itemset S is maximal frequent itemset.\r
+\r
+ === closed itemset mining ===\r
+To enumerate closed itemsets, we use the ppc extension (prefix preserving\r
+closure extension). For an itemset P, we define P(i) by the items of P which\r
+are smaller than i. The closure C(P) of P is the closed itemset including P\r
+and having the same frequency to P. When P is a closed itemset, we define\r
+its core index, denoted by core_i(P), by the minimum item i such that\r
+C(P(i)) = P. Then, a closed itemset P' is said to be a ppc extension of P\r
+if and only if \r
+\r
+(i) P' = C(P\cup {i}) for some i>core_i(P).\r
+(ii) P(i) = P'(i).\r
+\r
+Note that P' has smaller frequency than P. It is proved that any closed\r
+itemset is a ppc extension of the other unique closed itemset.\r
+Thus, the binary relation ppc extension induces a rooted tree whose root\r
+is C(emptyset). Thus, starting from the smallest closed itemset (which\r
+is usually empty set) and find ppc extension recursively for all i, we\r
+can perform depth first search on the rooted tree. The computation of \r
+closure of P can be done by taking the intersection of transactions\r
+including P, thus it can be done by occurrence deliver, in the linear\r
+time of T(P).\r
+\r
+ ==== sweep pointer method ====\r
+Actually, we do not have to compute the intersection completely. We \r
+choose one transaction T among them, and check whether there is an item \r
+in T\setminus P which is included in all the other transactions.\r
+We trace T in the increasing order of items, and when we meet an item i\r
+in T\setminus P, we trace the other transactions from the head whether they\r
+include i or not. Notice that to check the next item j in T\setminus P,\r
+we can start the trance of the other transactions from the positions \r
+which we terminated the trace for checking i. This does not increase the \r
+computation time much since the time complexities are the same, and \r
+usually we check only few items and conclude that the itemset is not\r
+a child. Thus, we can do ppc check very quickly.\r
+\r
+ ===== bit-mask method ======\r
+Moreover, when the frequency of the itemset is small, we can use bit\r
+operations so that we can operate 32 or 64 bits at once.\r
+Suppose that the frequency frq(I) of an itemset I is less than 32.\r
+We give ID's 0,1,2,4,...,2^{frq(I)} to Occ(I), which is the set of occurrences\r
+of I. Let the bit-mask b(S) of a subset S of Occ(I) be the sum of ID's of the\r
+occurrences in S. For each item j included in at least one occurrence\r
+of I, we compute b(Occ(I\cup {j})). When we compute the closure C(I\cup {j})\r
+of I\cup {j}, an item e not in I\cup {j} is included in C(I\cup {j}) \r
+if and only if b(Occ(I\cup {e})) \cap b(Occ(I\cup {j})) = b(Occ(I\cup {j})).\r
+Here \cap means the and operation for bit string, and two numbers are \r
+regarded as bit-strings. This operation can be done in very few steps, thus\r
+we can accelerate the closure computation. If I\cup {j} is a closed itemset,\r
+we can use the bit-masks for the ppc extensions of I\cup {j}. Thus \r
+we do not have to re-compute the bit-masks in the recursive calls. In practice,\r
+the bit-mask method accelerates the speed of the algorithm 2 or 3 times when \r
+the data set is sparse and the minimum support is small, say 10.\r
+\r
+ ==== recursive pruning for closed itemset ===\r
+For the efficient computation of closed itemsets, we have one more technique.\r
+Suppose that for a closed itemset I and an item j, C(I\cup {j}) is not a ppc \r
+extension of I, because C(I\cup {j}) includes an item e<j, not in I.\r
+Then, we can see for any ppc extension I\cup {j'}, j'<j, C(I\cup {'j}\cup {j})\r
+includes item e, thereby C(I\cup {'j}\cup {j}) is not a ppc extension of\r
+I\cup {j'}. It implies that we can never get a ppc extension by adding j,\r
+in the recursion. This reduces the number of candidates of ppc extensions,\r
+so reduce the computation time.\r
+In practice, when the difference between the number of frequent closed\r
+itemsets and the number of the frequent itemsets is large, it speeds the \r
+algorithm about 2 or 3 times.\r
+\r
+\r
+\r
+The details of the algorithm is described as follows.\r
+\r
+1. Loading the input file and initialize the memory\r
+ - scan the file and for each item i, count #transactions, sum of transaction size, frq(i), where frq(i) = #transactions including i\r
+ - allocate pointer array for T[][] (2d array for transactions) , Occ[][] (2d array of integers)\r
+ - allocate memory for w[] (transaction weights), "buf" for T[][] and occ_buf for Occ[][] (size of buf is ||D||*2, and size of occ_buf = ||D||, where D is the removal of infrequent items (items i, frq(i)<th had removed) ). Size of Occ[i] is equal to frq(i)\r
+ - load the file to buffer. If neither gap nor window constraint is given, skip items i with frq(i) < th, \r
+ set T[t] to the pointer to the beginning of T[i] in "buf", put "end mark" (large int) to the last of each T[]\r
+ - sort each transactions in increasing order\r
+ - load the weight file, or set the transaction weights to 1\r
+ - find the same transactions by radix sort (with using Occ[][])\r
+ - unify the same transactions into one, with adding the transaction weights\r
+ - set occ to the array of {0,1,...,#transactions-1}\r
+ - allocate int array "jump" of size #items\r
+ - call LCM_seq ( occ, #transactions, current end of buffer )\r
+\r
+2. LCM (occ, ii, t_new, buf)\r
+ - call Delivery(occ, ii), to compute for each item i<ii, sum of transaction weights (occ_w[i]), and positive transactions weights (occ_pw[i]) in transactions in occ including i.\r
+ ( Delivery set "jump" to items where occ_pw[i] or occ_w[i] is not equal to 0)\r
+ - in the case of closed/maximal itemset mining, instead of call Delivery(occ, ii), call Delivery(occ, "end mark")\r
+\r
+ - in the case of closed/maximal itemset mining, return if there is an item j > ii, j is not in the current itemset such that occ_w[j] = sum of transaction weights in occ, and occ_pw[j] = sum of positive transaction weights in occ\r
+ (it is the check of "prefix preserving closure extension")\r
+\r
+ - for each i in jump with occ_pw[i] < th, set occ_w[i] and occ_pw[i] to 0 and remove i from jump\r
+ - if the sum of transaction weights in occ >= th, (and if there is no j>ii, j is not in the current itemset with occ_w[j]>=th ,in the case of maximal itemset mining) output itemset, or rules \r
+ \r
+ - if jump_t = 0, clear occ_w, occ_pw and jump, and return\r
+ \r
+ - find the same transactions by radix sort, with ignoring the items not included in "jump", and items larger than ii\r
+ - create a new transaction for the same transactions detected above into one, with adding the transaction weights. \r
+ (the buffer and ID of created transactions start from buf, and t_new\r
+ update buf/t_new to the end of buffer/ID )\r
+ --- in the case of closed itemset mining, take intersection of the suffixes of transactions to be merged\r
+ --- in the case of maximal itmeset mining, compute the union of the suffixes of transactions to be merged, and compute the weight of each item (item weight of item i is the sum of weights of transactions to be merged including i).\r
+ - replace the "merged" transactions from occ, and insert the newly created transactions to occ.\r
+\r
+ - call Delivery(occ, ii) to compute Occ[i] for each item i with occ_pw[i]>=th\r
+\r
+ - for each item i in jump in increasing order, \r
+ call LCM (Occ[i], t_new, buf ) (note that t_new and buf are updated)\r
+ clear Occ[i], occ_w[i] to 0, occ_pw[i] to 0\r
+ end for\r
+end of LCM\r
+\r
+\r
+\r
+=== Delivery is done as follows\r
+\r
+Delivery (occ, ii)\r
+ - for each transaction t in occ\r
+ - for each item i in t with i<ii\r
+ ( for computing occ_pw and occ_w)\r
+ if occ_pw[i] = 0 and occ_w[i] = 0, insert i to "jump"\r
+ add the weight of t to occ_w[i] and add to occ_pw[i] if the weight is positive\r
+ ( for computing Occ[i])\r
+ if occ_pw[i] >= th, then insert t to Occ[i]\r
+ end for\r
+ end for\r
+end of Delivery\r
+\r
+\r
+=== Memory allocation and loading the transactions are described as follows.\r
+ This data storage method is called "forward star", in graph data structures.\r
+\r
+ 1. allocate int array of size #transactions + (sum of frq(i) with frq(i)>=th) for "buf"\r
+ 2. allocate pointer (to int) array of size #transactions for T[][]\r
+ 3. buf' := pointer to the start potition of buf, t=0\r
+ \r
+ 4. while ( not end of the file )\r
+ 4.1 set T[t] to the pointer to buf'\r
+ 4.2 read integer to memory starting from buf', until newline\r
+ 4.3 put "end mark" to the tail of the integers\r
+ 4.4 buf' = the position next to "end mark", t = t+1\r
+ end while\r
+\r
+\r
+\r
+\r
+###############################\r
+#### Acknowledgments #### \r
+###############################\r
+\r
+We thank to Ken Satoh of National Institute of Informatics Japan,\r
+Hiroki Arimura of Hokkaido University for their contribution for the\r
+research, to Tatsuya Asai, Yuzo Uchida, Masashi Kiyomi for their\r
+contribution for computational experiments and coding. We would also like\r
+to present our sincere thanks to Bart Goethal, one of the organizers of\r
+FIMI (Frequent Itemset Mining Implementation) for his organizing the \r
+workshop to which the first version of LCM was submitted, which was the\r
+start of our research.\r
+\r
+A part of the research of LCM is supported by joint-research fund of\r
+National Institute of Informatics Japan, and Grant-in-aid from the\r
+Ministry of Education, Science, Sport and Culture of Japan\r
+(Monbu-Kagaku-Sho).\r
+\r
+We also thank to Ilpo Lyytinen of University of Helsinki, Sancho,\r
+R. Arun Kumar, Sethu Institue of Technology, Pulloor, Tamilnadu, Koji Tsuda\r
+of Advanced Industrial Science and Technology, JAPAN, Yukinobu Hamuro of\r
+Kwansei gakuin University, JAPAN, Hiroyuki Morita of Osaka Prefecture\r
+University, JAPAN, Yasuyuki Shirai of Mitsubishi Research Institute, for\r
+their bug reports.\r
+\r
+\r
+##########################\r
+#### References #### \r
+##########################\r
+\r
+Bart Goethal, "FIMI repository", http://fimi.cs.helsinki.fi/\r
+(various frequent itemset implementation, benchmark databases, computational\r
+experiments comparing all implementations, and papers explaining the\r
+implementations, very useful site)\r
+\r
+Takeaki Uno, Masashi Kiyomi, Hiroki Arimura, LCM ver.3: Collaboration of Array, Bitmap and Prefix Tree for Frequent Itemset Mining, Open Source Data Mining Workshop on Frequent Pattern Mining Implementations 2005, Aug/2005\r
+\r
+Takeaki Uno, Masashi Kiyomi, Hiroaki Arimura, "LCM ver.2: Efficient Mining Algorithms for Frequent/Closed/Maximal Itemsets," in Proceedings of IEEE ICDM'04 Workshop FIMI'04, 1/Nov/2004, http://sunsite.informatik.rwth-aachen.de/Publications/CEUR-WS//Vol-126/\r
+\r
+Takeaki Uno and Tatsuya Asai, Hiroaki Arimura and Yuzo Uchida, "LCM: An Efficient Algorithm for Enumerating Frequent Closed Item Sets," Workshop on Frequent Itemset Mining Implementations (FIMI'03), http://sunsite.informatik.rwth-aachen.de/Publications/CEUR-WS//Vol-90/\r
+\r
+Takeaki Uno,Tatsuya Asai,Yuzo Uchida, Hiroki Arimura, "An Efficient Algorithm for Enumerating Closed Patterns in Transaction Databases," Lecture Notes in Artificial Intelligence 3245 (Proceedings of Discovery Science 2004), 4/Oct/2004 \r
+\r
+\r
--- /dev/null
+/* graph library by array list
+ 12/Feb/2002 by Takeaki Uno
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _sgraph_c_
+#define _sgraph_c_
+
+#include"sgraph.h"
+#include"vec.c"
+
+SGRAPH INIT_SGRAPH = {TYPE_SGRAPH,INIT_SETFAMILY_,INIT_SETFAMILY_,INIT_SETFAMILY_,0,0,NULL,NULL};
+
+/* initialization */
+void SGRAPH_alloc (SGRAPH *G, QUEUE_ID nodes, size_t edge_num, size_t arc_num){
+ if ( edge_num > 0 ){
+ SETFAMILY_alloc (&G->edge, nodes, NULL, nodes, edge_num);
+ if ( G->flag&LOAD_EDGEW && (!ERROR_MES) ) SETFAMILY_alloc_weight (&G->edge);
+ }
+ if ( arc_num > 0 ){
+ SETFAMILY_alloc (&G->in, nodes, NULL, nodes, arc_num);
+ SETFAMILY_alloc (&G->out, nodes, NULL, nodes, arc_num);
+ if ( G->flag&LOAD_EDGEW && (!ERROR_MES) ){
+ SETFAMILY_alloc_weight (&G->in);
+ SETFAMILY_alloc_weight (&G->out);
+ }
+ }
+ if (G->flag&LOAD_NODEW) calloc2 (G->node_w, nodes, "SGRAPH_alloc: node_w", G->node_w=0);
+ if ( ERROR_MES ){ SGRAPH_end (G); EXIT; }
+}
+
+/* copy graph G to graph G2. Underconstruction */
+//void SGRAPH_cpy (SGRAPH *G2, SGRAPH *G){}
+
+/* free graph object */
+void SGRAPH_end (SGRAPH *G){
+ SETFAMILY_end (&G->edge);
+ SETFAMILY_end (&G->in);
+ SETFAMILY_end (&G->out);
+ mfree (G->wbuf, G->perm);
+ *G = INIT_SGRAPH;
+}
+
+
+/* make an edge between u and v.
+ If they are already connected, it will be a multiple edge */
+void SGRAPH_edge_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w){
+ if ( G->edge.w ){
+ G->edge.w[u][G->edge.v[u].t] = w;
+ G->edge.w[v][G->edge.v[v].t] = w;
+ }
+ ARY_INS (G->edge.v[u], v);
+ ARY_INS (G->edge.v[v], u);
+ G->edge.eles += 2;
+}
+
+/* make an arc between u and v.
+ If they are already connected, it will be a multiple arc */
+void SGRAPH_arc_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w){
+ if ( G->out.w ) G->out.w[u][G->out.v[u].t] = w;
+ if ( G->in.w ) G->in.w[v][G->in.v[v].t] = w;
+ ARY_INS (G->out.v[u], v);
+ ARY_INS (G->in.v[v], u);
+ G->in.eles++;
+ G->out.eles++;
+}
+
+/* Delete the edge connecting u and v. If edge (u,v) does not exist, nothing will occur. */
+void SGRAPH_edge_rm_iter (SETFAMILY *M, QUEUE_INT u, QUEUE_INT v){
+ QUEUE_INT i;
+ if ( (i = (QUEUE_INT)QUEUE_ele (&M->v[u], v)) >= 0 ){
+ QUEUE_rm (&M->v[u], i);
+ if ( M->w ) M->w[u][i] = M->w[u][M->v[u].t];
+ M->eles--;
+ }
+}
+
+/* Delete the edge connecting u and v. If edge (u,v) does not exist, nothing will occur. */
+void SGRAPH_edge_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v){
+ SGRAPH_edge_rm_iter (&G->edge, u, v);
+ SGRAPH_edge_rm_iter (&G->edge, v, u);
+}
+
+/* Delete the arc connecting u and v. If arc (u,v) does not exist, nothing will occur. */
+void SGRAPH_arc_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v){
+ SGRAPH_edge_rm_iter (&G->out, u, v);
+ SGRAPH_edge_rm_iter (&G->in, v, u);
+}
+
+/* print graph by numbers */
+void SGRAPH_print (SGRAPH *G){
+ VEC_ID i;
+ QUEUE_ID j;
+ QUEUE_INT e;
+
+ printf ("#node "VEC_IDF" ,#edge %zd ,#arc %zd\n", SGRAPH_NODE_NUM(*G), G->edge.eles, G->in.eles);
+ FLOOP (i, 0, SGRAPH_NODE_NUM(*G)){
+ printf ("NODE "VEC_IDF" ", i);
+ if ( G->node_w ){ putchar ('('); print_WEIGHT (G->node_w[i]); putchar (')'); }
+ printf (" >>\n");
+ if ( G->edge.v && G->edge.v[i].t ){
+ printf (" edge : ");
+ ARY_FLOOP (G->edge.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->edge.w ){ putchar ('('); print_WEIGHT (G->edge.w[i][j]); putchar (')'); }
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ if ( G->in.w ){
+ if ( G->in.v[i].t ){
+ printf (" in-arc : ");
+ ARY_FLOOP (G->in.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->in.w ){ putchar ('('); print_WEIGHT (G->in.w[i][j]); putchar (')'); }
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ }
+ if ( G->out.w ){
+ if ( G->out.v[i].t ){
+ printf (" out-arc : ");
+ ARY_FLOOP (G->out.v[i], j, e){
+ printf (VEC_IDF, e);
+ if ( G->out.w ){ putchar ('('); print_WEIGHT (G->out.w[i][j]); putchar (')');}
+ putchar (',');
+ }
+ putchar ('\n');
+ }
+ }
+ }
+}
+
+/* Output a graph to file
+ Vertices, edges, arcs less than node_num, edge_num, arc_num are written to the file. Input parameters are
+ (graph) (file name) (flag)
+ SGRAPH_READ_NODEW 512 // read node weight
+ SGRAPH_READ_EDGEW 1024 // read edge weight
+*/
+/*
+ format of file:(including notifications to make input file)
+
+ the ith row corresponds to node i-1, and
+ ID list of nodes adjacent to i, and having ID > i, for undirected graph
+ ID list of nodes adjacent to i by out-going arc of i, for directed graph
+ Separator is ",", but graph load routine accepts any letter for
+ separator but not a number.
+ If the graph has both edges and arcs, write them in two lines separately,
+ so a node then uses two lines, and #nodes = #lines/2.
+
+ == Notifications to make input file ==
+ Notice that if 0th line has node 2, and the 2nd line has 0, then there
+ will be multiple edge (0,2) and (2,0).
+ The read routine does not make error with multiple edges, it is allowed.
+
+ The ID of nodes begin from 0. After reading graph, node_num is set to
+ node_end.
+
+ Input file example, without weights, E={(0,1),(0,2),(1,1),(1,3),(2,3)}
+===========
+ 1,2
+ 1 3
+ 3
+
+ [EOF]
+=========
+ Nodes are 0,1, and 2, both edges and arcs exist, with node/edge/arc weights)
+ 5000,1,30
+ 0,50,1,20,
+ 100,1,3
+ 2,20
+ 200
+
+ [EOF]
+=======
+ where node weights are 5000, 100, 200, and edges and their weights are
+ (0,1),30, (1,1),3
+ arcs and their weights are (0,0),50, (0,1), 20, (1,2), 20
+
+ In the case of bipartite graph, write the adjacent-node lists only for
+ the node in node set one.
+
+
+*/
+
+/* graph load routine. Allocate memory as much as the size of input file.
+ parameters are,
+ (graph) (file name)
+ LOAD_EDGE // read undirected edge from file
+ LOAD_ARC // read directed arc from file
+ LOAD_BIPARTITE // load bipartite graph
+ LOAD_NODEW // read node weight
+ LOAD_EDGEW // read edge weight
+*/
+/* In the bipartite case, even if the IDs of node set 2 begin from 0, i.e.,
+ overlaps with node 1, the routine automatically correct them. */
+/* Directed bipartite graph, all arcs are considered to be from node set 1
+ to node set 2. If both directions exist, read as a general graph, and set
+ node1_num later in some way. */
+/* The routine compares the maximum node index and #lines, and set #node
+ to the larger one. However, if node weight exists, weights will be included
+ in the candidates of maximum index, thus in this case we fix #node := #lines.
+ In the case of bipartite graph, the routine compares, but the weights of
+ non-existing lines will be -1. */
+
+/* make the opposite direction edge, for each edge; buffers have to be already doubly allocated */
+void SGRAPH_load_delivery (SGRAPH *G, SETFAMILY *OO, SETFAMILY *MM, QUEUE_ID *c){
+ VEC_ID i;
+ QUEUE_ID j;
+ QUEUE_INT e;
+ FLOOP (i, 0, MM->t) c[i] = MM->v[i].t;
+ FLOOP (i, 0, MM->t){
+ FLOOP (j, 0, c[i]){
+ e = MM->v[i].v[j];
+ if ( OO->w ) OO->w[e][OO->v[e].t] = MM->w[i][j];
+ ARY_INS (OO->v[e], i);
+ }
+ }
+}
+
+/* make the opposite direction edge, for each edge; buffers have to be already doubly allocated */
+void SGRAPH_mk_opposite_edge (SGRAPH *G, QUEUE_ID *c){
+ VEC_ID i;
+ size_t j, jj;
+ j = G->edge.eles; // shift the arrays to insert edges of opposite directions
+ BLOOP (i, G->edge.t, 0){
+ j -= G->edge.v[i].t+c[i];
+ jj = G->edge.v[i].t+1;
+ do {
+ jj--;
+ G->edge.buf[j+i+jj] = G->edge.v[i].v[jj];
+ } while ( jj>0 );
+ G->edge.v[i].end += c[i];
+ G->edge.v[i].v = &G->edge.buf[j+i];
+ if ( G->edge.w ){
+ memcpy ( &G->edge.buf[j], G->edge.w[i], sizeof(WEIGHT)*G->edge.v[i].t );
+ G->edge.w[i] = &G->edge.wbuf[j];
+ }
+ }
+}
+
+/* load edges/arcs (determined by G->flag) from file */
+void SGRAPH_load (SGRAPH *G, char *fname, char *wfname){
+ VEC_ID i;
+ QUEUE_ID *c;
+ SETFAMILY *F1, *F2;
+
+ if ( G->flag&LOAD_EDGE ){ F1 = F2 = &G->edge; G->edge.flag |= LOAD_DBLBUF; }
+ else { F1 = &G->in; F2 = &G->out; }
+ SETFAMILY_load (F1, fname, wfname);
+ // adjact so that #rows and #colums are the same
+ if ( !(G->flag&LOAD_BIPARTITE)){
+ if ( F1->clms < F1->t ){
+ F1->clms = F1->t;
+ FLOOP (i, 0, F1->t) F1->v[i].v[F1->v[i].t] = F1->t; // re-set endmark
+ } else if ( F1->clms > F1->t ){
+ reallocx_ (F1->v, F1->t, F1->clms, INIT_QUEUE, "SGRAPH_load: v", EXIT);
+ FLOOP (i, F1->t, F1->clms){
+ F1->v[i].v = F1->v[F1->t -1].v +F1->v[F1->t -1].t +1 +(i -(F1->t-1));
+ F1->v[i].v[0] = F1->clms;
+ } // re-set endmark
+ F1->t = F1->clms;
+ }
+ }
+
+ calloc2 (c, F1->t, "SGRAPH_load: c", EXIT);
+ QUEUE_delivery (NULL, c, NULL, F1->v, NULL, F1->t, F1->t);
+// SETFAMILY_print (stdout, F1);
+
+ if ( F1 != F2 ) SETFAMILY_alloc (F2, F1->t, c, F1->t, 0);
+ else {
+ G->edge.eles *= 2; G->edge.ele_end *= 2;
+ SGRAPH_mk_opposite_edge (G, c); // shift the arrays to insert edges of opposite directions
+ }
+
+ SGRAPH_load_delivery (G, F2, F1, c);
+ free (c);
+ F2->clms = F2->t; FLOOP (i, 0, F2->t) F2->v[i].v[F2->v[i].t] = F2->t; // re-set endmark
+
+ F1->flag |= G->flag; SETFAMILY_sort (F1);
+ if ( F1 != F2 ){ F2->flag |= G->flag; SETFAMILY_sort (F2); }
+}
+
+/* replace node i by perm[i] */
+void SGRAPH_replace_index (SGRAPH *G, PERM *perm, PERM *invperm){
+ QUEUE_INT *x;
+ VEC_ID i;
+ QUEUE Q;
+ WEIGHT *w, ww;
+
+ FLOOP (i, 0, G->edge.t)
+ if ( G->edge.v ){
+ MQUE_FLOOP (G->edge.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->edge.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->in.v ){
+ MQUE_FLOOP (G->in.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->in.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->out.v ){
+ MQUE_FLOOP (G->out.v[i], x) *x = perm[*x];
+ ARY_INVPERMUTE (G->out.v, invperm, Q, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ }
+ if ( G->edge.w ) ARY_INVPERMUTE (G->edge.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->in.w ) ARY_INVPERMUTE (G->in.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->out.w ) ARY_INVPERMUTE (G->out.w, invperm, w, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ if ( G->node_w ) ARY_INVPERMUTE (G->node_w, invperm, ww, G->edge.t, "SGRAPH_repl_ind:", EXIT);
+ G->perm = perm;
+}
+
+/* sort the nodes by Q->t, increasing if flag=1, decreasing if flag=-1 */
+void SGRAPH_perm_node (SGRAPH *G, PERM *tmp){
+ VEC_ID c1=0, c2=G->node1_num, i;
+ PERM *perm;
+ malloc2 (perm, G->edge.t, "SGRAPH_perm_node", {free(tmp);EXIT;});
+ FLOOP (i, 0, G->edge.t)
+ if ( tmp[i]<G->node1_num ) perm[tmp[i]] = c1++; else perm[tmp[i]] = c2++;
+ ARY_INV_PERM_ (tmp, perm, G->edge.t);
+ SGRAPH_replace_index (G, perm, tmp);
+ free2 (tmp);
+}
+
+#endif
--- /dev/null
+/* graph library by array list
+ 12/Feb/2002 by Takeaki Uno
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+/****************************************************************************/
+/* d = degree of node i := G->edge/in/out.v[i].t
+ d = max/min (in/out) degree := VEC_MAXT(d,G->edge.v/in.v/out.v,0,...->t) (VEC_MINT, resp.)
+ #nodes := SGRAPH_NODE_NUM(G)
+ #edges := G->edge.eles/2
+ #arcs := G->in.eles or G->out.eles
+ load_node_weight := ARY_LOAD_WEIGHT(G->node_w,WEIGHT,filename,counter,"errormes", EXIT)
+ load_node_weight := ARY_LOAD_WEIGHT(G->node_w,WEIGHT,filename,counter,"errormes", EXIT)
+
+ sort_node by size := SGRAPH_sort_node_iter (G, qsort_perm_VECt ((VEC *)Q, G->node_end, flag)
+ sort_node by weight := SGRAPH_sort_node_iter (G, qsort_perm_WEIGHT (w, G->node_end, flag)
+*/
+/****************************************************************************/
+
+#ifndef _sgraph_h_
+#define _sgraph_h_
+
+#include"stdlib2.h"
+#include"vec.h"
+
+
+/* structure for graph */
+typedef struct {
+ unsigned char type; // structure type flag
+ SETFAMILY edge, in, out; // setfamily for edge, in-arc, out-arc
+ QUEUE_INT node1_num; // the size of vertex set 1, bipartite case. otherwise 0
+ int flag; // flag for load routine
+ WEIGHT *node_w, *wbuf; // pointer to the node weight array(int)
+ PERM *perm; // node permutation (nodes->original)
+} SGRAPH;
+extern SGRAPH INIT_SGRAPH;
+
+#define SGRAPH_NODE_NUM(G) MAX((G).edge.t,(G).in.t)
+
+/*************** initialization/termination ***********************/
+
+/* initialization, termination, allocate arrays for weights, copy and duplication */
+void SGRAPH_alloc (SGRAPH *G, int node_num, size_t edge_num, size_t arc_num);
+void SGRAPH_cpy (SGRAPH *G2, SGRAPH *G);
+void SGRAPH_end (SGRAPH *G);
+
+
+/**************** addition/deletion **********************************/
+
+/* make/take/remove edge e as connecting vertices u and v,
+ and edge (u,v).
+ do nothing if when make already existing edge, or delete non-existing edge.
+ with range check of parameters */
+
+void SGRAPH_edge_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w);
+void SGRAPH_edge_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v);
+void SGRAPH_arc_mk (SGRAPH *G, QUEUE_INT u, QUEUE_INT v, WEIGHT w);
+void SGRAPH_arc_rm (SGRAPH *G, QUEUE_INT u, QUEUE_INT v);
+
+
+/******************* node/edge sort, and duplication reduction *********************/
+
+/* subroutine of sort_edge_list */
+void SGRAPH_sort_edge_list_iter (QUEUE *Q, WEIGHT **w, PERM *invperm, VEC_ID i, int flag);
+
+/* sort each array list, increasing if flag=1, and decreasing if flag=-1 */
+void SGRAPH_sort_edge_list (SGRAPH *G, int flag);
+
+/* replace node i by perm and invperm */
+void SGRAPH_replace_index (SGRAPH *G, PERM *perm, PERM *invperm);
+
+/* sort the nodes by permutation given by tmp */
+PERM *SGRAPH_sort_node_iter (SGRAPH *G, PERM *tmp);
+
+/* sort the nodes by degrees, increasing if flag=1, decreasing if flag=-1 */
+PERM *SGRAPH_sort_node_t (SGRAPH *G, QUEUE *Q, int flag);
+
+/* sort the nodes by node_weight, increasing if flag=1, decreasing if flag=-1 */
+PERM *SGRAPH_sort_node_w (SGRAPH *G, WEIGHT *w, int flag);
+
+/* remove multiple edges/arcs and self loops
+ it works only when after applying sort_incident_edges */
+void SGRAPH_simple (SGRAPH *G, int flag);
+
+
+
+
+/******************* print routines *************************************/
+
+
+/* print graph by numbers */
+void SGRAPH_print (SGRAPH *G);
+
+/* Write the graph to file. Edges, arcs, and nodes from 0 to node_num/edge_num/arc_num are written to file. Parameters are
+ (graph) (file name) (not write edge weight => 0) (not write node weight => 0) */
+void SGRAPH_save (SGRAPH *G, char *fname);
+
+/* graph load routine. Allocate memory as much as the size of input file.
+ parameters are,
+ (graph) (file name) (read edges?) (read arcs?) (read node weights?) (read edge weight?) (bipartite?) */
+/* In the row of each vertex, write only vertices larger than it connected by an edge */
+void SGRAPH_load (SGRAPH *G, char *fname, char *wfname);
+void SGRAPH_load_node_weight (SGRAPH *G, char *filename);
+
+/*
+ format of file:(including notifications to make input file)
+
+ the ith row corresponds to node i-1, and
+ ID list of nodes adjacent to i, and having ID > i, for undirected graph
+ ID list of nodes adjacent to i by out-going arc of i, for directed graph
+ Separator is ",", but graph load routine accepts any letter for
+ separator but not a number.
+ If the graph has both edges and arcs, write them in two lines separately,
+ so a node then uses two lines, and #nodes = #lines/2.
+
+ == Notifications to make input file ==
+ Notice that if 0th line has node 2, and the 2nd line has 0, then there
+ will be multiple edge (0,2) and (2,0).
+ The read routine does not make error with multiple edges, it is allowed.
+
+ The ID of nodes begin from 0. After reading graph, node_num is set to
+ node_end.
+
+ Input file example, without weights, E={(0,1),(0,2),(1,1),(1,3),(2,3)}
+===========
+ 1,2
+ 1 3
+ 3
+
+ [EOF]
+=========
+ Nodes are 0,1, and 2, both edges and arcs exist, with node/edge/arc weights)
+ 5000,1,30
+ 0,50,1,20,
+ 100,1,3
+ 2,20
+ 200
+
+ [EOF]
+=======
+ where node weights are 5000, 100, 200, and edges and their weights are
+ (0,1),30, (1,1),3
+ arcs and their weights are (0,0),50, (0,1), 20, (1,2), 20
+
+ In the case of bipartite graph, write the adjacent-node lists only for
+ the node in node set one.
+
+
+*/
+
+
+/*************************************************************************/
+
+
+#endif
+
+
+
+
+
+
+
+
--- /dev/null
+/* library for standard macros and functions */
+/* by Takeaki Uno 2/22/2002, e-mail: uno@nii.jp
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _stdlib2_c_
+#define _stdlib2_c_
+
+#include"stdlib2.h"
+#ifdef MTWISTER
+#include"dSFMT.c"
+#endif
+
+size_t common_size_t;
+INT common_INT, common_INT2;
+char *common_charp, *common_pnt;
+FILE *common_FILE;
+FILE2 common_FILE2;
+PERM common_PERM;
+
+char *ERROR_MES = NULL;
+int print_time_flag=0;
+PARAMS internal_params;
+#ifdef MULTI_CORE
+int SPIN_LOCK_dummy;
+#endif
+FILE2 INIT_FILE2 = {TYPE_FILE2,NULL,NULL,NULL,NULL};
+VEC INIT_VEC = {TYPE_VEC,NULL,0,0};
+FILE_COUNT INIT_FILE_COUNT = {0,0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,0,0,NULL,NULL,0,0,NULL,NULL};
+
+QSORT_TYPE (int, int)
+QSORT_TYPE (uint, unsigned int)
+QSORT_TYPE (double, double)
+QSORT_TYPE (char, char)
+QSORT_TYPE (uchar, unsigned char)
+QSORT_TYPE (short, short)
+QSORT_TYPE (ushort, unsigned short)
+QSORT_TYPE (WEIGHT, WEIGHT)
+QSORT_TYPE (LONG, LONG)
+QSORT_TYPE (VEC_ID, VEC_ID)
+QSORT_TYPE (VEC_VAL, VEC_VAL)
+QSORT_TYPE (VEC_VAL2, VEC_VAL2)
+QSORT_TYPE (FILE_COUNT_INT, FILE_COUNT_INT)
+
+ /* bitmasks, used for bit operations */
+int BITMASK_UPPER1[32] = { 0xffffffff, 0xfffffffe, 0xfffffffc, 0xfffffff8,
+ 0xfffffff0, 0xffffffe0, 0xffffffc0, 0xffffff80,
+ 0xffffff00, 0xfffffe00, 0xfffffc00, 0xfffff800,
+ 0xfffff000, 0xffffe000, 0xffffc000, 0xffff8000,
+ 0xffff0000, 0xfffe0000, 0xfffc0000, 0xfff80000,
+ 0xfff00000, 0xffe00000, 0xffc00000, 0xff800000,
+ 0xff000000, 0xfe000000, 0xfc000000, 0xf8000000,
+ 0xf0000000, 0xe0000000, 0xc0000000, 0x80000000 };
+int BITMASK_UPPER1_[32] = { 0xfffffffe, 0xfffffffc, 0xfffffff8, 0xfffffff0,
+ 0xffffffe0, 0xffffffc0, 0xffffff80, 0xffffff00,
+ 0xfffffe00, 0xfffffc00, 0xfffff800, 0xfffff000,
+ 0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000,
+ 0xfffe0000, 0xfffc0000, 0xfff80000, 0xfff00000,
+ 0xffe00000, 0xffc00000, 0xff800000, 0xff000000,
+ 0xfe000000, 0xfc000000, 0xf8000000, 0xf0000000,
+ 0xe0000000, 0xc0000000, 0x80000000, 0x00000000 };
+
+int BITMASK_LOWER1[32] = { 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff };
+int BITMASK_LOWER1_[32] = { 0x00000001, 0x00000003, 0x00000007, 0x0000000f,
+ 0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
+ 0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
+ 0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
+ 0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
+ 0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
+ 0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
+ 0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff };
+
+int BITMASK_1[32] = { 0x00000001, 0x00000002, 0x00000004, 0x00000008,
+ 0x00000010, 0x00000020, 0x00000040, 0x00000080,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000, 0x80000000 };
+int BITMASK_31[32] = { 0xfffffffe, 0xfffffffd, 0xfffffffb, 0xfffffff7,
+ 0xffffffef, 0xffffffdf, 0xffffffbf, 0xffffff7f,
+ 0xfffffeff, 0xfffffdff, 0xfffffbff, 0xfffff7ff,
+ 0xffffefff, 0xffffdfff, 0xffffbfff, 0xffff7fff,
+ 0xfffeffff, 0xfffdffff, 0xfffbffff, 0xfff7ffff,
+ 0xffefffff, 0xffdfffff, 0xffbfffff, 0xff7fffff,
+ 0xfeffffff, 0xfdffffff, 0xfbffffff, 0xf7ffffff,
+ 0xefffffff, 0xdfffffff, 0xbfffffff, 0x7fffffff };
+
+int BITMASK_16[8] = { 0x0000000f, 0x000000f0, 0x00000f00, 0x0000f000,
+ 0x000f0000, 0x00f00000, 0x0f000000, 0xf0000000 };
+int BITMASK_UPPER16[8] = { 0xffffffff, 0xfffffff0, 0xffffff00, 0xfffff000,
+ 0xffff0000, 0xfff00000, 0xff000000, 0xf0000000 };
+int BITMASK_LOWER16[8] = { 0x0000000f, 0x000000ff, 0x00000fff, 0x0000ffff,
+ 0x000fffff, 0x00ffffff, 0x0fffffff, 0xffffffff };
+int BITMASK_FACT16[8] = { 0x1, 0x10, 0x100, 0x1000,
+ 0x10000, 0x100000, 0x1000000,0x10000000 };
+
+/* free many pointers */
+void mfree_(void *x, ...){
+ va_list argp;
+ void *a;
+ va_start (argp, x);
+ while((a = va_arg(argp, void *)) != (void*)1){ free (a); }
+ va_end (argp);
+}
+
+/* compute the minimum prime no less than n */
+#define MINPRIME_END 6000
+LONG min_prime (LONG n){
+ LONG i, j=30, k;
+ char f[MINPRIME_END];
+ while(1) {
+ FLOOP (i, 0, j) f[i]=0;
+ for ( i=3 ; i*i < n+j ; i+=2 )
+ for ( k=((n+i-1)/i)*i ; k<i+j ; k+=i ) f[(k-n)/2] = 1;
+ FLOOP (i, 0, j) if ( f[i] == 0 ) return (n+ i*2+1);
+ j *= 2;
+ }
+}
+
+/* decompose the string by separator, and set v[i] to each resulted string.
+ consecutive separators are regarded as one separator. */
+/* string s has to have end mark 0 at the end */
+/* original string s will be written, so that each separator will be end mark 0 */
+/* at most [num] strings will be generated */
+int string_decompose ( char **v, char *s, char sep, int max){
+ int i=0;
+ char *ss = s;
+ do {
+ while (*ss == sep) ss++;
+ if ( *ss == 0 ) break;
+ v[i++] = ss;
+ while (*ss != sep){
+ if ( *ss == 0 ) break;
+ ss++;
+ }
+ if ( *ss == 0 ) break;
+ *ss = 0;
+ ss++;
+ } while ( i<max);
+ return (i);
+}
+
+unsigned long xor128(){
+ static unsigned long x=123456789,y=362436069,z=521288629,w=88675123;
+ unsigned long t;
+ t=(x^(x<<11));x=y;y=z;z=w; return( w=(w^(w>>19))^(t^(t>>8)) );
+}
+
+/***********************************************************************/
+/***********************************************************************/
+#ifdef USE_MATH
+#define NORMAL_RAND_BASE 2147483648LL
+
+/* make two random numbers under normal distribution N(0,1) */
+void rand_mk_2normal (double *a, double *b){
+ double r1, r2;
+ do {
+ r1 = RAND1;
+ } while (r1==0);
+ r2 = RAND1;
+ r1 = sqrt(-log(r1)*2);
+ r2 *= 2*PI;
+ *a = r1*sin(r2);
+ *b = r1*cos(r2);
+}
+
+/* make a random point on a supersphere of d-dim., and set to double array already allocated */
+void rand_d_gaussian (double *p, int d){
+ int i;
+ double a, b;
+ for (i=0 ; i<d ; i+=2){
+ rand_mk_2normal ( &a, &b);
+ p[i] = a;
+ if ( i+1 < d ) p[i+1] = b;
+ }
+}
+void rand_sphere (double *p, int d){
+ rand_d_gaussian (p, d);
+ ARY_NORMALIZE (p, d);
+}
+#endif
+
+/******************** file I/O routines ********************************/
+
+int FILE_err; /* signals 0: for normal termination
+ 1: read a number, then encountered a newline,
+ 2: read a number, then encountered the end-of-file
+ 5: read no number, and encountered a newline
+ 6: read no number, and encountered the end-of-file */
+
+
+void FILE2_flush (FILE2 *fp){
+ if ( fp->buf > fp->buf_org ){
+ fwrite ( fp->buf_org, fp->buf-fp->buf_org, 1, fp->fp);
+ fp->buf = fp->buf_org;
+ }
+}
+void FILE2_close (FILE2 *fp){
+ fclose2 (fp->fp);
+ free2 (fp->buf_org);
+}
+void FILE2_closew (FILE2 *fp){
+ FILE2_flush (fp);
+ fclose2 (fp->fp);
+ free2 (fp->buf_org);
+}
+void FILE2_reset (FILE2 *fp){
+ fp->buf = fp->buf_org;
+ fp->buf_end = fp->buf_org-1;
+ fseek (fp->fp, 0, SEEK_SET);
+}
+/* fast file routine, getc, putc, puts, */
+int FILE2_getc (FILE2 *fp){
+ int c;
+ if ( fp->buf >= fp->buf_end ){
+ if ( (fp->buf_end < fp->buf_org+FILE2_BUFSIZ) && (fp->buf_end>=fp->buf_org) ) return (-1);
+ fp->buf = fp->buf_org;
+ fp->buf_end = fp->buf_org + fread (fp->buf, 1, FILE2_BUFSIZ, fp->fp);
+ return (FILE2_getc (fp));
+ }
+ c = (unsigned char)(*(fp->buf));
+ fp->buf++;
+ return (c);
+}
+void FILE2_puts (FILE2 *fp, char *s){
+ while ( *s != 0 ){
+ *(fp->buf) = *s;
+ s++;
+ fp->buf++;
+ }
+}
+void FILE2_putc (FILE2 *fp, char c){
+ *(fp->buf) = c;
+ fp->buf++;
+}
+/* fast file routine, print number, c is the char to be printed preceding to the number
+ if c==0, nothing will be printed preceding the number
+ if len<0 then the #digits following '.' does not change (filed by '0') */
+void FILE2_print_int (FILE2 *fp, LONG n, char c){
+ LONG nn = n;
+ char *s;
+ if ( c ) FILE2_putc ( fp, c);
+ if ( n == 0 ){ *(fp->buf) = '0'; fp->buf++; return; }
+ if ( n < 0 ){ *(fp->buf) = '-'; fp->buf++; n = -n; }
+ while ( nn>0 ){ nn /= 10; fp->buf++; }
+ s = fp->buf-1;
+ *(fp->buf) = 0;
+ while ( n>0 ){ *s = '0'+(char)(n%10); s--; n/=10; }
+}
+/******/
+void FILE2_print_real (FILE2 *fp, double n, int len, char c){
+ int i=0, flag=1;
+ double j=1;
+ char *back;
+
+ if ( c ) FILE2_putc (fp, c);
+ if ( n<0 ){ FILE2_putc (fp, '-'); n *= -1; }
+ while ( n >= j ) j*=10;
+ if ( j==1 ){ *(fp->buf) = '0'; fp->buf++; }
+ else while ( j>1 ){
+ j /= 10;
+ i = (int)(n/j);
+ *(fp->buf) = '0'+i;
+ n -= j*i;
+ fp->buf++;
+ }
+ *(fp->buf) = '.'; back = fp->buf;
+ fp->buf++;
+ if ( len<0 ){ len = -len; flag = 0; }
+ for ( ; len>0 ; len--){
+ n *= 10.0;
+ i = (int)n;
+ *(fp->buf) = '0'+i;
+ n -= i;
+ fp->buf++;
+ if ( i>0 ) back = fp->buf;
+ }
+ if ( flag ) fp->buf = back;
+}
+/******/
+void FILE2_print_WEIGHT (FILE2 *fp, WEIGHT w, int len, char c){
+#ifdef WEIGHT_DOUBLE
+ FILE2_print_real(fp, w, len, c);
+#else
+ FILE2_print_int(fp, w, c);
+#endif
+}
+
+/* Read an integer/a double from the file and return it,
+ with read through the non-numeric letters.
+ If it reaches to the end-of-file, then set FILE_err=2, if it reads a
+ newline, then set FILE_err=1.
+ If read either the end-of-file or newline before reading an integer,
+ return 5, and 6 */
+FILE_LONG FILE2_read_int (FILE2 *fp){
+ FILE_LONG item;
+ int flag =1;
+ int ch;
+ FILE_err = 0;
+ do {
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 5; return (-INTHUGE); }
+ if ( ch < 0 ){ FILE_err = 6; return (-INTHUGE); }
+ if ( ch=='-' ) flag = -1;
+ } while ( ch<'0' || ch>'9' );
+ for ( item=(int)(ch-'0') ; 1 ; item=item*10 +(int)(ch-'0') ){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 1; return (flag*item); }
+ if ( ch < 0 ){ FILE_err = 2; return (flag*item); }
+ if ( (ch < '0') || (ch > '9')) return (flag*item);
+ }
+}
+double FILE2_read_double (FILE2 *fp){
+ double item, geta=1;
+ int sign=1, ch;
+ FILE_err = 0;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch < 0 ){ FILE_err = 6; return (-DOUBLEHUGE); }
+ if ( ch == '\n' ){ FILE_err = 5; return (-DOUBLEHUGE); }
+ if ( ch=='-' ) sign *= -1;
+ else if ( ch=='.' ) geta = 0.1;
+ else if ( ch>='0' && ch<='9' ) break;
+ else { sign = 1; geta = 1; }
+ }
+
+ item = geta * (ch-'0');
+ if ( geta < 1.0 ) geta *= .1;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 1; return (item*sign); }
+ if ( ch<0 ){ FILE_err = 2; return (item*sign); }
+ if ( ch == '.' ) geta = .1;
+ else if ( (ch < '0') || (ch > '9')) return (item*sign);
+ else if ( geta < 1.0 ){
+ item += geta*(ch-'0');
+ geta *= 0.1;
+ } else item = item*10 + (ch-'0');
+ }
+}
+
+/* read a WEIGHT from file */
+WEIGHT FILE2_read_WEIGHT (FILE2 *fp){
+#ifdef WEIGHT_DOUBLE
+ return (FILE2_read_double(fp));
+#else
+ return ((WEIGHT)FILE2_read_int(fp));
+#endif
+}
+
+/* read through the file until newline or EOF */
+void FILE2_read_until_newline (FILE2 *fp){
+ int ch;
+ if (FILE_err & 3) return;
+ while (1){
+ ch = FILE2_getc(fp);
+ if ( ch == '\n' ){ FILE_err = 5; return; }
+ if ( ch < 0 ){ FILE_err = 6; return; }
+ }
+}
+
+void FILE2_printf (FILE2 *fp, char *mes, ...){
+ va_list argp;
+ va_start (argp, mes);
+ sprintf (fp->buf, mes, argp);
+ va_end (argp);
+}
+
+/* print a real number in a good style */
+void fprint_real (FILE *fp, double f){
+ char s[200];
+ size_t i;
+ i = sprintf (s, "%f", f);
+ while ( s[i-1] == '0' ) i--;
+ if ( s[i-1] == '.' ) i--;
+ s[i] = 0;
+ fprintf (fp, s);
+}
+void print_real (double f){
+ fprint_real (stdout, f);
+}
+
+void fprint_WEIGHT (FILE *fp, WEIGHT f){
+#ifdef WEIGHT_DOUBLE
+ fprint_real (fp, f);
+#else
+ fprintf (fp, "%d", f);
+#endif
+}
+void print_WEIGHT (WEIGHT f){
+ fprint_WEIGHT (stdout, f);
+}
+
+/* count the clms, rows, items, each row size, each column size */
+/* file types can be, array list and element list*/
+/* support transpose */
+FILE_COUNT FILE2_count (FILE2 *fp, int flag, int skip_rows, int int_rows, int skip_clms, int int_clms, FILE_COUNT_INT row_limit){
+ FILE_COUNT_INT k=0, j, x, y, t=0;
+ int fr = flag&FILE_COUNT_ROWT, fc = flag&FILE_COUNT_CLMT;
+ int fe = flag&LOAD_ELE, ft = flag&LOAD_TPOSE;
+ FILE_COUNT C = INIT_FILE_COUNT;
+ C.flag = flag;
+
+ FLOOP (j, 0, skip_rows) FILE2_read_until_newline (fp);
+ if ( flag & (FILE_COUNT_NUM+FILE_COUNT_GRAPHNUM) ){
+ C.clms = (FILE_COUNT_INT)FILE2_read_int (fp);
+ C.rows = (flag & FILE_COUNT_NUM)? (FILE_COUNT_INT)FILE2_read_int (fp): C.clms;
+ C.eles = (FILE_COUNT_INT)FILE2_read_int (fp);
+ if ( !(flag & (FILE_COUNT_ROWT + FILE_COUNT_CLMT)) ) return (C);
+ FILE2_read_until_newline (fp);
+ }
+
+ do {
+ if ( fe ){
+ FLOOP (j, 0, skip_clms){ FILE2_read_double (fp); if ( FILE_err&3 ) goto ROW_END; }
+ x = (FILE_COUNT_INT)FILE2_read_int (fp); if ( FILE_err&3 ) goto ROW_END;
+ y = (FILE_COUNT_INT)FILE2_read_int (fp); if ( FILE_err&4 ) goto ROW_END;
+ FILE2_read_until_newline (fp);
+ } else {
+ if ( k==0 ) FLOOP (j, 0, skip_clms){ FILE2_read_double (fp); if (FILE_err&3) goto ROW_END; }
+ x = t;
+ y = (FILE_COUNT_INT)FILE2_read_int (fp); if (FILE_err&4 ) goto ROW_END;
+ FLOOP (j, 0, int_clms){ FILE2_read_double (fp); if (FILE_err&3 ) break; }
+ k++;
+ }
+
+ if ( ft ) SWAP_FILE_COUNT_INT (x, y);
+ if ( y >= C.clms ){
+ C.clms = y+1;
+ if ( fc ) reallocx (C.clmt, C.clm_end, C.clms, 0, "file_count: clmt", goto END);
+ }
+ if ( x >= C.rows ){
+ C.rows = x+1;
+ if ( fr ) reallocx (C.rowt, C.row_end, C.rows, 0, "file_count: rowt", goto END);
+ }
+ if ( x < C.clm_btm || C.eles == 0 ) C.clm_btm = x;
+ if ( y < C.row_btm || C.eles == 0 ) C.row_btm = y;
+ if ( fc ) C.clmt[y]++;
+ if ( fr ) C.rowt[x]++;
+ C.eles++;
+
+ ROW_END:;
+ if ( !fe && (FILE_err&1) ){
+ t++; C.rows = t;
+ ENMAX (C.clm_max, k);
+ ENMAX (C.clm_min, k);
+ FLOOP (j, 0, int_rows) FILE2_read_until_newline (fp);
+ if ( row_limit>0 && t>=row_limit ) break;
+ } else if ( row_limit>0 && C.eles>=row_limit ) break;
+
+ } while ( (FILE_err&2)==0 );
+ END:;
+ if ( C.rowt ){
+ ARY_MAX (C.row_max, k, C.rowt, 0, C.rows);
+ ARY_MIN (C.row_min, k, C.rowt, 0, C.rows);
+ }
+ if ( fe && C.clmt ){
+ ARY_MAX (C.clm_max, k, C.clmt, 0, C.clms);
+ ARY_MIN (C.clm_min, k, C.clmt, 0, C.clms);
+ }
+ if ( ERROR_MES ) mfree (C.rowt, C.clmt);
+ return (C);
+}
+
+
+/* SLIST:very simple one-sided list */
+void SLIST_init (int *l, int num, int siz){
+ malloc2 (l, num+siz, "SLIST_init: l", EXIT);
+ ARY_FILL (l, num, num+siz, -1);
+}
+void SLIST_end (int *l){ free (l); }
+#define SLIST_INS(l,m,e) (l[e]=l[m],l[m]=e);
+
+/* qsort according to "->t" */
+int qsort_cmp_VECt (const void *x, const void *y){
+ if ( ((VEC *)x)->t < ((VEC *)y)->t ) return (-1);
+ else return ( ((VEC *)x)->t > ((VEC *)y)->t);
+}
+int qsort_cmp__VECt (const void *x, const void *y){
+ if ( ((VEC *)x)->t > ((VEC *)y)->t ) return (-1);
+ else return ( ((VEC *)x)->t < ((VEC *)y)->t);
+}
+void qsort_VECt (VEC *v, size_t siz, int unit){
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (VEC);
+ if ( unit < 0 ) qsort (v, siz, -unit, qsort_cmp__VECt);
+ else qsort (v, siz, unit, qsort_cmp_VECt);
+}
+
+int qqsort_cmp_VECt (const void *x, const void *y){
+ if ( QQSORT_ELEt(VEC,x) < QQSORT_ELEt(VEC,y) ) return (-1);
+ else return ( QQSORT_ELEt(VEC,x) > QQSORT_ELEt(VEC,y) );
+}
+int qqsort_cmp__VECt (const void *x, const void *y){
+ if ( QQSORT_ELEt(VEC,x) > QQSORT_ELEt(VEC,y) ) return (-1);
+ else return ( QQSORT_ELEt(VEC,x) < QQSORT_ELEt(VEC,y) );
+}
+void qsort_perm__VECt (VEC *v, size_t siz, PERM *perm, int unit){
+ if ( unit == 1 || unit==-1 ) unit *= sizeof(VEC);
+ common_int=MAX(unit,-unit); common_charp=(char *)v;
+ if (unit<0) qsort (perm, siz, sizeof(PERM), qqsort_cmp__VECt);
+ else qsort (perm, siz, sizeof(PERM), qqsort_cmp_VECt);
+}
+
+PERM *qsort_perm_VECt (VEC *v, size_t siz, int unit){
+ PERM *perm;
+ malloc2 (perm, siz, "qsort_perm_VECt: perm", EXIT0);
+ ARY_INIT_PERM(perm,siz);
+ qsort_perm__VECt (v, siz, perm, unit);
+ return(perm);
+}
+
+#ifdef STDLIB2_RADIX_SORT // radix sort with 1M byte static memory
+
+#define RADIX_SORT_BUCKET_SIZ 2048
+/* sort of integer array with combination of radix sort and quick sort */
+/* flag&1: sort in decreasing order */
+
+// sort by lower bits
+void intarray_sort_iter (unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ size_t k, x;
+ int i, ii, j, flag=1;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ buf = bbuf; buf2 = bbuf2;
+ if ( init_flag == 1 ){
+ init_flag = 0;
+ ARY_FILL (cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[(*((unsigned int *)aa)) & (RADIX_SORT_BUCKET_SIZ-1)]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP (x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = *((unsigned int *)buf) & (RADIX_SORT_BUCKET_SIZ-1); // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy ( buf2, aaa, unit);
+ memcpy ( aaa, buf, unit);
+ SWAP_PNT ( buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy ( aa, buf, unit);
+ }
+ cnt[i]=0; // difference!!
+ }
+}
+// sort by middle bits
+void intarray_sort_iter_ ( unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ int i, ii, j, flag=1;
+ size_t k, x;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ buf = bbuf; buf2 = bbuf2;
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ if ( init_flag == 1 ){
+ init_flag = 0;
+ ARY_FILL ( cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[((*((unsigned int *)aa))/RADIX_SORT_BUCKET_SIZ) & (RADIX_SORT_BUCKET_SIZ-1)]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP(x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = (*((unsigned int *)buf)/RADIX_SORT_BUCKET_SIZ) & (RADIX_SORT_BUCKET_SIZ-1); // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy (buf2, aaa, unit);
+ memcpy (aaa, buf, unit);
+ SWAP_PNT (buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy (aa, buf, unit);
+ }
+ }
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ intarray_sort_iter ( (unsigned int*)(((char*)a)+unit*k), cnt[ii]-k, unit*flag);
+ k = cnt[ii];
+ cnt[i]=0;
+ }
+}
+
+// sort by upper bits
+void intarray_sort ( unsigned int *a, size_t siz, int unit){
+ static size_t cnt[RADIX_SORT_BUCKET_SIZ], cnt2[RADIX_SORT_BUCKET_SIZ], init_flag = 1;
+ int i, ii, j, flag=1;
+ size_t k, x;
+ static char bbuf[1000], bbuf2[1000];
+ char *aa, *aaa, *aa_end, *buf, *buf2;
+
+ if ( siz<1000 ){ qsort_uint ( a, siz, unit); return; }
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ if ( unit == 1 ) unit = sizeof (int);
+ buf = bbuf; buf2 = bbuf2;
+ if ( init_flag == 1){
+ init_flag = 0;
+ ARY_FILL (cnt, 0, RADIX_SORT_BUCKET_SIZ, 0);
+ }
+ // count elements of each number
+ for ( aa=(char*)a,aa_end=aa+siz*unit ; aa<aa_end ; aa+=unit )
+ cnt[(*((unsigned int *)aa)) / RADIX_SORT_BUCKET_SIZ / RADIX_SORT_BUCKET_SIZ]++; // difference!!
+
+ // sum up the numbers in increasing order
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ cnt2[ii] = k;
+ k += cnt[ii];
+ cnt[ii] = k;
+ }
+
+ FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ FLOOP (x, cnt2[ii], cnt[ii]){
+ aa = ((char*)a) + x*unit;
+ memcpy ( buf, aa, unit);
+ while (1){
+ j = *((unsigned int *)buf) / RADIX_SORT_BUCKET_SIZ / RADIX_SORT_BUCKET_SIZ; // difference!!
+ if ( j == ii ) break;
+ aaa = ((char*)a) + cnt2[j]*unit;
+// printf ("pos[xx]=%d, cnt %d, cnt+1 %d\n", pos[xx], S->let_cnt[dep][cc], S->let_cnt[dep+1][cc]);
+ memcpy (buf2, aaa, unit);
+ memcpy (aaa, buf, unit);
+ SWAP_PNT (buf, buf2);
+ cnt2[j]++;
+ }
+ memcpy ( aa, buf, unit);
+ }
+ }
+ k=0; FLOOP (i, 0, RADIX_SORT_BUCKET_SIZ){
+ ii = flag==1? i: RADIX_SORT_BUCKET_SIZ-i-1;
+ intarray_sort_iter_ ( (unsigned int*)(((char*)a)+unit*k), cnt[ii]-k, unit*flag);
+ k = cnt[ii];
+ cnt[i]=0;
+ }
+
+/*
+ for ( i=0 ; i<siz ; i++){
+ k = *((int *)(((char*)a) + i*unit));
+ printf ("%d %d,%d\n", k, k/65536, k&65535);
+ }
+*/
+}
+
+#endif
+
+/* radix sort for array of structures, by their integer members
+ ranging from mm to m */
+/* sort array "perm" according to (int/void*) array "a".
+ if perm==NULL, allocate memory and for perm */
+/* return the permutation array of the result of the sorting
+ in the decreasing order if unit<0 (unimplemented!!!) */
+int *radix_sort ( void *a, size_t siz, int unit, int mm, int m, int *perm){
+ int *ll, *l, k, i, t, flag=1;
+ malloc2 (l, m-mm, "radix_sort", EXIT0);
+ ARY_FILL (l, 0, m-mm, -1);
+ malloc2 (ll, siz, "radix_sort: ll", {free2(l);EXIT0;});
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ FLOOP (i, 0, (int)siz){
+ k = (*((int *)(((char *)a) + unit*i ))) - mm;
+ ll[i] = l[k];
+ l[k] = i;
+ }
+ if ( perm ){
+ i=0; FLOOP (k, 0, m-mm){
+ while ( l[k] >= 0 ){
+ t = l[k];
+ l[k] = ll[t];
+ ll[t] = perm[i];
+ i++;
+ }
+ }
+ memcpy (perm, ll, sizeof(int)*siz);
+ free ( ll);
+ free ( l);
+ return ( perm);
+ } else {
+ i=0; FLOOP (k, 0, m-mm){
+ while ( l[k] >= 0 ){
+ t = l[k];
+ l[k] = ll[t];
+ ll[t] = i;
+ i++;
+ }
+ }
+ free (l);
+ return (ll);
+ }
+}
+
+/* permutate structure array *tt of unit size unit of size num, according to perm array *pp */
+/* num has to be <INTHUGE/2 */
+/* unit<0 means decreasing order (un-implemented!!!) */
+void structure_permute (void *tt, int unit, int num, void *pp, int weight_siz){
+ int i, ii, *ip, flag=1;
+ char *tmp, *t=(char *)tt, *p=(char *)pp;
+ if ( unit <0 ){ unit = -unit; flag = -1; }
+ malloc2 (tmp, unit, "structure_permute: tmp", EXIT);
+ FLOOP (i, 0, num){
+ ip = (int *)(p + (sizeof(int)+weight_siz)*i + weight_siz);
+ if ( *ip< num && *ip != i ){
+ ii = i;
+ memcpy ( tmp, t + unit*i, unit);
+ while (1) {
+ if ( *ip == i ){
+ memcpy ( t+unit*ii, tmp, unit);
+ *ip += num;
+ break;
+ }
+ memcpy ( t+unit*ii, t+unit*(*ip), unit);
+ ii = *ip;
+ *ip += num;
+ ip = (int *)(p + (sizeof(int)+weight_siz)*ii + weight_siz);
+ }
+ } else *ip += num;
+ }
+ FLOOP (i, 0, num) *(int *)(p + (sizeof(int)+weight_siz)*i + weight_siz ) -= num;
+ free (tmp);
+}
+
+
+
+#endif
+
+
+/******************************************/
+/* ==== terminology for comments ====
+ range check: to check the input parameter is valid, or in the valid range.
+ If a function does not have this, its comment has "no range check"
+ */
+
+/* ==== rules for the name of functions and routines ====
+ init: initialization for an object, structure, etc. memory is allocated
+ if needed.
+ end: compared to init, termination of structures, etc.
+ free allocated memory if it exists, but not free itself.
+ different from ordinary new, create, del, free.
+
+ cpy: copy an object without allocating memory
+ dup: make a duplication of an object with allocating new memory
+
+ new: new. allocate memory for new object. also used for re-allocation from
+ the list of deleted objects
+ del: delete. free memory, or insert it to the list of deleted objects
+
+ ins : insert. insert an element (active, not deleted) to an object, possible
+ at the given position.
+ out : extract. extract an element, possibly specified, from an object.
+ it will be not deleted.
+ rm : extract, and delete
+ rmall: delete all (specified) elements of an object
+ mk : make. new+ins\81B
+ mv : move. move the elements from an object to another,
+ or change the position.
+
+ update : update an object, possibly of specified position, to the exact,
+ or to the current one.
+ chg : change the status of an object to the specified one.
+
+ prv: point the previous element
+ nxt: point the next element
+ end: the maximum size (allocated size) of an array, etc.
+ num: the (current) number of elements in an array, etc.
+ kth: for the use of "first k object"
+ tkth: for the use of "first k object from the end". to kth.
+ rnd: random
+ print: print structure and etc.
+ find: search or find an specified element from the set of structures, etc.
+*/
+
+/* ==== rules for the name of variables ====
+ - use i or j for the counter in loops
+ - use e for elements
+ - use k for the specified rank
+ - use f or flag for flagment
+ - use m for maximum value or minimum value
+ - use c for counters
+*/
+
+
--- /dev/null
+/* library for standard macros and functions
+ by Takeaki Uno 2/22/2002 e-mail: uno@nii.jp
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _stdlib2_h_
+#define _stdlib2_h_
+
+#include<stdlib.h>
+#include<stdio.h>
+#include<string.h>
+#include<math.h>
+#include<time.h>
+#include<stdarg.h>
+
+#if defined(__cplusplus) && defined(__GNUC__)
+ #define _cplusplus_
+#endif
+
+#ifdef MULTI_CORE
+#include <pthread.h>
+#endif
+
+/* comment out the following line if no error check is needed */
+//#define ERROR_CHECK
+/* comment out the following if exit is not needed after each error routine */
+//#define ERROR_RET
+
+#ifdef ERROR_RET // definition of the process for errors
+ #define EXIT return
+ #define EXIT0 return(0)
+#else
+ #define EXIT exit(1)
+ #define EXIT0 exit(1)
+#endif
+
+// for dealing with files more than 2GB
+#define _LARGEFILE_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+#ifdef MTWISTER
+ #define RANDOM ((long)(dsfmt_gv_genrand_close_open()*2147483648LL))
+ #define RAND1 dsfmt_gv_genrand_close_open()
+ #define RAND_INIT dsfmt_gv_init_gen_rand(514346237)
+#elif defined(__GNUC__)
+ #define RANDOM xor128()
+ #define RAND1 ((double)xor128())/4294967296.0
+ #define RAND_INIT xor128()
+#else
+ #define RANDOM rand()
+ #define RAND1 ((double)rand())/2147483648.0
+ #define RAND_INIT srand(0)
+#endif
+
+
+// 64bit integer
+#ifndef LONG
+ #define LONG long long
+ #define LONGHUGE 9000000000000000000LL
+ #define LONGF "%lld"
+#endif
+
+// actual int (most proper sized integer, for the processor)
+#ifdef INT_64
+ #define INT LONG
+ #define INTF LONGF
+#else
+ #define INT int
+ #define INTF "%d"
+#endif
+
+#ifndef FILE_LONG
+ #define FILE_LONG LONG
+ #define FILE_LONGHUGE LONGHUGE
+ #define FILE_LONGF "%lld"
+#endif
+
+#define UINTHUGE 4000000000U
+#define INTHUGE 2000000000
+#define USHORTHUGE 32767
+#define SHORTHUGE 65535
+#define DOUBLEHUGE 999999999999999999999999999999.9
+#define ISEQUAL_VALUE 0.0000001
+#define ISEQUAL_VALUE2 0.00001
+#define PI 3.1415926535897932384647950288
+#define PI_INT 31416
+#define NPE 2.718281828459045235360287471352
+#define NPE_INT 27183
+#define MULTI_CORE_MAX 64
+
+#ifndef WEIGHT
+ #ifdef WEIGHT_DOUBLE
+ #define WEIGHT double
+ #define WEIGHTHUGE DOUBLEHUGE
+ #define WEIGHTF "%f"
+ #else // define WEIGHT by int if it's undefined
+ #define WEIGHT int
+ #define WEIGHTHUGE INTHUGE
+ #define WEIGHTF "%d"
+ #endif
+#endif
+
+#ifndef PERM
+ #ifdef PERM_LONG
+ #define PERM LONG
+ #define PERMHUGE LONGHUGE
+ #define PERMF "%lld"
+ #else
+ #define PERM int
+ #define PERMHUGE INTHUGE
+ #define PERMF "%d"
+ #endif
+#endif
+
+
+extern size_t common_size_t;
+extern INT common_INT, common_INT2;
+extern char *common_pnt, *common_charp;
+extern FILE *common_FILE;
+extern WEIGHT common_WEIGHT, *common_WEIGHTp;
+extern char *ERROR_MES;
+extern int print_time_flag;
+typedef struct {
+ int i1, i2, i3, i4, i5, i6, i7, i8, i9;
+ LONG l1, l2, l3, l4, l5, l6, l7, l8, l9;
+ double d1, d2, d3, d4, d5, d6, d7, d8, d9;
+ char *s1, *s2, *s3, *s4, *s5, *s6, *s7, *s8, *s9;
+ void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9;
+} PARAMS;
+extern PARAMS internal_params;
+
+/* lock&unlock for multi-core mode */
+#ifdef MULTI_CORE
+ extern int SPIN_LOCK_dummy;
+ #define SPIN_LOCK(b,a) (SPIN_LOCK_dummy=(((b)>1)&&pthread_spin_lock(&(a))))
+ #define SPIN_UNLOCK(b,a) (SPIN_LOCK_dummy=(((b)>1)&&pthread_spin_unlock(&(a))))
+#else
+ #define SPIN_LOCK(b,a)
+ #define SPIN_UNLOCK(b,a)
+#endif
+
+#define TYPE_VEC 1
+#define TYPE_MAT 2
+#define TYPE_SVEC 3
+#define TYPE_SMAT 4
+#define TYPE_QUEUE 5
+#define TYPE_SETFAMILY 6
+#define TYPE_TRSACT 7
+#define TYPE_ALIST 8
+#define TYPE_MALIST 9
+#define TYPE_AGRAPH 10
+#define TYPE_SGRAPH 11
+#define TYPE_AHEAP 12
+#define TYPE_BASE 13
+#define TYPE_FSTAR 14
+#define TYPE_FILE2 15
+
+
+
+
+/* random */
+#define rnd(a) (random()%(a))
+#define prob(a) ((random()%65536)<(int)((a)*65536.0))
+
+#define MARK 1
+#define UNMARK 0
+#define TRUE 1
+#define FALSE 0
+
+/* equal/inequal with allowing numerical error for double */
+#define ISEQUAL(a,b) ((a)-(b)<ISEQUAL_VALUE&&(b)-(a)<ISEQUAL_VALUE)
+#define ISGREAT(a,b) ((a)-(b)>ISEQUAL_VALUE)
+#define ISLESS(a,b) ((b)-(a)>ISEQUAL_VALUE)
+#define RANGE(a,b,c) (((a)<=(b))&&((b)<=(c)))
+#define BITRM(a,b) ((a)-=((a)&(b)));
+
+/* macro for getting maximum/minimum of two values */
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define ENMAX(a,b) ((a)=((a)>(b)?(a):(b)))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+#define ENMIN(a,b) ((a)=((a)<(b)?(a):(b)))
+
+/* error routine */
+#define error(mes,x) do{ERROR_MES=mes;fprintf(stderr,"%s\n",mes);x;}while(0)
+#define error_num(mes,n,x) do{ERROR_MES=mes;fprintf(stderr,"%s: %g\n",mes,(double)(n));x;}while(0)
+#define error_str(mes,s,x) do{ERROR_MES=mes;fprintf(stderr,"%s: %s\n",mes,s);x;}while(0)
+#define print_err(...) fprintf(stderr,__VA_ARGS__)
+#define print_mes(flag,...) do{if((flag)&1)fprintf(stderr,__VA_ARGS__);}while(0)
+#define mfree(...) mfree_(NULL, __VA_ARGS__,(void *)1)
+
+
+/* basic array operations and loops */
+#define ARY_FILL(f,start,end,c) do{for(common_size_t=(size_t)(start);common_size_t<(size_t)(end);common_size_t++)(f)[common_size_t]=(c);}while(0)
+#define ARY_INS(f,b) do{(f).v[(f).t++]=(b);}while(0)
+#define ARY_FLOOP(V,i,x) for( (i)=0,x=(V).v[0] ; (i)<(V).t ; (i)++,x=(V).v[i])
+#define ARY_BLOOP(V,i,x) for( (i)=(V).t-1,x=i>0?(V).v[i]:0 ; (i)>=0 ; (i)--,x=i>0?(V).v[i]:0)
+#define FLOOP(i,x,y) for ((i)=(x) ; (i)<(y) ; (i)++)
+#define BLOOP(i,x,y) for ((i)=(x) ; ((i)--)>(y) ; )
+#define MLOOP(z,x,M) for ((z)=(x) ; *(z)<(M) ; (z)++)
+/* binary search: return maximum index no larger than c */
+#define BIN_SRCH(x,a,s,t,c) \
+ do {\
+ x=s; common_size_t=t; while ( x<common_size_t-1 ){\
+ if ( a[(x+common_size_t)/2] <= c ) x = (x+common_size_t)/2; else common_size_t = (x+common_size_t)/2;\
+ } while (0)\
+
+/* allocate memory, and exit with error message if fault */
+#ifdef _cplusplus_
+#define malloc2(f,b,c,x) do{if(!((f)=(typeof(f))malloc(((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define calloc2(f,b,c,x) do{if(!((f)=(typeof(f))calloc(sizeof((f)[0]),b))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define realloc2(f,b,c,x) do{if(!(f=(typeof(f))realloc(f,((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#else
+#define malloc2(f,b,c,x) do{if(!((f)=malloc(((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define calloc2(f,b,c,x) do{if(!((f)=calloc(sizeof((f)[0]),b))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#define realloc2(f,b,c,x) do{if(!(f=realloc(f,((size_t)sizeof((f)[0]))*(b)))){fprintf(stderr,"memory allocation error %s (%lld byte)\n",c,(LONG)((LONG)sizeof((f)[0])*(b)));ERROR_MES="out of memory";x;}}while(0)
+#endif
+
+#define malloc2d(f,b,d,c,x) do{malloc2(f,b,c,x);malloc2((f)[0],(b)*(d)+2,c,{free2(f);x;});FLOOP(common_size_t,0,(size_t)b)(f)[common_size_t]=&((f)[0][common_size_t*(d)]);}while(0)
+#define calloc2d(f,b,d,c,x) do{malloc2(f,b,c,x);calloc2((f)[0],(b)*(d)+2,c,{free2(f);x;});FLOOP(common_size_t,0,(size_t)b)(f)[common_size_t]=&((f)[0][common_size_t*(d)]);}while(0)
+
+/* reallocate memory and expand the memory size */
+#define reallocx_(f,end,end2,e,c,x) do{realloc2(f,end2,c,x);FLOOP(common_size_t,(size_t)end,(size_t)end2)(f)[common_size_t]=(e);}while(0)
+#define reallocx(f,end,i,e,c,x) do{if((size_t)(i)>=(size_t)(end)){reallocx_(f,end,MAX((end)*2+100,(i)+1),e,c,x);end=MAX((end)*2,(i)+1);}}while(0)
+
+/* basic array operations */
+#define ARY_DUP(f,p,end,c,x) do{malloc2(f,end,c,x);memcpy(f,p,sizeof(*(f))*(end));}while(0)
+#define ARY_MAX(m,i,f,x,y) do{(m)=(f)[x];(i)=(x);FLOOP(common_INT,(x)+1,(y))if((m)<(f)[common_INT]){(i)=common_INT;(m)=(f)[i];}}while(0)
+#define ARY_MIN(m,i,f,x,y) do{(m)=(f)[x];(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)>(f)[common_INT]){(i)=common_INT;(m)=(f)[i];}}while(0)
+#define ARY_SUM(f,v,x,y) do{(f)=0;FLOOP(common_INT,x,y)(f)+=(v)[common_INT];}while(0)
+#define ARY_NORM(f,v,b) do{(f)=0;FLOOP(common_INT,0,b)(f)+=(v)[common_INT]*(v)[common_INT];(f)=sqrt(f);}while(0)
+#define ARY_NORMALIZE(v,b) do{ARY_NORM(common_double,v,b);FLOOP(common_INT,0,b)(v)[common_INT]/=common_double;}while(0)
+#define ARY_INPRO(f,u,v,b) do{(f)=0;for (common_INT=0 ; common_INT<(b)-3 ; common_INT+=4) (f)+=(u)[common_INT]*(v)[common_INT] + (u)[common_INT+1]*(v)[common_INT+1] + (u)[common_INT+2]*(v)[common_INT+2] + (u)[common_INT+3]*(v)[common_INT+3]; if (common_INT+1<(b)){(f)+=(u)[common_INT]*v[common_INT]+(u)[common_INT+1]*(v)[common_INT+1]; if (common_INT+2<(b)) (f)+=(u)[common_INT+2]*(v)[common_INT+2];} else if (common_INT<(b)) (f)+=(u)[common_INT]*(v)[common_INT];}while(0)
+
+//#define ARY_DIST(f,u,v,b) do{(f)=0;for (common_size_t=0 ; common_size_t<(b)-3 ; common_size_t+=4)(f)+=(u)[common_size_t]*(v)[common_size_t]; if (common_size_t+1<(b)){(f)+=(u)[common_size_t]*v[common_size_t]+(u)[common_size_t+1]*(v)[common_size_t+1]; if (common_size_t+2<(b)) (f)+=(u)[common_size_t+2]*(v)[common_size_t+2];} else if (common_size_t<b) (f)+=(u)[common_size_t]*(v)[common_size_t];}while(0)
+
+/* macros for permutation arrays */
+#define ARY_INIT_PERM(f,end) do{FLOOP(common_INT,0,(INT)end)(f)[common_INT]=common_INT;}while(0)
+#define ARY_INV_PERM_(f,p,end) do{ARY_FILL(f,0,end,-1);FLOOP(common_INT,0,end)if((p)[common_INT]>=0&&(p)[common_INT]<(end))(f)[(p)[common_INT]]=common_INT;}while(0)
+#define ARY_INV_PERM(f,p,end,c,x) do{malloc2(f,end,c,x);ARY_INV_PERM_(f,p,end);}while(0)
+#define ARY_RND_PERM_(f,end) do{(f)[0]=0;FLOOP(common_INT,1,end){common_INT2=rnd(common_INT+1);(f)[common_INT]=(f)[common_INT2];(f)[common_INT2]=common_INT;}}while(0)
+#define ARY_RND_PERM(f,end,c,x) do{malloc2(f,end,c,x);ARY_RND_PERM_(f,end);}while(0)
+ /* permute f so that f[i]=f[p[i]] (inverse perm). p will be destroyed (filled by end) */
+#define ARY_INVPERMUTE_(f,p,s,end) do{ FLOOP(common_INT,0,end){ if ( (p)[common_INT]<(end) ){ (s)=(f)[common_INT]; do { common_INT2=common_INT; common_INT=(p)[common_INT]; (f)[common_INT2]=(f)[common_INT]; (p)[common_INT2]=end; }while ( (p)[common_INT]<(end) ); (f)[common_INT2] = (s);}}}while(0)
+ /* permute f so that f[i]=f[p[i]] (inverse perm). not destroy p by allocating tmp memory */
+#define ARY_INVPERMUTE(f,p,s,end,c,x) do{ calloc2(common_pnt,end,c,x);FLOOP(common_INT,0,end){ if ( common_pnt[common_INT]==0 ){ (s)=(f)[common_INT]; do{ common_INT2=common_INT; common_INT=(p)[common_INT]; (f)[common_INT2]=(f)[common_INT]; common_pnt[common_INT2]=1; }while( common_pnt[common_INT]==0 ); (f)[common_INT2] = (s);}} free(common_pnt); }while(0)
+//#define ARY_PERM(f,p,s,mark,end) do{FLOOP(common_size_t,0,end){ }}while(0)
+
+/* macros for printing (writing to file) arrays */
+#define ARY_PRINT(f,x,y,a) do{FLOOP(common_size_t,x,y)printf(a,(f)[common_size_t]);printf("\n");}while(0)
+#define ARY_FPRINT(fp,f,x,y,a) do{FLOOP(common_size_t,(size_t)x,(size_t)y)fprintf((FILE *)fp,a,(f)[common_size_t]);fputc('\n',(FILE *)fp);}while(0)
+#define ARY_EXP(f,a,c,x) do{reallocx((f).v,a,(f).end,(f).t,e,c,x);}while(0)
+
+#define ST_MAX(m,i,S,a,x,y) do{(m)=(S)[x].a;(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)<(S)[common_INT].a){(i)=common_INT;(m)=(S)[i].a;}}while(0)
+#define ST_MIN(m,i,S,a,x,y) do{(m)=(S)[x].a;(i)=(x);FLOOP(common_INT,(x)+1,y)if((m)>(S)[common_INT].a){(i)=common_INT;(m)=(S)[i].a;}}while(0)
+#define ST_SUM(k,S,a,x,y) do{(k)=0;FLOOP(common_INT,x,y)(k)+=(S)[common_INT].a;}while(0)
+#define ST_FILL(S,a,start,end,c) do{for(common_INT=(start);common_INT<(end);common_INT++)(S)[common_INT].a = (c);}while(0)
+#define ST_PRINT(S,a,x,y,f) do{FLOOP(common_size_t,x,y)printf(f,(S)[common_size_t].a );printf("\n");}while(0)
+
+
+
+/* a macro for open files with exiting if an error occurs */
+#ifdef _MSC_
+ #define fopen2(f,a,b,c,x) do{fopen_s(&f,a,b);if(!f){ERROR_MES="file open error";fprintf(stderr,"file open error: %s, file name %s, open mode %s\n",c,a,b);x;}}while(0)
+#else
+ #define fopen2(f,a,b,c,x) do{if(!((f)=fopen(a,b))){ERROR_MES="file open error";fprintf(stderr,"file open error: %s, file name %s, open mode %s\n",c,a,b);x;}}while(0)
+#endif
+#define FILE2_open(f,a,b,c,x) do{if(a)fopen2((f).fp,a,b,c,x);else(f).fp=NULL;malloc2((f).buf_org,FILE2_BUFSIZ+1,c,x);(f).buf=(f).buf_org;(f).buf_end=(f).buf_org-1;}while(0)
+#define FILE2_open_(f,a,c,x) do{(f).fp=a;malloc2((f).buf_org,FILE2_BUFSIZ+1,c,x);(f).buf=(f).buf_org;(f).buf_end=(f).buf_org-1;}while(0)
+
+/* macros for allocating memory with exiting if an error occurs */
+#define free2(a) do{if(a){free(a);(a)=NULL;}}while(0)
+#define free2d(a) do{if(a){free2((a)[0]);}free(a);(a)=NULL;}while(0)
+#define fclose2(a) do{if(a){fclose(a);(a)=NULL;}}while(0)
+
+/* macros for reading integers from file, d=0 read one-line, d=1 read all file */
+//#define ARY_SCAN(k,a,fp,d) do{(k)=0;do{do{FILE2_read_##a(&(fp));}while((FILE_err&6)==8-(d)*4);if(FILE_err&(4-2*(d)))break;(k)++;}while((FILE_err&(3-(d)))==0);}while(0)
+#define ARY_SCAN(k,a,fp,d) do{(k)=0;do{do{FILE2_read_##a(&(fp));}while((FILE_err&((d)*5))==5);if(RANGE(5+(int)(d),FILE_err,6))break;(k)++;}while((FILE_err&(3-(int)(d)))==0);}while(0)
+#define ARY_READ(f,a,k,fp) do{FLOOP(common_size_t,0,(size_t)k){do{(f)[common_size_t]=FILE2_read_##a(&(fp));}while((FILE_err&6)==4);if(FILE_err&2)break;}}while(0)
+#define ARY_LOAD(f,a,k,n,d,c,x) do{FILE2_open(common_FILE2,n,"r",c,x);ARY_SCAN(k,a,common_FILE2,d);malloc2(f,(k)+1,c,x);FILE2_reset(&common_FILE2);ARY_READ(f,a,k,common_FILE2);FILE2_close(&common_FILE2);}while(0)
+#define ARY_WRITE(n,f,k,q,c,x) do{fopen2(common_FILE,n,"w",c,x);ARY_FPRINT(common_FILE,f,0,k,q);fclose(common_FILE);}while(0)
+
+/* macros for generalized queue; end mark is necessary for INTSEC */
+#define MQUE_FLOOP(V,z) for((z)=(V).v;(z)<(V).v+(V).t ; (z)++)
+
+#ifdef _cplusplus_
+ #define MQUE_FLOOP_(V,z,s) for((z)=(V).v ; (char *)(z)<((char *)(V).v)+(V).t*(s) ; (z)=(typeof(z))(((char *)(z))+(s)))
+#else
+ #define MQUE_FLOOP_(V,z,s) for((z)=(V).v ; (char *)(z)<((char *)(V).v)+(V).t*(s) ; (z)=(void *)(((char *)(z))+(s)))
+#endif
+
+#define MQUE_MLOOP(V,z,M) for((z)=(V).v; *((QUEUE_INT *)z)<(M) ; (z)++)
+
+/// !!! errr MQUE_INTSEC !!!!!
+#define MQUE_INTSEC(f,U,V) do{\
+common_INT=0;(f)=0;\
+FLOOP(common_INT2,0,(U).t){\
+ while(*((QUEUE_INT *)(&((V).v[common_INT])))<*((QUEUE_INT *)(&((U).v[common_INT2])))&&common_INT<(V).t){ \
+ if (++common_INT >= (V).t) break;\
+ }if(*((QUEUE_INT *)(&((V).v[common_INT])))==*((QUEUE_INT *)(&((U).v[common_INT2]))))(f)++;\
+}}while(0)
+#define MQUE_UNION(f,U,V) do{MQUE_INTSEC(f,U,V);(f)=(U).t+(V).t-(f);}while(0)
+#define MQUE_DIF(f,U,V) do{MQUE_INTSEC(f,U,V);(f)=(U).t+(V).t-(f)-(f);}while(0)
+#define MQUE_RM_DUP(V) do{\
+if((V).t>1){\
+ common_INT=1;\
+ FLOOP(common_INT2,1,(V).t){\
+ if ( *((QUEUE_INT *)(&((V).v[common_INT2-1]))) != *((QUEUE_INT *)(&((V).v[common_INT2]))) ) (V).v[common_INT++]=(V).v[common_INT2];\
+ } (V).t=common_INT;\
+ }\
+}while(0)
+
+#define MQUE_UNIFY(V,a) do{\
+if((V).t>1){\
+ common_INT=0;\
+ FLOOP(common_INT2,1,(V).t){\
+ if ( *((QUEUE_INT *)(&((V).v[common_INT2-1]))) != *((QUEUE_INT *)(&((V).v[common_INT2]))) ) (V).v[++common_INT]=(V).v[common_INT2];\
+ else *((a*)(((QUEUE_INT *)(&((V).v[common_INT2])))+1)) += *((a*)(((QUEUE_INT *)(&((V).v[common_INT2])))+1));\
+ } (V).t=common_INT+1;\
+}}while(0)
+
+
+
+
+#ifndef VEC_VAL
+ #ifdef VEC_VAL_CHAR
+ #define VEC_VAL char
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END 128
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%hhd"
+ #elif defined(VEC_VAL_UCHAR)
+ #define VEC_VAL unsigned char
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END 256
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%hhu"
+ #elif defined(VEC_VAL_INT)
+ #define VEC_VAL int
+ #define VEC_VAL2 LONG
+ #define VEC_VAL_END INTHUGE
+ #define VEC_VAL2_END LONGHUGE
+ #define VEC_VALF "%d"
+ #else
+ #define VEC_VAL double
+ #define VEC_VAL2 double
+ #define VEC_VAL_END DOUBLEHUGE
+ #define VEC_VAL2_END DOUBLEHUGE
+ #define VEC_VALF "%f"
+ #endif
+#endif
+
+#ifndef VEC_ID
+ #ifdef VEC_ID_LONG
+ #define VEC_ID LONG
+ #define VEC_ID_END LONGHUGE
+ #define VEC_IDF "%lld"
+ #else
+ #define VEC_ID int
+ #define VEC_ID_END INTHUGE
+ #define VEC_IDF "%d"
+ #endif
+#endif
+
+/* vector */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ VEC_VAL *v;
+ VEC_ID end;
+ VEC_ID t;
+} VEC;
+
+extern VEC INIT_VEC;
+extern PERM common_PERM, *common_PERMp;
+extern VEC_VAL common_VEC_VAL, *common_VEC_VALp;
+extern VEC_ID common_VEC_ID;
+
+/* tranpose the matrix ; counting/transpose/memory_allocate */
+#define MQUE_DELIVERY_CNT(c,jump,f,y,M) do{ \
+FLOOP(common_VEC_ID, 0, (f).t){ \
+ MQUE_MLOOP( (f).v[common_VEC_ID], y, M){ \
+ if( (c)[*((QUEUE_INT *)y)] == 0 ) ARY_INS(jump, *((QUEUE_INT *)y)); \
+ (c)[*((QUEUE_INT *)y)]++; \
+ } \
+}}while(0)
+#define MQUE_DELIVERY(occ,jump,f,y,M) do{ \
+FLOOP (common_VEC_ID, 0, (f).t){ \
+ MQUE_MLOOP ((f).v[common_VEC_ID], y, M){ \
+ if( (occ)[*((QUEUE_INT *)y)].t == 0 ) ARY_INS( jump, *((QUEUE_INT *)y)); \
+ ARY_INS( (occ)[*((QUEUE_INT *)y)], common_VEC_ID); \
+ } \
+}}while(0)
+#ifdef _cplusplus_
+#define MQUE_ALLOC(Q,rows,rowt,unit,ext,x) do{ \
+common_size_t=0; \
+FLOOP (common_VEC_ID, 0, rows) common_size_t += rowt[common_VEC_ID]; \
+calloc2 (Q, (rows)+1, "MQUE_ALLOC: Q", x); \
+malloc2 (common_pnt, (common_size_t+(rows)*(ext)+2)*((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit)), "MQUE_ALLOC: Q.v", {free(Q);x;}); \
+FLOOP (common_VEC_ID, 0, rows){ \
+ (Q)[common_VEC_ID].end = rowt[common_VEC_ID]; \
+ (Q)[common_VEC_ID].v = (typeof((Q)[common_VEC_ID].v))common_pnt; \
+ common_pnt += ((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit))*(rowt[common_VEC_ID]+(ext));\
+}}while(0)
+#else
+#define MQUE_ALLOC(Q,rows,rowt,unit,ext,x) do{ \
+common_size_t=0; \
+FLOOP (common_VEC_ID, 0, rows) common_size_t += rowt[common_VEC_ID]; \
+calloc2 (Q, (rows)+1, "MQUE_ALLOC: Q", x); \
+malloc2 (common_pnt, (common_size_t+(rows)*(ext)+2)*((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit)), "MQUE_ALLOC: Q.v", {free(Q);x;}); \
+FLOOP (common_VEC_ID, 0, rows){ \
+ (Q)[common_VEC_ID].end = rowt[common_VEC_ID]; \
+ (Q)[common_VEC_ID].v = (void *)common_pnt; \
+ common_pnt += ((unit)<sizeof(QUEUE_INT)?sizeof(QUEUE_INT):(unit))*(rowt[common_VEC_ID]+(ext));\
+}}while(0)
+#endif
+
+/*********************************************************/
+
+#define SHOW_MESSAGE 1 // not print messages
+#define SHOW_PROGRESS 2 // show progress of the computation
+#define LOAD_PERM 8 // permute the nodes/items by something
+#define LOAD_RM_DUP 16 // duplicate items in each row, for loading data
+#define LOAD_INCSORT 32 // sort rows in increasing order, for loading data
+#define LOAD_DECSORT 64 // sort rows in decreasing order, for loading data
+#define LOAD_ELE 128 // load tuple-list file
+#define LOAD_TPOSE 256 // transpose the file when load
+#define LOAD_DBLBUF 512 // transpose the file when load
+#define LOAD_WSORT 1024 // sort rows by their weights
+#define LOAD_SIZSORT 2048 // sort rows by their sizes
+#define LOAD_DECROWSORT 4096 // sort rows in decreasing order
+#define LOAD_NUM 8192 // read #columns, #rows and #elements from the 1st line of the file
+
+#define LOAD_EDGEW 16384 // read edge weight
+#define LOAD_ARCW 32768 // read arc weight
+#define LOAD_NODEW 65536 // read node weight
+#define LOAD_BIPARTITE 131072 // read bipartite graph
+#define LOAD_EDGE 262144 // read edge
+#define LOAD_ARC 524288 // read arc
+#define LOAD_GRAPHNUM 1048576 // read #vertices and #edges from the 1st line of the file
+#define LOAD_ID1 2097152 // node ID begins from 1
+
+#define FILE_COUNT_ROWT 32 // count size of each row
+#define FILE_COUNT_CLMT 64 // count size of each column
+#define FILE_COUNT_NUM LOAD_NUM // read #columns, #rows and #elements
+#define FILE_COUNT_GRAPHNUM LOAD_GRAPHNUM // read #vertices and #edges
+
+#define FILE2_BUFSIZ 16384
+typedef struct { // structure for fast file reader routines
+ unsigned char type; // type definition
+ FILE *fp;
+ char *buf_org, *buf, *buf_end; // head/current/tail of buffer
+} FILE2;
+extern FILE2 INIT_FILE2, common_FILE2;
+
+void FILE2_flush (FILE2 *fp);
+void FILE2_close (FILE2 *fp);
+void FILE2_closew (FILE2 *fp);
+void FILE2_reset (FILE2 *fp);
+int FILE2_getc (FILE2 *fp);
+void FILE2_puts (FILE2 *fp, char *s);
+void FILE2_putc (FILE2 *fp, char c);
+
+/* message output */
+//void print_mes (int flag, char *mes, ...);
+//void print_err (char *mes, ...);
+void mfree_(void *x, ...);
+
+/* compute the minimum prime no less than n */
+LONG min_prime (LONG n);
+
+/* decompose the string by separator, and set v[i] to each resulted string.
+ consecutive separators are regarded as one separator. */
+int string_decompose (char **v, char *s, char sep, int max);
+
+/* make two random numbers under normal distribution N(0,1) */
+void rand_mk_2normal (double *a, double *b);
+/* make a random point on a supersphere of d-dim., and set to double array already allocated */
+void rand_d_gaussian (double *p, int d);
+void rand_sphere (double *p, int d);
+
+
+
+/* Read an integer from the file and return it,
+ with read through the non-numeric letters.
+ If it reaches to the end-of-file, then set FILE_err=2, if it reads a
+ newline, then set FILE_err=1.
+ If read either the end-of-file or newline before reading an integer,
+ return -1 */
+FILE_LONG FILE2_read_int (FILE2 *fp);
+double FILE2_read_double (FILE2 *fp);
+WEIGHT FILE2_read_WEIGHT (FILE2 *fp);
+
+/* fast file routine, print number, c is the char to be printed preceding to the number
+ if c==0, nothing will be printed preceding the number
+ if len<0 then the #digits following '.' does not change (filed by '0') */
+void FILE2_print_int (FILE2 *fp, LONG n, char c);
+void FILE2_print_real (FILE2 *fp, double n, int len, char c);
+void FILE2_print_WEIGHT (FILE2 *fp, WEIGHT w, int len, char c);
+void FILE2_printf (FILE2 *fp, char *mes, ...);
+
+/* print a real number in a good style */
+void fprint_real (FILE *fp, double f);
+void print_real (double f);
+void fprint_WEIGHT (FILE *fp, WEIGHT f);
+void print_WEIGHT (WEIGHT f);
+
+#define FILE_COUNT_INT VEC_ID
+#define FILE_COUNT_INTF VEC_IDF
+typedef struct {
+ int flag;
+ FILE_COUNT_INT clms, rows, eles, clm_end, row_end, row_btm, clm_btm; // #rows, #column, #elements, minimum elements
+ FILE_COUNT_INT row_min, row_max, clm_min, clm_max; // maximum/minimum size of column
+ FILE_COUNT_INT *rowt, *clmt; // size of each row/clmn
+ WEIGHT total_rw, total_cw, *rw, *cw; // WEIGHTs for rows/columns ... reserved.
+ FILE_COUNT_INT rw_end, cw_end;
+ PERM *rperm, *cperm; // permutation (original->internal) of rows and columns
+} FILE_COUNT;
+
+extern FILE_COUNT INIT_FILE_COUNT;
+
+/* count the clms, rows, items, each row size, each column size */
+/* file types can be, array list and element list*/
+/* support transpose */
+FILE_COUNT FILE2_count (FILE2 *fp, int flag, int skip_rows, int int_rows, int skip_clms, int int_clms, FILE_COUNT_INT row_limit);
+
+/******************* integer array routines **************************/
+
+/******************************* permutation routines ****************/
+/* permutation is given by an integer array */
+
+/* sort an array of size "siz", composed of a structure of size "unit" byte
+ in the order of perm */
+/* use temporary memory of siz*unit byte */
+//void perm_struct (void *a, int unit, int *perm, size_t siz);
+
+/* SLIST:very simple one-sided list */
+void SLIST_init (int *l, int num, int siz);
+void SLIST_end (int *l);
+#define SLIST_INS(l,m,e) (l[e]=l[m],l[m]=e);
+
+#define QQSORT_ELE(a,x) ((a *)(&(common_pnt[(*((PERM *)(x)))*common_int])))
+#define QQSORT_ELEt(a,x) (((a *)&(common_pnt[(*((PERM *)x))*common_int]))->t)
+/* quick sort macros */
+#define QSORT_TYPE(a,b) \
+b common_##a; \
+int qsort_cmp_##a (const void *x, const void *y){ \
+ if ( *((b *)x) < *((b *)y) ) return (-1); else return ( *((b *)x) > *((b *)y) ); \
+} \
+int qsort_cmp__##a (const void *x, const void *y){ \
+ if ( *((b *)x) > *((b *)y) ) return (-1); else return ( *((b *)x) < *((b *)y) ); \
+} \
+int qqsort_cmp_##a (const void *x, const void *y){ \
+ b *xx=QQSORT_ELE(b,x), *yy=QQSORT_ELE(b,y); \
+ if ( *xx < *yy ) return (-1); \
+ else return ( *xx > *yy ); \
+} \
+int qqsort_cmp__##a (const void *x, const void *y){ \
+ b *xx=QQSORT_ELE(b,x), *yy=QQSORT_ELE(b,y); \
+ if ( *xx > *yy ) return (-1); \
+ else return ( *xx < *yy ); \
+} \
+void qsort_##a (b *v, size_t siz, int unit){ \
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (b); \
+ if (unit<0) qsort (v, siz, -unit, qsort_cmp__##a); else qsort (v, siz, unit, qsort_cmp_##a); \
+} \
+void qsort_perm__##a (b *v, size_t siz, PERM *perm, int unit){ \
+ ARY_INIT_PERM(perm,(INT)siz); \
+ if ( unit == 1 || unit==-1 ) unit *= sizeof (b); \
+ common_int=MAX(unit,-unit); common_pnt=(char *)v; \
+ if (unit<0) qsort (perm, siz, sizeof(PERM), qqsort_cmp__##a); \
+ else qsort (perm, siz, sizeof(PERM), qqsort_cmp_##a); \
+} \
+PERM *qsort_perm_##a (b *v, size_t siz, int unit){ \
+ PERM *perm; malloc2(perm, siz, "qsort_perm_##a:perm", EXIT0); \
+ qsort_perm__##a (v, siz, perm, unit); return(perm); \
+} \
+size_t bin_search_##a (b *v, b u, size_t siz, int unit){ \
+ size_t s=0, t; \
+ b n; \
+ int sign = 1; \
+ if ( unit < 0 ){ sign = -1; unit = -unit; } \
+ if ( unit == 1 ) unit *= sizeof (b); \
+ while(1) { \
+ t = (s+siz) /2; \
+ n = *((b *)(((char *)v)+unit*t)); \
+ if ( u == n ){ common_int = 1; return (t); }; \
+ if ( s == t ) break; \
+ if ( (u < n && sign>0) || (u > n && sign<0) ) siz = t; else s = t; \
+ } \
+ common_int = 0; \
+ return (u<=n? s: s+1); \
+}
+#define QSORT_TYPE_HEADER(a,b) \
+extern b common_##a; \
+int qsort_cmp_##a (const void *x, const void *y); \
+int qsort_cmp__##a (const void *x, const void *y); \
+int qqsort_cmp_##a (const void *x, const void *y); \
+int qqsort_cmp__##a (const void *x, const void *y); \
+void qsort_##a(b *v, size_t siz, int unit); \
+void qsort_perm__##a (b *v, size_t siz, PERM *perm, int unit); \
+PERM *qsort_perm_##a (b *v, size_t siz, int unit); \
+size_t bin_search_##a (b *v, b u, size_t siz, int unit);
+
+QSORT_TYPE_HEADER(int, int)
+QSORT_TYPE_HEADER(uint, unsigned int)
+QSORT_TYPE_HEADER(double, double)
+QSORT_TYPE_HEADER(char, char)
+QSORT_TYPE_HEADER(uchar, unsigned char)
+QSORT_TYPE_HEADER(short, short)
+QSORT_TYPE_HEADER(ushort, unsigned short)
+QSORT_TYPE_HEADER(WEIGHT, WEIGHT)
+QSORT_TYPE_HEADER(LONG, LONG)
+QSORT_TYPE_HEADER(VEC_ID, VEC_ID)
+QSORT_TYPE_HEADER(VEC_VAL, VEC_VAL)
+QSORT_TYPE_HEADER(VEC_VAL2, VEC_VAL2)
+QSORT_TYPE_HEADER(FILE_COUNT_INT, FILE_COUNT_INT)
+
+int qsort_cmp_VECt (const void *x, const void *y);
+int qsort_cmp__VECt (const void *x, const void *y);
+void qsort_VECt (VEC *v, size_t siz, int unit);
+int qqsort_cmp_VECt (const void *x, const void *y);
+int qqsort_cmp__VECt (const void *x, const void *y);
+void qsort_perm__VECt (VEC *v, size_t siz, PERM *perm, int unit);
+PERM *qsort_perm_VECt (VEC *v, size_t siz, int unit);
+
+/* swap macro for integer, double, char, and pointer */
+#define SWAP_INT(a,b) (common_LONG=a,a=b,b=common_LONG)
+#define SWAP_DOUBLE(a,b) (common_double=a,a=b,b=common_double)
+#define SWAP_size_t(a,b) (common_size_t=a,a=b,b=common_size_t)
+#ifdef _cplusplus_
+ #define SWAP_PNT(a,b) (common_pnt=(typeof(common_pnt))a,a=(typeof(a))b,b=(typeof(b))common_pnt)
+#else
+ #define SWAP_PNT(a,b) (common_pnt=(void *)a,a=(void *)b,b=(void *)common_pnt)
+#endif
+
+#define SWAP_VEC_ID(a,b) (common_VEC_ID=a,a=b,b=common_VEC_ID)
+#define SWAP_FILE_COUNT_INT(a,b) (common_FILE_COUNT_INT=a,a=b,b=common_FILE_COUNT_INT)
+
+/* sort index(int)/WEIGHT array and return the indices of the result */
+/* perm[i*2] := rank of ith cell */
+/* perm[i*2+1] := index of ith smallest cell */
+/* flag!=NULL => opposite direction sort */
+
+//int *int_index_sort (int *w, size_t siz, int flag);
+//int *WEIGHT_index_sort (WEIGHT *w, size_t siz, int flag);
+
+/* radix sort for array of structures, by their integer members
+ ranging from mm to m */
+/* sort array "perm" according to (int/void*) array "a".
+ if perm==NULL, allocate memory and for perm */
+/* return the permutation array of the result of the sorting
+ in the decreasing order if unit<0 (unimplemented!!!) */
+int *radix_sort (void *a, size_t siz, int unit, int mm, int m, int *perm);
+
+/* permutate structure array *tt of unit size unit of size num, according to perm array *pp */
+/* num has to be <INTHUGE/2 */
+/* unit<0 means decreasing order (un-implemented!!!) */
+void structure_permute (void *tt, int unit, int num, void *pp, int weight_siz);
+
+#ifdef STDLIB2_RADIX_SORT // radix sort with 1M byte static memory
+void intarray_sort_iter (unsigned int *a, size_t siz, int unit);
+void intarray_sort_iter_ (unsigned int *a, size_t siz, int unit);
+void intarray_sort (unsigned *a, size_t siz, int unit);
+#endif
+
+ /* bitmasks, used for bit operations */
+extern int BITMASK_UPPER1[32];
+extern int BITMASK_UPPER1_[32];
+extern int BITMASK_LOWER1[32];
+extern int BITMASK_LOWER1_[32];
+extern int BITMASK_1[32];
+extern int BITMASK_31[32];
+extern int BITMASK_16[8];
+extern int BITMASK_UPPER16[8];
+extern int BITMASK_LOWER16[8];
+extern int BITMASK_FACT16[8];
+
+
+#endif
+
+
+/******************************************/
+/* ==== terminology for comments ====
+ range check: to check the input parameter is valid, or in the valid range.
+ If a function does not have this, its comment has "no range check"
+ */
+
+/* ==== rules for the name of functions and routines ====
+ init: initialization for an object, structure, etc. memory is allocated
+ if needed.
+ end: compared to init, termination of structures, etc.
+ free allocated memory if it exists, but not free itself.
+ different from ordinary new, create, del, free.
+
+ cpy: copy an object without allocating memory
+ dup: make a duplication of an object with allocating new memory
+
+ new: new. allocate memory for new object. also used for re-allocation from
+ the list of deleted objects
+ del: delete. free memory, or insert it to the list of deleted objects
+
+ ins : insert. insert an element (active, not deleted) to an object, possible
+ at the given position.
+ out : extract. extract an element, possibly specified, from an object.
+ it will be not deleted.
+ rm : extract, and delete
+ rmall: delete all (specified) elements of an object
+ mk : make. new+ins\81B
+ mv : move. move the elements from an object to another,
+ or change the position.
+
+ update : update an object, possibly of specified position, to the exact,
+ or to the current one.
+ chg : change the status of an object to the specified one.
+
+ prv: point the previous element
+ nxt: point the next element
+ end: the maximum size (allocated size) of an array, etc.
+ num: the (current) number of elements in an array, etc.
+ kth: for the use of "first k object"
+ tkth: for the use of "first k object from the end". to kth.
+ rnd: random
+ print: print structure and etc.
+ find: search or find an specified element from the set of structures, etc.
+*/
+
+/* ==== rules for the name of variables ====
+ - use i or j for the counter in loops
+ - use e for elements
+ - use k for the specified rank
+ - use f or flag for flagment
+ - use m for maximum value or minimum value
+ - use c for counters
+*/
+
+
--- /dev/null
+/* QUEUE based Transaction library, including database reduction.
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _trsact_c_
+#define _trsact_c_
+
+// #define WEIGHT_DOUBLE
+
+#include"trsact.h"
+#include"base.c"
+#include"vec.c"
+
+/***********************************/
+/* print transactions */
+/***********************************/
+void TRSACT_print (TRSACT *T, QUEUE *occ, PERM *p){
+ VEC_ID i, t;
+ QUEUE_ID j;
+ QUEUE_INT e;
+ FLOOP (i, 0, occ? occ->t: T->T.t){
+ t = occ? *((QUEUE_INT *)(&(((char *)(occ->v))[i*T->occ_unit]))): i;
+ if ( occ ) printf (QUEUE_INTF "::: ", t);
+ ARY_FLOOP (T->T.v[t], j, e){
+ printf (QUEUE_INTF, p? p[e]: e);
+ if ( T->T.w ) printf ("(" WEIGHTF ")", T->T.w[t][j]);
+ printf (",");
+ }
+ if ( T->w ) printf (" :" WEIGHTF " ", T->w[t]);
+ printf (" (" QUEUE_INTF ")\n", T->T.v[t].end);
+ }
+}
+
+/*
+void TRSACT_prop_print (TRSACT *T){
+ print_err ("trsact: %s", P->trsact_fname);
+ if ( P->trsact2_fname2 ) print_err (" ,2nd-trsact2 %s (from ID %d)", P->trsact_fname2, P->TT.end1);
+ print_err (" ,#transactions %d ,#items %d ,size %zd", P->TT.rows_org, P->TT.clms_org, P->TT.eles_org);
+ print_err (" extracted database: #transactions %d ,#items %d ,size %zd", P->TT.T.t, P->TT.T.clms, P->TT.T.eles);
+ if ( P->trsact_wfname ) print_err (" ,weightfile %s", P->trsact_wfname);
+ if ( P->trsact_wfname2 ) print_err (" ,2nd-weightfile %s", P->trsact_wfname2);
+ if ( P->trsact_pfname ) print_err (" ,item-order-file %s", P->trsact_pfname);
+ print_err ("\n");
+}
+*/
+
+/* initialization of structure TRSACT */
+void TRSACT_init (TRSACT *T){
+ T->type = TYPE_TRSACT;
+ T->flag = 0;
+ T->T = INIT_SETFAMILY;
+ T->clms_org = T->clm_max = T->clms_end = T->non_empty_clms = 0;
+ T->rows_org = T->row_max = T->end1 = T->sep = 0;
+ T->perm = NULL;
+ T->trperm = NULL;
+ T->w = T->pw = NULL;
+
+ T->clm_lb = 0;
+ T->clm_ub = VEC_ID_END;
+ T->row_lb = 0;
+ T->row_ub = QUEUE_IDHUGE;
+ T->w_lb = -WEIGHTHUGE; T->w_ub = WEIGHTHUGE;
+
+ T->eles_org = 0;
+ T->total_w = T->total_pw = T->total_w_org = T->total_pw_org =0;
+
+ T->jump = INIT_QUEUE;
+ T->str_num = 0;
+ T->head = T->strID = NULL;
+
+ T->th = 1;
+ T->mark = NULL;
+ T->shift = NULL;
+ T->occ_unit = sizeof(QUEUE_INT);
+ T->OQ = NULL;
+ T->sc = NULL;
+
+ T->new_t = 0;
+ T->buf = INIT_BASE;
+ T->wbuf = INIT_BASE;
+}
+
+/**************************************************************/
+void TRSACT_end (TRSACT *T){
+ if ( T->OQ ){ free2 (T->OQ->v ); free2 (T->OQ[T->T.clms].v); }
+ free2 (T->T.w);
+ SETFAMILY_end (&T->T);
+ if ( T->w != T->pw ) free2 (T->pw);
+ mfree (T->w, T->perm, T->trperm);
+ mfree (T->mark, T->shift, T->sc, T->OQ, T->head, T->strID);
+ QUEUE_end (&T->jump);
+ BASE_end (&T->buf);
+ BASE_end (&T->wbuf);
+ TRSACT_init (T);
+}
+
+/*****************************************/
+/* scan file "fp" with weight file wfp and count #items, #transactions in the file. */
+/* count weight only if wfp!=NULL */
+/* T->rows_org, clms_org, eles_org := #items, #transactions, #all items */
+/* ignore the transactions of size not in range T->clm_lb - clm_ub */
+/* T->total_w, total_pw := sum of (positive) weights of transactions */
+/* C->clmt[i],C->cw[i] := the number/(sum of weights) of transactions including i */
+/****************************************/
+void TRSACT_file_count (TRSACT *T, FILE_COUNT *C, FILE2 *fp, char *wf){
+ QUEUE_INT i, item, kk=0, k, jump_end=0;
+ WEIGHT w, s;
+ VEC_ID *jump=NULL;
+ FILE2 wfp;
+
+ if ( wf ){
+ FILE2_open (wfp, wf, "r", "TRSACT_file_count:weight file", goto ERR);
+ ARY_SCAN (kk, WEIGHT, wfp, 1);
+ kk += T->rows_org;
+ realloc2 (C->rw, kk+1, "TRSACT_file_count: C->rw", goto ERR);
+ FILE2_reset (&wfp);
+ ARY_READ (C->rw, double, kk, wfp);
+ ARY_MIN (w, i, C->rw, 0, kk);
+ if ( w<0 ) T->flag |= TRSACT_NEGATIVE;
+ FILE2_close (&wfp);
+ }
+ do {
+ s=0;
+ k=0;
+ w = wf? (T->rows_org<kk? C->rw[T->rows_org]: TRSACT_DEFAULT_WEIGHT): 1;
+ do {
+ item = (QUEUE_INT)FILE2_read_int (fp);
+ if ( (FILE_err&4)==0 ){
+ ENMAX (T->clms_org, item+1); // update #items
+ reallocx (jump, jump_end, k, 0, "TRSACT_file_count: jump", goto ERR);
+ jump[k] = item;
+ k++;
+ s += wf? (item<kk? MAX(C->rw[item],0): TRSACT_DEFAULT_WEIGHT): 1;
+
+ // count/weight-sum for the transpose mode
+ reallocx (C->clmt, C->clm_end, item, 0, "TRSACT_file_count:clmt",goto ERR);
+ C->clmt[item]++;
+ if ( !(T->flag&LOAD_TPOSE) ){
+ reallocx (C->cw, C->cw_end, item, 0, "TRSACT_file_count: cw", goto ERR);
+ C->cw[item] += MAX(w,0); // sum up positive weights
+ }
+ }
+ } while ( (FILE_err&3)==0);
+
+ // count/weight-sum for the transpose mode
+ reallocx (C->rowt, C->row_end, T->rows_org, 0, "TRSACT_file_count:rowt", goto ERR);
+ C->rowt[T->rows_org] = k;
+ if ( T->flag&LOAD_TPOSE ){
+ reallocx (C->cw, C->cw_end, T->rows_org, 0, "TRSACT_file_count: cw", goto ERR);
+ C->cw[T->rows_org] = s; // sum up positive weights
+ }
+ if ( k==0 && FILE_err&2 ) break;
+ T->rows_org++; // increase #transaction
+
+ if ( !wf ) s = k; // un-weighted case; weighted sum is #included-items
+ if ( k==0 ){
+ T->str_num++; // increase #streams if empty transaction is read
+ } else {
+ T->eles_org += k;
+ if ( (!(T->flag&LOAD_TPOSE) && !RANGE (T->row_lb, k, T->row_ub))
+ || ((T->flag&LOAD_TPOSE) && (!RANGE(T->w_lb, s, T->w_ub) || !RANGE (T->clm_lb, k, T->clm_ub)) ) ) FLOOP (i, 0, k) C->clmt[jump[i]]--;
+ }
+ } while ( (FILE_err&2)==0);
+ free2 (jump);
+ // swap the variables in transpose mode
+ if ( C->rw == NULL ){ T->total_w_org = T->total_pw_org = T->rows_org; return; }
+ C->clm_btm = MIN(kk, T->rows_org);
+ reallocx (C->rw, kk, T->rows_org, TRSACT_DEFAULT_WEIGHT, "TRSACT_file_count: rw", goto ERR);
+ FLOOP (k, 0, T->rows_org){
+ T->total_w_org += C->rw[k];
+ T->total_pw_org += MAX(C->rw[k],0);
+ }
+ return;
+ ERR:;
+ mfree (C->rw, C->cw, C->clmt, C->rowt, jump);
+ EXIT;
+}
+
+/* allocate memory, set permutation, and free C.clmt,rowt,rw,cw */
+int TRSACT_alloc (TRSACT *T, char *pfname, FILE_COUNT *C){
+ VEC_ID t, tt=0, ttt=T->clms_org, ttt_max = ttt, h, flag, org;
+ FILE_COUNT_INT *ct;
+ size_t s=0;
+ PERM *q, *p=NULL;
+ char *buf;
+
+ // swap variables in the case of transpose
+ if ( T->flag & LOAD_TPOSE ){
+ common_QUEUE_INT = T->clms_org; T->clms_org = (QUEUE_INT)T->rows_org; T->rows_org = (VEC_ID)common_QUEUE_INT;
+ SWAP_PNT (C->clmt, C->rowt);
+ }
+
+ if ( T->flag&TRSACT_SHRINK ) T->flag |= LOAD_DBLBUF;
+ // count valid columns/elements
+
+ if ( pfname && !(T->flag&TRSACT_WRITE_PERM) ){
+ ARY_LOAD (p, QUEUE_INT, ttt, pfname, 1, "TRSACT_load: item order file", EXIT0);
+ ARY_MAX (ttt_max, tt, p, 0, ttt);
+// ENMAX (T->clms_org, ttt_max+1);
+ T->T.clms = ttt_max+1;
+ } else {
+ if ( T->flag&LOAD_PERM ){
+ if ( T->flag&TRSACT_FRQSORT )
+ p = qsort_perm_WEIGHT (C->cw, T->clms_org, (T->flag&LOAD_INCSORT)?1:-1);
+ else p = qsort_perm_FILE_COUNT_INT (C->clmt, T->clms_org, (T->flag&LOAD_INCSORT)?1:-1);
+ }
+ if ( pfname ) ARY_WRITE (pfname, p, T->clms_org, PERMF " ", "TRSACT_alloc: item-order output", EXIT0);
+ }
+ T->clms_end = MAX (T->clms_org, T->T.clms);
+
+ malloc2 (C->cperm, T->clms_org+1, "TRSACT_alloc: cperm", EXIT0);
+ ARY_FILL (C->cperm, 0, T->clms_org, T->clms_org+1);
+ FLOOP (t, 0, ttt){
+ tt = p? p[t]: t;
+ if ( tt >= T->clms_org ) continue;
+ if ( RANGE(T->w_lb, C->cw[tt], T->w_ub) && RANGE (T->clm_lb, C->clmt[tt], T->clm_ub)){
+ s += C->clmt[tt];
+ C->cperm[tt] = (pfname && !(T->flag&TRSACT_WRITE_PERM))? t: T->T.clms++;
+ T->non_empty_clms++;
+ } else C->cperm[tt] = T->clms_end+1;
+ }
+ free2 (p);
+
+ // count valid rows/elements
+ if ( T->flag&(LOAD_SIZSORT+LOAD_WSORT) ){
+ if ( T->flag&LOAD_WSORT && C->rw )
+ p = qsort_perm_WEIGHT (C->rw, T->rows_org, (T->flag&LOAD_DECROWSORT)?-1:1);
+ else p = qsort_perm_FILE_COUNT_INT (C->rowt, T->rows_org, (T->flag&LOAD_DECROWSORT)?-1:1);
+ }
+ malloc2 (C->rperm, T->rows_org, "TRSACT_alloc: rperm", EXIT0);
+ FLOOP (t, 0, T->rows_org){ // compute #elements according to rowt, and set rperm
+ tt = p? p[t]: t;
+ if ( RANGE (T->row_lb, C->rowt[tt], T->row_ub) ){
+ C->rperm[tt] = T->T.t++;
+ T->T.eles += C->rowt[t];
+ } else C->rperm[tt] = T->rows_org+1;
+ }
+
+ free2 (p); free2 (C->cw);
+ flag = (T->T.eles > s && !(T->flag & LOAD_TPOSE) );
+ if ( flag ) T->T.eles = s;
+
+ T->T.end = T->T.t * ((T->flag&LOAD_DBLBUF)? 2: 1)+1;
+ malloc2 (T->w, T->T.end, "TRSACT_alloc: T->w", EXIT0);
+ if ( TRSACT_NEGATIVE ) malloc2 (T->pw, T->T.end, "TRSACT_alloc: T->pw", EXIT0);
+ else T->pw = NULL;
+ malloc2 (T->trperm, T->T.t, "TRSACT_alloc: T->trperm", EXIT0);
+ malloc2 (T->T.v, T->T.end, "TRSACT_alloc: T->T.v", EXIT0);
+ malloc2 (buf, (T->T.eles+T->T.end+1)*T->T.unit, "TRSACT_alloc: T->T.buf", EXIT0);
+ T->T.buf = (QUEUE_INT *)buf;
+ calloc2 (T->perm, T->T.clms+1, "TRSACT_alloc: T->perm", EXIT0);
+ QUEUE_alloc (&T->jump, T->T.clms+1);
+ BASE_alloc (&T->buf, sizeof(QUEUE_INT), MAX((int)T->row_max*4,(int)(T->T.eles+T->T.end+1)/10+100));
+ BASE_alloc (&T->wbuf, sizeof(WEIGHT), MAX((int)T->row_max*4, (int)(T->T.eles+T->T.end+1)/10+100));
+ if ( T->flag&TRSACT_SHRINK ){
+ malloc2 (T->mark, T->T.end, "TRSACT_alloc: mark", EXIT0);
+ malloc2 (T->shift, T->T.end, "TRSACT_alloc: shift", EXIT0);
+ calloc2 (T->sc, T->T.clms, "TRSACT_alloc: sc", EXIT0);
+ }
+ if ( T->flag&TRSACT_MULTI_STREAM ){
+ malloc2 (T->head, T->str_num+2, "TRSACT_alloc: haed", EXIT0);
+ malloc2 (T->strID, (T->flag&LOAD_TPOSE)?T->T.clms:T->T.end, "TRSACT_alloc:ID", EXIT0);
+ }
+ if ( T->flag&TRSACT_UNION )
+ calloc2 (T->T.w, T->T.end, "TRSACT_alloc: T->T.w", EXIT0);
+
+if ( ERROR_MES ) return(0);
+
+ // set variables w.r.t rows
+ tt=0; FLOOP (t, 0, T->rows_org){
+ if ( C->rperm[t] <= T->rows_org ){
+ T->T.v[tt] = INIT_QUEUE;
+ T->trperm[tt] = t;
+ C->rperm[t] = tt;
+ T->w[tt] = C->rw? C->rw[t]: 1;
+ if ( T->pw ) T->pw[tt] = MAX (T->w[tt], 0);
+ if ( !flag ){
+ T->T.v[tt].v = (QUEUE_INT *)buf;
+ buf += (C->rowt[t]+1)*T->T.unit;
+ }
+ tt++;
+ }
+ }
+ free2 (C->rw);
+ // make the inverse perm of items
+ FLOOP (t, 0, T->clms_org)
+ if ( C->cperm[t] <= T->clms_end ) T->perm[C->cperm[t]] = t;
+
+ // set head of each stream, and stream ID of each transaction
+ if ( T->flag&TRSACT_MULTI_STREAM ){
+ malloc2 (T->head, T->str_num+2, "TRSACT_alloc: haed", EXIT0);
+ malloc2 (T->strID, (T->flag&LOAD_TPOSE)?T->T.clms:T->T.end, "TRSACT_alloc:ID", EXIT0);
+ }
+ org = (T->flag&LOAD_TPOSE)? T->clms_org: T->rows_org;
+ q = (T->flag&LOAD_TPOSE)? C->cperm: C->rperm;
+ ct = (T->flag&LOAD_TPOSE)? C->clmt: C->rowt;
+ h=1; tt=0; FLOOP (t, 0, org){
+ if ( q[t] <= org ){
+ if ( t == T->end1 && T->sep==0 ) T->sep = tt;
+ if ( t == T->sep && T->sep>0 ) T->sep = tt;
+ if ( T->strID ) T->strID[tt] = h;
+ tt++;
+ }
+ if ( T->head && ct[t]==0 ) T->head[h++] = tt+1;
+ }
+
+ T->new_t = T->T.t;
+ free2 (C->rowt); free2 (C->clmt);
+ return ( flag );
+}
+
+
+/* load the file to allocated memory according to permutation, and free C.rw, C.cw */
+void TRSACT_file_read (TRSACT *T, FILE2 *fp, FILE_COUNT *C, VEC_ID *t, int flag){
+ QUEUE_INT item;
+
+ FILE2_reset (fp);
+ do {
+ if ( flag ) T->T.v[*t].v = *t? T->T.v[*t-1].v + T->T.v[*t-1].t +1: T->T.buf;
+ do {
+ item = (QUEUE_INT)FILE2_read_int (fp);
+ if ( (FILE_err&4)==0 ){
+// printf ("%d %d %d %d\n", C->rperm[*t], T->rows_org, C->cperm[item], T->clms_org );
+ if ( T->flag&LOAD_TPOSE ){
+ if ( C->rperm[item]<=T->rows_org && C->cperm[*t]<=T->clms_end )
+ ARY_INS (T->T.v[ C->rperm[item] ], C->cperm[*t]);
+ } else if ( C->rperm[*t]<=T->rows_org && C->cperm[item]<=T->clms_end )
+ ARY_INS (T->T.v[ C->rperm[*t] ], C->cperm[item]);
+ }
+ } while ( (FILE_err&3)==0);
+ (*t)++;
+ } while ( (FILE_err&2)==0 );
+}
+
+/* sort the transactions and items according to the flag, allocate OQ, and database reduction */
+void TRSACT_sort (TRSACT *T, FILE_COUNT *C, int flag){
+ VEC_ID t, *p;
+ int f;
+ PERM pp;
+ QUEUE Q;
+ QUEUE_ID i;
+
+ FLOOP (t, 0, T->T.t)
+ T->T.v[t].v[T->T.v[t].t] = T->T.clms;
+ if ( flag )
+ flag = (T->flag&(LOAD_SIZSORT+LOAD_WSORT)? ((T->flag&LOAD_DECROWSORT)? -1:1):0) *sizeof(QUEUE);
+ if ( flag ){ // sort rows for the case that some columns are not read
+ qsort_perm__VECt ((VEC *)T->T.v, T->T.t, C->rperm, flag);
+ ARY_INVPERMUTE (T->T.v, C->rperm, Q, T->T.t, "TRSACT_sort: ARY_INVPERMUTE", EXIT);
+ ARY_INVPERMUTE_ (T->trperm, C->rperm, pp, T->T.t);
+ }
+ free2 (C->rperm); free2 (C->cperm);
+
+ if ( T->flag & LOAD_PERM ) flag = 1;
+ else flag = (T->flag&LOAD_INCSORT)? 1: ((T->flag&LOAD_DECSORT)? -1: 0);
+ if ( flag ) FLOOP (t, 0, T->T.t) qsort_QUEUE_INT (T->T.v[t].v, T->T.v[t].t, flag);
+ if ( T->flag & LOAD_RM_DUP ) FLOOP (t, 0, T->T.t) MQUE_RM_DUP (T->T.v[t]);
+ ST_MAX (T->row_max, i, T->T.v, t, 0, T->T.t);
+
+ if ( T->flag&(TRSACT_ALLOC_OCC+TRSACT_SHRINK) ){
+ calloc2 (p, T->T.clms, "TRSACT_sort: p", EXIT);
+ QUEUE_delivery (NULL, p, NULL, T->T.v, NULL, T->T.t, T->T.clms);
+ ARY_MAX (T->clm_max, i, p, 0, T->T.clms);
+ MQUE_ALLOC (T->OQ, T->T.clms, p, T->occ_unit, 1, EXIT);
+ QUEUE_alloc (&T->OQ[T->T.clms], MAX(T->T.t, T->clm_max));
+ FLOOP (i, 0, T->T.clms+1) T->OQ[i].end = 0; // end is illegally set to 0, for the use in "TRSACT_find_same"
+ ARY_INIT_PERM (T->OQ[T->T.clms].v, T->T.t); // initial occurrence := all transactions
+ T->OQ[T->T.clms].t = T->T.t;
+ free (p);
+ }
+
+ // shrinking database
+ if ( T->flag&TRSACT_SHRINK ){
+ Q = T->OQ[T->T.clms];
+ T->OQ[T->T.clms].t = 0;
+ TRSACT_find_same (T, &Q, T->T.clms);
+ f = T->flag; // preserve the flag
+ BITRM (T->flag ,TRSACT_MAKE_NEW +TRSACT_UNION +TRSACT_INTSEC);
+ TRSACT_merge_trsact (T, &T->OQ[T->T.clms], T->T.clms); // just remove duplicated trsacts
+ T->flag = f; // recover flag
+ T->OQ[T->T.clms].t = 0;
+ FLOOP (t, 0, T->T.t) if ( T->mark[t]>0 ) ARY_INS(T->OQ[T->T.clms], t); // make resulted occ
+ }
+
+// QUEUE_delivery (T->OQ, NULL, NULL, T->T.v, &T->OQ[T->T.clms], T->T.t, T->T.clms);
+}
+
+/*****************************************/
+/* load transaction file and its weight */
+/*****************************************/
+void TRSACT_load (TRSACT *T, char *fname, char *fname2, char *wfname, char *wfname2, char *pfname){
+ FILE2 fp, fp2;
+ FILE_COUNT C = INIT_FILE_COUNT;
+ VEC_ID t=0;
+ int f;
+
+ FILE2_open (fp, fname, "r", "input-file open error", EXIT);
+ if ( fname2 ) FILE2_open (fp2, fname2, "r", "input-file2 open error", EXIT);
+ TRSACT_file_count (T, &C, &fp, wfname); if (ERROR_MES) goto END;
+ T->end1 = T->rows_org;
+ if ( fname2 ) TRSACT_file_count (T, &C, &fp2, wfname2); if (ERROR_MES) goto END;
+ f = TRSACT_alloc (T, pfname, &C); if (ERROR_MES) goto END;
+ TRSACT_file_read (T, &fp, &C, &t, f); if (ERROR_MES) goto END;
+ if ( fname2 ) TRSACT_file_read (T, &fp2, &C, &t, f); if (ERROR_MES) goto END;
+ TRSACT_sort (T, &C, f);
+
+ END:;
+ FILE2_close (&fp);
+ if (ERROR_MES) TRSACT_end (T);
+ return;
+}
+
+/* iteration of delivery; operate one transaction */
+/* use OQ.end to count the number of items */
+/* jump will be cleared (t := s) at the beginning */
+void TRSACT_delivery_iter (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, VEC_ID t, QUEUE_INT m){
+ WEIGHT *y=0;
+ QUEUE_INT *x;
+ int f = T->flag&TRSACT_NEGATIVE;
+
+ if ( T->T.w ) y = T->T.w[t];
+ MQUE_MLOOP (T->T.v[t], x, m){
+ if ( T->OQ[*x].end == 0 ){ ARY_INS (*jump, *x); w[*x] = 0; if ( f ) pw[*x] = 0; }
+ T->OQ[*x].end++;
+ if ( y ){
+ w[*x] += *y; if ( *y>0 && f) pw[*x] += *y;
+ y++;
+ } else {
+ w[*x] += T->w[t]; if ( f ) pw[*x] += T->pw[t];
+ }
+ }
+}
+
+void TRSACT_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, QUEUE *occ, QUEUE_INT m){
+ VEC_ID i, t;
+ char *b = (char *)(occ?occ->v: NULL);
+ jump->t = jump->s;
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ TRSACT_delivery_iter (T, jump, w, pw, t, m);
+ b += T->occ_unit;
+ }
+}
+
+/* usual delivery (make transpose) with checking sc
+ don't touch jump */
+/* if (T->flag&TRSACT_DELIV_SC), do not stack to items e with non-zero T->sc[e] */
+void TRSACT_deliv (TRSACT *T, QUEUE *occ, QUEUE_INT m){
+ VEC_ID i, t;
+ QUEUE_INT *x;
+ char *b = (char *)(occ?occ->v: NULL);
+ if ( T->flag&TRSACT_DELIV_SC ){
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ MQUE_MLOOP (T->T.v[t], x, m)
+ if ( !T->sc[*x] ) ARY_INS (T->OQ[*x], t);
+ b += T->occ_unit;
+ }
+ } else {
+ FLOOP (i, occ?occ->s:0, occ?occ->t:T->T.t){
+ t = occ? *((QUEUE_INT *)b): i;
+ MQUE_MLOOP (T->T.v[t], x, m) ARY_INS (T->OQ[*x], t);
+ b += T->occ_unit;
+ }
+ }
+}
+
+/**************************************************************/
+/* Find identical transactions in a subset of transactions, by radix-sort like method */
+/* infrequent items (refer LCM_occ) and items larger than item_max are ignored */
+/* INPUT: T:transactions, occ:subset of T represented by indices, result:array for output, item_max:largest item not to be ignored */
+/* OUTPUT: if transactions i1, i2,..., ik are the same, they have same value in T->mark[i]
+ (not all) isolated transaction may have mark 1 */
+/* use 0 to end-1 of QQ temporary, and QQ[i].t and QQ[i].s have to be 0. */
+/*************************************************************************/
+void TRSACT_find_same (TRSACT *T, QUEUE *occ, QUEUE_INT end){
+ VEC_ID mark=0, t_end;
+ QUEUE *o=occ, *Q = T->T.v, *EQ, *QQ = T->OQ;
+ QUEUE_INT *x, *y, e;
+ QUEUE_ID ot = occ->t;
+
+ // initialization
+ MQUE_FLOOP (*occ, x){ T->mark[*x] = mark; T->shift[*x] = Q[*x].v; }
+ T->jump.t = T->jump.s; QQ[T->T.clms].s = 0;
+
+ while (1){
+ if ( o->t - o->s == 1 ) T->mark[o->v[--o->t]] = 1; // no same transactions; mark by 1
+ if ( o->t == 0 ) goto END;
+ // if previously inserted transactions are in different group, then change their marks with incrementing mark by one
+ mark++; for (x=&o->v[o->s] ; x <&o->v[o->t] ; x++) T->mark[*x] = mark;
+ t_end = o->t;
+ o->s = o->t = 0;
+
+ // insert each t to buckets
+ for (x=o->v ; x<o->v+t_end ; x++){
+ // get next item in transaction t
+ do {
+ e = *(T->shift[*x]);
+ T->shift[*x]++;
+ if ( e >= end ){ e = T->T.clms; break; }
+ } while ( T->sc[e] );
+ EQ = &QQ[e];
+ // if previously inserted transactions are in different group, then change their mark to the transaction ID of top transacion.
+ y = &(EQ->v[EQ->s]);
+ if ( EQ->s < EQ->t && T->mark[*y] != T->mark[*x] ){
+ if ( EQ->t - EQ->s == 1 ) T->mark[EQ->v[--EQ->t]] = 1; // the tail of the queue has no same transaction; mark the tail by 1
+ else {
+ mark++; for ( ; y< EQ->v + EQ->t ; y++) T->mark[*y] = mark;
+ EQ->s = EQ->t;
+ }
+ } else if ( EQ->t == 0 && e<T->T.clms ) ARY_INS (T->jump, e);
+ ARY_INS (*EQ, *x); // insert t to bucket of e
+ }
+ END:;
+ if ( QUEUE_LENGTH_(T->jump) == 0 ) break;
+ o = &QQ[QUEUE_ext_tail_ (&T->jump)];
+ }
+
+ // same transactions are in queue of item_max
+ if ( QQ[T->T.clms].t -QQ[T->T.clms].s == 1 ) T->mark[QQ[T->T.clms].v[--QQ[T->T.clms].t]] = 1;
+ if ( occ != &QQ[T->T.clms] ) occ->t = ot;
+}
+
+
+/****************************************************************************/
+/* copy transaction t to tt (only items i s.t. sc[i]==0) **/
+/* T->w has to be allocated. itemweight will be alocated even if T->w[t] == NULL */
+/****************************************************************************/
+void TRSACT_copy (TRSACT *T, VEC_ID tt, VEC_ID t, QUEUE_INT end){
+ QUEUE_INT *x, *buf;
+ WEIGHT *wbuf = NULL, tw = T->w[t], *w = T->T.w? T->T.w[t]: NULL;
+ int bnum = T->buf.num, bblock = T->buf.block_num, wflag = (w || (T->flag&TRSACT_UNION));
+
+ buf = (QUEUE_INT *)BASE_get_memory (&T->buf, T->T.v[t].t+1);
+if ( ERROR_MES ) return;
+ if ( wflag ) T->T.w[tt] = wbuf = (WEIGHT *)BASE_get_memory (&T->wbuf, T->T.v[t].t+1);
+if ( ERROR_MES ){ T->buf.num = bnum; T->buf.block_num = bblock; return; }
+ T->T.v[tt].v = buf;
+ T->w[tt] = T->w[t];
+ if ( T->flag&TRSACT_NEGATIVE ) T->pw[tt] = T->pw[t];
+ MQUE_MLOOP (T->T.v[t], x, end){
+ if ( !T->sc[*x] ){
+ *buf = *x; buf++;
+ if ( wflag ){ *wbuf = w? *w: tw; wbuf++; }
+ }
+ if ( w ) w++;
+ }
+ T->T.v[tt].t = (VEC_ID)(buf - T->T.v[tt].v);
+ *buf = T->T.clms;
+ T->buf.num = (int)(buf - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) + 1);
+ if ( wflag ) T->wbuf.num = (int)(wbuf - ((WEIGHT *)T->wbuf.base[T->wbuf.block_num]) + 1);
+}
+
+/****************************************************************************/
+/* intersection of transaction t and tt (only items i s.t. sc[i]==0) **/
+/* shift is the array of pointers indicates the start of each transaction **/
+/****************************************************************************/
+void TRSACT_suffix_and (TRSACT *T, VEC_ID tt, VEC_ID t){
+ QUEUE_INT *x=T->shift[tt], *y=T->shift[t], *xx=T->shift[tt];
+ while ( *x < T->T.clms && *y < T->T.clms ){
+ if ( *x > *y ) y++;
+ else {
+ if ( *x == *y ){
+ if ( !T->sc[*x] ){ *xx = *x; xx++; }
+ y++;
+ }
+ x++;
+ }
+ }
+ T->T.v[tt].t = (VEC_ID)(xx - T->T.v[tt].v);
+ *xx = T->T.clms;
+ T->buf.num = (int)(xx - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) + 1);
+}
+
+
+/***************************************************************************/
+/* take union of transaction t to tt (only items i s.t. pw[i]>=th) */
+/* CAUSION: t has to be placed at the last of trsact_buf2. */
+/* if the size of t inclreases, the following memory will be overwrited */
+/* if memory (T->buf, T->wbuf) is short, do nothing and return 1 */
+/* T->T.w[t] can be NULL, but T->T.w[x] can not */
+/***************************************************************************/
+void TRSACT_itemweight_union (TRSACT *T, VEC_ID tt, VEC_ID t){
+ int bnum = T->buf.num, bblock = T->buf.block_num;
+ QUEUE_ID siz = T->T.v[tt].t +T->T.v[t].t;
+ QUEUE_INT *xx_end = T->T.v[tt].v + siz, *xx = xx_end;
+ QUEUE_INT *x = T->T.v[tt].v + T->T.v[tt].t-1, *y = T->T.v[t].v + T->T.v[t].t-1;
+ WEIGHT *ww = T->T.w[tt] +siz, *wx = T->T.w[tt] +T->T.v[tt].t-1, *wy = T->T.w[t] +T->T.v[t].t-1;
+ WEIGHT tw = T->w[t];
+ int flag=0, wf = (T->T.w[t]!=NULL);
+
+ // if sufficiently large memory can not be taken from the current memory block, use the next block
+ if ( xx_end >= (QUEUE_INT *)T->buf.base[T->buf.block_num] +T->buf.block_siz ){
+ xx_end = xx = ((QUEUE_INT*)BASE_get_memory (&T->buf, T->buf.block_siz)) +siz;
+if (ERROR_MES) return;
+ ww = ((WEIGHT *)BASE_get_memory (&T->wbuf, T->wbuf.block_siz)) +siz;
+if ( ERROR_MES ){ T->buf.num = bnum; T->buf.block_num = bblock; return; }
+ flag =1;
+ }
+ if ( ERROR_MES ) return;
+
+ // take union and store it in the allocated memory
+ while ( x >= T->T.v[tt].v && y >= T->T.v[t].v ){
+ if ( *x > *y ){
+ if ( !T->sc[*x] ){ *xx = *x; *ww = *wx; xx--; ww--; }
+ x--; wx--;
+ if ( x < T->T.v[tt].v ){
+ while ( y >= T->T.v[t].v ){
+ if ( !T->sc[*y] ){ *xx = *y; *ww = wf? *wy: tw; xx--; ww--; }
+ y--; wy--;
+ }
+ }
+ } else {
+ if ( !T->sc[*y] ){
+ *ww = wf? *wy: tw; *xx = *y;
+ if ( *x == *y ){ *ww += *wx; x--; wx--; }
+ xx--; ww--;
+ }
+ y--; wy--;
+ if ( y < T->T.v[t].v ){
+ while ( x >= T->T.v[tt].v ){
+ if ( !T->sc[*x] ){ *xx = *x; *ww = *wx; xx--; ww--; }
+ x--; wx--;
+ }
+ }
+ }
+ }
+ T->T.v[tt].t = (VEC_ID)(xx_end -xx);
+
+ // if [tt].v will overflow, set [tt].v to the top of next memory block
+ if ( flag ){
+ if ( T->T.v[tt].v + T->T.v[tt].t+1 >= (QUEUE_INT *)T->buf.base[T->buf.block_num-1] +T->buf.block_siz ){
+ T->T.v[tt].v = (QUEUE_INT *)T->buf.base[T->buf.block_num];
+ T->T.w[tt] = (WEIGHT *)T->wbuf.base[T->wbuf.block_num];
+ } else { // new memory block is allocated, but the transaction fits in the previous block
+ T->buf.block_num--;
+ T->wbuf.block_num--;
+ }
+ }
+
+ // copy the union to the original position
+ for ( x=T->T.v[tt].v,wx=T->T.w[tt] ; xx<xx_end ; ){
+ xx++; ww++;
+ *x = *xx; *wx = *ww;
+ x++; wx++;
+ }
+ *x = T->T.clms;
+ T->wbuf.num = T->buf.num = (int)(x - ((QUEUE_INT *)T->buf.base[T->buf.block_num]) +1);
+ return;
+}
+
+
+
+/*****/
+/* merge duplicated transactions in occ according to those having same value in T->mark
+ the mark except for the representative will be zero, for each group of the same transactions
+ the mark of the representative will be its (new) ID +2 (one is for identical transaction) */
+/* T->flag&TRSACT_MAKE_NEW: make new trsact for representative
+ T->flag&TRSACT_INTSEC: take suffix intersection of the same trsacts
+ T->flag&TRSACT_UNION: take union of the same trsacts */
+/* o will be cleard after the execution */
+void TRSACT_merge_trsact (TRSACT *T, QUEUE *o, QUEUE_INT end){
+ VEC_ID mark = 0, tt=0;
+ QUEUE_INT *x;
+
+ MQUE_FLOOP (*o, x){
+ if ( mark == T->mark[*x] ){
+ T->mark[*x] = 0; // mark of unified (deleted) transaction
+ T->w[tt] += T->w[*x]; if ( T->pw ) T->pw[tt] += T->pw[*x];
+ if ( T->flag & TRSACT_INTSEC ){
+ TRSACT_suffix_and (T, tt, *x);
+ T->buf.num = (int)(T->T.v[tt].v - (QUEUE_INT *)T->buf.base[T->buf.block_num] +T->T.v[tt].t +1);
+ }
+ if ( T->flag & TRSACT_UNION ){
+ TRSACT_itemweight_union (T, tt, *x);
+ if ( ERROR_MES ) T->mark[*x] = *x+2; // do not merge if not enough memory
+ }
+ }
+ if ( mark != T->mark[*x] && T->mark[*x] > 1 ){ // *x is not the same to the previous, or memory short
+ mark = T->mark[*x];
+ if ( T->flag&TRSACT_MAKE_NEW ){
+ tt = T->new_t++;
+ TRSACT_copy (T, tt, *x, (T->flag&(TRSACT_INTSEC+TRSACT_UNION))? T->T.clms: end);
+ if ( ERROR_MES ){ T->new_t--; tt = *x; }
+ else for (T->shift[tt]=T->T.v[tt].v ; *(T->shift[tt])<end ; T->shift[tt]++);
+ } else tt = *x;
+ T->mark[*x] = tt+2;
+ }
+ }
+ o->t = o->s = 0;
+}
+
+/* remove the unified transactions from occ (consider T->occ_unit) */
+void TRSACT_reduce_occ (TRSACT *T, QUEUE *occ){
+ QUEUE_INT *x, *y=occ->v;
+ QUEUE_ID i=0;
+ if ( T->occ_unit == sizeof(QUEUE_INT) ){
+ MQUE_FLOOP (*occ, x){
+ if ( T->mark[*x] == 0 ) continue;
+ *y = T->mark[*x]>1? T->mark[*x]-2: *x;
+ y++; i++;
+ }
+ } else {
+ MQUE_FLOOP_ (*occ, x, T->occ_unit){
+ if ( T->mark[*x] == 0 ) continue;
+ memcpy (y, x, T->occ_unit);
+ *y = T->mark[*x]>1? T->mark[*x]-2: *x;
+ y = (QUEUE_INT *)(((char *)y)+T->occ_unit);
+ i++;
+ }
+ }
+ occ->t = i;
+}
+
+#endif
--- /dev/null
+/* QUEUE based Transaction library, including database reduction.
+ 25/Nov/2007 by Takeaki Uno e-mail:uno@nii.jp,
+ homepage: http://research.nii.ac.jp/~uno/index.html */
+/* This program is available for only academic use, basically.
+ Anyone can modify this program, but he/she has to write down
+ the change of the modification on the top of the source code.
+ Neither contact nor appointment to Takeaki Uno is needed.
+ If one wants to re-distribute this code, do not forget to
+ refer the newest code, and show the link to homepage of
+ Takeaki Uno, to notify the news about the codes for the users.
+ For the commercial use, please make a contact to Takeaki Uno. */
+
+#ifndef _trsact_h_
+#define _trsact_h_
+
+// #define WEIGHT double
+// #define WEIGHT_DOUBLE
+
+#include"vec.h"
+#include"base.h"
+
+#ifndef WEIGHT
+#define WEIGHT int
+#ifdef WEIGHT_DOUBLE
+#undef WEIGHT_DOUBLE
+#endif
+#endif
+
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SETFAMILY T; // transaction
+ int flag; // flag
+ WEIGHT *w, *pw; // weight/positive-weight of transactions
+
+ QUEUE_INT clms_org, clm_max, clms_end, non_empty_clms; // #items in original file, max size of clms, and max of (original item, internal item)
+ VEC_ID rows_org, row_max; // #transactions in the original file
+ VEC_ID end1, sep; // #trsact in 1st file, the ID of the last permed trsact of 1st file
+ size_t eles_org; // #elements in the original file
+ WEIGHT total_w, total_pw, total_w_org, total_pw_org;
+ WEIGHT th; // threshold for frequency of items
+ PERM *perm, *trperm; // original item permutation loaded from permutation file (and inverse)
+
+ // lower/upper bound of #elements in a column/row. colunmn or row of out of range will be ignored
+ VEC_ID clm_lb, clm_ub;
+ QUEUE_ID row_lb, row_ub;
+ WEIGHT w_lb, w_ub;
+
+ VEC_ID str_num; // number of database (itemset stream/string datasets) in T
+ VEC_ID *head, *strID; // the head (beginning) of each stream, stream ID of each transaction
+ int occ_unit;
+
+ // for finding same transactions
+ QUEUE jump, *OQ; // queue of non-empty buckets, used in find_same_transactions
+ VEC_ID *mark; // marks for transactions
+ QUEUE_INT **shift; // memory for shift positions of each transaction
+ char *sc; // flag for non-active (in-frequent) items
+
+ // for extra transactions
+ VEC_ID new_t; // the start ID of un-used transactions
+ BASE buf; // buffer for transaction
+ BASE wbuf; // buffer for itemweights
+} TRSACT;
+
+#define TRSACT_FRQSORT 65536 // sort transactions in decreasing order
+#define TRSACT_ITEMWEIGHT 131072 // initialize itemweight by transaction weights
+#define TRSACT_SHRINK 262144 // do not allocate memory for shrink, but do for mining
+#define TRSACT_MULTI_STREAM 524288 // separate the datasets at each empty transaction
+#define TRSACT_UNION 1048576 // take union of transactions, at the database reduction
+#define TRSACT_INTSEC 2097152 // take intersection of transactions, at the database reduction
+#define TRSACT_MAKE_NEW 4194304 // make new transaction for each
+#define TRSACT_ALLOC_OCC 8388608 // make new transaction for each
+#define TRSACT_DELIV_SC 16777216 // look T->sc when delivery
+#define TRSACT_NEGATIVE 33554432 // flag for whether some transaction weights are negative or not
+//#define TRSACT_INIT_SHRINK 65536 // allocate memory for database reduction
+#define TRSACT_WRITE_PERM 67108864 // write item-order to file
+
+#ifndef TRSACT_DEFAULT_WEIGHT
+ #define TRSACT_DEFAULT_WEIGHT 0 // default weight of the transaction, for missing weights in weight file
+#endif
+
+/* print transactions */
+void TRSACT_print (TRSACT *T, QUEUE *occ, PERM *p);
+void TRSACT_prop_print (TRSACT *T);
+
+/**************************************************************/
+void TRSACT_init (TRSACT *T);
+
+/**************************************************************/
+void TRSACT_end (TRSACT *T);
+
+/*****************************************/
+/* scan file "fp" with weight file wfp and count #items, #transactions in the file. */
+/* count weight only if wfp!=NULL */
+/* T->rows_org, clms_org, eles_org := #items, #transactions, #all items */
+/* ignore the transactions of size not in range T->clm_lb - clm_ub */
+/* T->total_w, total_pw := sum of (positive) weights of transactions */
+/* C.clmt[i],C.cw[i] := the number/(sum of weights) of transactions including i */
+/****************************************/
+void TRSACT_file_count (TRSACT *T, FILE_COUNT *C, FILE2 *fp, char *wf);
+
+/* allocate memory, set permutation, and free C.clmt,rowt,rw,cw */
+int TRSACT_alloc (TRSACT *T, char *pfname, FILE_COUNT *C);
+
+/* load the file to allocated memory according to permutation, and free C.rw, C.cw */
+void TRSACT_file_read (TRSACT *T, FILE2 *fp, FILE_COUNT *C, VEC_ID *t, int flag);
+
+/*****************************************/
+/* load transaction file to TRSACT */
+void TRSACT_load (TRSACT *T, char *fname, char *fname2, char *wfname, char *wfname2, char *pfname);
+
+/* occurrence deliver (only counting) */
+/* WARNING: next cell of the last item of each transaction must be INTHUGE */
+/* compute occurrence for items less than max item, in the database induced
+ by occ */
+/* if jump!=0, all i with non-zero occ[i].t will be inserted to jump */
+/* be careful for overflow of jump */
+/* if occ==NULL, scan all transactions */
+/* flag&1: count only positive weights */
+void TRSACT_delivery_iter (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, VEC_ID t, QUEUE_INT m);
+void TRSACT_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, QUEUE *occ, QUEUE_INT m);
+// QUEUE *TRSACT_alloc_occ (TRSACT *T, QUEUE_INT end);
+//QUEUE_ID TRSACT_occ_dup (SETFAMILY *S, QUEUE *OQ, QUEUE *jump, WEIGHT *occ_w, WEIGHT *occ_pw);
+
+/**************************************************************/
+/* Find identical transactions in a subset of transactions, by radix-sort like method */
+/* infrequent items (refer LCM_occ) and items larger than item_max are ignored */
+/* INPUT: T:transactions, occ:subset of T represented by indices, result:array for output, item_max:largest item not to be ignored */
+/* OUTPUT: if transactions i1, i2,..., ik are the same, they have same value in T->mark[i]
+ (not all) isolated transaction may have mark 1 */
+/* use 0 to end-1 of QQ temporary, and QQ[i].t and QQ[i].s have to be 0. */
+/*************************************************************************/
+void TRSACT_find_same (TRSACT *T, QUEUE *occ, QUEUE_INT end);
+
+/* copy transaction t to tt (only items i s.t. pw[i]>=th) **/
+void TRSACT_copy (TRSACT *T, VEC_ID tt, VEC_ID t, QUEUE_INT end);
+
+/* intersection of transaction t and tt (only items i s.t. pw[i]>=th) **/
+/* shift is the array of pointers indicates the start of each transaction **/
+void TRSACT_suffix_and (TRSACT *T, VEC_ID tt, VEC_ID t);
+
+/* take union of transaction t to tt (only items i s.t. pw[i]>=th) */
+/* CAUSION: t has to be placed at the last of trsact_buf2. */
+/* if the size of t inclreases, the following memory will be overwrited */
+/* if memory (T->buf) is short, do nothing and return 1 */
+void TRSACT_itemweight_union (TRSACT *T, VEC_ID tt, VEC_ID t);
+
+
+/*****/
+/* remove duplicated transactions from occ, and add the weight of the removed trsacts to the representative one */
+/* duplicated trsacts are in occ[item_max]. Clear the queue when return */
+/* T->flag&TRSACT_MAKE_NEW: make new trsact for representative
+ T->flag&TRSACT_INTSEC: take suffix intersection of the same trsacts
+ T->flag&TRSACT_UNION: take union of the same trsacts */
+void TRSACT_merge_trsact (TRSACT *T, QUEUE *o, QUEUE_INT end);
+
+/* remove the unified transactions from occ (consider T->occ_unit) */
+void TRSACT_reduce_occ (TRSACT *T, QUEUE *occ);
+
+#ifdef _alist_h_
+
+/* occurrence deliver (only counting), for MALIST */
+//void TRSACT_MALIST_delivery (TRSACT *T, QUEUE *jump, WEIGHT *w, WEIGHT *pw, MALIST *occ, ALIST_ID l, QUEUE_INT m);
+//void TRSACT_MALIST_occ_deliver (TRSACT *TT, MALIST *occ, int l, int item_max);
+
+#endif
+
+#endif
--- /dev/null
+/* library for vector and sparse vector, and matrix */
+/* Takeaki Uno 27/Dec/2008 */
+
+#ifndef _vec_c_
+#define _vec_c_
+
+#include"vec.h"
+#include"stdlib2.c"
+#include"queue.c"
+
+MAT INIT_MAT = {TYPE_MAT,NULL,0,0,NULL,NULL,0,0,0};
+SVEC INIT_SVEC_ELE = {0,0};
+SVEC INIT_SVEC = {TYPE_SVEC,NULL,0,0};
+SMAT INIT_SMAT = {TYPE_SMAT,NULL,0,0,NULL,NULL,0,0,0,0};
+SETFAMILY INIT_SETFAMILY = INIT_SETFAMILY_;
+
+QSORT_TYPE (SVEC_VAL, SVEC_VAL)
+QSORT_TYPE (SVEC_VAL2, SVEC_VAL2)
+
+/* allocate memory according to rows and rowt */
+void VEC_alloc (VEC *V, VEC_ID clms){
+ *V = INIT_VEC;
+ V->end = clms;
+ calloc2 (V->v, clms+1, "VEC_alloc: V->v", EXIT);
+}
+
+/* terminate routine for VEC */
+void VEC_end (VEC *V){
+ free2 (V->v);
+ *V = INIT_VEC;
+}
+
+/* allocate memory according to rows and rowt */
+void MAT_alloc (MAT *M, VEC_ID rows, VEC_ID clms){
+ VEC_ID i;
+ calloc2 (M->v, rows+1, "MAT_alloc: M->v", EXIT);
+ calloc2 (M->buf, (clms+1) * (rows+1), "MAT_alloc: M->v", {free(M->v);EXIT;});
+ M->end = rows;
+ M->clms = clms;
+ FLOOP (i, 0, rows){
+ M->v[i].end = M->v[i].t = clms;
+ M->v[i].v = M->buf + i*(clms+1);
+ }
+}
+
+/* terminate routine for MAT */
+void MAT_end (MAT *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ *M = INIT_MAT;
+}
+
+/* allocate memory */
+void SVEC_alloc (SVEC *V, VEC_ID end){
+ *V = INIT_SVEC;
+ calloc2 (V->v, end+1, "SVEC_alloc: V->v", EXIT);
+ V->end = end;
+ V->t = 0;
+}
+
+/* terminate routine for SVEC */
+void SVEC_end (SVEC *V){
+ free2 (V->v);
+ *V = INIT_SVEC;
+}
+
+/* allocate memory according to rows and rowt */
+void SMAT_alloc (SMAT *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles){
+ VEC_ID i;
+ if ( eles == 0 ) ARY_SUM (M->ele_end, rowt, 0, rows); else M->ele_end = eles;
+ calloc2 (M->buf, M->ele_end*((M->flag&LOAD_DBLBUF)?2:1) +rows +2, "SMAT_alloc: buf", EXIT);
+ malloc2 (M->v, rows+1, "SMAT_alloc: M->v", {free(M->buf);EXIT;});
+ ARY_FILL (M->v, 0, rows, INIT_SVEC);
+ M->end = rows;
+ M->clms = clms;
+ if ( rowt ){
+ FLOOP (i, 0, rows){
+ M->v[i].v = i? M->v[i-1].v + rowt[i-1] +1: M->buf;
+ M->v[i].end = rowt[i];
+ }
+ }
+}
+
+/* terminate routine for MAT */
+void SMAT_end (SMAT *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ *M = INIT_SMAT;
+}
+
+
+
+/* allocate memory according to rows and rowt */
+/* if eles == 0, compute eles from rowt and rows */
+void SETFAMILY_alloc (SETFAMILY *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles){
+ VEC_ID i;
+ char *buf;
+ if ( eles == 0 ) ARY_SUM (M->ele_end, rowt, 0, rows); else M->ele_end = eles;
+ calloc2 (buf, (M->ele_end*((M->flag&LOAD_DBLBUF)?2:1) +((M->flag&LOAD_DBLBUF)?MAX(rows,clms):rows)+2)*M->unit, "SETFAMILY_alloc: buf", EXIT);
+ M->buf = (QUEUE_INT *)buf;
+ malloc2 (M->v, rows+1, "SETFAMILY_alloc: M->v", {free(M->buf);EXIT;});
+ ARY_FILL (M->v, 0, rows, INIT_QUEUE);
+ M->end = rows;
+ M->clms = clms;
+ if ( rowt ){
+ FLOOP (i, 0, rows){
+ M->v[i].v = (QUEUE_INT *)buf;
+ buf += (rowt[i] +1)*M->unit;
+ M->v[i].end = rowt[i]+1;
+ }
+ }
+}
+
+/* allocate memory according to rows and rowt */
+/* if eles == 0, compute eles from rowt and rows */
+void SETFAMILY_alloc_weight (SETFAMILY *M){
+ VEC_ID i;
+ calloc2 (M->w, M->end +1, "SETFAMILY_alloc_weight: w", EXIT);
+ calloc2 (M->wbuf, M->ele_end*((M->flag&LOAD_DBLBUF)?2:1)+1, "SETFAMILY_alloc_weight: *w", {free(M->w);EXIT;});
+ FLOOP (i, 1, M->t) M->w[i] = i? M->w[i-1] + M->v[i-1].t: M->wbuf;
+}
+
+/* terminate routine for MAT */
+void SETFAMILY_end (SETFAMILY *M){
+ free2 (M->buf);
+ free2 (M->buf2);
+ free2 (M->v);
+ free2 (M->wbuf);
+ free2 (M->w);
+ *M = INIT_SETFAMILY;
+}
+
+/****************************************************************/
+/****************************************************************/
+/****************************************************************/
+
+/* read binary file for MAT */
+/* each unit-byte will be one number. if unit<0, the sign of unit is flipped, and each value is minesed the half of the maximum */
+void MAT_load_bin (MAT *M, FILE2 *fp, int unit){
+ VEC_ID flag=0, i, j, jj;
+ size_t siz=0;
+ VEC_VAL z, neg=0;
+
+ if ( unit < 0 ){
+ unit = -unit; flag = 1; neg=128;
+ FLOOP (jj, 0, unit-1) neg *= 256;
+ }
+ if ( M->t == 0 ){ // determine #rows if M->t is 0 (not specified)
+ fseek(fp->fp, 0, SEEK_END);
+ siz = ftell(fp->fp);
+ fseek(fp->fp, 0, SEEK_SET);
+ M->t = (VEC_ID)(siz / unit / M->clms);
+ if ( M->flag & LOAD_TPOSE ) SWAP_VEC_ID (M->t, M->clms);
+ }
+ MAT_alloc (M, M->t, M->clms); if (ERROR_MES) return;
+ M->end = M->t;
+ FLOOP (i, 0, M->t){
+ FLOOP (j, 0, M->clms){
+ z=0; FLOOP (jj, 0, unit){ z *= 256; z += FILE2_getc (fp); }
+ if ( flag ) z -= neg;
+ if ( M->flag & LOAD_TPOSE ) M->v[j].v[i] = z;
+ else M->v[i].v[j] = z;
+ }
+ }
+}
+
+/* segmentation fault for illegal files */
+/* count/read the number in file for MAT */
+/* if *rows>0, only read count the numbers in a row, for the first scan. */
+void MAT_file_load (MAT *M, FILE2 *fp){
+ QUEUE_ID c;
+ VEC_ID t=0;
+ double p;
+
+ for ( t=0 ; (FILE_err&2)==0 ; t++){
+ ARY_SCAN (c, double, *fp, 0);
+ if ( M->flag & LOAD_TPOSE ){
+ if ( M->t == 0 ){ M->t = c; if ( M->clms>0 ) break; }
+ } else if ( M->clms == 0 ){ M->clms = c; if ( M->t>0 ) break; }
+ }
+ if ( M->flag & LOAD_TPOSE ){ if ( M->clms==0 ) M->clms = t;} else if ( M->t==0 ) M->t = t;
+ FILE2_reset (fp);
+ M->end = M->t;
+ MAT_alloc (M, M->t, M->clms); if (ERROR_MES) return;
+ FLOOP (t, 0, M->t ){
+ FLOOP (c, 0, M->clms){
+ p = FILE2_read_double(fp);
+ if ( M->flag&LOAD_TPOSE ) M->v[c].v[t] = p;
+ else M->v[t].v[c] = p;
+ if ( c>= ((M->flag&LOAD_TPOSE)? M->t: M->clms) ) break;
+ }
+ if ( !FILE_err ) FILE2_read_until_newline (fp);
+ if ( c>= ((M->flag&LOAD_TPOSE)? M->clms: M->t) ) break;
+ }
+}
+
+/* load file with switching the format according to the flag */
+void MAT_load (MAT *M, char *fname){
+ FILE2 fp;
+ int unit=0;
+#ifdef USE_MATH
+ VEC_ID i;
+#endif
+ if ( M->flag & VEC_LOAD_BIN ) unit = 1;
+ else if ( M->flag & VEC_LOAD_BIN2 ) unit = 2;
+ else if ( M->flag & VEC_LOAD_BIN4 ) unit = 4;
+ if ( M->flag & VEC_LOAD_CENTERIZE ) unit = -unit;
+
+ FILE2_open (fp, fname, "rb", "MAT_load", EXIT);
+ if ( unit ) MAT_load_bin (M, &fp, unit);
+ else MAT_file_load (M, &fp);
+ FILE2_close (&fp); if (ERROR_MES) EXIT;
+#ifdef USE_MATH
+ if ( M->flag&VEC_NORMALIZE ) FLOOP (i, 0, M->t) ARY_NORMALIZE (M->v[i].v,M->v[i].t);
+#endif
+}
+
+
+/* scan file and read the numbers for SMAT */
+/* flag&1? SMAT, SETFAMILY, flag&2? tuple list format: array list :*/
+void SMAT_file_load (SMAT *M, FILE2 *fp){
+ SVEC_VAL z=0;
+ VEC_ID flag= (M->type==TYPE_SMAT), t, x, y;
+ FILE_COUNT C;
+
+ C = FILE2_count (fp, (M->flag&(LOAD_ELE+LOAD_TPOSE)) | FILE_COUNT_ROWT, 0, 0, 0, 0, 0);
+ if ( M->clms == 0 ) M->clms = C.clms;
+ if ( M->t == 0 ) M->t = C.rows;
+ if ( flag ) SMAT_alloc (M, M->t, C.rowt, M->clms, 0);
+ else SETFAMILY_alloc ((SETFAMILY *)M, M->t, C.rowt, M->clms, 0);
+ free2 (C.rowt);
+ if ( ERROR_MES ) return;
+ FILE2_reset (fp);
+ t=0;
+ do {
+ if ( M->flag&LOAD_ELE ){
+ x = (VEC_ID)FILE2_read_int (fp);
+ y = (VEC_ID)FILE2_read_int (fp);
+ if ( flag ) z = FILE2_read_double (fp);
+ if ( FILE_err&4 ) goto LOOP_END2;
+ FILE2_read_until_newline (fp);
+ } else {
+ x = t;
+ y = (VEC_ID)FILE2_read_int (fp);
+ if ( FILE_err&4 ) goto LOOP_END2;
+ if ( flag ) z = FILE2_read_double (fp);
+ }
+ if ( M->flag&LOAD_TPOSE ) SWAP_VEC_ID (x, y);
+// printf ("%d %d %d %d\n", x, M->t, y, M->clms);
+ if ( y >= M->clms || x >= M->t ) goto LOOP_END2;
+// printf ("## %d %d\n", x, y);
+ if ( flag ){
+ M->v[x].v[M->v[x].t].i = y;
+ M->v[x].v[M->v[x].t].a = z;
+ M->v[x].t++;
+ } else ARY_INS (((SETFAMILY *)M)->v[x], y);
+ LOOP_END2:;
+ if ( !(M->flag&LOAD_ELE) && (FILE_err&3) ){ t++; if ( t >= M->t ) break; }
+ } while ( (FILE_err&2)==0 );
+}
+
+/* scan file and read the numbers for SMAT */
+/* flag&1? SMAT, SETFAMILY, flag&2? tuple list format: array list :*/
+void SETFAMILY_load_weight (SETFAMILY *M, char *fname){
+ FILE2 fp;
+ VEC_ID i;
+ QUEUE_ID j;
+ if ( M->flag&LOAD_TPOSE ) error ("transope and weight can't be specified simultaneously", EXIT);
+ FILE2_open (fp, fname, "r", "SETFAMILY_load_weight", EXIT);
+ SETFAMILY_alloc_weight (M);
+ FLOOP (i, 0, M->t){
+ FLOOP (j, 0, M->v[i].t)
+ M->w[i][j] = (WEIGHT)FILE2_read_double (&fp);
+ FILE2_read_until_newline (&fp);
+ }
+}
+
+
+/* load file with switching the format according to the flag */
+void SMAT_load (SMAT *M, char *fname){
+ FILE2 fp;
+ VEC_ID i;
+ M->type = TYPE_SMAT;
+ FILE2_open (fp, fname, "r", "SMAT_load", EXIT);
+ SMAT_file_load (M, &fp);
+ FILE2_close (&fp); if (ERROR_MES) EXIT;
+ FLOOP (i, 0, M->t) M->v[i].v[M->v[i].t].i = M->clms; // end mark
+
+#ifdef USE_MATH
+ if ( M->flag&VEC_NORMALIZE ) FLOOP (i, 0, M->t) SVEC_normalize (&M->v[i]); // normalize
+#endif
+ if (M->flag&LOAD_INCSORT)
+ FLOOP (i, 0, M->t) qsort_VEC_ID ((VEC_ID *)(M->v[i].v), M->v[i].t, sizeof(SVEC_ELE));
+ if (M->flag&LOAD_DECSORT)
+ FLOOP (i, 0, M->t) qsort_VEC_ID ((VEC_ID *)(M->v[i].v), M->v[i].t, -(int)sizeof(SVEC_ELE));
+ if (M->flag&LOAD_RM_DUP)
+ FLOOP (i, 0, M->t) MQUE_UNIFY (M->v[i], SVEC_VAL);
+ M->eles = M->ele_end;
+}
+
+/* sort and duplication check */
+void SETFAMILY_sort (SETFAMILY *M){
+ VEC_ID i;
+ PERM *p;
+ WEIGHT *ww;
+ QUEUE Q;
+ int flag = (M->flag&LOAD_INCSORT)? 1: ((M->flag&LOAD_DECSORT)? -1: 0);
+ if ( flag ){ // sort items in each row
+ malloc2 (p, M->clms, "SETFAMILY_sort: p", EXIT);
+ FLOOP (i, 0, M->t)
+ QUEUE_perm_WEIGHT (&M->v[i], M->w?M->w[i]:NULL, p, flag);
+ free (p);
+ }
+ flag = ((M->flag&LOAD_SIZSORT)? ((M->flag&LOAD_DECROWSORT)? -1: 1): 0) *sizeof(QUEUE);
+ if ( flag ){ // sort the rows
+ p = qsort_perm_VECt ((VEC *)M->v, M->t, flag);
+ ARY_INVPERMUTE_ (M->w, p, ww, M->t);
+ ARY_INVPERMUTE (M->v, p, Q, M->t, "SETFAMILY_sort: ARY_INVPERMUTE", EXIT);
+ free (p);
+ }
+ if (M->flag&LOAD_RM_DUP){ // unify the duplicated edges
+ FLOOP (i, 0, M->t)
+ QUEUE_rm_dup_WEIGHT (&M->v[i], M->w?M->w[i]:NULL);
+ }
+}
+
+/* scan file and load the data from file to SMAT structure */
+void SETFAMILY_load (SETFAMILY *M, char *fname, char *wfname){
+ FILE2 fp;
+ VEC_ID i;
+ M->type = TYPE_SETFAMILY;
+ FILE2_open (fp, fname, "r", "SETFAMILY_load", EXIT);
+ SMAT_file_load ((SMAT *)M, &fp);
+ FILE2_close (&fp); if(ERROR_MES) EXIT;
+ FLOOP (i, 0, M->t) M->v[i].v[M->v[i].t] = M->clms; // end mark
+
+ if ( !(M->flag&LOAD_ELE) && wfname ){
+ SETFAMILY_load_weight (M, wfname);
+ if ( ERROR_MES ){ SETFAMILY_end (M); EXIT; }
+ }
+
+ SETFAMILY_sort (M);
+ M->eles = M->ele_end;
+}
+
+/* print routines */
+void MAT_print (FILE *fp, MAT *M){
+ VEC *V;
+ MQUE_FLOOP (*M, V) ARY_FPRINT (fp, V->v, 0, V->t, VEC_VALF" ");
+}
+void SVEC_print (FILE *fp, SVEC *V){
+ SVEC_ELE *x;
+ MQUE_FLOOP (*V, x) fprintf (fp, "("QUEUE_IDF","SVEC_VALF") ", (*x).i, (*x).a);
+ fputc ('\n', fp);
+}
+void SMAT_print (FILE *fp, SMAT *M){
+ SVEC *V;
+ MQUE_FLOOP (*M, V) SVEC_print (fp, V);
+}
+void SETFAMILY_print (FILE *fp, SETFAMILY *M){
+ QUEUE *V;
+ MQUE_FLOOP (*M, V) ARY_FPRINT (fp, V->v, 0, V->t, QUEUE_INTF" ");
+}
+
+/*
+void SETFAMILY_print_WEIGHT (FILE *fp, SETFAMILY *M){
+ if ( M->w ){
+ printf (","); fprint_WEIGHT (stdout, M->w[i][j]); }
+ printf ("\n");
+}
+*/
+
+/****************************************************************/
+/** Inner product routines **************************************/
+/****************************************************************/
+SVEC_VAL2 SVEC_inpro (SVEC *V1, SVEC *V2){
+ VEC_ID i1, i2=0;
+ SVEC_VAL2 sum=0;
+ FLOOP (i1, 0, V1->t){
+ while (V2->v[i2].i < V1->v[i1].i) i2++;
+ if (V2->v[i2].i == V1->v[i1].i) sum += ((SVEC_VAL2)V2->v[i2].a)*V1->v[i1].a;
+ }
+ return (sum);
+}
+
+
+/* get ith vector */
+void *MVEC_getvec (void *M, int i, int flag){
+ MAT *MM = (MAT *)M;
+ if (MM->type==TYPE_MAT) return (&MM->v[i]);
+ if (MM->type==TYPE_SMAT) return (&((SVEC *)M)->v[i]);
+ if (MM->type==TYPE_SETFAMILY) return (&((QUEUE *)M)->v[i]);
+ return (NULL);
+}
+
+#ifdef USE_MATH
+
+/****************************************************************/
+/** Norm computation and normalization ************************/
+/****************************************************************/
+double SVEC_norm (SVEC *V){
+ SVEC_ELE *v;
+ double sum=0;
+ MQUE_FLOOP (*V, v) sum += ((double)(v->a)) * (v->a);
+ return (sqrt(sum));
+}
+void SVEC_normalize (SVEC *V){
+ SVEC_ELE *v;
+ double norm = SVEC_norm (V);
+ MQUE_FLOOP (*V, v) v->a /= norm;
+}
+
+/****************************************************************/
+/** Euclidean distance routines *********************************/
+/****************************************************************/
+
+/* compute the inner product of two vectors */
+double VEC_eucdist (VEC *V1, VEC *V2){
+ VEC_ID i, end=MIN(V1->end,V2->end);
+ double sum=0, a0, a1, a2, a3;
+ for (i=0 ; i<end ; i+=4){
+ a0 = ((double)V1->v[i])- ((double)V2->v[i]);
+ a1 = ((double)V1->v[i+1])- ((double)V2->v[i+1]);
+ a2 = ((double)V1->v[i+2])- ((double)V2->v[i+2]);
+ a3 = ((double)V1->v[i+3])- ((double)V2->v[i+3]);
+ sum += a0*a0 + a1*a1 + a2*a2 + a3*a3;
+ }
+ if ( i+1<end ){
+ a0 = ((double)V1->v[i])- ((double)V2->v[i]);
+ a1 = ((double)V1->v[i+1])- ((double)V2->v[i+1]);
+ sum += a0*a0 + a1*a1;
+ if ( i+2<end ){ a2 = ((double)V1->v[i+2])- ((double)V2->v[i+2]); sum += a2*a2; }
+ } else if ( i<end ){ a0 = ((double)V1->v[i])- ((double)V2->v[i]); sum += a0*a0; }
+ return (sqrt(sum));
+}
+
+/* compute the inner product of two vectors */
+double SVEC_eucdist (SVEC *V1, SVEC *V2){
+ VEC_ID i1, i2;
+ double sum=0, a;
+ for ( i1=i2=0 ; i1<V1->t && i2<V2->t ; ){
+ if (V2->v[i2].i > V1->v[i1].i) a = V1->v[i1].a;
+ else if (V2->v[i2].i < V1->v[i1].i) a = V2->v[i2].a;
+ else a = ((double)V2->v[i2].a) - ((double)V1->v[i1].a);
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/* compute the inner product of two vectors */
+double VEC_SVEC_eucdist (VEC *V1, SVEC *V2){
+ VEC_ID i, i2=0;
+ double sum=0, a;
+ FLOOP (i, 0, V1->end){
+ if ( i < V2->v[i2].i ) a = V1->v[i];
+ else { a = ((double)V1->v[i]) - ((double)V2->v[i2].a); i2++; }
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/**********************************************************/
+/* Euclidean distance of vector and set */
+double VEC_QUEUE_eucdist (VEC *V, QUEUE *Q){
+ VEC_ID i;
+ QUEUE_ID i2=0;
+ double sum=0, a;
+ FLOOP (i, 0, V->end){
+ if ( i < Q->v[i2] ) a = V->v[i];
+ else { a = ((double)V->v[i]) - 1.0; i2++; }
+ sum += a*a;
+ }
+ return (sqrt(sum));
+}
+
+/* compute Euclidean distance of two sets */
+double QUEUE_eucdist (QUEUE *Q1, QUEUE *Q2){
+ double f;
+ MQUE_UNION(f, *Q1, *Q2);
+ return (sqrt(f));
+}
+
+double MVEC_norm (void *V){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC){ ARY_NORM (p, VV->v, VV->t); return (p); }
+ if (VV->type==TYPE_SVEC) return (SVEC_norm ((SVEC *)V));
+ if (VV->type==TYPE_QUEUE) return (sqrt(((QUEUE*)V)->t));
+ return (0.0);
+}
+
+double MMAT_norm_i (void *M, int i){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_NORM (p, MM->v[i].v, MM->v[i].t); return (p); }
+ if (MM->type==TYPE_SMAT) return (SVEC_norm (&((SMAT *)M)->v[i]));
+ if (MM->type==TYPE_SETFAMILY) return (sqrt (((SETFAMILY *)M)->v[i].t));
+ return (0.0);
+}
+
+double MVEC_eucdist (void *V, void *U){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC) return (VEC_eucdist ((VEC *)V, (VEC *)U));
+ if (VV->type==TYPE_SVEC) return (SVEC_eucdist ((SVEC *)V, (SVEC *)U));
+ if (VV->type==TYPE_QUEUE){ MQUE_DIF (p, *((QUEUE *)V), *((QUEUE *)U)); return (sqrt(p));}
+ return (0.0);
+}
+
+double MMAT_eucdist_ij (void *M, int i, int j){
+ MAT *MM=(MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT) return (VEC_eucdist ( &MM->v[i], &MM->v[j] ));
+ if (MM->type==TYPE_SMAT) return (SVEC_eucdist ( &((SMAT *)M)->v[i], &((SMAT *)M)->v[j]));
+ if (MM->type==TYPE_SETFAMILY){ MQUE_DIF (p, ((SETFAMILY *)M)->v[i], ((SETFAMILY *)M)->v[j]); return (sqrt(p)); }
+ return (0.0);
+}
+
+
+#endif
+
+/**********************************************************/
+/** multi-vector routines ******************************/
+/**********************************************************/
+
+/* compute the inner product, Euclidean distance for multi vector */
+double MVEC_inpro (void *V, void *U){
+ VEC *VV = (VEC *)V, *UU = (VEC *)U;
+ double p;
+ if (VV->type==TYPE_VEC){
+ if (UU->type==TYPE_VEC){ ARY_INPRO (p, VV->v, UU->v, VV->t); return (p); }
+ if (UU->type==TYPE_SVEC){ ARY_SVEC_INPRO (p, *((SVEC *)U), VV->v); return (p); }
+ if (UU->type==TYPE_QUEUE){ ARY_QUEUE_INPRO (p, *((QUEUE *)U), VV->v); return (p); }
+ }
+ if (VV->type==TYPE_SVEC){
+ if (UU->type==TYPE_VEC){ ARY_SVEC_INPRO (p, *((SVEC *)V), UU->v); return (p);}
+ if (UU->type==TYPE_SVEC) return (SVEC_inpro ((SVEC *)V, (SVEC *)U));
+// if (UU->type==TYPE_QUEUE) return (VEC_QUEUE_inpro (V, U));
+ }
+ if (VV->type==TYPE_QUEUE){
+ if (UU->type==TYPE_VEC){ ARY_QUEUE_INPRO (p, *((QUEUE *)V), UU->v); return (p); }
+// else if (UU->type==TYPE_SVEC) return (SVEC_inpro (V, U));
+ if (UU->type==TYPE_QUEUE){ MQUE_INTSEC (p, *((QUEUE *)V), *((QUEUE *)U)); return (p);}
+ }
+ return (0.0);
+}
+
+double MVEC_double_inpro (void *V, double *w){
+ VEC *VV = (VEC *)V;
+ double p;
+ if (VV->type==TYPE_VEC){ ARY_INPRO (p, VV->v, w, VV->t); return (p); }
+ if (VV->type==TYPE_SVEC){ ARY_SVEC_INPRO (p, *((SVEC *)V), w); return (p); }
+ if (VV->type==TYPE_QUEUE){ ARY_QUEUE_INPRO (p, *((QUEUE *)V), w); return (p); }
+ return (0.0);
+}
+
+/* compute the inner product, euclidean distance for i,jth vector */
+double MMAT_inpro_ij (void *M, int i, int j){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_INPRO (p, MM->v[i].v, MM->v[j].v, MM->v[j].t); return (p); }
+ if (MM->type==TYPE_SMAT) return (SVEC_inpro (&((SMAT *)M)->v[i], &((SMAT *)M)->v[j]));
+ if (MM->type==TYPE_SETFAMILY){
+ p = QUEUE_intsec_ (&((SETFAMILY *)M)->v[i], &((SETFAMILY *)M)->v[j]); return (p); }
+ return (0.0);
+}
+
+double MMAT_double_inpro_i (void *M, int i, double *w){
+ MAT *MM = (MAT *)M;
+ double p;
+ if (MM->type==TYPE_MAT){ ARY_INPRO (p, MM->v[i].v, w, MM->v[i].t); return (p); }
+ if (MM->type==TYPE_SMAT){ ARY_SVEC_INPRO (p, ((SMAT *)M)->v[i], w); return (p); }
+ if (MM->type==TYPE_SETFAMILY){ ARY_QUEUE_INPRO (p, ((SETFAMILY *)M)->v[i], w); return (p); }
+ return (0.0);
+}
+
+
+
+#endif
+
+
--- /dev/null
+/* library for sparse vector */
+/* Takeaki Uno 27/Dec/2008 */
+
+#ifndef _vec_h_
+#define _vec_h_
+
+#define STDLIB2_USE_MATH
+
+#include"math.h"
+#include"queue.h"
+
+#ifndef SVEC_VAL
+ #ifdef SVEC_VAL_INT
+ #define SVEC_VAL int
+ #define SVEC_VAL2 LONG
+ #define SVEC_VAL_END INTHUGE
+ #define SVEC_VAL2_END LONGHUGE
+ #define SVEC_VALF "%d"
+ #else
+ #define SVEC_VAL double
+ #define SVEC_VAL2 double
+ #define SVEC_VAL_END DOUBLEHUGE
+ #define SVEC_VAL2_END DOUBLEHUGE
+ #define SVEC_VALF "%f"
+ #endif
+#endif
+
+#define VEC_LOAD_BIN 16777216 // read binary file
+#define VEC_LOAD_BIN2 33554432 // read binary file with 2byte for each number
+#define VEC_LOAD_BIN4 67108864 // read binary file with 4byte for each number
+#define VEC_LOAD_CENTERIZE 134217728 // read binary file, and minus the half(128) from each number
+#define VEC_NORMALIZE 268435456 // read binary file, and minus the half(128) from each number
+
+/* matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ VEC *v;
+ VEC_ID end;
+ VEC_ID t;
+ VEC_VAL *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles;
+} MAT;
+
+/* sparse vector, element */
+typedef struct {
+ QUEUE_ID i;
+ SVEC_VAL a;
+} SVEC_ELE;
+
+/* sparse vector, vector */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SVEC_ELE *v;
+ VEC_ID end;
+ VEC_ID t;
+} SVEC;
+
+/* sparse vector, matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ SVEC *v;
+ VEC_ID end;
+ VEC_ID t;
+ SVEC_ELE *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles, ele_end;
+} SMAT;
+
+/* sparse vector, matrix */
+typedef struct {
+ unsigned char type; // mark to identify type of the structure
+ QUEUE *v;
+ VEC_ID end;
+ VEC_ID t;
+ QUEUE_INT *buf, *buf2;
+ int flag;
+ VEC_ID clms;
+ size_t eles, ele_end;
+ WEIGHT **w, *wbuf;
+ int unit;
+} SETFAMILY;
+
+#define INIT_SETFAMILY_ {TYPE_SETFAMILY,NULL,0,0,NULL,NULL,0,0,0,0,NULL,NULL,sizeof(QUEUE_INT)}
+
+extern MAT INIT_MAT;
+extern SVEC INIT_SVEC;
+extern SMAT INIT_SMAT;
+extern SETFAMILY INIT_SETFAMILY;
+
+QSORT_TYPE_HEADER (SVEC_VAL, SVEC_VAL)
+QSORT_TYPE_HEADER (SVEC_VAL2, SVEC_VAL2)
+
+#define ARY_QUEUE_INPRO(f,U,V) do{(f)=0;FLOOP(common_QUEUE_ID, 0, (QUEUE_ID)(U).t)(f)+=(V)[(U).v[common_QUEUE_ID]];}while(0)
+#define ARY_SVEC_INPRO(f,U,V) do{(f)=0;FLOOP(common_VEC_ID, 0, (VEC_ID)(U).t)(f)+=((double)(U).v[common_VEC_ID].a)*(V)[(U).v[common_VEC_ID].i];}while(0)
+
+/* terminate routine for VEC */
+void VEC_end (VEC *V);
+void MAT_end (MAT *M);
+void SVEC_end (SVEC *V);
+void SMAT_end (SMAT *M);
+void SETFAMILY_end (SETFAMILY *M);
+
+/* allocate memory according to rows and rowt */
+void VEC_alloc (VEC *V, VEC_ID clms);
+void MAT_alloc (MAT *M, VEC_ID rows, VEC_ID clms);
+void SVEC_alloc (SVEC *V, VEC_ID end);
+void SMAT_alloc (SMAT *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles);
+void SETFAMILY_alloc (SETFAMILY *M, VEC_ID rows, VEC_ID *rowt, VEC_ID clms, size_t eles);
+void SETFAMILY_alloc_weight (SETFAMILY *M);
+
+/* count/read the number in file for MAT */
+/* if *rows>0, only read count the numbers in a row, for the first scan. */
+void MAT_load_bin (MAT *M, FILE2 *fp, int unit);
+void MAT_file_load (MAT *M, FILE2 *fp);
+void MAT_load (MAT *M, char *fname);
+void SMAT_load (SMAT *M, char *fname);
+void SETFAMILY_load (SETFAMILY *M, char *fname, char *wfname);
+void SETFAMILY_load_weight (SETFAMILY *M, char *fname);
+
+void MAT_print (FILE *fp, MAT *M);
+void SVEC_print (FILE *fp, SVEC *M);
+void SMAT_print (FILE *fp, SMAT *M);
+void SETFAMILY_print (FILE *fp, SETFAMILY *M);
+void SETFAMILY_print_weight (FILE *fp, SETFAMILY *M);
+
+
+/* norm, normalization **************************/
+double SVEC_norm (SVEC *V);
+void SVEC_normalize (SVEC *V);
+
+/* inner product **************************/
+SVEC_VAL2 SVEC_inpro (SVEC *V1, SVEC *V2);
+
+/** Euclidean distance routines *********************************/
+double VEC_eucdist (VEC *V1, VEC *V2);
+double SVEC_eucdist (SVEC *V1, SVEC *V2);
+double VEC_SVEC_eucdist (VEC *V1, SVEC *V2);
+double QUEUE_eucdist (QUEUE *Q1, QUEUE *Q2);
+double VEC_QUEUE_eucdist (VEC *V, QUEUE *Q);
+
+void VEC_rand_gaussian (VEC *V);
+
+/* compute the inner product, Euclidean distance for multi vector */
+double MVEC_norm (void *V);
+double MVEC_inpro (void *V, void *U);
+double MVEC_double_inpro (void *V, double *p);
+double MVEC_eucdist (void *V, void *U);
+
+/* compute the inner product, euclidean distance for i,jth vector */
+double MMAT_inpro_ij (void *M, int i, int j);
+double MMAT_double_inpro_i (void *M, int i, double *p);
+double MMAT_eucdist_ij (void *M, int i, int j);
+double MMAT_norm_i (void *M, int i);
+
+
+#endif
--- /dev/null
+CC = gcc
+DIR = ../..
+INCL = $(DIR)/include
+OPT = -O3 -I$(INCL)
+OPT64 = $(OPT) -DB_64
+
+WINDOWDEF = -DLINE
+#WINDOWDEF = -DSPLINE -DVERBOSE
+
+all: graph.o interface.o location.o parts11.o \
+ reorder.o train.o window11.o
+
+64: graph_64.o interface_64.o location_64.o parts11_64.o \
+ reorder_64.o train_64.o window11_64.o
+
+clean:
+ rm -f *.o *.a *~
+
+graph.o: graph.c train.h defs.h reorder.h $(INCL)/bddc.h
+ $(CC) $(OPT) -c graph.c
+ rm -f graph_64.o
+
+graph_64.o: graph.c train.h defs.h reorder.h $(INCL)/bddc.h
+ $(CC) $(OPT64) -c graph.c -o graph_64.o
+ rm -f graph.o
+
+interface.o: interface.c $(INCL)/bddc.h
+ $(CC) $(OPT) -c interface.c
+ rm -f interface_64.o
+
+interface_64.o: interface.c $(INCL)/bddc.h
+ $(CC) $(OPT64) -c interface.c -o interface_64.o
+ rm -f interface.o
+
+location.o: location.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT) -c location.c
+ rm -f location_64.o
+
+location_64.o: location.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT64) -c location.c -o location_64.o
+ rm -f location.o
+
+parts11.o: parts11.c defs.h $(INCL)/bddc.h
+ $(CC) $(OPT) $(WINDOWDEF) -c parts11.c
+ rm -f parts11_64.o
+
+parts11_64.o: parts11.c defs.h $(INCL)/bddc.h
+ $(CC) $(OPT64) $(WINDOWDEF) -c parts11.c -o parts11_64.o
+ rm -f parts11.o
+
+reorder.o: reorder.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT) -c reorder.c
+ rm -f reorder_64.o
+
+reorder_64.o: reorder.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT64) -c reorder.c -o reorder_64.o
+ rm -f reorder.o
+
+train.o: train.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT) -c train.c
+ rm -f train_64.o
+
+train_64.o: train.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT64) -c train.c -o train_64.o
+ rm -f train.o
+
+window11.o: window11.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT) $(WINDOWDEF) -c window11.c
+ rm -f window11_64.o
+
+window11_64.o: window11.c train.h $(INCL)/bddc.h
+ $(CC) $(OPT64) $(WINDOWDEF) -c window11.c -o window11_64.o
+ rm -f window11.o
+
--- /dev/null
+#define TRUE 1
+#define FALSE 0
+#define EMPTY -1
+
+#define NORMAL 0x00000000
+#define NEGATIV 0x00000001
+#define EXCHANGE 0x00000002
+
+/* for further expanded edge attribute, name it as 0x4, 0x8, 0x10 ... */
+
+extern int edgemode; /* 0:Nomal 1:Out-Inv 2:Ont&In-Inv */
+
--- /dev/null
+#include <stdio.h>
+#include "bddc.h"
+#include "defs.h"
+#include "train.h"
+#include "reorder.h"
+
+#define NODEBLUSH 2
+#define DEFAULTRADIX 20
+#define SPOTRADIX 3
+#define CHECKCOUNT 20
+
+extern train BDDIOpacks;
+extern int BDDIOfunctionlevel;
+extern int BDDIOwidth, BDDIOheight;
+
+static unsigned int radix = DEFAULTRADIX;
+
+static int top, toe;
+static int fore, back;
+
+
+void SetRadix( r )
+ int r;
+{
+ if( r > DEFAULTRADIX ){
+ radix = DEFAULTRADIX;
+ }
+ else{
+ radix = r;
+ }
+}
+
+
+int GetRadix(){
+ return( radix );
+}
+
+
+void PutNode( level, number )
+ short level;
+ int number;
+{
+ int x, y;
+
+ Center( level, number, &x, &y );
+ if( level == BDDIOfunctionlevel ){
+ Circle( x, y, radix, fore, NODEBLUSH );
+ DrawBoldInt( number + 1, x, y );
+ }
+ else if( level > 0 ){
+ Circle( x, y, radix, fore, NODEBLUSH );
+ if( radix > MeanFontWidth() ){
+ DrawInt( level, x, y );
+ }
+ }
+ else{
+ Square( x, y, radix, fore, NODEBLUSH );
+ DrawInt( NameOfLeaf( *(bddp*)TrainIndex( (train*)TrainIndex( &BDDIOpacks,
+ level ),
+ number) ),
+ x, y );
+ }
+}
+
+
+void LeftEdge( flevel, fnumber, tlevel, tnumber )
+ short flevel, tlevel;
+ int fnumber, tnumber;
+{
+ int x0, y0, xf, yf, xp, yp, xt, yt;
+
+ if( flevel > 0 ){
+ Center( flevel, fnumber, &x0, &y0 );
+ LeftLeg( flevel, fnumber, &xf, &yf );
+ LeftFoot( flevel, fnumber, &xp, &yp );
+ Head( tlevel, tnumber, &xt, &yt );
+ if( xf > xt ){
+ RightShoulder( tlevel, tnumber, &xt, &yt );
+ }
+ else if( xf < xt ){
+ LeftShoulder( tlevel, tnumber, &xt, &yt );
+ }
+ Curve( x0, y0, xf, yf, xp, yp, xt, yt, ( flevel - tlevel != 1 ) );
+ }
+}
+
+
+void RightEdge( flevel, fnumber, tlevel, tnumber )
+ short flevel, tlevel;
+ int fnumber, tnumber;
+{
+ int x0, y0, xf, yf, xp, yp, xt, yt;
+
+ if( flevel > 0 ){
+ Center( flevel, fnumber, &x0, &y0 );
+ RightLeg( flevel, fnumber, &xf, &yf );
+ RightFoot( flevel, fnumber, &xp, &yp );
+ Head( tlevel, tnumber, &xt, &yt );
+ if( xf > xt ){
+ RightShoulder( tlevel, tnumber, &xt, &yt );
+ }
+ else if( xf < xt ){
+ LeftShoulder( tlevel, tnumber, &xt, &yt );
+ }
+ Curve( x0, y0, xf, yf, xp, yp, xt, yt, ( flevel - tlevel != 1 ) );
+ }
+}
+
+
+void TailEdge( flevel, fnumber, tlevel, tnumber )
+ short flevel, tlevel;
+ int fnumber, tnumber;
+{
+ int x1, x2, y1, y2;
+
+ if( flevel > 0 ){
+ Hip( flevel, fnumber, &x1, &y1 );
+ Head( tlevel, tnumber, &x2, &y2 );
+ if( x1 > x2 ){
+ RightShoulder( tlevel, tnumber, &x2, &y2 );
+ }
+ else if( x1 < x2 ){
+ LeftShoulder( tlevel, tnumber, &x2, &y2 );
+ }
+ Line( x1, y1, x2, y2 );
+ }
+}
+
+
+static void NegativPochi( level, number )
+ short level;
+ int number;
+{
+ int x, y;
+
+ if( level != BDDIOfunctionlevel ){
+ RightLeg( level, number, &x, &y );
+ }
+ else{
+ Hip( level, number, &x, &y );
+ }
+/* Circle( x, y, SPOTRADIX / 2, back, SPOTRADIX / 2 + 2 );*/
+ Circle( x, y, SPOTRADIX, fore, NODEBLUSH );
+}
+
+
+static void LeftNegativPochi( level, number )
+ short level;
+ int number;
+{
+ int x, y;
+
+ if( level != BDDIOfunctionlevel ){
+ LeftLeg( level, number, &x, &y );
+ }
+ else{
+ Hip( level, number, &x, &y );
+ }
+/* Circle( x, y, SPOTRADIX / 2, back, SPOTRADIX / 2 + 2 );*/
+ Circle( x, y, SPOTRADIX, fore, NODEBLUSH );
+}
+
+
+void ExPochi( level, number )
+ short level;
+ int number;
+{
+ int x, y;
+
+ if( level != BDDIOfunctionlevel ){
+ RightLeg( level, number, &x, &y );
+ }
+ else{
+ Hip( level, number, &x, &y );
+ }
+ Cross( x, y, SPOTRADIX * 2, NODEBLUSH );
+}
+
+void LeftExPochi( level, number )
+ short level;
+ int number;
+{
+ int x, y;
+
+ if( level != BDDIOfunctionlevel ){
+ LeftLeg( level, number, &x, &y );
+ }
+ else{
+ Hip( level, number, &x, &y );
+ }
+ Cross( x, y, SPOTRADIX * 2, NODEBLUSH );
+}
+
+
+static int HaveTheAttribute( atr, name )
+ int atr, name;
+{
+ return( ( atr & name ) != 0 );
+}
+
+
+static void DrawNodes(){
+ int i, j;
+ int cnt;
+ train *p;
+ pack *pk;
+
+ cnt = 0;
+ for( i = toe; i <= top ; i ++ ){
+ p = ( train *)TrainIndex( &BDDIOpacks, i );
+ for( j = 0; j < TrainBound( p ) ; j ++ ){
+ pk = ( pack *)TrainIndex( p, j );
+ if( cnt == 0 ){
+ cnt = CHECKCOUNT;
+ if( Interrupt() ){
+ goto loopabort;
+ }
+ }
+ else{
+ cnt --;
+ }
+ PutNode( i, j );
+ if( i == BDDIOfunctionlevel ){
+ TailEdge( i, j, pk->llevel, pk->lnumber );
+ if( HaveTheAttribute( pk->lattrib, NEGATIV ) ) NegativPochi( i, j );
+ if( HaveTheAttribute( pk->lattrib, EXCHANGE ) ) ExPochi( i, j );
+ }
+ else if( i > 0 ){
+ if( ( AttributeOfEdge(pk->node) & EXCHANGE ) != 0 ){
+ RightEdge( i, j, pk->llevel, pk->lnumber );
+ if( HaveTheAttribute( pk->lattrib, NEGATIV ) ) NegativPochi( i, j );
+ if( HaveTheAttribute( pk->lattrib, EXCHANGE ) ) ExPochi( i, j );
+ LeftEdge( i, j, pk->rlevel, pk->rnumber );
+ if( HaveTheAttribute( pk->rattrib, NEGATIV ) ) LeftNegativPochi( i, j );
+ if( HaveTheAttribute( pk->rattrib, EXCHANGE ) ) LeftExPochi( i, j );
+ }
+ else{
+ LeftEdge( i, j, pk->llevel, pk->lnumber );
+ if( HaveTheAttribute( pk->lattrib, NEGATIV ) ) LeftNegativPochi( i, j );
+ if( HaveTheAttribute( pk->lattrib, EXCHANGE ) ) LeftExPochi( i, j );
+ RightEdge( i, j, pk->rlevel, pk->rnumber );
+ if( HaveTheAttribute( pk->rattrib, NEGATIV ) ) NegativPochi( i, j );
+ if( HaveTheAttribute( pk->rattrib, EXCHANGE ) ) ExPochi( i, j );
+ }
+ }
+ }
+ }
+ loopabort:;
+}
+
+
+void Show(){
+ ResetWindowSize();
+ DrawNodes();
+}
+
+
+void Draw( server, fontname )
+ char *server;
+ char *fontname;
+{
+ top = TrainBound( &BDDIOpacks ) - 1;
+ toe = 0;
+ LocationSetMaximumSize( TableMaximumBound(), top );
+ if( WindowOpen( server, fontname ) != FALSE ){
+ QueryColor( &fore, &back );
+ Wait();
+ WindowClose();
+ }
+}
+
+
+void BDDgraph0( server, fontname, number, bddps )
+ char *server, *fontname;
+ int number;
+ bddp bddps[];
+{
+ edgemode = 0;
+ ClearTable();
+ TraverseFunctions( number, bddps );
+ Draw( server, fontname );
+ FreeTable();
+}
+
+void BDDgraph1( server, fontname, number, bddps )
+ char *server, *fontname;
+ int number;
+ bddp bddps[];
+{
+ edgemode = 1;
+ ClearTable();
+ TraverseFunctions( number, bddps );
+ Draw( server, fontname );
+ FreeTable();
+}
+
+void BDDgraph2( server, fontname, number, bddps )
+ char *server, *fontname;
+ int number;
+ bddp bddps[];
+{
+ edgemode = 2;
+ ClearTable();
+ TraverseFunctions( number, bddps );
+ Draw( server, fontname );
+ FreeTable();
+}
+
+void SetWindowSize( x, y )
+ int x, y;
+{
+ BDDIOwidth = x;
+ BDDIOheight = y;
+}
+
+void bddgraph0(f)
+bddp f;
+{
+ if(f != bddnull) BDDgraph0(0, 0, 1, &f);
+}
+
+
+void bddvgraph0(ptr, lim)
+bddp *ptr;
+int lim;
+{
+ int n;
+
+ n = 0;
+ while(n < lim)
+ {
+ if(ptr[n] == bddnull) break;
+ n++;
+ }
+ BDDgraph0(0, 0, n, ptr);
+}
+
+void bddgraph(f)
+bddp f;
+{
+ if(f != bddnull) BDDgraph1(0, 0, 1, &f);
+}
+
+
+void bddvgraph(ptr, lim)
+bddp *ptr;
+int lim;
+{
+ int n;
+
+ n = 0;
+ while(n < lim)
+ {
+ if(ptr[n] == bddnull) break;
+ n++;
+ }
+ BDDgraph1(0, 0, n, ptr);
+}
+
+
--- /dev/null
+#include <stdio.h>
+#include "bddc.h"
+#include "defs.h"
+
+int edgemode;
+
+bddp Strip( n_node )
+ bddp n_node;
+{
+ if( edgemode >= 1 ) n_node &= ~B_INV_MASK ;
+ return( n_node );
+}
+
+
+int AttributeOfEdge( node )
+ bddp node;
+{
+ int attr;
+
+ attr = NORMAL;
+ if( edgemode >= 1 && (node & B_INV_MASK) ) attr |= NEGATIV;
+ return( attr );
+}
+
+
+int SameNode( n1, n2 )
+ bddp n1, n2;
+{
+ return( (n1 & ~B_INV_MASK) == (n2 & ~B_INV_MASK) );
+}
+
+
+short GetLevelOf( node )
+ bddp node;
+{
+ return( bddlevofvar(bddtop( node )) );
+}
+
+
+bddp GetLeftPtrOf( node )
+ bddp node;
+{
+ bddp ret;
+
+ ret = bddat0( node, bddvaroflev(GetLevelOf( node )));
+ bddfree( ret );
+ return( ret );
+}
+
+
+bddp GetRightPtrOf( node )
+ bddp node;
+{
+ bddp ret;
+
+ ret = bddat1( node, bddvaroflev(GetLevelOf( node )));
+ bddfree( ret );
+ return( ret );
+}
+
+
+int NameOfLeaf( leaf )
+ bddp leaf;
+{
+ if( leaf == bddfalse ){
+ return( 0 );
+ }
+ else if( leaf == bddtrue ){
+ return( 1 );
+ }
+ else if( leaf == bddnull ){
+ return( -1 );
+ }
+ else{
+ fprintf( stderr, "Something is wrong. (%d)\n" , leaf);
+ }
+}
--- /dev/null
+ /* bddio libraries */
+
+bddp Strip(); /* Strip( bddp node ) */
+int AttributeOfEdge(); /* AttributeOfEdge( bddp edge ) */
+int SameNode(); /* SameNode( bddp n1, n2 ) */
+short GetLevelOf(); /* GetLevelOf( bddp node ) */
+bddp GetLeftPtrOf(); /* GetLeftPtrOf( bddp node ) */
+bddp GetRightPtrOf(); /* GetRightPtrOf( bddp node ) */
+bddp ParseNode(); /* ParseNode( char *word ) */
--- /dev/null
+#include "defs.h"
+#include "train.h"
+
+extern train BDDIOpacks;
+static unsigned int width, height;
+
+static int top, span;
+static int xinterval, yinterval;
+
+
+void LocationResetLocation( w, h )
+ unsigned int w, h;
+{
+ int r, rx, ry;
+
+ width = w;
+ height = h;
+ xinterval = width / ( span + 1 );
+ yinterval = height / ( top + 2 );
+ rx = xinterval / 3;
+ ry = yinterval / 3;
+ if( rx > ry ){
+ r = ry;
+ }
+ else{
+ r = rx;
+ }
+ SetRadix( r );
+}
+
+
+void LocationSetMaximumSize( x, y )
+ int x, y;
+{
+ span = x;
+ top = y;
+ LocationResetLocation( width, height );
+}
+
+
+void Center( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int size;
+
+ size = TrainBound( (train*)TrainIndex( &BDDIOpacks, level ) );
+ *x = (
+ (int)width
+ + ( 2 * number - ( size - 1 ) )
+ * (int)width / ( size + 1 )
+ ) / 2;
+ *y = yinterval * ( top - level + 1 );
+}
+
+
+int Head( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy - GetRadix() );
+}
+
+
+int Top( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int LeftHand( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int RightHand( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int LeftLeg( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() / 4 * 3 );
+ *y = ( cy + GetRadix() / 4 * 3 );
+}
+
+int RightLeg( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() / 4 * 3 );
+ *y = ( cy + GetRadix() / 4 * 3 );
+}
+
+int LeftFoot( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() * 2 );
+ *y = ( cy + GetRadix() * 2 );
+}
+
+int RightFoot( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() * 2 );
+ *y = ( cy + GetRadix() * 2 );
+}
+
+int Hip( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy + GetRadix() );
+}
+
+int RightShoulder( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() * 3 / 4 );
+ if( level != 0 )
+ *y = ( cy - GetRadix() * 3 / 4 );
+ else
+ *y = ( cy - GetRadix() );
+}
+
+int LeftShoulder( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() * 3 / 4 );
+ if( level != 0 )
+ *y = ( cy - GetRadix() * 3 / 4 );
+ else
+ *y = ( cy - GetRadix() );
+}
+
--- /dev/null
+
+#include "defs.h"
+#include "train.h"
+
+extern train BDDIOpacks;
+static unsigned int width, height;
+
+static int top, span;
+static int xinterval, yinterval;
+
+
+void LocationResetLocation( w, h )
+ unsigned int w, h;
+{
+ int r, rx, ry;
+
+ width = w;
+ height = h;
+ xinterval = width / ( span + 1 );
+ yinterval = height / ( top + 2 );
+ rx = xinterval / 3;
+ ry = yinterval / 3;
+ if( rx > ry ){
+ r = ry;
+ }
+ else{
+ r = rx;
+ }
+ SetRadix( r );
+}
+
+
+void LocationSetMaximumSize( x, y )
+ int x, y;
+{
+ span = x;
+ top = y;
+ LocationResetLocation( width, height );
+}
+
+
+void Center( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int size;
+
+ size = TrainBound( (train*)TrainIndex( &BDDIOpacks, level ) );
+ *x = (
+ (int)width
+ + ( 2 * number - ( size - 1 ) )
+/* * (int)width / ( span + 1 ) /**/
+/* * (int)width / ( (top==level ? size : span) + 1 ) /**/
+ * (int)width / ( (top==level||0==level ? size : span) + 1 ) /**/
+ ) / 2;
+ *y = yinterval * ( top - level + 1 );
+}
+
+
+int Head( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy - GetRadix() );
+}
+
+
+int Top( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int LeftHand( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int RightHand( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() );
+ *y = ( cy - 2 * GetRadix() );
+}
+
+
+int LeftLeg( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() / 4 * 3 );
+ *y = ( cy + GetRadix() / 4 * 3 );
+}
+
+int RightLeg( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() / 4 * 3 );
+ *y = ( cy + GetRadix() / 4 * 3 );
+}
+
+int LeftFoot( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() * 2 );
+ *y = ( cy + GetRadix() * 2 );
+}
+
+int RightFoot( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() * 2 );
+ *y = ( cy + GetRadix() * 2 );
+}
+
+int Hip( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx );
+ *y = ( cy + GetRadix() );
+}
+
+int RightShoulder( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx + GetRadix() * 3 / 4 );
+ if( level != 0 )
+ *y = ( cy - GetRadix() * 3 / 4 );
+ else
+ *y = ( cy - GetRadix() );
+}
+
+int LeftShoulder( level, number, x, y )
+ short level;
+ int number;
+ int *x, *y;
+{
+ int cx, cy;
+
+ Center( level, number, &cx, &cy );
+ *x = ( cx - GetRadix() * 3 / 4 );
+ if( level != 0 )
+ *y = ( cy - GetRadix() * 3 / 4 );
+ else
+ *y = ( cy - GetRadix() );
+}
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include "defs.h"
+
+#define EDGEBLUSH 1
+
+extern Display *disp;
+extern Window window;
+extern XFontStruct *fontinfo;
+extern GC wingc;
+extern int scrn;
+
+
+void Spark(){
+ int x, y;
+ Window tmpw;
+ int tmpi;
+ unsigned int tmpm;
+
+ XQueryPointer( disp, window,
+ &tmpw, &tmpw,
+ &tmpi, &tmpi,
+ &x, &y,
+ &tmpm );
+ XDrawLine( disp, window, wingc,
+ x - 20, y, x - 10, y );
+ XDrawLine( disp, window, wingc,
+ x + 10, y, x + 20, y );
+ XDrawLine( disp, window, wingc,
+ x, y - 20 , x, y - 10 );
+ XDrawLine( disp, window, wingc,
+ x, y + 10 , x, y + 20 );
+ XDrawLine( disp, window, wingc,
+ x - 20, y - 20, x - 10, y - 10 );
+ XDrawLine( disp, window, wingc,
+ x + 10, y + 10, x + 20, y + 20 );
+ XDrawLine( disp, window, wingc,
+ x - 20, y + 20 , x - 10, y + 10 );
+ XDrawLine( disp, window, wingc,
+ x + 10, y - 10 , x + 20, y - 20 );
+}
+
+
+void DrawInt( number, x, y )
+ int number;
+{
+ int width, height;
+ char letter[ 15 ];
+
+ if( DontCrip( x, y ) ){
+ sprintf( letter, "%d", number );
+ width = XTextWidth( fontinfo, letter, strlen( letter ) );
+ height = fontinfo->ascent + fontinfo->descent;
+ XDrawImageString( disp, window, wingc,
+ x - width / 2, y - height / 2 + fontinfo->ascent,
+ letter, strlen( letter ) );
+ }
+}
+
+
+void DrawBoldInt( number, x, y )
+ int number;
+{
+ int width, height;
+ char letter[ 15 ];
+
+ if( DontCrip( x, y ) ){
+ sprintf( letter, "%d", number );
+ width = XTextWidth( fontinfo, letter, strlen( letter ) );
+ height = fontinfo->ascent + fontinfo->descent;
+ XDrawImageString( disp, window, wingc,
+ x - width / 2, y - height / 2 + fontinfo->ascent,
+ letter, strlen( letter ) );
+ XDrawString( disp, window, wingc,
+ x - width / 2 + 1, y - height / 2 + fontinfo->ascent,
+ letter, strlen( letter ) );
+ }
+}
+
+
+void Circle( x, y, r, pixel, blush )
+ int x, y;
+ unsigned int r;
+ int pixel;
+ int blush;
+{
+ int i;
+
+ if( DontCrip( x, y ) ){
+ XDrawArc( disp, window, wingc, x - (int)r, y - (int)r, 2 * r, 2 * r,
+ 0, 23040 );
+ }
+}
+
+
+void Square( x, y, r, pixel, blush )
+ int x, y;
+ unsigned int r;
+ int pixel;
+ int blush;
+{
+ if( DontCrip( x, y ) ){
+ XDrawRectangle( disp, window, wingc,
+ x - (int)r, y - (int)r,
+ 2 * r, 2 * r );
+ }
+}
+
+
+Curve( x0, y0, xf, yf, xp, yp, xt, yt, splineflag )
+ int x0, y0, xf, yf, xp, yp, xt, yt;
+ int splineflag;
+{
+ XPoint list[ 4 ];
+
+ if( DontCrip( x0, y0 ) && DontCrip( xt, yt ) ){
+#ifdef SPLINE
+ if( splineflag ){
+ list[ 0 ].x = xf;
+ list[ 0 ].y = yf;
+ list[ 0 ].flags = VertexCurved | VertexStartClosed;
+ list[ 1 ].x = xp;
+ list[ 1 ].y = yp;
+ list[ 1 ].flags = VertexCurved;
+ list[ 2 ].x = xt;
+ list[ 2 ].y = yt;
+ list[ 2 ].flags = VertexCurved | VertexEndClosed;
+ XDraw( window, list, 3, EDGEBLUSH, EDGEBLUSH,
+ BlackPixel, GXcopy, AllPlanes );
+ }
+ else{
+ XLine( window, xf, yf, xt, yt,
+ EDGEBLUSH, EDGEBLUSH, BlackPixel, GXcopy, AllPlanes );
+ }
+#else
+#ifdef LINE
+ if( splineflag ){
+ list[ 0 ].x = xf;
+ list[ 0 ].y = yf;
+ list[ 1 ].x = xp;
+ list[ 1 ].y = yp;
+ list[ 2 ].x = xt;
+ list[ 2 ].y = yt;
+ XDrawLines( disp, window, wingc, list, 3, CoordModeOrigin );
+ }
+ else{
+ XDrawLine( disp, window, wingc, xf, yf, xt, yt );
+ }
+#else
+ XLine( window, xf, yf, xt, yt,
+ EDGEBLUSH, EDGEBLUSH, BlackPixel, GXcopy, AllPlanes );
+#endif
+#endif
+ }
+}
+
+
+void Cross( x, y, s, brush )
+ int x, y, s;
+ int brush;
+{
+ if( DontCrip( x, y ) ){
+ XDrawLine( disp, window, wingc, x - s, y - s, x + s, y + s );
+ XDrawLine( disp, window, wingc, x - s, y + s, x + s, y - s );
+ }
+}
+
+
+void Line( x1, y1, x2, y2 )
+ int x1, y1, x2, y2;
+{
+ if( DontCrip( x1, y1 ) && DontCrip( x2, y2 ) ){
+ XDrawLine( disp, window, wingc, x1, y1, x2, y2 );
+ }
+}
+
+
+
--- /dev/null
+#include <stdio.h>
+#include "bddc.h"
+#include "train.h"
+#include "interface.h"
+#include "defs.h"
+#include "reorder.h"
+
+static train table;
+train BDDIOpacks;
+int BDDIOfunctionlevel;
+
+static int samenode( a, b )
+ pack *a;
+ bddp *b;
+{
+ return( a->node == *b );
+}
+
+
+void ClearTable(){
+ TrainReset( &table, sizeof( bddp ) );
+ TrainReset( &BDDIOpacks, sizeof( train ) );
+}
+
+
+void FreeTable(){
+ int i;
+
+ for( i = 0; i < TrainBound( &BDDIOpacks ); i ++ ){
+ TrainFree( (train*)TrainIndex( &BDDIOpacks, i ) );
+ }
+ TrainFree( &table );
+ TrainFree( &BDDIOpacks );
+}
+
+
+static void Reserve( node )
+ bddp node;
+{
+ TrainLoad( &table, &node );
+}
+
+
+static int IsReserved( node )
+ bddp node;
+{
+ if( TrainCheck( &table, &node ) == EMPTY ) return( FALSE );
+ return( TRUE );
+}
+
+
+void Traverse( node )
+ bddp node;
+{
+ bddp left, right, nudeleft, nuderight;
+ short level;
+ pack tmp;
+ train new;
+
+ node = Strip( node );
+ if( !IsReserved( node ) ){
+ Reserve( node );
+ level = GetLevelOf( node );
+ tmp.node = node;
+ if( level > 0 ){
+ left = GetLeftPtrOf( node );
+ nudeleft = Strip( left );
+ right = GetRightPtrOf( node );
+ nuderight = Strip( right );
+ Traverse( left );
+ Traverse( right );
+ tmp.lattrib = AttributeOfEdge( left );
+ tmp.left = nudeleft;
+ tmp.llevel = GetLevelOf( nudeleft );
+ tmp.lnumber = TrainComp( (train*)TrainIndex( &BDDIOpacks, tmp.llevel ),
+ &nudeleft, samenode );
+ tmp.rattrib = AttributeOfEdge( right );
+ tmp.right = nuderight;
+ tmp.rlevel = GetLevelOf( nuderight );
+ tmp.rnumber = TrainComp( (train*)TrainIndex( &BDDIOpacks, tmp.rlevel ),
+ &nuderight, samenode );
+ while( TrainBound( &BDDIOpacks ) <= level ){
+ TrainReset( &new, sizeof( pack ) );
+ TrainLoad( &BDDIOpacks, &new );
+ }
+ TrainLoad( (train*)TrainIndex( &BDDIOpacks, level ), &tmp );
+ }
+ else{
+ while( TrainBound( &BDDIOpacks ) <= level ){
+ TrainReset( &new, sizeof( pack ) );
+ TrainLoad( &BDDIOpacks, &new );
+ }
+ TrainLoad( (train*)TrainIndex( &BDDIOpacks, level ), &tmp );
+ }
+ }
+}
+
+
+void TraverseFunctions( number, nodes )
+ int number;
+ bddp nodes[];
+{
+ int i;
+ train new;
+ pack id;
+
+ for( i = 0; i < number ; i ++ ){
+ Traverse( nodes[ i ] );
+ }
+ TrainReset( &new, sizeof( pack ) );
+ for( i = 0 ; i < number ; i ++ ){
+ id.node = Strip( nodes[ i ] );
+ id.llevel = id.rlevel = GetLevelOf( nodes[ i ] );
+ id.lattrib = id.rattrib = AttributeOfEdge( nodes[ i ] );
+ id.lnumber = id.rnumber = TrainComp( (train*)TrainIndex( &BDDIOpacks,
+ id.llevel ),
+ &id.node, samenode );
+ TrainLoad( &new, &id );
+ }
+ TrainLoad( &BDDIOpacks, &new );
+ BDDIOfunctionlevel = TrainBound( &BDDIOpacks ) - 1;
+}
+
+
+int TableMaximumBound(){
+ int i;
+ int t, max = 0;
+
+ for( i = 0; i < TrainBound( &BDDIOpacks ) ; i ++ ){
+ t = TrainBound( (train*)TrainIndex( &BDDIOpacks, i ) );
+ if( t > max ){
+ max = t;
+ }
+ }
+ return( max );
+}
--- /dev/null
+
+typedef
+ struct{
+ bddp node;
+ bddp left;
+ int lnumber;
+ short llevel;
+ int lattrib;
+ bddp right;
+ int rnumber;
+ short rlevel;
+ int rattrib;
+ } pack;
+
+extern void TraverseFunctions();
+
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "train.h"
+#include "defs.h"
+
+
+void TrainReset( root, size )
+ train *root;
+ int size;
+{
+ container *p;
+
+ root->size = size;
+ p = ( container *)malloc( sizeof( container ) );
+ root->head = p;
+ root->tail = p;
+ root->bound = 0;
+ p->rest = N;
+ p->next = NULL;
+ p->nodes = ( dummy *)malloc( N * root->size );
+ p->tail = p->nodes;
+}
+
+
+void TrainFree( root )
+ train *root;
+{
+ container *t, *tv;
+
+ t = root->head;
+ do{
+ tv = t;
+ t = t->next;
+ free( tv->nodes );
+ free( tv );
+ }while( t != NULL );
+ root->head = NULL;
+ root->tail = NULL;
+ root->size = 0;
+}
+
+
+static void AllocContainer( root )
+ train *root;
+{
+ container *p;
+
+ p = ( container *)malloc( sizeof( container ) );
+ root->tail->next = p;
+ root->tail = p;
+ p->rest = N;
+ p->next = NULL;
+ p->nodes = ( dummy * )malloc( N * root->size );
+ p->tail = p->nodes;
+}
+
+
+void TrainLoad( root, node )
+ train *root;
+ dummy *node;
+{
+ if( root->tail->rest == 0 ) AllocContainer( root );
+ bcopy( node, root->tail->tail, root->size );
+ root->tail->tail += root->size;
+ root->tail->rest --;
+ root->bound ++;
+}
+
+
+int TrainCheck( root, node )
+ train *root;
+ dummy *node;
+{
+ container *t;
+ int i, x;
+
+ t = root->head;
+ x = 0;
+ do{
+ for( i = 0; i < N - ( t->rest ); i++ ){
+ if( bcmp( t->nodes + i * root->size , node, root->size ) == 0 )
+ return( x + i );
+ }
+ t = t->next;
+ x += N;
+ }while( t != NULL );
+ return( EMPTY );
+}
+
+
+int TrainComp( root, node, func )
+ train *root;
+ dummy *node;
+ int (*func)();
+{
+ container *t;
+ int i, x;
+
+ t = root->head;
+ x = 0;
+ do{
+ for( i = 0; i < N - ( t->rest ); i++ ){
+ if( (*func)( t->nodes + i * root->size , node ) )
+ return( x + i );
+ }
+ t = t->next;
+ x += N;
+ }while( t != NULL );
+ return( EMPTY );
+}
+
+
+dummy *TrainIndex( root, x )
+ train *root;
+ int x;
+{
+ container *t;
+
+ if( root->bound <= x ){
+ fprintf( stderr, "ChuDoon\n" );
+ exit( 1 );
+ }
+ t = root->head;
+ do{
+ if( N - ( t->rest ) > x ) return( t->nodes + x * root->size );
+ t = t->next;
+ x -= N;
+ }while( t != NULL );
+ return( NULL );
+}
+
+
+int TrainBound( root )
+ train *root;
+{
+ return( root->bound );
+}
+
--- /dev/null
+
+#define N 100
+
+typedef char dummy;
+
+struct _container{
+ dummy *nodes;
+ dummy *tail;
+ int rest;
+ struct _container *next;
+};
+
+typedef struct _container container;
+
+typedef
+ struct{
+ container *head;
+ container *tail;
+ int size;
+ int bound;
+ } train;
+
+void TrainReset(); /* ( train *root, int size ) */
+void TrainFree(); /* ( train *root ) */
+void TrainLoad(); /* ( train *root, dummy *node ) */
+int TrainCheck(); /* ( train *root, dummy *node ) */
+int TrainComp(); /* ( train *root, dummy *node,
+ (*func)( *a1, *a2 ) ) */
+dummy *TrainIndex(); /* ( train *root, int x ) */
+int TrainBound(); /* ( train *root ) */
--- /dev/null
+#define wait_width 16
+#define wait_height 16
+#define wait_x_hot 7
+#define wait_y_hot 7
+static char wait_bits[] = {
+ 0x00, 0x00, 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0xd0, 0x05, 0xa8, 0x0a,
+ 0x98, 0x0c, 0x98, 0x0f, 0x18, 0x0c, 0x28, 0x0a, 0xd0, 0x05, 0xe0, 0x03,
+ 0xe0, 0x03, 0xe0, 0x03, 0xe0, 0x03, 0x00, 0x00};
--- /dev/null
+#define wait_mask_width 16
+#define wait_mask_height 16
+#define wait_mask_x_hot -1
+#define wait_mask_y_hot -1
+static char wait_mask_bits[] = {
+ 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf8, 0x0f, 0xfc, 0x1f, 0xfc, 0x1f,
+ 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xfc, 0x1f, 0xf8, 0x0f,
+ 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07, 0xf0, 0x07};
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include "defs.h"
+
+#include "yubi.ic"
+#include "yubi_mask.ic"
+#include "wait.ic"
+#include "wait_mask.ic"
+
+#define DEFAULTWIDTH 500
+#define DEFAULTHEIGHT 600
+
+
+unsigned int BDDIOwidth, BDDIOheight;
+
+ Display *disp;
+ Window window;
+ GC wingc;
+ XFontStruct *fontinfo;
+static Cursor yubicu, waitcu;
+ int scrn;
+static int cripx0, cripx1, cripy0, cripy1;
+
+
+void SetCrippingWindow( x0, y0, x1, y1 )
+ unsigned int x0, y0, x1, y1;
+{
+ cripx0 = x0;
+ cripy0 = y0;
+ cripx1 = x1;
+ cripy1 = y1;
+}
+
+
+static void ClearWindow(){
+ XClearWindow( disp, window );
+}
+
+
+void ResetWindowSize(){
+ XWindowAttributes info;
+
+ XGetWindowAttributes( disp, window, &info );
+ if( info.width != BDDIOwidth || info.height != BDDIOheight ){
+ BDDIOwidth = info.width;
+ BDDIOheight = info.height;
+ SetCrippingWindow( 0, 0, BDDIOwidth, BDDIOheight );
+ ClearWindow();
+ }
+ LocationResetLocation( BDDIOwidth, BDDIOheight );
+}
+
+
+void QueryColor( foreground, background )
+ int *foreground, *background;
+{
+ *foreground = BlackPixel( disp, scrn );
+ *background = WhitePixel( disp, scrn );
+}
+
+
+static void DefineCursor(){
+ static XColor frground = {0L, 0, 0, 0};
+ static XColor bground = {0L, 65535, 65535, 65535};
+ Pixmap pix, maskpix;
+
+ pix = XCreateBitmapFromData( disp, window,
+ yubi_bits, yubi_width, yubi_height );
+ maskpix = XCreateBitmapFromData( disp, window,
+ yubi_mask_bits,
+ yubi_mask_width, yubi_mask_height );
+/* pix = XCreatePixmapFromBitmapData( disp, window,
+ yubi_bits, yubi_width, yubi_height,
+ BlackPixel( disp, scrn ),
+ WhitePixel( disp, scrn ),
+ 1 );
+ maskpix = XCreatePixmapFromBitmapData( disp, window,
+ yubi_bits, yubi_width, yubi_height,
+ BlackPixel( disp, scrn ),
+ WhitePixel( disp, scrn ),
+ 1 );
+*/
+ yubicu = XCreatePixmapCursor( disp, pix, maskpix,
+ &frground, &bground,
+ (unsigned int)yubi_x_hot,
+ (unsigned int)yubi_y_hot );
+ XFreePixmap( disp, pix );
+ XFreePixmap( disp, maskpix );
+
+ pix = XCreateBitmapFromData( disp, window,
+ wait_bits, wait_width, wait_height );
+ maskpix = XCreateBitmapFromData( disp, window,
+ wait_mask_bits,
+ wait_mask_width, wait_mask_height );
+ waitcu = XCreatePixmapCursor( disp, pix, maskpix,
+ &frground, &bground,
+ (unsigned int)wait_x_hot,
+ (unsigned int)wait_y_hot );
+ XFreePixmap( disp, pix );
+ XFreePixmap( disp, maskpix );
+}
+
+
+static void KillCursor(){
+ XFreeCursor( disp, yubicu );
+ XFreeCursor( disp, waitcu );
+}
+
+
+int WindowOpen( server, fontname )
+ char *server;
+ char *fontname;
+{
+ char geo[ 50 ], defgeo[ 50 ];
+ char fname[ 50 ];
+
+ disp = XOpenDisplay( server );
+ if( disp == NULL ){
+ fprintf( stderr, "Can't open display '%s.'\n", server );
+ return( FALSE );
+ }
+ scrn = XDefaultScreen( disp );
+ if( fontname == NULL || *fontname == '\0' ){
+ strcpy( fname, "fixed" );
+ }
+ else{
+ strcpy( fname, fontname );
+ }
+ fontinfo = XLoadQueryFont( disp, fname );
+ if( fontinfo == NULL ){
+ fprintf( stderr, "Can't open font '%s.'\n", fname );
+ return( FALSE );
+ }
+ if( BDDIOwidth == 0 || BDDIOheight == 0 ){
+ BDDIOwidth = DEFAULTWIDTH;
+ BDDIOheight = DEFAULTHEIGHT;
+ SetCrippingWindow( 0, 0, BDDIOwidth, BDDIOheight );
+ LocationResetLocation( BDDIOwidth, BDDIOheight );
+ }
+ window = XCreateSimpleWindow( disp, XRootWindow( disp, scrn ),
+ 0, 0, BDDIOwidth, BDDIOheight, 3,
+ BlackPixel( disp, scrn ), WhitePixel( disp, scrn ) );
+ XSelectInput( disp, window, ButtonPressMask | ExposureMask | KeyPressMask );
+
+ XStoreName( disp, window, "BDD viewer" );
+ wingc = XCreateGC( disp, window, 0, NULL );
+ XSetState( disp, wingc,
+ BlackPixel( disp, scrn ), WhitePixel( disp, scrn ),
+ GXcopy, AllPlanes );
+ XSetFont( disp, wingc, fontinfo->fid );
+ XSetArcMode( disp, wingc, ArcChord );
+ DefineCursor();
+ XDefineCursor( disp, window, waitcu );
+ XMapWindow( disp, window );
+ return( TRUE );
+}
+
+
+void WindowClose(){
+ Spark();
+ XSync( disp, 0 );
+ KillCursor();
+ XDestroyWindow( disp, window );
+ XFreeFont( disp, fontinfo );
+ XCloseDisplay( disp );
+}
+
+
+void Wait(){
+ XEvent event;
+ int exitf;
+ static char message[] = " Beware of X's bug!";
+
+ exitf = 0;
+ do{
+ XNextEvent( disp, &event );
+ switch( event.type ){
+ case Expose:
+ XDefineCursor( disp, window, waitcu );
+ Show();
+#ifdef VERBOSE
+ XDrawImageString( disp, window, wingc,
+ 0, 0 + fontinfo->ascent, message, strlen( message ) );
+#endif
+ XDefineCursor( disp, window, yubicu );
+ break;
+ case ButtonPress:
+ exitf = 1;
+ break;
+ }
+ }while( exitf == 0 );
+}
+
+
+int MeanFontWidth(){
+ return( fontinfo->min_bounds.width );
+}
+
+
+int DontCrip( x, y )
+ int x, y;
+{
+ return( ( x >= cripx0 ) & ( x <= cripx1 )
+ & ( y >= cripy0 ) & ( y <= cripy1 ) );
+}
+
+
+Interrupt(){
+ int b;
+ XEvent event;
+
+ XSync( disp, 0 );
+/* b = XCheckWindowEvent( window, ExposeWindow, &event );
+ if( b == 1 ){
+ XPutBackEvent( &event );
+ }
+ return( b );*/
+ return( 0 );
+}
+
+
+
--- /dev/null
+#define yubi_width 30
+#define yubi_height 30
+#define yubi_x_hot 19
+#define yubi_y_hot 3
+static char yubi_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
+ 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00,
+ 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x09, 0x00,
+ 0x00, 0x80, 0x08, 0x00, 0x00, 0x80, 0x04, 0x00, 0x80, 0x41, 0xc4, 0x00,
+ 0x80, 0x42, 0x4e, 0x01, 0x80, 0x24, 0x4a, 0x01, 0x80, 0x24, 0x59, 0x01,
+ 0x80, 0x14, 0x69, 0x02, 0x80, 0x18, 0x68, 0x02, 0x80, 0x08, 0x20, 0x01,
+ 0x80, 0x00, 0x20, 0x01, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00,
+ 0x80, 0x00, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00,
+ 0x00, 0x01, 0x10, 0x00, 0x00, 0x01, 0x08, 0x00, 0x80, 0x00, 0x04, 0x00,
+ 0x80, 0x00, 0x02, 0x00, 0x80, 0x00, 0x02, 0x00, 0x40, 0x00, 0x02, 0x00};
--- /dev/null
+#define yubi_mask_width 30
+#define yubi_mask_height 30
+#define yubi_mask_x_hot -1
+#define yubi_mask_y_hot -1
+static char yubi_mask_bits[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00,
+ 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1e, 0x00,
+ 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00,
+ 0x00, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x07, 0x00, 0x80, 0xc1, 0xc7, 0x00,
+ 0x80, 0xc3, 0xcf, 0x01, 0x80, 0xe7, 0xcf, 0x01, 0x80, 0xe7, 0xdf, 0x01,
+ 0x80, 0xf7, 0xff, 0x03, 0x80, 0xff, 0xff, 0x03, 0x80, 0xff, 0xff, 0x01,
+ 0x80, 0xff, 0xff, 0x01, 0x80, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x00,
+ 0x80, 0xff, 0x7f, 0x00, 0x80, 0xff, 0x7f, 0x00, 0x00, 0xff, 0x3f, 0x00,
+ 0x00, 0xff, 0x1f, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x80, 0xff, 0x07, 0x00,
+ 0x80, 0xff, 0x03, 0x00, 0x80, 0xff, 0x03, 0x00, 0xc0, 0xff, 0x03, 0x00};
--- /dev/null
+/*****************************************
+* BDD Package (SAPPORO-1.57) - Body *
+* (C) Shin-ichi MINATO (June 14, 2013) *
+******************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "bddc.h"
+
+/* ----------------- MACRO Definitions ---------------- */
+/* Operation IDs in Cache */
+#define BC_NULL 0
+#define BC_AND 1
+#define BC_XOR 2
+#define BC_AT0 3
+#define BC_AT1 4
+#define BC_LSHIFT 5
+#define BC_RSHIFT 6
+#define BC_COFACTOR 7
+#define BC_UNIV 8
+#define BC_SUPPORT 9
+#define BC_INTERSEC 10
+#define BC_UNION 11
+#define BC_SUBTRACT 12
+#define BC_OFFSET 13
+#define BC_ONSET 14
+#define BC_CHANGE 15
+#define BC_CARD 16
+#define BC_LIT 17
+#define BC_LEN 18
+
+/* Macros for malloc, realloc */
+#define B_MALLOC(type, size) \
+ (type *)malloc(sizeof(type) * size)
+#define B_REALLOC(ptr, type, size) \
+ (type *)realloc(ptr, sizeof(type) * size)
+
+/* Printf format of bddp */
+#ifdef B_64
+# define B_BDDP_FD "%lld"
+# define B_BDDP_FX "0x%llX"
+#else
+# define B_BDDP_FD "%d"
+# define B_BDDP_FX "0x%X"
+#endif
+
+/* strtol or strtoll */
+#ifdef B_64
+# define B_STRTOI strtoll
+#else
+# define B_STRTOI strtol
+#endif
+
+/* Table spaces */
+#define B_NODE_MAX (B_VAL_MASK>>1U) /* Max number of BDD nodes */
+#define B_NODE_SPC0 256 /* Default initial node size */
+#define B_VAR_SPC0 16 /* Initial var table size */
+#define B_HASH_SPC0 4 /* Initial hash size */
+#define B_RFCT_SPC0 4 /* Initial RFCT size */
+
+/* Negative edge manipulation */
+#define B_NEG(f) ((f) & B_INV_MASK)
+#define B_NOT(f) ((f) ^ B_INV_MASK)
+#define B_ABS(f) ((f) & ~B_INV_MASK)
+
+/* Constant node manipulation */
+#define B_CST(f) ((f) & B_CST_MASK)
+#define B_VAL(f) ((f) & B_VAL_MASK)
+
+/* Conversion of bddp and node index/pointer */
+#define B_NP(f) (Node+(B_ABS(f)>>1U))
+#define B_NDX(f) (B_ABS(f)>>1U)
+#define B_BDDP_NP(p) ((bddp)((p)-Node) << 1U)
+
+/* Read & Write of bddp field in the tables */
+#ifdef B_64
+# define B_LOW32(f) ((bddp_32)((f)&((1ULL<<32U)-1U)))
+# define B_HIGH8(f) ((bddp_h8)((f)>>32U))
+# define B_SET_NXP(p, f, i) \
+ (p ## _h8 = f ## _h8 + i, p ## _32 = f ## _32 + i)
+# define B_GET_BDDP(f) \
+ ((bddp) f ## _32 | ((bddp) f ## _h8 << 32U))
+# define B_SET_BDDP(f, g) \
+ (f ## _h8 = B_HIGH8(g), f ## _32 = B_LOW32(g))
+# define B_CPY_BDDP(f, g) \
+ (f ## _h8 = g ## _h8, f ## _32 = g ## _32)
+#else
+# define B_SET_NXP(p, f, i) (p ## _32 = f ## _32 + i)
+# define B_GET_BDDP(f) (f ## _32)
+# define B_SET_BDDP(f, g) (f ## _32 = g)
+# define B_CPY_BDDP(f, g) (f ## _32 = g ## _32)
+#endif /* B_64 */
+
+/* var & rfc manipulation */
+#define B_VAR_NP(p) ((p)->varrfc & B_VAR_MASK)
+#define B_RFC_MASK (~B_VAR_MASK)
+#define B_RFC_UNIT (1U << B_VAR_WIDTH)
+#define B_RFC_NP(p) ((p)->varrfc >> B_VAR_WIDTH)
+#define B_RFC_ZERO_NP(p) ((p)->varrfc < B_RFC_UNIT)
+#define B_RFC_ONE_NP(p) (((p)->varrfc & B_RFC_MASK) == B_RFC_UNIT)
+#define B_RFC_INC_NP(p) \
+ (((p)->varrfc < B_RFC_MASK - B_RFC_UNIT)? \
+ ((p)->varrfc += B_RFC_UNIT, 0) : rfc_inc_ovf(p))
+#define B_RFC_DEC_NP(p) \
+ (((p)->varrfc >= B_RFC_MASK)? rfc_dec_ovf(p): \
+ (B_RFC_ZERO_NP(p))? \
+ err("B_RFC_DEC_NP: rfc under flow", p-Node): \
+ ((p)->varrfc -= B_RFC_UNIT, 0))
+
+/* ----------- Stack overflow limitter ------------ */
+const int BDD_RecurLimit = 8192;
+int BDD_RecurCount = 0;
+#define BDD_RECUR_INC \
+ {if(++BDD_RecurCount >= BDD_RecurLimit) \
+ err("BDD_RECUR_INC: Recursion Limit", BDD_RecurCount);}
+#define BDD_RECUR_DEC BDD_RecurCount--
+
+/* Conversion of ZBDD node flag */
+#define B_Z_NP(p) ((p)->f0_32 & (bddp_32)B_INV_MASK)
+
+/* Hash Functions */
+#define B_HASHKEY(f0, f1, hashSpc) \
+ (((B_CST(f0)? (f0): (f0)+2U) \
+ ^(B_NEG(f0)? ~((f0)>>1U): ((f0)>>1U)) \
+ ^(B_CST(f1)? (f1)<<1U: ((f1)+2U)<<1U) \
+ ^(B_NEG(f1)? ~((f1)>>1U): ((f1)>>1U)) )\
+ & (hashSpc-1U))
+/* (((f0)^((f0)>>10)^((f0)>>31)^(f1)^((f1)>>8)^((f1)>>31)) \*/
+#define B_CACHEKEY(op, f, g) \
+ ((((bddp)(op)<<2U) \
+ ^(B_CST(f)? (f): (f)+2U) \
+ ^(B_NEG(f)? ~((f)>>1U): ((f)>>1U)) \
+ ^(B_CST(g)? (g)<<3U: ((g)+2U)<<3U) \
+ ^(B_NEG(g)? ~((g)>>1U): ((g)>>1U)) )\
+ & (CacheSpc-1U))
+
+/* ------- Declaration of static (internal) data ------- */
+/* typedef of bddp field in the tables */
+typedef unsigned int bddp_32;
+#ifdef B_64
+ typedef unsigned char bddp_h8;
+#endif
+
+/* Declaration of Node table */
+struct B_NodeTable
+{
+ bddp_32 f0_32; /* 0-edge */
+ bddp_32 f1_32; /* 1-edge */
+ bddp_32 nx_32; /* Node index */
+ unsigned int varrfc; /* VarID & Reference counter */
+#ifdef B_64
+ bddp_h8 f0_h8; /* Extention of 0-edge */
+ bddp_h8 f1_h8; /* Extention of 1-edge */
+ bddp_h8 nx_h8; /* Extention of node index */
+#endif /* B_64 */
+};
+static struct B_NodeTable *Node = 0; /* Node Table */
+static bddp NodeLimit = 0; /* Final limit size */
+static bddp NodeUsed = 0; /* Number of used node */
+static bddp Avail = bddnull; /* Head of available node */
+static bddp NodeSpc = 0; /* Current Node-Table size */
+
+/* Declaration of Hash-table per Var */
+struct B_VarTable
+{
+ bddp hashSpc; /* Current hash-table size */
+ bddp hashUsed; /* Current used entries */
+ bddvar lev; /* Level of the variable */
+ bddp_32 *hash_32; /* Hash-table */
+#ifdef B_64
+ bddp_h8 *hash_h8; /* Extension of hash-table */
+#endif /* B_64 */
+};
+static struct B_VarTable *Var = 0; /* Var-tables */
+static bddvar *VarID = 0; /* VarID reverse table */
+static bddvar VarUsed = 0; /* Number of used Var */
+static bddvar VarSpc = 0; /* Current Var-table size */
+
+/* Declaration of Operation Cache */
+struct B_CacheTable
+{
+ bddp_32 f_32; /* an operand BDD */
+ bddp_32 g_32; /* an operand BDD */
+ bddp_32 h_32; /* Result BDD */
+ unsigned char op; /* Operation code */
+#ifdef B_64
+ bddp_h8 f_h8; /* Extention of an operand BDD */
+ bddp_h8 g_h8; /* Extention of an operand BDD */
+ bddp_h8 h_h8; /* Extention of result BDD */
+#endif /* B_64 */
+};
+static struct B_CacheTable *Cache = 0; /* Opeartion cache */
+static bddp CacheSpc = 0; /* Current cache size */
+
+/* Declaration of RFC-table */
+struct B_RFC_Table
+{
+ bddp_32 nx_32; /* Node index */
+ bddp_32 rfc_32; /* RFC */
+#ifdef B_64
+ bddp_h8 nx_h8; /* Extension of Node index */
+ bddp_h8 rfc_h8; /* Extension of RFC */
+#endif /* B_64 */
+};
+static struct B_RFC_Table *RFCT = 0; /* RFC-Table */
+static bddp RFCT_Spc; /* Current RFC-table size */
+static bddp RFCT_Used; /* Current RFC-table used entries */
+
+/* ----- Declaration of static (internal) functions ------ */
+/* Private procedure */
+static int err B_ARG((char *msg, bddp num));
+static int rfc_inc_ovf B_ARG((struct B_NodeTable *np));
+static int rfc_dec_ovf B_ARG((struct B_NodeTable *np));
+static void var_enlarge B_ARG((void));
+static int node_enlarge B_ARG((void));
+static int hash_enlarge B_ARG((bddvar v));
+static bddp getnode B_ARG((bddvar v, bddp f0, bddp f1));
+static bddp getbddp B_ARG((bddvar v, bddp f0, bddp f1));
+static bddp getzbddp B_ARG((bddvar v, bddp f0, bddp f1));
+static bddp apply B_ARG((bddp f, bddp g, unsigned char op, unsigned char skip));
+static void gc1 B_ARG((struct B_NodeTable *np));
+static bddp count B_ARG((bddp f));
+static void dump B_ARG((bddp f));
+static void reset B_ARG((bddp f));
+static void export B_ARG((FILE *strm, bddp f));
+static int import B_ARG((FILE *strm, bddp *p, int lim, int z));
+static int andfalse B_ARG((bddp f, bddp g));
+
+
+/* ------------------ Body of program -------------------- */
+/* ----------------- External functions ------------------ */
+int bddinit(initsize, limitsize)
+bddp initsize;
+bddp limitsize;
+/* Returns 1 if not enough memory (usually 0) */
+{
+ bddp ix;
+ bddvar i;
+
+ /* Check dupulicate initialization */
+ if(Node) free(Node);
+ if(Var)
+ {
+ for(i=0; i<VarSpc; i++)
+ {
+ if(Var[i].hash_32) free(Var[i].hash_32);
+#ifdef B_64
+ if(Var[i].hash_h8) free(Var[i].hash_h8);
+#endif
+ }
+ free(Var);
+ }
+ if(VarID) free(VarID);
+ if(Cache) free(Cache);
+ if(RFCT) free(RFCT);
+
+ /* Set NodeLimit */
+ if(limitsize < B_NODE_SPC0) NodeLimit = B_NODE_SPC0;
+ else if(limitsize > B_NODE_MAX) NodeLimit = B_NODE_MAX;
+ else NodeLimit = limitsize;
+
+ /* Set NodeSpc */
+ if(initsize < B_NODE_SPC0) NodeSpc = B_NODE_SPC0;
+ else if(initsize > NodeLimit) NodeSpc = NodeLimit;
+ else NodeSpc = initsize;
+
+ /* Set CacheSpc */
+ for(CacheSpc=B_NODE_SPC0; CacheSpc<NodeSpc>>1; CacheSpc<<=1U)
+ ; /* empty */
+
+ /* Set VarSpc */
+ VarSpc = B_VAR_SPC0;
+
+ /* Memory allocation */
+ Node = B_MALLOC(struct B_NodeTable, NodeSpc);
+ Var = B_MALLOC(struct B_VarTable, VarSpc);
+ VarID = B_MALLOC(bddvar, VarSpc);
+ Cache = B_MALLOC(struct B_CacheTable, CacheSpc);
+
+ /* Check overflow */
+ if(Node == 0 || Var == 0 || VarID == 0 || Cache == 0)
+ {
+ if(Cache){ free(Cache); Cache = 0; }
+ if(VarID){ free(VarID); VarID = 0; }
+ if(Var){ free(Var); Var = 0; }
+ if(Node){ free(Node); Node = 0; }
+ NodeLimit = 0;
+ return 1;
+ }
+
+ /* Initialize */
+ NodeUsed = 0;
+ Node[NodeSpc-1U].varrfc = 0;
+ B_SET_BDDP(Node[NodeSpc-1U].nx, bddnull);
+ for(ix=0; ix<NodeSpc-1U; ix++)
+ {
+ Node[ix].varrfc = 0;
+ B_SET_BDDP(Node[ix].nx, ix+1U);
+ }
+ Avail = 0;
+
+ VarUsed = 0;
+ for(i=0; i<VarSpc; i++)
+ {
+ Var[i].hashSpc = 0;
+ Var[i].hashUsed = 0;
+ Var[i].lev = i;
+ VarID[i] = i;
+ Var[i].hash_32 = 0;
+#ifdef B_64
+ Var[i].hash_h8 = 0;
+#endif
+ }
+
+ for(ix=0; ix<CacheSpc; ix++) Cache[ix].op = BC_NULL;
+
+ RFCT_Spc = 0;
+ RFCT_Used = 0;
+
+ return 0;
+}
+
+bddp bddcopy(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f; /* Constant */
+ fp = B_NP(f);
+ if(fp >= Node+NodeSpc || fp->varrfc == 0)
+ err("bddcopy: Invalid bddp", f);
+ B_RFC_INC_NP(fp);
+ return f;
+}
+
+void bddfree(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return;
+ if(B_CST(f)) return; /* Constant */
+ fp = B_NP(f);
+ if(fp >= Node+NodeSpc || fp->varrfc == 0)
+ err("bddfree: Invalid bddp", f);
+ B_RFC_DEC_NP(fp);
+}
+
+int bddgc()
+/* Returns 1 if there are no free node (usually 0) */
+{
+ bddp i, n, f;
+ struct B_NodeTable *fp;
+ struct B_CacheTable *cachep;
+ struct B_NodeTable *np;
+ struct B_VarTable *varp;
+ bddvar v;
+ bddp oldSpc, newSpc, nx, key, f0, f1;
+ bddp_32 *newhash_32, *p_32, *p2_32;
+#ifdef B_64
+ bddp_h8 *newhash_h8, *p_h8, *p2_h8;
+#endif
+
+ n = NodeUsed;
+ for(fp=Node; fp<Node+NodeSpc; fp++)
+ if(fp->varrfc != 0 && B_RFC_ZERO_NP(fp))
+ gc1(fp);
+ if(n == NodeUsed) return 1; /* No free node */
+
+ /* Cache clear */
+ for(cachep=Cache; cachep<Cache+CacheSpc; cachep++)
+ {
+ switch(cachep->op)
+ {
+ case BC_NULL:
+ break;
+ case BC_AND:
+ case BC_XOR:
+ case BC_INTERSEC:
+ case BC_UNION:
+ case BC_SUBTRACT:
+ case BC_CHANGE:
+ f = B_GET_BDDP(cachep->f);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ f = B_GET_BDDP(cachep->g);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ f = B_GET_BDDP(cachep->h);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ break;
+ case BC_AT0:
+ case BC_AT1:
+ case BC_OFFSET:
+ case BC_ONSET:
+ f = B_GET_BDDP(cachep->f);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ f = B_GET_BDDP(cachep->h);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ break;
+ case BC_CARD:
+ case BC_LIT:
+ case BC_LEN:
+ f = B_GET_BDDP(cachep->f);
+ if(!B_CST(f) && (fp=B_NP(f))<Node+NodeSpc && fp->varrfc == 0)
+ {
+ cachep->op = BC_NULL;
+ break;
+ }
+ break;
+ default:
+ cachep->op = BC_NULL;
+ break;
+ }
+ }
+
+ /* Hash-table packing */
+ for(v=1; v<=VarUsed; v++)
+ {
+ varp = &Var[v];
+
+ /* Get new size */
+ oldSpc = varp->hashSpc;
+ newSpc = oldSpc;
+ while(newSpc > B_HASH_SPC0)
+ {
+ if(newSpc>>2 < varp->hashUsed) break;
+ newSpc >>= 1;
+ }
+ if(newSpc == oldSpc) continue;
+
+ /* Reduce space */
+#ifdef B_64
+ newhash_32 = B_MALLOC(bddp_32, newSpc);
+ newhash_h8 = B_MALLOC(bddp_h8, newSpc);
+ if(!newhash_32 || !newhash_h8)
+ {
+ if(newhash_32) free(newhash_32);
+ if(newhash_h8) free(newhash_h8);
+ break; /* Not enough memory */
+ }
+#else
+ newhash_32 = B_MALLOC(bddp_32, newSpc);
+ if(!newhash_32) break; /* Not enough memory */
+#endif
+
+ /* Initialize new hash entry */
+ for(i=0; i<newSpc; i++)
+ {
+ B_SET_NXP(p, newhash, i);
+ B_SET_BDDP(*p, bddnull);
+ }
+
+ /* restore hash entry */
+ for(i=0; i<oldSpc; i++)
+ {
+ key = i & (newSpc-1U);
+ np = 0;
+ B_SET_NXP(p, newhash, key);
+ nx = B_GET_BDDP(*p);
+ while(nx != bddnull)
+ {
+ np = Node + nx;
+ nx = B_GET_BDDP(np->nx);
+ }
+ if(np) { B_SET_NXP(p2, varp->hash, i); B_CPY_BDDP(np->nx, *p2); }
+ else
+ {
+ B_SET_NXP(p, newhash, key);
+ B_SET_NXP(p2, varp->hash, i);
+ B_CPY_BDDP(*p, *p2);
+ }
+ }
+ varp->hashSpc = newSpc;
+ free(varp->hash_32);
+ varp->hash_32 = newhash_32;
+#ifdef B_64
+ free(varp->hash_h8);
+ varp->hash_h8 = newhash_h8;
+#endif
+ }
+ return 0;
+}
+
+bddp bddused() { return NodeUsed; }
+
+bddp bddsize(f)
+bddp f;
+/* Returns 0 for bddnull */
+{
+ bddp num;
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return 0;
+ if(B_CST(f)) return 0; /* Constant */
+ if((fp=B_NP(f))>=Node+NodeSpc || fp->varrfc == 0)
+ err("bddsize: Invalid bddp", f);
+
+ num = count(f);
+ reset(f);
+ return num;
+}
+
+bddp bddvsize(p, lim)
+bddp *p;
+int lim;
+/* Returns 0 for bddnull */
+{
+ bddp num;
+ struct B_NodeTable *fp;
+ int n, i;
+
+ /* Check operand */
+ n = lim;
+ for(i=0; i<n; i++)
+ {
+ if(p[i] == bddnull)
+ {
+ n = i;
+ break;
+ }
+ if(!B_CST(p[i])&&
+ ((fp=B_NP(p[i]))>=Node+NodeSpc || fp->varrfc==0))
+ err("bddvsize: Invalid bddp", p[i]);
+ }
+ num = 0;
+ for(i=0; i<n; i++) num += count(p[i]);
+ for(i=0; i<n; i++) reset(p[i]);
+ return num;
+}
+
+void bddexport(strm, p, lim)
+FILE *strm;
+bddp *p;
+int lim;
+{
+ struct B_NodeTable *fp;
+ int n, i, lev, lev0;
+
+ /* Check operands */
+ n = lim;
+ lev = 0;
+ for(i=0; i<n; i++)
+ {
+ if(p[i] == bddnull)
+ {
+ n = i;
+ break;
+ }
+ if(!B_CST(p[i])&&
+ ((fp=B_NP(p[i]))>=Node+NodeSpc || fp->varrfc==0))
+ err("bddvexport: Invalid bddp", p[i]);
+ lev0 = bddlevofvar(bddtop(p[i]));
+ if(lev0 > lev) lev = lev0;
+ }
+
+ fprintf(strm, "_i %d\n_o %d\n_n ", lev, n);
+ fprintf(strm, B_BDDP_FD, bddvsize(p, n));
+ fprintf(strm, "\n");
+
+ /* Put internal nodes */
+ for(i=0; i<n; i++) export(strm, p[i]);
+ for(i=0; i<n; i++) reset(p[i]);
+
+ /* Put external node */
+ for(i=0; i<n; i++)
+ {
+ if(p[i] == bddfalse) fprintf(strm, "F");
+ else if(p[i] == bddtrue) fprintf(strm, "T");
+ else fprintf(strm, B_BDDP_FD, p[i]);
+ fprintf(strm, "\n");
+ }
+}
+
+void bdddump(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ /* Check indexes */
+ if(f == bddnull) { printf("RT = NULL\n\n"); return; }
+ if(!B_CST(f)&&
+ ((fp=B_NP(f))>=Node+NodeSpc || fp->varrfc==0))
+ err("bdddump: Invalid bddp", f);
+
+ /* Dump nodes */
+ dump(f);
+ reset(f);
+
+ /* Dump top node */
+ printf("RT = ");
+ if(B_NEG(f)) putchar('~');
+ if(B_CST(f)) printf(B_BDDP_FD, B_ABS(B_VAL(f)));
+ else { printf("N"); printf(B_BDDP_FD, B_NDX(f)); }
+ printf("\n\n");
+}
+
+void bddvdump(p, n)
+bddp *p;
+int n;
+{
+ struct B_NodeTable *fp;
+ int i;
+
+ /* Check operands */
+ for(i=0; i<n; i++)
+ {
+ if(p[i] == bddnull) return;
+ if(!B_CST(p[i])&&
+ ((fp=B_NP(p[i]))>=Node+NodeSpc || fp->varrfc==0))
+ err("bddvdump: Invalid bddp", p[i]);
+ }
+
+ /* Dump nodes */
+ for(i=0; i<n; i++) if(p[i] != bddnull) dump(p[i]);
+ for(i=0; i<n; i++) if(p[i] != bddnull) reset(p[i]);
+
+ /* Dump top node */
+ for(i=0; i<n; i++)
+ {
+ printf("RT%d = ", i);
+ if(p[i] == bddnull) printf("NULL");
+ else
+ {
+ if(B_NEG(p[i])) putchar('~');
+ if(B_CST(p[i])) printf(B_BDDP_FD, B_ABS(B_VAL(p[i])));
+ else { printf("N"); printf(B_BDDP_FD, B_NDX(p[i])); }
+ }
+ putchar('\n');
+ }
+ printf("\n");
+}
+
+bddp bddrcache(op, f, g)
+unsigned char op;
+bddp f, g;
+{
+ struct B_CacheTable *cachep;
+
+ cachep = Cache + B_CACHEKEY(op, f, g);
+ if(op == cachep->op &&
+ f == B_GET_BDDP(cachep->f) &&
+ g == B_GET_BDDP(cachep->g))
+ return B_GET_BDDP(cachep->h); /* Hit */
+ return bddnull;
+}
+
+void bddwcache(op, f, g, h)
+unsigned char op;
+bddp f, g, h;
+{
+ struct B_CacheTable *cachep;
+
+ if(op < 20) err("bddwcache: op < 20", op);
+ if(h == bddnull) return;
+ cachep = Cache + B_CACHEKEY(op, f, g);
+ cachep->op = op;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, h);
+}
+
+bddp bddnot(f)
+bddp f;
+{
+ if(f == bddnull) return bddnull;
+ return B_NOT(bddcopy(f));
+}
+
+bddvar bddlevofvar(v)
+bddvar v;
+{
+ if(v > VarUsed)
+ err("bddlevofvar: Invalid VarID", v);
+ return Var[v].lev;
+}
+
+bddvar bddvaroflev(lev)
+bddvar lev;
+{
+ if(lev > VarUsed)
+ err("bddvaroflev: Invalid level", lev);
+ return VarID[lev];
+}
+
+bddvar bddvarused()
+{
+ return VarUsed;
+}
+
+bddvar bddnewvar()
+{
+ if(++VarUsed == VarSpc) var_enlarge();
+ return VarUsed;
+}
+
+bddvar bddnewvaroflev(lev)
+bddvar lev;
+{
+ bddvar i, v;
+
+ if(lev == 0 || lev > ++VarUsed)
+ err("bddnewvaroflev: Invalid level", lev);
+ if(VarUsed == VarSpc) var_enlarge();
+ for(i=VarUsed; i>lev; i--) Var[ VarID[i] = VarID[i-1U] ].lev = i;
+ Var[ VarID[lev] = VarUsed ].lev = lev;
+ return VarUsed;
+}
+
+bddvar bddtop(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return 0;
+ if(B_CST(f)) return 0; /* Constant */
+ fp = B_NP(f);
+ if(fp >= Node+NodeSpc || fp->varrfc == 0)
+ err("bddtop: Invalid bddp", f);
+ return B_VAR_NP(fp);
+}
+
+bddp bddprime(v)
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ if(v == 0 || v > VarUsed)
+ err("bddprime: Invalid VarID", v);
+ return getbddp(v, bddfalse, bddtrue);
+}
+
+
+bddp bddand(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddand: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddand: Invalid bddp", f);
+ if(B_Z_NP(fp)) err("bddand: applying ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddand: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddand: Invalid bddp", g);
+ if(B_Z_NP(fp)) err("bddand: applying ZBDD node", g);
+ }
+
+ return apply(f, g, BC_AND, 0);
+}
+
+bddp bddor(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ bddp h;
+
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ h = bddand(B_NOT(f), B_NOT(g));
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+}
+
+bddp bddxor(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddand: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddxor: Invalid bddp", f);
+ if(B_Z_NP(fp)) err("bddand: applying ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddand: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddxor: Invalid bddp", g);
+ if(B_Z_NP(fp)) err("bddand: applying ZBDD node", g);
+ }
+
+ return apply(f, g, BC_XOR, 0);
+}
+
+bddp bddnand(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ bddp h;
+
+ h = bddand(f, g);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+}
+
+bddp bddnor(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ return bddand(B_NOT(f), B_NOT(g));
+}
+
+bddp bddxnor(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ if(g == bddnull) return bddnull;
+ return bddxor(f, B_NOT(g));
+}
+
+bddp bddcofactor(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddcofactor: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddcofactor: Invalid bddp", f);
+ if(B_Z_NP(fp)) err("bddcofactor: applying ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddcofactor: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddcofactor: Invalid bddp", g);
+ if(B_Z_NP(fp)) err("bddcofactor: applying ZBDD node", g);
+ }
+
+ return apply(f, g, BC_COFACTOR, 0);
+}
+
+bddp bdduniv(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bdduniv: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bdduniv: Invalid bddp", f);
+ if(B_Z_NP(fp)) err("bdduniv: applying ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bdduniv: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bdduniv: Invalid bddp", g);
+ if(B_Z_NP(fp)) err("bdduniv: applying ZBDD node", g);
+ }
+
+ return apply(f, g, BC_UNIV, 0);
+}
+
+bddp bddexist(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ bddp h;
+
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ h = bdduniv(B_NOT(f), g);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+}
+
+int bddimply(f, g)
+bddp f, g;
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return 0;
+ if(g == bddnull) return 0;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddimply: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddimply: Invalid bddp", f);
+ if(B_Z_NP(fp)) err("bddimply: applying ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddimply: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddimply: Invalid bddp", g);
+ if(B_Z_NP(fp)) err("bddimply: applying ZBDD node", g);
+ }
+
+ return ! andfalse(f, B_NOT(g));
+}
+
+bddp bddsupport(f)
+bddp f;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return bddfalse;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddsupport: Invalid bddp", f);
+
+ return apply(f, bddfalse, BC_SUPPORT, 0);
+}
+
+bddp bddat0(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddat0: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddat0: Invalid bddp", f);
+
+ return apply(f, (bddp)v, BC_AT0, 0);
+}
+
+bddp bddat1(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddat1: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddat1: Invalid bddp", f);
+
+ return apply(f, (bddp)v, BC_AT1, 0);
+}
+
+bddp bddlshift(f, shift)
+bddp f;
+bddvar shift;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+ bddvar flev;
+
+ /* Check operands */
+ if(shift >= VarUsed)
+ err("bddlshift: Invalid shift", shift);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f;
+ if(shift == 0) return bddcopy(f);
+ if((fp=B_NP(f))>=Node+NodeSpc || !fp->varrfc)
+ err("bddlshift: Invalid bddp", f);
+
+ return apply(f, (bddp)shift, BC_LSHIFT, 0);
+}
+
+bddp bddrshift(f, shift)
+bddp f;
+bddvar shift;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+ bddvar flev;
+
+ /* Check operands */
+ if(shift >= VarUsed)
+ err("bddrshift: Invalid shift", shift);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f;
+ if(shift == 0) return bddcopy(f);
+ if((fp=B_NP(f))>=Node+NodeSpc || !fp->varrfc)
+ err("bddrshift: Invalid bddp", f);
+
+ return apply(f, (bddp)shift, BC_RSHIFT, 0);
+}
+
+bddp bddoffset(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddoffset: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return f;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddoffset: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddoffset: applying non-ZBDD node", f);
+
+ return apply(f, (bddp)v, BC_OFFSET, 0);
+}
+
+bddp bddonset0(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddonset0: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+ if(B_CST(f)) return bddfalse;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddonset0: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddonset0: applying non-ZBDD node", f);
+
+ return apply(f, (bddp)v, BC_ONSET, 0);
+}
+
+bddp bddonset(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ bddp g, h;
+
+ g = bddonset0(f, v);
+ h = bddchange(g, v);
+ bddfree(g);
+ return h;
+}
+
+bddp bddchange(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddchange: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+ if(!B_CST(f))
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddchange: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddchange: applying non-ZBDD node", f);
+ }
+
+ return apply(f, (bddp)v, BC_CHANGE, 0);
+}
+
+bddp bddintersec(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddintersec: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddintersec: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddintersec: applying non-ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddintersec: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddintersec: Invalid bddp", g);
+ if(!B_Z_NP(fp)) err("bddintersec: applying non-ZBDD node", g);
+ }
+
+ return apply(f, g, BC_INTERSEC, 0);
+}
+
+bddp bddunion(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddunion: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddunion: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddunion: applying non-ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddunion: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddunion: Invalid bddp", g);
+ if(!B_Z_NP(fp)) err("bddunion: applying non-ZBDD node", g);
+ }
+
+ return apply(f, g, BC_UNION, 0);
+}
+
+bddp bddsubtract(f, g)
+bddp f, g;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(f == bddnull) return bddnull;
+ if(g == bddnull) return bddnull;
+ if(B_CST(f))
+ { if(B_ABS(f) != bddfalse) err("bddsubtract: Invalid bddp", f); }
+ else
+ {
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddsubtarct: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddsubtarct: applying non-ZBDD node", f);
+ }
+ if(B_CST(g))
+ { if(B_ABS(g) != bddfalse) err("bddsubtarct: Invalid bddp", g); }
+ else
+ {
+ fp = B_NP(g);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddsubtarct: Invalid bddp", g);
+ if(!B_Z_NP(fp)) err("bddsubtarct: applying non-ZBDD node", g);
+ }
+
+ return apply(f, g, BC_SUBTRACT, 0);
+}
+
+bddp bddcard(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return 0;
+ if(B_CST(f)) return (f == bddempty)? 0: 1;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddcard: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddcard: applying non-ZBDD node", f);
+
+ return apply(f, bddempty, BC_CARD, 0);
+}
+
+bddp bddlit(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return 0;
+ if(B_CST(f)) return 0;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddlit: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddlit: applying non-ZBDD node", f);
+
+ return apply(f, bddempty, BC_LIT, 0);
+}
+
+bddp bddlen(f)
+bddp f;
+{
+ struct B_NodeTable *fp;
+
+ if(f == bddnull) return 0;
+ if(B_CST(f)) return 0;
+ fp = B_NP(f);
+ if(fp>=Node+NodeSpc || !fp->varrfc)
+ err("bddlen: Invalid bddp", f);
+ if(!B_Z_NP(fp)) err("bddlen: applying non-ZBDD node", f);
+
+ return apply(f, bddempty, BC_LEN, 0);
+}
+
+
+
+/* ----------------- Internal functions ------------------ */
+static void var_enlarge()
+{
+ bddvar i, newSpc;
+ struct B_VarTable *newVar;
+ unsigned int *newVarID;
+
+ /* Get new size */
+ if(VarSpc == bddvarmax+1U)
+ err("var_enlarge: var index range full", VarSpc);
+ newSpc = VarSpc << 2U;
+ if(newSpc > bddvarmax+1) newSpc = bddvarmax+1U;
+
+ /* Enlarge space */
+ newVar = B_MALLOC(struct B_VarTable, newSpc);
+ newVarID = B_MALLOC(unsigned int, newSpc);
+ if(newVar && newVarID)
+ {
+ for(i=0; i<VarSpc; i++)
+ {
+ newVar[i].hashSpc = Var[i].hashSpc;
+ newVar[i].hashUsed = Var[i].hashUsed;
+ newVar[i].lev = Var[i].lev;
+ newVar[i].hash_32 = Var[i].hash_32;
+ newVarID[i] = VarID[i];
+#ifdef B_64
+ newVar[i].hash_h8 = Var[i].hash_h8;
+#endif
+ }
+ free(Var);
+ free(VarID);
+ Var = newVar;
+ VarID = newVarID;
+ }
+ else
+ {
+ if(newVar) free(newVar);
+ if(newVarID) free(newVarID);
+ err("var_enlarge: memory allocation failed", VarSpc);
+ }
+
+ /* Initialize new space */
+ for(i=VarSpc; i<newSpc; i++)
+ {
+ Var[i].hashSpc = 0;
+ Var[i].hashUsed = 0;
+ Var[i].lev = i;
+ Var[i].hash_32 = 0;
+ VarID[i] = i;
+#ifdef B_64
+ Var[i].hash_h8 = 0;
+#endif
+ }
+ VarSpc = newSpc;
+}
+
+static int node_enlarge()
+/* Returns 1 if not enough memory */
+{
+ bddp i, newSpc;
+ struct B_NodeTable *newNode;
+ struct B_CacheTable *newCache, *cp, *cp1;
+
+ /* Get new size */
+ if(NodeSpc == NodeLimit) return 1; /* Cannot enlarge */
+ newSpc = NodeSpc << 1U;
+ if(newSpc > NodeLimit) newSpc = NodeLimit;
+
+ /* Enlarge space */
+ newNode = B_MALLOC(struct B_NodeTable, newSpc);
+ if(newNode)
+ {
+ for(i=0; i<NodeSpc; i++)
+ {
+ newNode[i].varrfc = Node[i].varrfc;
+ newNode[i].f0_32 = Node[i].f0_32;
+ newNode[i].f1_32 = Node[i].f1_32;
+ newNode[i].nx_32 = Node[i].nx_32;
+#ifdef B_64
+ newNode[i].f0_h8 = Node[i].f0_h8;
+ newNode[i].f1_h8 = Node[i].f1_h8;
+ newNode[i].nx_h8 = Node[i].nx_h8;
+#endif /* B_64 */
+ }
+ free(Node);
+ Node = newNode;
+ }
+ else return 1; /* Not enough memory */
+
+ /* Initialize new space */
+ Node[newSpc-1U].varrfc = 0;
+ B_SET_BDDP(Node[newSpc-1U].nx, Avail);
+ for(i=NodeSpc; i<newSpc-1U; i++)
+ {
+ Node[i].varrfc = 0;
+ B_SET_BDDP(Node[i].nx, i+1U);
+ }
+ Avail = NodeSpc;
+ NodeSpc = newSpc;
+
+ /* Realloc Cache */
+ for(newSpc=CacheSpc; newSpc<NodeSpc>>1U; newSpc<<=1U)
+ ; /* empty */
+ newCache = B_MALLOC(struct B_CacheTable, newSpc);
+ if(newCache)
+ {
+ for(i=0; i<CacheSpc; i++)
+ {
+ cp = newCache + i;
+ cp1 = Cache + i;
+ cp->op = cp1->op;
+ B_CPY_BDDP(cp->f, cp1->f);
+ B_CPY_BDDP(cp->g, cp1->g);
+ B_CPY_BDDP(cp->h, cp1->h);
+ }
+ free(Cache);
+ Cache = newCache;
+ }
+ else return 0; /* Only NodeTable enlarged */
+
+ /* Reconstruct Cache */
+ for(i=CacheSpc; i<newSpc; i++)
+ {
+ cp = Cache + i;
+ cp1 = Cache + (i & (CacheSpc - 1));
+ cp->op = cp1->op;
+ B_CPY_BDDP(cp->f, cp1->f);
+ B_CPY_BDDP(cp->g, cp1->g);
+ B_CPY_BDDP(cp->h, cp1->h);
+ }
+ CacheSpc = newSpc;
+
+ return 0;
+}
+
+static int hash_enlarge(v)
+bddvar v;
+/* Returns 1 if not enough memory */
+{
+ struct B_NodeTable *np, *np0;
+ struct B_VarTable *varp;
+ bddp i, oldSpc, newSpc, nx, key, f0, f1;
+ bddp_32 *newhash_32, *p_32;
+#ifdef B_64
+ bddp_h8 *newhash_h8, *p_h8;
+#endif
+
+ varp = &Var[v];
+ /* Get new size */
+ oldSpc = varp->hashSpc;
+ if(oldSpc == B_NODE_MAX + 1U)
+ return 0; /* Cancel enlarging */
+ newSpc = oldSpc << 1U;
+
+ /* Enlarge space */
+#ifdef B_64
+ newhash_32 = B_MALLOC(bddp_32, newSpc);
+ newhash_h8 = B_MALLOC(bddp_h8, newSpc);
+ if(newhash_32 && newhash_h8)
+ {
+ for(i=0; i<varp->hashSpc; i++)
+ {
+ newhash_32[i] = varp->hash_32[i];
+ newhash_h8[i] = varp->hash_h8[i];
+ }
+ free(varp->hash_32);
+ free(varp->hash_h8);
+ varp->hash_32 = newhash_32;
+ varp->hash_h8 = newhash_h8;
+ }
+ else
+ {
+ if(newhash_32) free(newhash_32);
+ if(newhash_h8) free(newhash_h8);
+ return 1;
+ }
+#else
+ newhash_32 = B_MALLOC(bddp_32, newSpc);
+ if(newhash_32)
+ {
+ for(i=0; i<varp->hashSpc; i++) newhash_32[i] = varp->hash_32[i];
+ free(varp->hash_32);
+ varp->hash_32 = newhash_32;
+ }
+ else return 1; /* Not enough memory */
+#endif
+ varp->hashSpc = newSpc;
+
+ /* Initialize new hash entry */
+ for(i=oldSpc; i<newSpc; i++)
+ {
+ B_SET_NXP(p, varp->hash, i);
+ B_SET_BDDP(*p, bddnull);
+ }
+
+ /* restore hash entry */
+ for(i=0; i<oldSpc; i++)
+ {
+ np0 = 0;
+ B_SET_NXP(p, varp->hash, i);
+ nx = B_GET_BDDP(*p);
+ while(nx != bddnull)
+ {
+ np = Node + nx;
+ f0 = B_GET_BDDP(np->f0);
+ f1 = B_GET_BDDP(np->f1);
+ key = B_HASHKEY(f0, f1, newSpc);
+ if(key == i) np0 = np;
+ else
+ {
+ if(np0) B_CPY_BDDP(np0->nx, np->nx);
+ else { B_SET_NXP(p, varp->hash, i); B_CPY_BDDP(*p, np->nx); }
+ B_SET_NXP(p, varp->hash, key);
+ B_CPY_BDDP(np->nx, *p);
+ B_SET_BDDP(*p, nx);
+ }
+ if(np0) nx = B_GET_BDDP(np0->nx);
+ else { B_SET_NXP(p, varp->hash, i); nx = B_GET_BDDP(*p); }
+ }
+ }
+ return 0;
+}
+
+static bddp getnode(v, f0, f1)
+bddvar v;
+bddp f0, f1;
+/* Returns bddnull if not enough memory */
+{
+ /* After checking elimination rule & negative edge rule */
+ struct B_NodeTable *np, *fp;
+ struct B_VarTable *varp;
+ bddp ix, nx, key;
+ bddp_32 *p_32;
+#ifdef B_64
+ bddp_h8 *p_h8;
+#endif
+
+ varp = &Var[v];
+ if(varp->hashSpc == 0)
+ /* Create hash-table */
+ {
+ varp->hash_32 = B_MALLOC(bddp_32, B_HASH_SPC0);
+ if(!varp->hash_32) return bddnull;
+#ifdef B_64
+ varp->hash_h8 = B_MALLOC(bddp_h8, B_HASH_SPC0);
+ if(!varp->hash_h8)
+ {
+ free(varp->hash_32);
+ return bddnull;
+ }
+#endif
+ for(ix=0; ix<B_HASH_SPC0; ix++)
+ {
+ B_SET_NXP(p, varp->hash, ix);
+ B_SET_BDDP(*p, bddnull);
+ }
+ varp->hashSpc = B_HASH_SPC0;
+ key = B_HASHKEY(f0, f1, varp->hashSpc);
+ }
+ else
+ /* Looking for equivalent existing node */
+ {
+ key = B_HASHKEY(f0, f1, varp->hashSpc);
+ B_SET_NXP(p, varp->hash, key);
+ nx = B_GET_BDDP(*p);
+ while(nx != bddnull)
+ {
+ np = Node + nx;
+ if(f0 == B_GET_BDDP(np->f0) &&
+ f1 == B_GET_BDDP(np->f1) )
+ {
+ /* Sharing equivalent node */
+ if(!B_CST(f0)) { fp = B_NP(f0); B_RFC_DEC_NP(fp); }
+ if(!B_CST(f1)) { fp = B_NP(f1); B_RFC_DEC_NP(fp); }
+ B_RFC_INC_NP(np);
+ return B_BDDP_NP(np);
+ }
+ nx = B_GET_BDDP(np->nx);
+ }
+ }
+
+ /* Check hash-table overflow */
+ if(++ varp->hashUsed >= varp->hashSpc)
+ {
+ if(hash_enlarge(v)) return bddnull; /* Hash-table overflow */
+ key = B_HASHKEY(f0, f1, varp->hashSpc); /* Enlarge success */
+ }
+
+ /* Check node-table overflow */
+ if(NodeUsed >= NodeSpc-1U)
+ {
+ if(node_enlarge())
+ {
+ if(bddgc()) return bddnull; /* Node-table overflow */
+ key = B_HASHKEY(f0, f1, varp->hashSpc);
+ }
+ /* Node-table enlarged or GC succeeded */
+ }
+ NodeUsed++;
+
+ /* Creating a new node */
+ nx = Avail;
+ np = Node + nx;
+ Avail = B_GET_BDDP(np->nx);
+ B_SET_NXP(p, varp->hash, key);
+ B_CPY_BDDP(np->nx, *p);
+ B_SET_BDDP(*p, nx);
+ B_SET_BDDP(np->f0, f0);
+ B_SET_BDDP(np->f1, f1);
+ np->varrfc = v;
+ B_RFC_INC_NP(np);
+ return B_BDDP_NP(np);
+}
+
+static bddp getbddp(v, f0, f1)
+bddvar v;
+bddp f0, f1;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check elimination rule */
+ if(f0 == f1)
+ {
+ if(!B_CST(f0)) { fp = B_NP(f0); B_RFC_DEC_NP(fp); }
+ return f0;
+ }
+
+ /* Negative edge constraint */
+ if(B_NEG(f0))
+ {
+ bddp h;
+
+ h = getnode(v, B_NOT(f0), B_NOT(f1));
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+ }
+ return getnode(v, f0, f1);
+}
+
+static bddp apply(f, g, op, skip)
+bddp f, g;
+unsigned char op, skip;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp, *gp;
+ struct B_CacheTable *cachep;
+ bddp key, f0, f1, g0, g1, h0, h1, h;
+ bddvar v, flev, glev;
+ char z; /* flag to check ZBDD node */
+
+ /* Check terminal case */
+ if(!skip) switch(op)
+ {
+ case BC_AND:
+ /* Check trivial cases */
+ if(f == bddfalse || g == bddfalse || f == B_NOT(g))
+ return bddfalse;
+ if(f == g)
+ {
+ if(f != bddtrue) { fp = B_NP(f); B_RFC_INC_NP(fp); }
+ return f;
+ }
+ if(f == bddtrue) { fp = B_NP(g); B_RFC_INC_NP(fp); return g; }
+ if(g == bddtrue) { fp = B_NP(f); B_RFC_INC_NP(fp); return f; }
+ /* Check operand swap */
+ if(f < g) { h = f; f = g; g = h; } /* swap (f, g) */
+ break;
+
+ case BC_XOR:
+ /* Check trivial cases */
+ if(f == g) return bddfalse;
+ if(f == B_NOT(g)) return bddtrue;
+ if(f == bddfalse) { fp = B_NP(g); B_RFC_INC_NP(fp); return g; }
+ if(g == bddfalse) { fp = B_NP(f); B_RFC_INC_NP(fp); return f; }
+ if(f == bddtrue) {fp=B_NP(g); B_RFC_INC_NP(fp); return B_NOT(g);}
+ if(g == bddtrue) {fp=B_NP(f); B_RFC_INC_NP(fp); return B_NOT(f);}
+ /* Check negation */
+ if(B_NEG(f) && B_NEG(g)) { f = B_NOT(f); g = B_NOT(g); }
+ else if(B_NEG(f) || B_NEG(g))
+ {
+ f = B_ABS(f); g = B_ABS(g);
+ /* Check operand swap */
+ h = (f < g)? apply(g, f, op, 1): apply(f, g, op, 1);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+ }
+ /* Check operand swap */
+ if(f < g) { h = f; f = g; g = h; } /* swap (f, g) */
+ break;
+
+ case BC_COFACTOR:
+ /* Check trivial cases */
+ if(B_CST(f)) return f;
+ if(g == bddfalse || f == B_NOT(g)) return bddfalse;
+ if(f == g) return bddtrue;
+ if(g == bddtrue) { fp = B_NP(f); B_RFC_INC_NP(fp); return f; }
+ break;
+
+ case BC_UNIV:
+ /* Check trivial cases */
+ if(B_CST(f)) return f;
+ if(B_CST(g)) { fp = B_NP(f); B_RFC_INC_NP(fp); return f; }
+ if(B_NEG(g)) g = B_NOT(g);
+ break;
+
+ case BC_SUPPORT:
+ if(B_CST(f)) return bddfalse;
+ if(B_NEG(f)) f = B_NOT(f);
+ break;
+
+ case BC_INTERSEC:
+ /* Check trivial cases */
+ if(f == bddfalse || g == bddfalse) return bddfalse;
+ if(f == bddtrue) return B_NEG(g)? bddtrue: bddfalse;
+ if(g == bddtrue) return B_NEG(f)? bddtrue: bddfalse;
+ if(f == g) { fp = B_NP(f); B_RFC_INC_NP(fp); return f; }
+ if(f == B_NOT(g)) {fp=B_NP(f); B_RFC_INC_NP(fp); return B_ABS(f); }
+ /* Check operand swap */
+ if(f < g) { h = f; f = g; g = h; } /* swap (f, g) */
+ break;
+
+ case BC_UNION:
+ /* Check trivial cases */
+ if(f == bddfalse)
+ {
+ if(!B_CST(g)) {fp=B_NP(g); B_RFC_INC_NP(fp); }
+ return g;
+ }
+ if(f == bddtrue)
+ {
+ if(!B_CST(g)) {fp=B_NP(g); B_RFC_INC_NP(fp); }
+ return B_NEG(g)? g: B_NOT(g);
+ }
+ if(g == bddfalse || f == g)
+ { fp=B_NP(f); B_RFC_INC_NP(fp); return f; }
+ if(g == bddtrue || f == B_NOT(g))
+ {
+ fp=B_NP(f); B_RFC_INC_NP(fp);
+ return B_NEG(f)? f: B_NOT(f);
+ }
+ /* Check operand swap */
+ if(f < g) { h = f; f = g; g = h; } /* swap (f, g) */
+ break;
+
+ case BC_SUBTRACT:
+ /* Check trivial cases */
+ if(f == bddfalse || f == g) return bddfalse;
+ if(f == bddtrue || f == B_NOT(g))
+ return B_NEG(g)? bddfalse: bddtrue;
+ if(g == bddfalse) { fp=B_NP(f); B_RFC_INC_NP(fp); return f; }
+ if(g == bddtrue) { fp=B_NP(f); B_RFC_INC_NP(fp); return B_ABS(f); }
+ break;
+
+ case BC_AT0:
+ case BC_AT1:
+ case BC_OFFSET:
+ /* Check trivial cases */
+ if(B_CST(f)) return f;
+ /* special cases */
+ fp = B_NP(f); flev = Var[B_VAR_NP(fp)].lev;
+ glev = Var[(bddvar)g].lev;
+ if(flev < glev) { B_RFC_INC_NP(fp); return f; }
+ if(flev == glev)
+ {
+ if(op != BC_AT1)
+ {
+ h = B_GET_BDDP(fp->f0);
+ if(B_NEG(f)^B_NEG(h)) h = B_NOT(h);
+ }
+ else
+ {
+ h = B_GET_BDDP(fp->f1);
+ if(B_NEG(f)) h = B_NOT(h);
+ }
+ if(!B_CST(h)) { fp = B_NP(h); B_RFC_INC_NP(fp); }
+ return h;
+ }
+ /* Check negation */
+ if(B_NEG(f))
+ {
+ h = apply(B_NOT(f), g, op, 1);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+ }
+ break;
+
+ case BC_ONSET:
+ /* Check trivial cases */
+ if(B_CST(f)) return bddfalse;
+ /* special cases */
+ fp = B_NP(f); flev = Var[B_VAR_NP(fp)].lev;
+ glev = Var[(bddvar)g].lev;
+ if(flev < glev) return bddfalse;
+ if(flev == glev)
+ {
+ h = B_GET_BDDP(fp->f1);
+ if(!B_CST(h)) { fp = B_NP(h); B_RFC_INC_NP(fp); }
+ return h;
+ }
+ /* Check negation */
+ if(B_NEG(f)) f = B_NOT(f);
+ break;
+
+ case BC_CHANGE:
+ /* Check trivial cases */
+ if(f == bddfalse) return f;
+ if(B_CST(f)) return getzbddp((bddvar)g, bddfalse, f);
+ /* special cases */
+ fp = B_NP(f); flev = Var[B_VAR_NP(fp)].lev;
+ glev = Var[(bddvar)g].lev;
+ if(flev < glev)
+ {
+ B_RFC_INC_NP(fp);
+ h = getzbddp((bddvar)g, bddfalse, f);
+ if(h == bddnull) bddfree(f);
+ return h;
+ }
+ if(flev == glev)
+ {
+ h0 = B_GET_BDDP(fp->f1);
+ h1 = B_GET_BDDP(fp->f0);
+ if(B_NEG(f)^B_NEG(h1)) h1 = B_NOT(h1);
+ if(!B_CST(h0)) { fp = B_NP(h0); B_RFC_INC_NP(fp); }
+ if(!B_CST(h1)) { fp = B_NP(h1); B_RFC_INC_NP(fp); }
+ h = getzbddp((bddvar)g, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); }
+ return h;
+ }
+ break;
+
+ case BC_LSHIFT:
+ case BC_RSHIFT:
+ /* Check trivial cases */
+ if(B_CST(f)) return f;
+
+ /* Check negation */
+ if(B_NEG(f))
+ {
+ h = apply(B_NOT(f), g, op, 1);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+ }
+ break;
+
+ case BC_CARD:
+ if(B_CST(f)) return (f == bddempty)? 0: 1;
+ if(B_NEG(f)) return apply(B_NOT(f), bddempty, op, 1) + 1;
+ break;
+
+ case BC_LIT:
+ if(B_CST(f)) return 0;
+ if(B_NEG(f)) f = B_NOT(f);
+ break;
+
+ case BC_LEN:
+ if(B_CST(f)) return 0;
+ if(B_NEG(f)) f = B_NOT(f);
+ break;
+
+ default:
+ err("apply: unknown opcode", op);
+ break;
+ }
+
+ /* Non-trivial operations */
+ switch(op)
+ {
+ /* binary operation */
+ case BC_AND:
+ case BC_XOR:
+ case BC_COFACTOR:
+ case BC_UNIV:
+ case BC_INTERSEC:
+ case BC_UNION:
+ case BC_SUBTRACT:
+ /* Try cache? */
+ if((B_CST(f) || B_RFC_ONE_NP(B_NP(f))) &&
+ (B_CST(g) || B_RFC_ONE_NP(B_NP(g)))) key = bddnull;
+ else
+ {
+ /* Checking Cache */
+ key = B_CACHEKEY(op, f, g);
+ cachep = Cache + key;
+ if(cachep->op == op &&
+ f == B_GET_BDDP(cachep->f) &&
+ g == B_GET_BDDP(cachep->g))
+ {
+ /* Hit */
+ h = B_GET_BDDP(cachep->h);
+ if(!B_CST(h) && h != bddnull) { fp = B_NP(h); B_RFC_INC_NP(fp); }
+ return h;
+ }
+ }
+ /* Get (f0, f1) and (g0, g1)*/
+ z = 0;
+ fp = B_NP(f);
+ flev = B_CST(f)? 0: Var[B_VAR_NP(fp)].lev;
+ gp = B_NP(g);
+ glev = B_CST(g)? 0: Var[B_VAR_NP(gp)].lev;
+ f0 = f; f1 = f;
+ g0 = g; g1 = g;
+
+ if(flev <= glev)
+ {
+ v = B_VAR_NP(gp);
+ if(B_Z_NP(gp))
+ {
+ z = 1;
+ if(flev < glev) f1 = bddfalse;
+ }
+ g0 = B_GET_BDDP(gp->f0);
+ g1 = B_GET_BDDP(gp->f1);
+ if(B_NEG(g)^B_NEG(g0)) g0 = B_NOT(g0);
+ if(B_NEG(g) && !z) g1 = B_NOT(g1);
+ }
+
+ if(flev >= glev)
+ {
+ v = B_VAR_NP(fp);
+ if(B_Z_NP(fp))
+ {
+ z = 1;
+ if(flev > glev) g1 = bddfalse;
+ }
+ f0 = B_GET_BDDP(fp->f0);
+ f1 = B_GET_BDDP(fp->f1);
+ if(B_NEG(f)^B_NEG(f0)) f0 = B_NOT(f0);
+ if(B_NEG(f) && !z) f1 = B_NOT(f1);
+ }
+ break;
+
+ /* unary operation */
+ case BC_AT0:
+ case BC_AT1:
+ case BC_LSHIFT:
+ case BC_RSHIFT:
+ case BC_SUPPORT:
+ case BC_OFFSET:
+ case BC_ONSET:
+ case BC_CHANGE:
+ fp = B_NP(f);
+ if(B_RFC_ONE_NP(fp)) key = bddnull;
+ else
+ {
+ /* Checking Cache */
+ key = B_CACHEKEY(op, f, g);
+ cachep = Cache + key;
+ if(cachep->op == op &&
+ f == B_GET_BDDP(cachep->f) &&
+ g == B_GET_BDDP(cachep->g))
+ {
+ /* Hit */
+ h = B_GET_BDDP(cachep->h);
+ if(!B_CST(h) && h != bddnull) { fp = B_NP(h); B_RFC_INC_NP(fp); }
+ return h;
+ }
+ }
+ /* Get (f0, f1)*/
+ v = B_VAR_NP(fp);
+ z = B_Z_NP(fp)? 1: 0;
+ f0 = B_GET_BDDP(fp->f0);
+ f1 = B_GET_BDDP(fp->f1);
+ if(B_NEG(f)^B_NEG(f0)) f0 = B_NOT(f0);
+ if(B_NEG(f) && !z) f1 = B_NOT(f1);
+ break;
+
+ case BC_CARD:
+ case BC_LIT:
+ case BC_LEN:
+ fp = B_NP(f);
+ if(B_RFC_ONE_NP(fp)) key = bddnull;
+ else
+ {
+ /* Checking Cache */
+ key = B_CACHEKEY(op, f, bddempty);
+ cachep = Cache + key;
+ if(cachep->op == op &&
+ f == B_GET_BDDP(cachep->f) &&
+ bddempty == B_GET_BDDP(cachep->g))
+ {
+ /* Hit */
+ return B_GET_BDDP(cachep->h);
+ }
+ }
+ /* Get (f0, f1)*/
+ f0 = B_GET_BDDP(fp->f0);
+ f1 = B_GET_BDDP(fp->f1);
+ if(B_NEG(f)^B_NEG(f0)) f0 = B_NOT(f0);
+ break;
+
+ default:
+ err("apply: unknown opcode", op);
+ }
+
+ /* Stack overflow limitter */
+ BDD_RECUR_INC;
+
+ /* Get result node */
+ switch(op)
+ {
+ case BC_AND:
+ case BC_XOR:
+ case BC_INTERSEC:
+ case BC_UNION:
+ case BC_SUBTRACT:
+ h0 = apply(f0, g0, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g1, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = z? getzbddp(v, h0, h1): getbddp(v, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); } /* Overflow */
+ break;
+
+ case BC_COFACTOR:
+ if(g0 == bddfalse && g1 != bddfalse)
+ {
+ h = apply(f1, g1, op, 0);
+ }
+ else if(g1 == bddfalse && g0 != bddfalse)
+ {
+ h = apply(f0, g0, op, 0);
+ }
+ else
+ {
+ h0 = apply(f0, g0, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g1, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = getbddp(v, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); } /* Overflow */
+ }
+ break;
+
+ case BC_UNIV:
+ if(g0 != g1)
+ {
+ h0 = apply(f0, g0, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g0, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = apply(h0, h1, BC_AND, 0);
+ bddfree(h0); bddfree(h1);
+ }
+ else
+ {
+ h0 = apply(f0, g0, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g0, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = getbddp(v, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); } /* Overflow */
+ }
+ break;
+
+ case BC_AT0:
+ case BC_AT1:
+ case BC_OFFSET:
+ case BC_ONSET:
+ case BC_CHANGE:
+ h0 = apply(f0, g, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = z? getzbddp(v, h0, h1): getbddp(v, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); } /* Overflow */
+ break;
+
+ case BC_SUPPORT:
+ h0 = apply(f0, bddfalse, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, bddfalse, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = z? apply(h0, h1, BC_UNION, 0):
+ apply(B_NOT(h0), B_NOT(h1), BC_AND, 0);
+ bddfree(h0); bddfree(h1);
+ if(h == bddnull) break; /* Overflow */
+ h0 = h;
+ h = z? getzbddp(v, h0, bddtrue):
+ getbddp(v, B_NOT(h0), bddtrue);
+ if(h == bddnull) bddfree(h0); /* Overflow */
+ break;
+
+ case BC_LSHIFT:
+ case BC_RSHIFT:
+ /* Get VarID of new level */
+ {
+ bddvar flev, newlev;
+
+ flev = bddlevofvar(v);
+ if(op == BC_LSHIFT)
+ {
+ newlev = flev + (bddvar)g;
+ if(newlev > VarUsed || newlev < flev)
+ err("apply: Invald shift", newlev);
+ }
+ else
+ {
+ newlev = flev - (bddvar)g;
+ if(newlev == 0 || newlev > flev)
+ err("apply: Invald shift", newlev);
+ }
+ v = bddvaroflev(newlev);
+ }
+ h0 = apply(f0, g, op, 0);
+ if(h0 == bddnull) { h = h0; break; } /* Overflow */
+ h1 = apply(f1, g, op, 0);
+ if(h1 == bddnull) { bddfree(h0); h = h1; break; } /* Overflow */
+ h = z? getzbddp(v, h0, h1): getbddp(v, h0, h1);
+ if(h == bddnull) { bddfree(h0); bddfree(h1); } /* Overflow */
+ break;
+
+ case BC_CARD:
+ h = apply(f0, bddempty, op, 0)
+ + apply(f1, bddempty, op, 0);
+ if(h >= bddnull) h = bddnull - 1;
+ break;
+
+ case BC_LIT:
+ h = apply(f0, bddempty, op, 0)
+ + apply(f1, bddempty, op, 0);
+ if(h >= bddnull) h = bddnull - 1;
+ h += apply(f1, bddempty, BC_CARD, 0);
+ if(h >= bddnull) h = bddnull - 1;
+ break;
+
+ case BC_LEN:
+ h0 = apply(f0, bddempty, op, 0);
+ h1 = apply(f1, bddempty, op, 0) + 1;
+ h = (h0 < h1)? h1: h0;
+ break;
+
+ default:
+ err("apply: unknown opcode", op);
+ break;
+ }
+
+ /* Stack overflow limitter */
+ BDD_RECUR_DEC;
+
+ /* Saving to Cache */
+ if(key != bddnull && h != bddnull)
+ {
+ cachep = Cache + key;
+ cachep->op = op;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, h);
+ if(h == f) switch(op)
+ {
+ case BC_AT0:
+ key = B_CACHEKEY(BC_AT1, f, g);
+ cachep = Cache + key;
+ cachep->op = BC_AT1;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, h);
+ break;
+ case BC_AT1:
+ key = B_CACHEKEY(BC_AT0, f, g);
+ cachep = Cache + key;
+ cachep->op = BC_AT0;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, h);
+ break;
+ case BC_OFFSET:
+ key = B_CACHEKEY(BC_ONSET, f, g);
+ cachep = Cache + key;
+ cachep->op = BC_ONSET;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, bddfalse);
+ break;
+ default:
+ break;
+ }
+ if(h == bddfalse && op == BC_ONSET)
+ {
+ key = B_CACHEKEY(BC_OFFSET, f, g);
+ cachep = Cache + key;
+ cachep->op = BC_OFFSET;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, f);
+ }
+ }
+ return h;
+}
+
+static void gc1(np)
+struct B_NodeTable *np;
+{
+ /* np is a node ptr to be collected. (refc == 0) */
+ bddp key, nx1, f0, f1;
+ struct B_VarTable *varp;
+ struct B_NodeTable *np1, *np2;
+ bddp_32 *p_32;
+#ifdef B_64
+ bddp_h8 *p_h8;
+#endif
+
+ /* remove the node from hash list */
+ varp = Var + B_VAR_NP(np);
+ f0 = B_GET_BDDP(np->f0);
+ f1 = B_GET_BDDP(np->f1);
+ key = B_HASHKEY(f0, f1, varp->hashSpc);
+ B_SET_NXP(p, varp->hash, key);
+ nx1 = B_GET_BDDP(*p);
+ np1 = Node + nx1;
+
+ if(np1 == np) B_CPY_BDDP(*p, np->nx);
+ else
+ {
+ while(np1 != np)
+ {
+ if(nx1 == bddnull)
+ err("gc1: Fail to find the node to be deleted", np-Node);
+ np2 = np1;
+ nx1 = B_GET_BDDP(np2->nx);
+ np1 = Node + nx1;
+ }
+ B_CPY_BDDP(np2->nx, np->nx);
+ }
+ varp->hashUsed--;
+
+ /* append the node to avail list */
+ B_SET_BDDP(np->nx, Avail);
+ Avail = np - Node;
+
+ NodeUsed--;
+ np->varrfc = 0;
+
+ /* Check sub-graphs recursively */
+ if(!B_CST(f0))
+ {
+ np1 = B_NP(f0);
+ B_RFC_DEC_NP(np1);
+ if(B_RFC_ZERO_NP(np1))
+ { BDD_RECUR_INC; gc1(np1); BDD_RECUR_DEC; }
+ }
+ if(!B_CST(f1))
+ {
+ np1 = B_NP(f1);
+ B_RFC_DEC_NP(np1);
+ if(B_RFC_ZERO_NP(np1))
+ { BDD_RECUR_INC; gc1(np1); BDD_RECUR_DEC; }
+ }
+}
+
+static bddp count(f)
+bddp f;
+{
+ bddp nx;
+ bddp c, g;
+ bddvar flev, glev;
+ struct B_NodeTable *fp;
+ struct B_NodeTable *gp;
+
+ /* Check consistensy
+ if(f == bddnull)
+ err("count: bddnull found", bddnull);
+ */
+
+ if(B_CST(f)) return 0; /* Constant */
+ fp = B_NP(f);
+
+ /* Check visit flag */
+ nx = B_GET_BDDP(fp->nx);
+ if(nx & B_CST_MASK) return 0;
+
+ /* Check consistensy
+ flev = Var[B_VAR_NP(fp)].lev;
+ g = B_GET_BDDP(fp->f0);
+ if(!B_CST(g))
+ {
+ gp = B_NP(g); glev = Var[B_VAR_NP(gp)].lev;
+ if(flev <= glev)
+ err("count: inconsistensy found at f0", fp-Node);
+ }
+ g = B_GET_BDDP(fp->f1);
+ if(!B_CST(g))
+ {
+ gp = B_NP(g); glev = Var[B_VAR_NP(gp)].lev;
+ if(flev <= glev)
+ err("count: inconsistensy found at f1", fp-Node);
+ }
+ */
+
+ BDD_RECUR_INC;
+ c = count(B_GET_BDDP(fp->f0)) + count(B_GET_BDDP(fp->f1)) + 1U ;
+ BDD_RECUR_DEC;
+
+ /* Set visit flag */
+ B_SET_BDDP(fp->nx, nx | B_CST_MASK);
+
+ return c;
+}
+
+static void export(strm, f)
+FILE *strm;
+bddp f;
+{
+ bddp nx, f0, f1;
+ bddvar v;
+ struct B_NodeTable *fp;
+
+ if(B_CST(f)) return; /* Constant */
+ fp = B_NP(f);
+
+ /* Check visit flag */
+ nx = B_GET_BDDP(fp->nx);
+ if(nx & B_CST_MASK) return;
+
+ /* Set visit flag */
+ B_SET_BDDP(fp->nx, nx | B_CST_MASK);
+
+ /* Dump its subgraphs recursively */
+ v = B_VAR_NP(fp);
+ f0 = B_GET_BDDP(fp->f0);
+ f0 = B_ABS(f0);
+ f1 = B_GET_BDDP(fp->f1);
+ BDD_RECUR_INC;
+ export(strm, f0);
+ export(strm, f1);
+ BDD_RECUR_DEC;
+
+ /* Dump this node */
+ fprintf(strm, B_BDDP_FD, B_ABS(f));
+ fprintf(strm, " %d ", Var[v].lev);
+ if(f0 == bddfalse) fprintf(strm, "F");
+ else if(f0 == bddtrue) fprintf(strm, "T");
+ else fprintf(strm, B_BDDP_FD, f0);
+ fprintf(strm, " ");
+ if(f1 == bddfalse) fprintf(strm, "F");
+ else if(f1 == bddtrue) fprintf(strm, "T");
+ else fprintf(strm, B_BDDP_FD, f1);
+ fprintf(strm, "\n");
+}
+
+static void dump(f)
+bddp f;
+{
+ bddp nx, f0, f1;
+ bddvar v;
+ struct B_NodeTable *fp;
+
+ if(B_CST(f)) return; /* Constant */
+ fp = B_NP(f);
+
+ /* Check visit flag */
+ nx = B_GET_BDDP(fp->nx);
+ if(nx & B_CST_MASK) return;
+
+ /* Set visit flag */
+ B_SET_BDDP(fp->nx, nx | B_CST_MASK);
+
+ /* Dump its subgraphs recursively */
+ v = B_VAR_NP(fp);
+ f0 = B_GET_BDDP(fp->f0);
+ f0 = B_ABS(f0);
+ f1 = B_GET_BDDP(fp->f1);
+ BDD_RECUR_INC;
+ dump(f0);
+ dump(f1);
+ BDD_RECUR_DEC;
+
+ /* Dump this node */
+ printf("N");
+ printf(B_BDDP_FD, B_NDX(f));
+ printf(" = [V%d(%d), ", v, Var[v].lev);
+ if(B_CST(f0)) printf(B_BDDP_FD, B_VAL(f0));
+ else { printf("N"); printf(B_BDDP_FD, B_NDX(f0)); }
+ printf(", ");
+ if(B_NEG(f1)) putchar('~');
+ if(B_CST(f1)) printf(B_BDDP_FD, B_ABS(B_VAL(f1)));
+ else { printf("N"); printf(B_BDDP_FD, B_NDX(f1)); }
+ printf("]");
+ if(B_Z_NP(fp)) printf(" #Z");
+ printf("\n");
+}
+
+static void reset(f)
+bddp f;
+{
+ bddp nx;
+ struct B_NodeTable *fp;
+
+ if(B_CST(f)) return; /* Constant */
+ fp = B_NP(f);
+
+ /* Check visit flag */
+ nx = B_GET_BDDP(fp->nx);
+ if(nx & B_CST_MASK)
+ {
+ /* Reset visit flag */
+ B_SET_BDDP(fp->nx, nx & ~B_CST_MASK);
+ BDD_RECUR_INC;
+ reset(B_GET_BDDP(fp->f0));
+ reset(B_GET_BDDP(fp->f1));
+ BDD_RECUR_DEC;
+ }
+}
+
+static bddp getzbddp(v, f0, f1)
+bddvar v;
+bddp f0, f1;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check elimination rule */
+ if(f1 == bddfalse) return f0;
+
+ /* Negative edge constraint */
+ if(B_NEG(f0))
+ {
+ bddp h;
+
+ h = getnode(v, f0, f1);
+ if(h == bddnull) return bddnull;
+ return B_NOT(h);
+ }
+ return getnode(v, B_NOT(f0), f1);
+}
+
+static int andfalse(f, g)
+bddp f, g;
+{
+ struct B_NodeTable *fp, *gp;
+ struct B_CacheTable *cachep;
+ bddp key, f0, f1, g0, g1, h0, h1, h;
+ bddvar v, flev, glev;
+
+ /* Check trivial cases */
+ if(f == bddfalse || g == bddfalse || f == B_NOT(g)) return 0;
+ if(f == bddtrue || g == bddtrue || f == g) return 1;
+ /* Check operand swap */
+ if(f > g) { h = f; f = g; g = h; } /* swap (f, g) */
+
+ /* Non-trivial operations */
+ /* Try cache? */
+ if((B_CST(f) || B_RFC_ONE_NP(B_NP(f))) &&
+ (B_CST(g) || B_RFC_ONE_NP(B_NP(g)))) key = bddnull;
+ else
+ {
+ /* Checking Cache */
+ key = B_CACHEKEY(BC_AND, f, g);
+ cachep = Cache + key;
+ if(cachep->op == BC_AND &&
+ f == B_GET_BDDP(cachep->f) &&
+ g == B_GET_BDDP(cachep->g))
+ {
+ /* Hit */
+ h = B_GET_BDDP(cachep->h);
+ return (h==bddfalse)? 0: 1;
+ }
+ }
+ /* Get (f0, f1) and (g0, g1)*/
+ fp = B_NP(f);
+ flev = B_CST(f)? 0: Var[B_VAR_NP(fp)].lev;
+ gp = B_NP(g);
+ glev = B_CST(g)? 0: Var[B_VAR_NP(gp)].lev;
+ f0 = f; f1 = f;
+ g0 = g; g1 = g;
+
+ if(flev <= glev)
+ {
+ v = B_VAR_NP(gp);
+ g0 = B_GET_BDDP(gp->f0);
+ g1 = B_GET_BDDP(gp->f1);
+ if(B_NEG(g)) { g0 = B_NOT(g0); g1 = B_NOT(g1); }
+ }
+
+ if(flev >= glev)
+ {
+ v = B_VAR_NP(fp);
+ f0 = B_GET_BDDP(fp->f0);
+ f1 = B_GET_BDDP(fp->f1);
+ if(B_NEG(f)) { f0 = B_NOT(f0); f1 = B_NOT(f1); }
+ }
+
+ /* Get result */
+ if(andfalse(f0, g0) == 1) return 1;
+ if(andfalse(f1, g1) == 1) return 1;
+
+ /* Saving to Cache */
+ if(key != bddnull)
+ {
+ cachep = Cache + key;
+ cachep->op = BC_AND;
+ B_SET_BDDP(cachep->f, f);
+ B_SET_BDDP(cachep->g, g);
+ B_SET_BDDP(cachep->h, bddfalse);
+ }
+ return 0;
+}
+
+static int err(msg, num)
+char *msg;
+bddp num;
+{
+ fprintf(stderr,"***** ERROR %s ( ", msg);
+ fprintf(stderr, B_BDDP_FX, num);
+ fprintf(stderr," ) *****\n");
+ fprintf(stderr," NodeLimit : ");
+ fprintf(stderr, B_BDDP_FD, NodeLimit);
+ fprintf(stderr,"\t NodeSpc : ");
+ fprintf(stderr, B_BDDP_FD, NodeSpc);
+ fprintf(stderr,"\t VarSpc : %d",VarSpc);
+ fprintf(stderr,"\n CacheSpc : ");
+ fprintf(stderr, B_BDDP_FD, CacheSpc);
+ fprintf(stderr,"\t NodeUsed : ");
+ fprintf(stderr, B_BDDP_FD, NodeUsed);
+ fprintf(stderr,"\t VarUsed : %d\n",VarUsed);
+ exit(1);
+ return 1;
+}
+
+static int rfc_inc_ovf(np)
+struct B_NodeTable *np;
+{
+ bddp ix, nx, nx2, key, rfc, oldSpc;
+ bddp *p, *p2;
+ struct B_RFC_Table *oldRFCT;
+
+/* printf("rfc_inc %d (u:%d)\n", np-Node, RFCT_Used); */
+ if(RFCT_Spc == 0)
+ {
+ /* Create RFC-table */
+ RFCT = B_MALLOC(struct B_RFC_Table, B_RFCT_SPC0);
+ if(!RFCT)
+ {
+ err("B_RFC_INC_NP: rfc memory over flow", np-Node);
+ return 1;
+ }
+ for(ix=0; ix<B_RFCT_SPC0; ix++)
+ {
+ B_SET_BDDP((RFCT+ix)->nx, bddnull);
+ B_SET_BDDP((RFCT+ix)->rfc, (bddp)0);
+ }
+ RFCT_Spc = B_RFCT_SPC0;
+ }
+
+ nx = np - Node;
+ key = nx & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ while(nx2 != bddnull)
+ {
+ if(nx == nx2)
+ {
+ if(np->varrfc < B_RFC_MASK)
+ {
+ rfc = 0;
+ np->varrfc += B_RFC_UNIT;
+ }
+ else rfc = B_GET_BDDP((RFCT+key)->rfc) + 1;
+ B_SET_BDDP((RFCT+key)->rfc, rfc);
+ return 0;
+ }
+ key = (key+1) & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ }
+
+ /* new rfc entry */
+ B_SET_BDDP((RFCT+key)->nx, nx);
+ B_SET_BDDP((RFCT+key)->rfc, (bddp)0);
+ np->varrfc += B_RFC_UNIT;
+ RFCT_Used++;
+
+ if((RFCT_Used << 1) >= RFCT_Spc)
+ {
+ /* Enlarge RFC-table */
+ oldSpc = RFCT_Spc;
+ RFCT_Spc <<= 2;
+
+ oldRFCT = RFCT;
+ RFCT = B_MALLOC(struct B_RFC_Table, RFCT_Spc);
+ if(!RFCT)
+ {
+ err("B_RFC_INC_NP: rfc memory over flow", np-Node);
+ return 1;
+ }
+ for(ix=0; ix<RFCT_Spc; ix++)
+ {
+ B_SET_BDDP((RFCT+ix)->nx, bddnull);
+ B_SET_BDDP((RFCT+ix)->rfc, (bddp)0);
+ }
+ for(ix=0; ix<oldSpc; ix++)
+ {
+ nx = B_GET_BDDP((oldRFCT+ix)->nx);
+ if(nx == bddnull) continue;
+ key = nx & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ while(nx2 != bddnull)
+ {
+ key = (key+1) & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ }
+ B_SET_BDDP((RFCT+key)->nx, nx);
+ rfc = B_GET_BDDP((oldRFCT+ix)->rfc);
+ B_SET_BDDP((RFCT+key)->rfc, rfc);
+ }
+ free(oldRFCT);
+ }
+
+ return 0;
+}
+
+static int rfc_dec_ovf(np)
+struct B_NodeTable *np;
+{
+ bddp nx, key, nx2, rfc;
+
+/* printf("rfc_dec %d (u:%d)\n", np-Node, RFCT_Used); */
+ nx = np - Node;
+ key = nx & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ while(nx2 != bddnull)
+ {
+ if(nx == nx2)
+ {
+ rfc = B_GET_BDDP((RFCT+key)->rfc);
+ if(rfc == 0)
+ {
+ np->varrfc -= B_RFC_UNIT;
+ return 0;
+ }
+ B_SET_BDDP((RFCT+key)->rfc, rfc-1);
+ return 0;
+ }
+ key = (key+1) & (RFCT_Spc-1);
+ nx2 = B_GET_BDDP((RFCT+key)->nx);
+ }
+ return 0;
+}
+
+#define IMPORTHASH(x) (((x >> 1) ^ (x >> 16)) & (hashsize - 1))
+
+int import(strm, p, lim, z)
+FILE *strm;
+bddp *p;
+int lim;
+int z;
+{
+ int n, m, v, i, lev, var, inv, e;
+ bddp n_nd, ix, f, f0, f1, nd, nd0, nd1, hashsize, ixx;
+ char s[256];
+ bddp *hash1;
+ bddp *hash2;
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ if(strcmp(s, "_i") != 0) return 1;
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ n = strtol(s, NULL, 10);
+ while(n > bddvarused()) bddnewvar();
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ if(strcmp(s, "_o") != 0) return 1;
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ m = strtol(s, NULL, 10);
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ if(strcmp(s, "_n") != 0) return 1;
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) return 1;
+ n_nd = B_STRTOI(s, NULL, 10);
+
+ for(hashsize = 1; hashsize < (n_nd<<1); hashsize <<= 1)
+ ; /* empty */
+ hash1 = B_MALLOC(bddp, hashsize);
+ if(hash1 == 0) return 1;
+ hash2 = B_MALLOC(bddp, hashsize);
+ if(hash2 == 0)
+ {
+ free(hash1);
+ return 1;
+ }
+ for(ix=0; ix<hashsize; ix++) hash1[ix] = bddnull;
+
+ e = 0;
+ for(ix=0; ix<n_nd; ix++)
+ {
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) { e = 1; break; }
+ nd = B_STRTOI(s, NULL, 10);
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) { e = 1; break; }
+ lev = strtol(s, NULL, 10);
+ var = bddvaroflev(lev);
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) { e = 1; break; }
+ if(strcmp(s, "F") == 0) f0 = bddfalse;
+ else if(strcmp(s, "T") == 0) f0 = bddtrue;
+ else
+ {
+ nd0 = B_STRTOI(s, NULL, 10);
+
+ ixx = IMPORTHASH(nd0);
+ while(hash1[ixx] != nd0)
+ {
+ if(hash1[ixx] == bddnull)
+ {
+ err("bddimport: internal error", ixx);
+ return 1;
+ }
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ f0 = bddcopy(hash2[ixx]);
+ }
+
+ v = fscanf(strm, "%s", s);
+ if(v == EOF) { e = 1; bddfree(f0); break; }
+ if(strcmp(s, "F") == 0) f1 = bddfalse;
+ else if(strcmp(s, "T") == 0) f1 = bddtrue;
+ else
+ {
+ nd1 = B_STRTOI(s, NULL, 10);
+ if(nd1 & 1) { inv = 1; nd1 ^= 1; }
+ else inv = 0;
+
+ ixx = IMPORTHASH(nd1);
+ while(hash1[ixx] != nd1)
+ {
+ if(hash1[ixx] == bddnull)
+ {
+ err("bddimport: internal error", ixx);
+ return 1;
+ }
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ f1 = (inv)? bddnot(hash2[ixx]): bddcopy(hash2[ixx]);
+ }
+
+ f = (z)? getzbddp(var, f0, f1): getbddp(var, f0, f1);
+ if(f == bddnull)
+ {
+ e = 1;
+ bddfree(f1);
+ bddfree(f0);
+ break;
+ }
+
+ ixx = IMPORTHASH(nd);
+ while(hash1[ixx] != bddnull)
+ {
+ if(hash1[ixx] == nd)
+ {
+ err("bddimport: internal error", ixx);
+ return 1;
+ }
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ hash1[ixx] = nd;
+ hash2[ixx] = f;
+ }
+
+ if(e)
+ {
+ for(ix=0; ix<hashsize; ix++)
+ if(hash1[ix] != bddnull) bddfree(hash2[ix]);
+ free(hash2);
+ free(hash1);
+ return 1;
+ }
+
+ for(i=0; i<m; i++)
+ {
+ if(i >= lim) break;
+ v = fscanf(strm, "%s", s);
+ if(v == EOF)
+ {
+ for(i--; i>=0; i--) bddfree(p[i]);
+ for(ix=0; ix<hashsize; ix++)
+ if(hash1[ix] != bddnull) bddfree(hash2[ix]);
+ free(hash2);
+ free(hash1);
+ return 1;
+ }
+ nd = B_STRTOI(s, NULL, 10);
+ if(strcmp(s, "F") == 0) p[i] = bddfalse;
+ else if(strcmp(s, "T") == 0) p[i] = bddtrue;
+ else
+ {
+ if(nd & 1) { inv = 1; nd ^= 1; }
+ else inv = 0;
+
+ ixx = IMPORTHASH(nd);
+ while(hash1[ixx] != nd)
+ {
+ if(hash1[ixx] == bddnull)
+ {
+ err("bddimport: internal error", ixx);
+ return 1;
+ }
+ ixx++;
+ ixx &= (hashsize-1);
+ }
+ p[i] = (inv)? bddnot(hash2[ixx]): bddcopy(hash2[ixx]);
+ }
+ }
+ if(i < lim) p[i] = bddnull;
+
+ /* clear hash table */
+ for(ix=0; ix<hashsize; ix++)
+ if(hash1[ix] != bddnull) bddfree(hash2[ix]);
+ free(hash2);
+ free(hash1);
+
+ return 0;
+}
+
+int bddimport(strm, p, lim)
+FILE *strm;
+bddp *p;
+int lim;
+{
+ return import(strm, p, lim, 0);
+}
+
+int bddimportz(strm, p, lim)
+FILE *strm;
+bddp *p;
+int lim;
+{
+ return import(strm, p, lim, 1);
+}
+
+bddp bddpush(f, v)
+bddp f;
+bddvar v;
+/* Returns bddnull if not enough memory */
+{
+ struct B_NodeTable *fp;
+
+ /* Check operands */
+ if(v > VarUsed || v == 0) err("bddpush: Invalid VarID", v);
+ if(f == bddnull) return bddnull;
+
+ if(!B_CST(f)) { fp = B_NP(f); B_RFC_INC_NP(fp); }
+ return getzbddp(v, bddfalse, f);
+}
+
--- /dev/null
+CC = gcc
+DIR = ../..
+INCL = $(DIR)/include
+OPT = -O3 -I$(INCL)
+OPT64 = $(OPT) -DB_64
+
+all: bddc.o
+
+64: bddc_64.o
+
+bddc.o: bddc.c $(INCL)/bddc.h
+ $(CC) $(OPT) -c bddc.c
+ rm -f bddc_64.o
+
+bddc_64.o: bddc.c $(INCL)/bddc.h
+ $(CC) $(OPT64) -c bddc.c -o bddc_64.o
+ rm -f bddc.o
+
+clean:
+ rm -f *.o *.a *~
+
--- /dev/null
+cd BDDc
+make clean
+cd ../BDDXc
+make clean
+cd ../BDDLCM
+make clean
+cd ../BDD+
+make clean
+cd ..
+
--- /dev/null
+cd BDDc
+make
+cd ../BDDXc
+make
+cd ../BDDLCM
+make
+cd ../BDD+
+make
+cd ..
+
--- /dev/null
+cd BDDc
+make 64
+cd ../BDDXc
+make 64
+cd ../BDDLCM
+make 64
+cd ../BDD+
+make 64
+cd ..
+
--- /dev/null
+require 'mkmf'
+
+cp="#{ENV['PWD'].chomp('/gem')}"
+
+$CFLAGS += " -O3 -Wall -I#{cp}/SAPPOROBDD/include -DB_STATIC -D_NO_MAIN_ -DLINE -fPIC"
+$CPPFLAGS += " -O3 -Wall -I#{cp}/SAPPOROBDD/include -DB_STATIC -D_NO_MAIN_ -DLINE -fPIC"
+$LOCAL_LIBS += " -lstdc++"
+if RUBY_VERSION < '1.9.0'
+ CONFIG['CXXFLAGS']= " -o $@"
+ $CFLAGS += " -o $@"
+end
+
+$srcs =[
+ "SAPPOROBDD/app/VSOP/table.cc",
+ "print.cc",
+ "zdd_so.cpp" ,
+ "SAPPOROBDD/src/BDD+/BDD.cc",
+ "SAPPOROBDD/src/BDD+/BDDDG.cc",
+ "SAPPOROBDD/src/BDD+/BDDHASH.cc",
+ "SAPPOROBDD/src/BDD+/BtoI.cc",
+ "SAPPOROBDD/src/BDD+/CtoI.cc",
+ "SAPPOROBDD/src/BDD+/MLZBDDV.cc",
+ "SAPPOROBDD/src/BDD+/SOP.cc",
+ "SAPPOROBDD/src/BDD+/ZBDD.cc",
+ "SAPPOROBDD/src/BDD+/ZBDDDG.cc",
+ "SAPPOROBDD/src/BDD+/ZBDDHASH.cc",
+ "SAPPOROBDD/src/BDDc/bddc.c",
+ "SAPPOROBDD/src/BDDLCM/lcm-vsop.cc",
+]
+$objs =[
+ "SAPPOROBDD/app/VSOP/table.o",
+ "print.o",
+ "zdd_so.o",
+ "SAPPOROBDD/src/BDD+/BDD.o",
+ "SAPPOROBDD/src/BDD+/BDDDG.o",
+ "SAPPOROBDD/src/BDD+/BDDHASH.o",
+ "SAPPOROBDD/src/BDD+/BtoI.o",
+ "SAPPOROBDD/src/BDD+/CtoI.o",
+ "SAPPOROBDD/src/BDD+/MLZBDDV.o",
+ "SAPPOROBDD/src/BDD+/SOP.o",
+ "SAPPOROBDD/src/BDD+/ZBDD.o",
+ "SAPPOROBDD/src/BDD+/ZBDDDG.o",
+ "SAPPOROBDD/src/BDD+/ZBDDHASH.o",
+ "SAPPOROBDD/src/BDDc/bddc.o",
+ "SAPPOROBDD/src/BDDLCM/lcm-vsop.o",
+]
+$cleanfiles.concat($objs)
+$cleanfiles << "zdd_so.cpp"
+$cleanfiles << "xxcc"
+$cleanfiles << "SAPPOROBDD/src/BDDLCM/lcm-vsop.cc"
+
+create_makefile("zdd_so")
+
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+#パターン&ソースの登録
+func = Hash.new()
+
+func['| expr QUESTION expr COLON expr'] =<<'SCP_EOF'
+"
+/*##vsop_iif##*/
+VALUE vsop_iif(int argc, VALUE *argv,VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v1;
+ VALUE v2;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,\"20\",&v1,&v2);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_modc = value2ctoi(v1);
+ CtoI *ctoi_mode = value2ctoi(v2);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MEET expr'] =<<'SCP_EOF'
+"
+/*##vsop_meet##*/
+VALUE vsop_meet(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr NE expr'] =<<'SCP_EOF'
+"
+/*##vsop_ne##*/
+VALUE vsop_ne(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| print QUOTIENT IDVAR expr'] =<<'SCP_EOF'
+"
+VALUE vsop_print_arg1(VALUE self,char *arg){
+ Vsop_Ruby* rmod;
+// VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modd =new CtoI(*rmod->cmod);
+ int len = strlen(arg);
+ char *str_c;
+ str_c = new char[len+1];
+ strcpy(str_c,arg);
+ #{pgm_src}
+ return self;
+}
+
+"
+SCP_EOF
+
+
+func['| print QUOTIENT IDVAR FNAME expr'] =<<'SCP_EOF'
+"
+VALUE vsop_print_arg2(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v1,v2;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_mode =new CtoI(*rmod->cmod);
+ rb_scan_args(argc, argv,\"20\",&v1,&v2);
+ 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 (2nd argument must be STRING)\");
+ }
+ char *arg1=RSTRING_PTR(v1);
+ char *arg2=RSTRING_PTR(v2);
+
+ int len;
+ len = strlen(arg1);
+ char *str_c;
+ if(*arg1=='/'){
+ str_c = new char[len];
+ strcpy(str_c,arg1+1);
+ }
+ else{
+ str_c = new char[len+1];
+ strcpy(str_c,arg1);
+ }
+
+ len = strlen(arg2);
+ char *str_d = new char[len+3];
+ sprintf(str_d,\"\\\"%s\\\"\",arg2);
+ int len_d = len+2;
+
+ #{pgm_src}
+ return self;
+}
+"
+SCP_EOF
+
+
+func['| IMPORT LPAREN FNAME RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_import##*/
+VALUE vsop_import(int argc, VALUE *argv, VALUE self){
+ VALUE v;
+ CtoI *ctoi_fin;
+/*
+ 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++;
+
+ 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;
+ len = strlen(argtmp);
+ char *str_c = new char[len+3];
+ sprintf(str_c,\"\\\"%s\\\"\",argtmp);
+ int len_c = len+2;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| expr LE expr'] =<<'SCP_EOF'
+"
+/*##vsop_le##*/
+VALUE vsop_le(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr LT expr'] =<<'SCP_EOF'
+"
+/*##vsop_lt##*/
+VALUE vsop_lt(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr GE expr'] =<<'SCP_EOF'
+"
+/*##vsop_ge##*/
+VALUE vsop_ge(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr GT expr'] =<<'SCP_EOF'
+"
+/*##vsop_gt##*/
+VALUE vsop_gt(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| expr EQ expr'] =<<'SCP_EOF'
+"
+/*##vsop_eq##*/
+VALUE vsop_eq(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TLE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsLE##*/
+VALUE vsop_termsLE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TLT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsLT##*/
+VALUE vsop_termsLT(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TGE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsGE##*/
+VALUE vsop_termsGE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TGT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsGT##*/
+VALUE vsop_termsGT(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TNE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsNE##*/
+VALUE vsop_termsNE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TEQ LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_termsEQ##*/
+VALUE vsop_termsEQ(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPC LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_freqpatC##*/
+VALUE vsop_freqpatC(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPM LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_freqpatM##*/
+VALUE vsop_freqpatM(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPA LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_freqpatA##*/
+VALUE vsop_freqpatA(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr SYMGRP'] =<<'SCP_EOF'
+"
+/*##vsop_symgrp##*/
+VALUE vsop_symgrp(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| MINUS expr %prec UMINUS'] =<<'SCP_EOF'
+"
+/*##vsop_minus_op##*/
+VALUE vsop_minus_op(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| PLUS expr %prec UPLUS'] =<<'SCP_EOF'
+"
+/*##vsop_plus_op##*/
+VALUE vsop_plus_op(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr PERMITSYM LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_permitsym##*/
+VALUE vsop_permitsym(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr RESTRICT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*##vsop_restrict##*/
+VALUE vsop_restrict(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| u_expr ITEMS'] =<<'SCP_EOF'
+"
+/*##vsop_items##*/
+VALUE vsop_items(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TOTALVAL'] =<<'SCP_EOF'
+"
+/*##vsop_totalval##*/
+VALUE vsop_totalval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ int val = rmod->cmod->TotalVal().GetInt();
+ return INT2NUM(val);
+}
+"
+SCP_EOF
+
+func['| u_expr MINVAL'] =<<'SCP_EOF'
+"
+/*##vsop_minval##*/
+VALUE vsop_minval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr MAXVAL'] =<<'SCP_EOF'
+"
+/*##vsop_maxval##*/
+VALUE vsop_maxval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr REMAINDER expr'] =<<'SCP_EOF'
+"
+/*##vsop_remainder##*/
+VALUE vsop_remainder(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr QUOTIENT expr'] =<<'SCP_EOF'
+"
+/*##vsop_quotiment##*/
+VALUE vsop_quotiment(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MULTIPLY expr'] =<<'SCP_EOF'
+"
+/*##vsop_multiply##*/
+VALUE vsop_multiply(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| LCM LPAREN FNAME FNAME NUMBER FNAME RPAREN'] =<<'SCP_EOF'
+"
+VALUE vsop_lcm_order(int argc, VALUE *argv, VALUE self){
+ 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_STRING){
+ rb_raise(rb_eRuntimeError,\"argument type error (4th argument must be STRING)\");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+ char *arg4 = RSTRING_PTR(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);
+
+ len = strlen(arg4);
+ char *str_f = new char[len+3];
+ sprintf(str_f,\"\\\"%s\\\"\",arg4);
+ int len_f = len+2;
+
+ #{pgm_src}
+
+ 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);
+}
+"
+SCP_EOF
+
+
+
+func['| LCM LPAREN FNAME FNAME NUMBER RPAREN'] =<<'SCP_EOF'
+"
+VALUE vsop_lcm_nomal(int argc, VALUE *argv, VALUE self){
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ VALUE v1,v2,v3;
+ CtoI *ctoi_fin;
+ rb_scan_args(argc, argv,\"30\",&v1,&v2,&v3);
+ 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)\");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+
+ 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);
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr PERMIT LPAREN expr RPAREN']=<<'SCP_EOF'
+"
+/*##vsop_permit##*/
+VALUE vsop_permit(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func[': print expr']=<<'SCP_EOF'
+"
+/*
+ * : print expr
+ */
+
+VALUE vsop_print(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ #{pgm_src}
+ return self;
+}
+"
+SCP_EOF
+
+func['| expr PLUS expr']=<<'SCP_EOF'
+"
+/*##vsop_plus##*/
+VALUE vsop_plus(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MINUS expr']=<<'SCP_EOF'
+"
+/*##vsop_minus##*/
+VALUE vsop_minus(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+
+
+def extract_pgm(src)
+ start_char =0
+ end_char =0
+ writeflg=1
+ pgmsrc = ""
+
+ src.each{|line|
+ writeflg =1
+ if "#{line}" =~ /\{/ then
+ if(start_char==0) then
+ writeflg= 0
+ end
+ start_char= start_char + 1
+ elsif "#{line}" =~ /\}/ then
+ end_char = end_char + 1
+ if(start_char==end_char) then
+ pgmsrc =pgmsrc.gsub("$1.str", "str_a")
+ pgmsrc =pgmsrc.gsub("$2.str", "str_b")
+ pgmsrc =pgmsrc.gsub("$3.str", "str_c")
+ pgmsrc =pgmsrc.gsub("$4.str", "str_d")
+ pgmsrc =pgmsrc.gsub("$5.str", "str_e")
+ pgmsrc =pgmsrc.gsub("$6.str", "str_f")
+ pgmsrc =pgmsrc.gsub("$1.len", "len_a")
+ pgmsrc =pgmsrc.gsub("$2.len", "len_b")
+ pgmsrc =pgmsrc.gsub("$3.len", "len_c")
+ pgmsrc =pgmsrc.gsub("$4.len", "len_d")
+ pgmsrc =pgmsrc.gsub("$5.len", "len_e")
+ pgmsrc =pgmsrc.gsub("$6.len", "len_f")
+ pgmsrc =pgmsrc.gsub("$$", "ctoi_fin")
+ pgmsrc =pgmsrc.gsub("$1", "ctoi_moda")
+ pgmsrc =pgmsrc.gsub("$2", "ctoi_modb")
+ pgmsrc =pgmsrc.gsub("$3", "ctoi_modc")
+ pgmsrc =pgmsrc.gsub("$4", "ctoi_modd")
+ pgmsrc =pgmsrc.gsub("$5", "ctoi_mode")
+ pgmsrc =pgmsrc.gsub("$6", "ctoi_modf")
+ return pgmsrc
+ end
+ end
+ if(writeflg == 1)then
+ pgmsrc = pgmsrc + "#{line}"
+ end
+ }
+end
+
+def func_set(func)
+ ##最初に%{から%}までint main以外をすべて抜き出す
+ File.open("SAPPOROBDD/app/VSOP/vsopyacc.y++","r"){|src|
+ writeflg=0
+ mainflg=0
+ main_s=0
+ main_e=0
+ src.each{|line|
+ if "#{line}" =~ /^%\{/ then
+ writeflg=1
+ elsif "#{line}" =~ /^%\}/ then
+ break
+ elsif "#{line}" =~ /^int main/ then
+ mainflg=1
+ writeflg=0
+ elsif "#{line}" =~ /\{|\}/ and mainflg == 1 then
+ if "#{line}" =~ /\{/ then
+ main_s = main_s+1
+ end
+ if "#{line}" =~ /\}/ then
+ main_e = main_e+1
+ if main_s == main_e then
+ writeflg =1
+ mainflg = 0
+ end
+ end
+ else
+ if writeflg==1 then
+ File.open("zdd_so.cpp","a"){|file|
+ file.puts line
+ }
+ end
+ end
+ }
+ }
+ #パターンごとの記述を抜き出す
+ File.open("SAPPOROBDD/app/VSOP/vsopyacc.y++","r"){|src|
+ src.each{|line|
+ if not func[line.squeeze(" ").chomp.lstrip.rstrip].nil?then
+ key = line.squeeze(" ").chomp.lstrip.rstrip
+ pgm_src = extract_pgm(src)
+ File.open("zdd_so.cpp","a"){|file|
+ eval "file.puts " + func[key]
+ }
+ end
+ }
+ }
+end
+
+
+if(File.exist?("zdd_so.cpp"))then
+ File.delete("zdd_so.cpp")
+end
+
+
+#zdd.cxxにsetfunc.cppを入れ込み、zdd_so.cppを作成
+File.open("zdd_so.cxx","r"){|src|
+ src.each{|line|
+ if "#{line}" =~ /^#include \"setfunc\.cpp\"/ then
+ func_set(func)
+ else
+ File.open("zdd_so.cpp","a"){|file|
+ file.puts line
+ }
+ end
+ }
+}
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+#!/usr/bin/env ruby
+# encoding: utf-8
+
+#パターン&ソースの登録
+func = Hash.new()
+
+func['| expr QUESTION expr COLON expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.iif(zdd2,zdd3) -> ZDD Object : 条件演算
+ *
+ * zdd1,zdd2,zdd3,zdd4 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合については、zdd2の項を選択し、それ以外のアイテム集合についてはzdd3の項を選択する。
+ * (a+b).iif(2a+3b+4c+5d,3a+4b+5c+6d) -> 2a+3b+5c+6d # zdd1に含まれるアイテム集合a,bは、zdd2の項2a,3bを選択し、それ以外はzdd3の項5c,6dを選択する。
+ *
+ * 典型的には比較演算子と組み合わせて以下のように利用する。
+ * > x.show # -> 3a+2b+2c
+ * > y.show # -> 2a+2b+4c
+ * # (x,yが上記の通り定義されていたとする)
+ *
+ * # xとyを比較し、yより大きい重みを持つ項をxから、それ以外をyから選ぶ。
+ * # x>yの結果はaであり、第1引数xから3aが選択され、その他のアイテム集合は第2引数yから2b,4cが選ばれる。
+ * > (x>y).iif(x,y) # -> 3a+2b+4c
+ *
+ * # xとyを比較し、yより大きい重みを持つ項をxから選ぶ。
+ * # 上の例と同様であるが、第2引数が0なのでa以外のアイテム集合は何も選択されない。
+ * > (x>y).iif(x,0) # -> 3a
+ *
+ * # xとyを比較し、yと同じ重みを持つ項をxから選ぶ。
+ * > (x==y).iif(x,0) # -> 2b
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_iif(int argc, VALUE *argv,VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v1;
+ VALUE v2;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ rb_scan_args(argc, argv,\"20\",&v1,&v2);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_modc = value2ctoi(v1);
+ CtoI *ctoi_mode = value2ctoi(v2);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MEET expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.meet(zdd2) -> ZDD Object : meet演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合αとzdd2に含まれるアイテム集合βの共通集合α∩βを求める。
+ * 例えば、アイテム集合abc と bcd の共通集合は以下の通り。
+ * abc.meet(bcd) = abc ∩ bcd = bc
+ * 複数のアイテム集合間の演算では全組合せについて共通集合を求める。
+ * (abc + a).meet(bcd + b) = abc ∩ bcd + abc ∩ b + a ∩ bcd + a ∩ b
+ * = bc + b + 1 + 1
+ * = bc + b + 2
+ * 重みについては、同じアイテム集合を複数に展開して計算すればよい。
+ * (2abc).meet(bcd) = (abc+abc).meet(bcd) = bc + bc = 2bc
+ *
+ * === 例
+ * > a=VSOP.itemset(\"a\")
+ * > b=VSOP.itemset(\"b\")
+ * > f=a+2*a*b+3*b
+ *
+ * # a + 2ab + 3b の各アイテム集合と引き数で指定されたアイテム集合 a との共通集合を求めると、
+ * # a + 2a + 3 = 3 a + 3となる。
+ * > f.meet(a).show
+ * 3 a + 3
+ *
+ * # アイテム集合bとの共通集合を求めると 1 + 2b + 3b = 5b + 1 となる。
+ * > f.meet(b).show
+ * 5 b + 1
+ *
+ * # アイテム集合 ab との共通集合を求めると a + 2ab + 3b となる。
+ * > f.meet(a*b).show
+ * 2 a b + a + 3 b
+ *
+ * # 定数1は空のアイテム集合なので、それとの共通集合を求めると係数だけが残り 1 + 2 + 3 = 6 となる。
+ * > f.meet(1).show
+ * 6
+ * > 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 = 2ab
+ * # 2ab ∩ 2ab = 4ab
+ * # bc ∩ 2ab = 2b
+ * # 1 ∩ 2ab = 2
+ * # abc ∩ a = a
+ * # 2ab ∩ a = 2a
+ * # bc ∩ a = 1
+ * # 1 ∩ a = 1
+ * # 結果をまとめると 6ab + 3a + 2b + 4 となる。
+ * #
+ * > f.meet(g).show
+ * 6 a b + 3 a + 2 b + 4
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_meet(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr NE expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.ne?(zdd2) -> ZDD Object : 不等比較演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みが異なるアイテム集合を選択する。
+ * 詳しくは==演算子を参照のこと。
+ *
+ * === 関連
+ * ==, >=, >, <=, <, iif
+ */
+
+VALUE vsop_ne(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| print QUOTIENT IDVAR expr'] =<<'SCP_EOF'
+"
+VALUE vsop_print_arg1(VALUE self,char *arg){
+ Vsop_Ruby* rmod;
+// VALUE v;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modd =new CtoI(*rmod->cmod);
+ int len = strlen(arg);
+ char *str_c;
+ str_c = new char[len+1];
+ strcpy(str_c,arg);
+ #{pgm_src}
+ return self;
+}
+
+"
+SCP_EOF
+
+
+func['| print QUOTIENT IDVAR FNAME expr'] =<<'SCP_EOF'
+"
+VALUE vsop_print_arg2(int argc, VALUE *argv, VALUE self){
+ Vsop_Ruby* rmod;
+ VALUE v1,v2;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_mode =new CtoI(*rmod->cmod);
+ rb_scan_args(argc, argv,\"20\",&v1,&v2);
+ 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 (2nd argument must be STRING)\");
+ }
+ char *arg1=RSTRING_PTR(v1);
+ char *arg2=RSTRING_PTR(v2);
+
+ int len;
+ len = strlen(arg1);
+ char *str_c;
+ if(*arg1=='/'){
+ str_c = new char[len];
+ strcpy(str_c,arg1+1);
+ }
+ else{
+ str_c = new char[len+1];
+ strcpy(str_c,arg1);
+ }
+
+ len = strlen(arg2);
+ char *str_d = new char[len+3];
+ sprintf(str_d,\"\\\"%s\\\"\",arg2);
+ int len_d = len+2;
+
+ #{pgm_src}
+ return self;
+}
+"
+SCP_EOF
+
+
+func['| IMPORT LPAREN FNAME RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * VSOP.import(fileName) -> ZDD Object : ZDDのインポート
+ *
+ * fileName : Ruby String
+ *
+ * === 説明
+ * exportメソッドで出力されたZDDファイル(fileNameで指定)をインポートしZDDオブジェクトを復元する。
+ * exportする時のsymbolによるアイテムの宣言順序とimportする時の宣言順序は同じでなければならない。
+ *
+ * === 例
+ *
+ * # まずZDDオブジェクトfをファイル\"dat.zdd\"にエキスポートする。
+ * > VSOP.symbol(\"a\")
+ * > VSOP.symbol(\"b\")
+ * > VSOP.symbol(\"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(\"dat.zdd\")
+ * > exit
+ *
+ * # エキスポートされたファイル内容は以下の通り。
+ * $ more xxa
+ * _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
+ *
+ * # 以下のようにsymbolを宣言した後にimportすれば正しく復元される。
+ * > VSOP.symbol(\"a\")
+ * > VSOP.symbol(\"b\")
+ * > VSOP.symbol(\"c\")
+ * > f=VSOP.import(\"dat.zdd\")
+ * > f.show
+ * 5 a b c + 3 a b + 2 b c + c
+ * > exit
+ *
+ * # もしアイテムb,cの宣言順序を入れ替えると結果においてもbとcが入れ替わってしまう。
+ * > VSOP.symbol(\"a\")
+ * > VSOP.symbol(\"c\")
+ * > VSOP.symbol(\"b\")
+ * > f=VSOP.import(\"dat.zdd\")
+ * > f.show
+ * 5 a c b + 3 a c + 2 c b + b
+ * > exit
+ *
+ * # 宣言せずにインポートすると、x1,x2,x3のようなアイテム名が使われる。
+ * # この時、各アイテムの後ろに付いた数字は、アイテムの宣言の逆順による連番となる。
+ * # 以下の例では、x1=c, x2=b, x3=cである。
+ * > VSOP.import(\"dat.zdd\")
+ * > f.show
+ * 5 x3 x2 x1 + 3 x3 x2 + 2 x2 x1 + x1
+ * > exit
+ */
+
+VALUE vsop_import(int argc, VALUE *argv, VALUE self){
+ VALUE v;
+ CtoI *ctoi_fin;
+/*
+ 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++;
+
+ 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;
+ len = strlen(argtmp);
+ char *str_c = new char[len+3];
+ sprintf(str_c,\"\\\"%s\\\"\",argtmp);
+ int len_c = len+2;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| expr LE expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 <= zdd2 : 以下比較演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みがzdd2以下のアイテム集合を選択する。
+ * 詳しくは==演算子を参照のこと。
+ *
+ * === 関連
+ * ==, >=, >, <, ne?, iif
+ */
+
+VALUE vsop_le(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr LT expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 < zdd2 -> ZDD Object : 小なり比較演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みがzdd2より小さいアイテム集合を選択する。
+ * 詳しくは==演算子を参照のこと。
+ *
+ * === 関連
+ * ==, >=, >, <=, ne?, iif
+ */
+
+VALUE vsop_lt(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr GE expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 >= zdd2 -> ZDD Object : 以上比較演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みがzdd2以上のアイテム集合を選択する。
+ * 詳しくは==演算子を参照のこと。
+ *
+ * === 関連
+ * ==, >, <=, <, ne?, iif
+ */
+
+VALUE vsop_ge(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr GT expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 > zdd2 -> ZDD Object : 大なり比較演算
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みがzdd2より大きいアイテム集合を選択する。
+ * 詳しくは==演算子を参照のこと。
+ *
+ * === 関連
+ * ==, >=, <=, <, ne?, iif
+ */
+
+VALUE vsop_gt(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| expr EQ expr'] =<<'SCP_EOF'
+"
+/**//*
+ * call-seq:
+ * zdd1 == zdd2 -> ZDD Object : 等価比較演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれるアイテム集合とzdd2に含まれるアイテム集合を比較し、重みが同じアイテム集合を選択する。アイテム集合のみを返し、重みは1となることに注意する。
+ *
+ * 本パッケージで扱える比較演算子(関数)は以下の通り。
+ * zdd1 == zdd2 : 等価演算子
+ * zdd1 >= zdd2 : 以上演算子
+ * zdd1 > zdd2 : 大なり演算子
+ * zdd1 <= zdd2 : 以下演算子
+ * zdd1 < zdd2 : 小なり演算子
+ * zdd1.ne?(zdd2) : 不等関数
+ *
+ * === 例
+ * > x.show
+ * 3 a + 2 b + 2 c
+ * > y.show
+ * 2 a + 2 b + 4 c
+ * # (x,yが上記の通り定義されていたとする)
+ *
+ * # xとyを比較し、同じ重みを持つアイテム集合を選択する。
+ * > (x==y).show
+ * b
+ *
+ * # xとyを比較し、y以上の重みを持つアイテム集合を選択する。
+ * > (x>=y).show
+ * a + b
+ *
+ * # xとyを比較し、異なる重みを持つアイテム集合を選択する。
+ * > (x.ne?(y)).show
+ * a + c
+ *
+ * zdd1にあってzdd2にない(もしくはその逆)アイテム集合の重みは0と考えればよい。
+ * x.show
+ * 3 a + 2 b + 2 c
+ * y.show
+ * 2 a + 2 b
+ * # (x,yが上記の通り定義されていたとする)
+ *
+ * # アイテム集合cはyにないので項0cを考えればよい。
+ * > (x>y).show
+ * a + c
+ * > (x.ne?(y)).show
+ * a + c
+ * > (x==y).show
+ * b
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_eq(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TLE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.termsLE(zdd2) -> ZDD Object : 重み比較による項選択(以下比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数以下の重みを持つ項(重み+アイテム集合)を選択する。
+ * 詳しくはtermsEQ演算子を参照のこと。
+ *
+ * === 関連
+ * termsEQ, termsNE, termsGE, termsGT, termsLE, termsLT, terms
+ */
+
+VALUE vsop_termsLE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TLT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.termsLT(zdd2) -> ZDD Object : 重み比較による項選択(小なり比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数より小さい重みを持つ項(重み+アイテム集合)を選択する。
+ * 詳しくはtermsEQ演算子を参照のこと。
+ *
+ * === 関連
+ * termsEQ, termsNE, termsGE, termsGT, termsLE, termsLT, terms
+ */
+
+VALUE vsop_termsLT(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TGE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.termsGE(zdd2) -> ZDD Object : 重み比較による項選択(以上比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数以上の重みを持つ項(重み+アイテム集合)を選択する。
+ * 詳しくはtermsEQ演算子を参照のこと。
+ *
+ * === 関連
+ * termsEQ, termsNE, termsGE, termsGT, termsLE, termsLT, terms
+ */
+
+VALUE vsop_termsGE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TGT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * 書式 zdd1.termsGT(zdd2) -> ZDD Object : 重み比較による項選択(大なり比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数より大きい重みを持つ項(重み+アイテム集合)を選択する。
+ * 詳しくはtermsEQ演算子を参照のこと。
+ *
+ * === 関連
+ * termsEQ, termsNE, termsGE, termsGT, termsLE, termsLT, terms
+ */
+
+
+VALUE vsop_termsGT(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TNE LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.termsNE(zdd2) -> ZDD Object : 重み比較による項選択(不等比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数と異なる重みを持つ項(重み+アイテム集合)を選択する。
+ * 詳しくはtermsEQ演算子を参照のこと。
+ *
+ * === 関連
+ * termsEQ, termsNE, termsGE, termsGT, termsLE, termsLT, terms
+ */
+
+VALUE vsop_termsNE(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TEQ LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.termsEQ(zdd2) -> ZDD Object : 重み比較による項選択(等価比較)
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる項のうち、zdd2で与えられた定数と同じ重みを持つ項(重み+アイテム集合)を選択する。
+ * zdd2にはconstantメソッドにより生成されたVSOP定数オブジェクト、もしくはFixnum,Bignumのrubyオブジェクトで指定する。
+ *
+ * 本パッケージで扱える全ての項選択メソッドは以下の通り。
+ * zdd1.termsEQ(zdd2) : 等価比較
+ * zdd1.termsGE(zdd2) : 以上比較
+ * zdd1.termsGT(zdd2) : 大なり比較
+ * zdd1.termsLE(zdd2) : 以下比較
+ * zdd1.termsLT(zdd2) : 小なり比較
+ * zdd1.termsNE(zdd2) : 不等比較
+ *
+ * === 例
+ * > x.show
+ * 5 a + 3 b + c
+ * # xが上記の通り定義されていたとする。
+ *
+ * # 3の重みを持つ項を選択する。
+ * > x.termsEQ(3).show
+ * 3 b
+ *
+ * # 3以上の重みを持つ項を選択する。
+ * > x.termsGE(3).show
+ * 5 a + 3 b
+ *
+ * # 3でない重みを持つ項を選択する。
+ * > x.termsNE(3).show
+ * 5 a + c
+ *
+ * # 条件に合う項がなければ0
+ * > x.termsGT(10).show
+ * 0
+ */
+
+VALUE vsop_termsEQ(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPC LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.freqpatC(minsup) : 頻出飽和アイテム集合の列挙
+ *
+ * zdd : ZDD Object
+ * minsup : Ruby Integer
+ *
+ * === 説明
+ * zddから最小サポートminsup以上出現する頻出飽和アイテム集合を全て列挙し、そのZDDオブジェクトを返す。
+ *
+ * === 例
+ * freqpatAを参照のこと。
+ */
+VALUE vsop_freqpatC(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPM LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/**//*
+ * call-seq:
+ * zdd.freqpatM(minsup) -> ZDD Object : 頻出極大アイテム集合の列挙
+ *
+ * zdd : ZDD Object
+ * minsup : Ruby Integer
+ *
+ * === 説明
+ * zddから最小サポートminsup以上出現する頻出極大アイテム集合を全て列挙し、そのZDDオブジェクトを返す。
+ *
+ * === 例
+ * freqpatAを参照のこと。
+ */
+VALUE vsop_freqpatM(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr FPA LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.freqpatA(minsup) : 頻出アイテム集合の列挙
+ *
+ * zdd : ZDD Object
+ * minsup : Ruby Integer
+ *
+ * === 説明
+ * zddから最小サポートminsup以上出現する頻出アイテム集合を全て列挙し、そのZDDオブジェクトを返す。
+ *
+ * === 例
+ * > a=VSOP.itemset(\"a\")
+ * > b=VSOP.itemset(\"b\")
+ * > c=VSOP.itemset(\"c\")
+ * > d=VSOP.itemset(\"d\")
+ * > t=a*b + a + b*c*d + a*b*c + a
+ * > t.show
+ * a b c + a b + 2 a + b c d
+ *
+ * > t.freqpatA(1).show
+ * a b c + a b + a c + a + b c d + b c + b d + b + c d + c + d + 1
+ * > t.freqpatM(1).show
+ * a b c + b c d
+ * > t.freqpatC(1).show
+ * a b c + a b + a + b c d + b c + b + 1
+ *
+ * > t.freqpatA(2).show
+ * a b + a + b c + b + c + 1
+ * > t.freqpatM(2).show
+ * a b + b c
+ * > t.freqpatC(2).show
+ * a b + a + b c + b + 1
+ * > t.freqpatA(3).show
+ * a + b + 1
+ * > t.freqpatM(3).show
+ * a + b
+ * > t.freqpatC(3).show
+ * a + b + 1
+ *
+ * === 関連
+ * freqpatM, freqpatC
+ */
+VALUE vsop_freqpatA(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr SYMGRP'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.symgrp : Generates symmetric item sets in zdd.
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ *
+ */
+VALUE vsop_symgrp(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| MINUS expr %prec UMINUS'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * - zdd -> ZDD Object : -単項演算子
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれる全てのアイテム集合の重みの符合を変える。
+ *
+ * === 例
+ * > x.show
+ * 3 a + 2 b
+ * > (-x).show
+ * -3 a - 2 b
+ */
+
+VALUE vsop_minus_op(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| PLUS expr %prec UPLUS'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * + zdd -> ZDD Object : 単項演算子
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれる全てのアイテム集合をそのまま返す(何もしない)。
+ *
+ * === 例
+ * > x.show
+ * 3 a + 2 b
+ * > (+x).show
+ * 3 a + 2 b
+ */
+
+VALUE vsop_plus_op(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr PERMITSYM LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.permitsym(zdd2) : Filters terms in zdd1 each of which consists of zdd2 number of items.
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ *
+ */
+
+VALUE vsop_permitsym(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr RESTRICT LPAREN expr RPAREN'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.restrict(zdd2) : restrict
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる組合せの中から、zdd2中の少なくとも1つの組合せを包含する要素だけを抽出する。
+ *
+ * === 例
+ * > x.show
+ * 5 a + 3 b + c
+ * > y.show
+ * a + b
+ * # x,yが上記の通り定義されていたとする。
+ * > z.show
+ * a b
+ * > x.restrinct(y).show
+ * 5 a + 3 b
+ * > x.restrinct(z).show
+ * 0
+ * > x.restrinct(\"a\").show
+ * 5 a
+ */
+
+VALUE vsop_restrict(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+func['| u_expr ITEMS'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.items -> ZDD Object : ZDDを構成する全アイテムの列挙
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zdd上の全アイテムとその重みについて、新しいZDDオブジェクトを生成し返す。
+ *
+ * === 例
+ * > a=VSOP.itemset(\"a\")
+ * > b=VSOP.itemset(\"b\")
+ * > c=VSOP.itemset(\"c\")
+ * > f=((a*b*c)+(a*b)+(b*c))
+ * > f.show
+ * a b c + 2 a b + b c
+ *
+ * # ZDDオブジェクトfは3つのアイテムa,b,cから構成されており、それぞれのアイテムの重みを以下の通り計算する。
+ * # アイテムaを含む項は\"a b c\"と\"2 a b\"で、その重み合計は3となる。
+ * # アイテムbは全ての項に含まれ、その重み合計は4となる。
+ * # アイテムcを含む項は\"a b c\"と\"b c\"で、その重み合計は2となる。
+ * > f.items.show
+ * 3 a + 4 b + 2 c
+ */
+
+VALUE vsop_items(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr TOTALVAL'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.totalval -> Ruby Integer : 重みの合計
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれる項(定数項も含む)の重みの合計をruby整数で返す。
+ *
+ * === 例
+ * > x.show
+ * 5 a + 3 b + c
+ * # xが上記の通り定義されていたとする。
+ *
+ * > puts x.totalval
+ * 9
+ *
+ * # 定数項も含めて求められる。
+ * > x.show
+ * 5 a + 3 b + c - 10
+ * # xが上記の通り定義されていたとする。
+ * > puts x.totalval
+ * -1
+ * === 関連
+ * minval, maxval
+ */
+
+VALUE vsop_totalval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ int val = rmod->cmod->TotalVal().GetInt();
+ return INT2NUM(val);
+/*
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+*/
+}
+"
+SCP_EOF
+
+func['| u_expr MINVAL'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.minval -> ZDD Object : 重みの最小値
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれる項(定数項も含む)のうち、最小の重みをVSOP定数オブジェクトで返す。
+ *
+ * === 例
+ * > x.show
+ * 5 a - 3 b + c
+ * # xが上記の通り定義されていたとする。
+ *
+ * > x.maxval.show
+ * -3
+ *
+ * # 最小値は定数項も含めて求められる。
+ * > x.show
+ * 5 a - 3 b + c - 10
+ * # xが上記の通り定義されていたとする。
+ * > x.maxval.show
+ * -10
+ *
+ * # 最小の重みを持つ項を選択する。
+ * > x.show
+ * 5 a - 3 b + 5 c - 3
+ * # xが上記の通り定義されていたとする。
+ * > x.termsEQ(x.maxval).show
+ * -3 b - 3
+ *
+ * === 関連
+ * maxval
+ */
+
+VALUE vsop_minval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr MAXVAL'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd.maxval -> ZDD Object : 重みの最大値
+ *
+ * zdd : ZDD Object
+ *
+ * === 説明
+ * zddに含まれる項(定数項も含む)のうち、最大の重みをVSOP定数オブジェクトで返す。
+ *
+ * === 例
+ * > x.show
+ * 5 a + 3 b + c
+ * # xが上記の通り定義されていたとする。
+ * > x.maxval.show
+ * 5
+ *
+ * # 最大値は定数項も含めて求められる。
+ * > x.show
+ * 5 a + 3 b + c + 10
+ * # xが上記の通り定義されていたとする。
+ * > x.maxval.show
+ * 10
+ *
+ * # 最大の重みを持つ項を選択する。
+ * > x.show
+ * 5 a + 3 b + 5 c + 2
+ * # xが上記の通り定義されていたとする。
+ * > x.termsEQ(x.maxval).show
+ * 5 a + 5 c
+ *
+ * === 関連
+ * minval
+ */
+
+VALUE vsop_maxval(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_moda =new CtoI(*rmod->cmod);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr REMAINDER expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 % zdd2 -> ZDD Object : 剰余演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * ===説明
+ * 剰余演算を行う。詳しくは / 演算子を参照。
+ */
+
+VALUE vsop_remainder(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr QUOTIENT expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 / zdd2 -> ZDD Object : 除算演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * ==== a. 定数除算
+ * 重み付き積和集合xの定数cによる除算x/cは、
+ * xの各項(アイテム集合)の重み(頻度)をcで整数除算した商を重みに持つアイテム集合が計算される。
+ * 通常の多項式と同様に考えれば良い。
+ * x.show # -> 13a+3b (xが左記の通り定義されていたとする)
+ * x/5 -> 2a # aの項:13/5の商は2であるから2a。bの項:3/5の商は0であるから0bとなり表示されない。
+ * x%5 -> 3a+3b # aの項:13/5の余りは3であるから3a。bの項:3/5の余りは3であるから3bとなる。
+ *
+ * ==== b. 1つのアイテム集合による除算
+ * 重み付き積和集合xのアイテム集合vによる除算x/vは、xの各項をvで除する演算である。
+ * 通常の多項式と同様に考えれば良い。
+ * x.show # -> 7ab+5bc
+ * y.show # -> 7ab+5bc+2c
+ * # (x,yが上記の通り定義されていたとする)
+ * x/'b' # -> 7a+5c # 7ab/bの商は7a。5bc/bの商は5c。
+ * y/'3b' # -> 2a+c # 7ab/3bの商は2a。5bc/3bの商は1c。2c/3bの商は0となり表示されない。
+ * x%'b' # -> 0 # 7ab/bの余りは0。5bc/bの余り0。
+ * y%'3b' # -> ab+2bc+2c # 7ab/3bの余りはab。5bc/3bの余りは2bc。2c/3bの余りは2c。
+ *
+ * ==== c. 2つ以上のアイテム集合による除算
+ * 2つの重み付き積和集合x,yの除算x/yは次のように計算される。
+ * 除数yの各項をT_iとしたときQ_i=x/T_iを全てのT_iについて得られたQ_i全て共通に含まれるアイテム集合(項)について、重みの絶対値が最小の項を商Qと定義する。
+ * 通常の多項式とは異なることに注意する。
+ * x.show # -> 2ab+4ac+ad-2bc+3bd
+ * y.show # -> a+b
+ * # (x,yが上記の通り定義されていたとする)
+ * # Q_1=(x/'a')=2b +4c +d +0 +0 = 0 +2b +4c +d
+ * # Q_2=(x/'b')=2a +0 +0 -2c +3d = 2a +0 -2c +3d
+ * # Q_1,Q_2で共通のアイテム集合はcとdであり、それぞれで絶対値が最小の項は-2cとdである。よって求める商は以下の通りとなる。
+ * (x/y).show # -> -2c+d
+ * # x%yについてはx-(y*Q)を計算すればよい。
+ * (x%y).show # -> 2ab+6ac+2bd
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_quotiment(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MULTIPLY expr'] =<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 * zdd2 -> ZDD Object : 乗算演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * ==== a. 定数乗算
+ * 重み付き積和集合xに定数cを掛けるx*cでは、xの各項の重みをc倍する。
+ * 通常の多項式と同様に考えれば良い。
+ * a=VSOP.itemset('a'); b=VSOP.itemset('b'); c=VSOP.itemset('c');
+ * (a*3).show # -> 3a
+ * (-2*a).show # -> -2a
+ * ((a+2*b+3*c)*4).show # -> 4a+8b+12c
+ *
+ * ==== b. 1つのアイテム集合の乗算
+ * 重み付き積和集合xに1つのアイテム集合yを掛けるx*yでは、xの各項目にアイテム集合yを加える。
+ * ただし、同じアイテム同士の掛け算 a*a=a となることに注意する。
+ * x.show # -> a+2ab+3c (xが左記の通り定義されていたとする)
+ * x*'d' # -> ad+2abd+3cd
+ * x*'b' # -> ab+2ab+3bc
+ * 4*x*'a' # -> 4a+8ab+12ac
+ *
+ * ==== c. 2つ以上のアイテム集合の乗算
+ * 2つの重み付き積和集合x,yの乗算x*yでは、xとyそれぞれの各項から一つずつ選ぶ組み合わせ全てについて上記a,bの乗算を付す。
+ * 乗算の結果同じアイテム集合の項は加減算される。
+ * a=VSOP.itemset('a'); b=VSOP.itemset('b');
+ * c=VSOP.itemset('c'); d=VSOP.itemset('d');
+ * ((a+b)*(c+d)).show # -> ac+ad+bc+bd
+ * ((a+b)*(b+c)).show # -> ab+ac+b+bc
+ * ((a+b)*(a+b)).show # -> a+2ab+b
+ * ((a+b)*(a-b)).show # -> a-b
+ * ----
+ * ====== 上記の例において出力結果を示したコメントでは、アイテムをアルファベット小文字1文字で表し、項における重みとアイテム間のスペースおよびアイテム間のスペースを省略して表記している。
+ */
+
+VALUE vsop_multiply(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| LCM LPAREN FNAME FNAME NUMBER FNAME RPAREN'] =<<'SCP_EOF'
+"
+VALUE vsop_lcm_order(int argc, VALUE *argv, VALUE self){
+ 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_STRING){
+ rb_raise(rb_eRuntimeError,\"argument type error (4th argument must be STRING)\");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+ char *arg4 = RSTRING_PTR(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);
+
+ len = strlen(arg4);
+ char *str_f = new char[len+3];
+ sprintf(str_f,\"\\\"%s\\\"\",arg4);
+ int len_f = len+2;
+
+ #{pgm_src}
+
+ 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);
+}
+"
+SCP_EOF
+
+
+
+func['| LCM LPAREN FNAME FNAME NUMBER RPAREN'] =<<'SCP_EOF'
+"
+VALUE vsop_lcm_nomal(int argc, VALUE *argv, VALUE self){
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ VALUE v1,v2,v3;
+ CtoI *ctoi_fin;
+ rb_scan_args(argc, argv,\"30\",&v1,&v2,&v3);
+ 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)\");
+ }
+ char *arg1 = RSTRING_PTR(v1);
+ char *arg2 = RSTRING_PTR(v2);
+ int arg3_fix = FIX2INT(v3);
+
+ 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);
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| u_expr PERMIT LPAREN expr RPAREN']=<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1.permit(zdd2) : permit演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1に含まれる組合せの中から、zdd2中の少なくとも1つの組合せに包含される要素だけを抽出する。
+ *
+ * === 例
+ * > x.show
+ * 5 a + 3 b + c
+ * > y.show
+ * a + b
+ * > z.show
+ * a b
+ * # x,y,zが上記の通り定義されていたとする。
+ *
+ * > x.permit(y).show
+ * 5 a + 3 b
+ * > x.permit(z).show
+ * 0
+ * > x.permit(\"a\").show
+ * 5 a
+ */
+VALUE vsop_permit(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_modd = value2ctoi(v);
+ CtoI *ctoi_fin;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func[': print expr']=<<'SCP_EOF'
+"
+/*
+ * : print expr
+ */
+
+VALUE vsop_print(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI *ctoi_modb =new CtoI(*rmod->cmod);
+ #{pgm_src}
+ return self;
+}
+"
+SCP_EOF
+
+func['| expr PLUS expr']=<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 + zdd2 -> ZDD Object : 加算演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1とzdd2の対応するアイテム集合同士の重みの加算を行う。
+ *
+ * === 例
+ * > x.show
+ * 3 a + 2 b
+ * > y.show
+ * 2 a + 2 b + 4 c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > (x+y).show
+ * 5 a + 4 b + 4 c
+ */
+
+VALUE vsop_plus(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+func['| expr MINUS expr']=<<'SCP_EOF'
+"
+/*
+ * call-seq:
+ * zdd1 - zdd2 -> ZDD Object : 減算演算子
+ *
+ * zdd1,zdd2 : ZDD Object
+ *
+ * === 説明
+ * zdd1とzdd2の対応するアイテム集合同士の重みの減算を行う。
+ *
+ * === 例
+ * > x.show
+ * 3 a + 2 b
+ * > y.show
+ * 2 a + 2 b + 4 c
+ * # x,yが上記の通り定義されていたとする。
+ *
+ * > (x-y).show
+ * a - 4 c
+ * > (y-x).show
+ * -a + 4 c
+ */
+
+VALUE vsop_minus(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;
+ #{pgm_src}
+ 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);
+}
+"
+SCP_EOF
+
+
+
+
+def extract_pgm(src)
+ start_char =0
+ end_char =0
+ writeflg=1
+ pgmsrc = ""
+
+ src.each{|line|
+ writeflg =1
+ if "#{line}" =~ /\{/ then
+ if(start_char==0) then
+ writeflg= 0
+ end
+ start_char= start_char + 1
+ elsif "#{line}" =~ /\}/ then
+ end_char = end_char + 1
+ if(start_char==end_char) then
+ pgmsrc =pgmsrc.gsub("$1.str", "str_a")
+ pgmsrc =pgmsrc.gsub("$2.str", "str_b")
+ pgmsrc =pgmsrc.gsub("$3.str", "str_c")
+ pgmsrc =pgmsrc.gsub("$4.str", "str_d")
+ pgmsrc =pgmsrc.gsub("$5.str", "str_e")
+ pgmsrc =pgmsrc.gsub("$6.str", "str_f")
+ pgmsrc =pgmsrc.gsub("$1.len", "len_a")
+ pgmsrc =pgmsrc.gsub("$2.len", "len_b")
+ pgmsrc =pgmsrc.gsub("$3.len", "len_c")
+ pgmsrc =pgmsrc.gsub("$4.len", "len_d")
+ pgmsrc =pgmsrc.gsub("$5.len", "len_e")
+ pgmsrc =pgmsrc.gsub("$6.len", "len_f")
+ pgmsrc =pgmsrc.gsub("$$", "ctoi_fin")
+ pgmsrc =pgmsrc.gsub("$1", "ctoi_moda")
+ pgmsrc =pgmsrc.gsub("$2", "ctoi_modb")
+ pgmsrc =pgmsrc.gsub("$3", "ctoi_modc")
+ pgmsrc =pgmsrc.gsub("$4", "ctoi_modd")
+ pgmsrc =pgmsrc.gsub("$5", "ctoi_mode")
+ pgmsrc =pgmsrc.gsub("$6", "ctoi_modf")
+ return pgmsrc
+ end
+ end
+ if(writeflg == 1)then
+ pgmsrc = pgmsrc + "#{line}"
+ end
+ }
+end
+
+def func_set(func)
+ ##最初に%{から%}までint main以外をすべて抜き出す
+ File.open("SAPPOROBDD/app/VSOP/vsopyacc.y++","r"){|src|
+ writeflg=0
+ mainflg=0
+ main_s=0
+ main_e=0
+ src.each{|line|
+ if "#{line}" =~ /^%\{/ then
+ writeflg=1
+ elsif "#{line}" =~ /^%\}/ then
+ break
+ elsif "#{line}" =~ /^int main/ then
+ mainflg=1
+ writeflg=0
+ elsif "#{line}" =~ /\{|\}/ and mainflg == 1 then
+ if "#{line}" =~ /\{/ then
+ main_s = main_s+1
+ end
+ if "#{line}" =~ /\}/ then
+ main_e = main_e+1
+ if main_s == main_e then
+ writeflg =1
+ mainflg = 0
+ end
+ end
+ else
+ if writeflg==1 then
+ File.open("zdd_so.cpp","a"){|file|
+ file.puts line
+ }
+ end
+ end
+ }
+ }
+ #パターンごとの記述を抜き出す
+ File.open("SAPPOROBDD/app/VSOP/vsopyacc.y++","r"){|src|
+ src.each{|line|
+ if not func[line.squeeze(" ").chomp.lstrip.rstrip].nil?then
+ key = line.squeeze(" ").chomp.lstrip.rstrip
+ pgm_src = extract_pgm(src)
+ File.open("zdd_so.cpp","a"){|file|
+ eval "file.puts " + func[key]
+ }
+ end
+ }
+ }
+end
+
+
+if(File.exist?("zdd_so.cpp"))then
+ File.delete("zdd_so.cpp")
+end
+
+
+#zdd.cxxにsetfunc.cppを入れ込み、zdd_so.cppを作成
+File.open("zdd_so.cxx","r"){|src|
+ src.each{|line|
+ if "#{line}" =~ /^#include \"setfunc\.cpp\"/ then
+ func_set(func)
+ else
+ File.open("zdd_so.cpp","a"){|file|
+ file.puts line
+ }
+ end
+ }
+}
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+/#define _lcm_c_/a\
+ #include "CtoI.h" //ZDD \
+
+/void LCM (/c\
+ CtoI LCM (PROBLEM *PP, int item, QUEUE *occ, WEIGHT frq, WEIGHT pfrq){ //ZDD \
+ int ii, xx,vv,iii,ix; //ZDD \
+ ZBDDV vz; //ZDD \
+ CtoI F, G,H,E; //ZDD \
+ F = CtoI(0); //ZDD
+
+/ITEMSET_check_all_rule (/a\
+if ( II->itemset.t>II->ub || (!(II->flag&ITEMSET_ALL) && II->itemset.t+II->add.t>II->ub)) goto UBSKIP; //ZDD\
+F = (II->flag & ITEMSET_PRE_FREQ)? CtoI((int)II->frq): CtoI(1); //ZDD \
+if(II->flag&ITEMSET_ALL && II->itemset.t+II->add.t>II->ub ){//ZDD-nain \
+ H = F; //ZDD-nain \
+ for(ii=0; ii<II->add.t; ii++) { //ZDD-nain \
+ xx = II->add.v[ii]; //ZDD-nain \
+ H = CtoI_Union(H, F.AffixVar(BDD_VarOfLev(xx+1))); //ZDD-nain\
+ }//ZDD-nain\
+ E = F; //ZDD-nain \
+ for(ii=1; ii<II->ub-II->itemset.t; ii++) { //ZDD-nain \
+ for(iii=0; iii<II->add.t; iii++) { //ZDD-nain \
+ xx = II->add.v[iii]; //ZDD-nain \
+ E = CtoI_Union(E,H.AffixVar(BDD_VarOfLev(xx+1))); //ZDD-nain \
+ } //ZDD-nain\
+ H=E; //ZDD-nain \
+ } //ZDD-nain \
+ F = H; //ZDD-nain \
+}else{ //ZDD-nain \
+ for(ii=0; ii<II->add.t; ii++) { //ZDD \
+ xx = II->add.v[ii]; //ZDD \
+ G = F.AffixVar(BDD_VarOfLev(xx+1)); //ZDD \
+ if(PP->problem & PROBLEM_FREQSET) { //ZDD \
+ F = CtoI_Union(F, G); //ZDD \
+ } //ZDD \
+ else F = G; //ZDD \
+ } //ZDD \
+} //ZDD-nain \
+UBSKIP:;
+
+/LCM (PP, e/c\
+ G = LCM (PP, e, &TT->OQ[e], PP->occ_w2[e], PP->occ_pw2[e]); // recursive call //ZDD \
+ F = CtoI_Union(F, G); //ZDD
+
+/END:;/a\
+ if(item < II->item_max) { //ZDD \
+ xx = item; //ZDD \
+ F = F.AffixVar(BDD_VarOfLev(xx+1)); //ZDD \
+ } //ZDD
+
+/PP->itemcand.s = js;/a\
+ return F; //ZDD
+/int LCM_main/c\
+ extern PROBLEM LCM_PP; //ZDD \
+PROBLEM LCM_PP; //ZDD \
+extern CtoI CtoI_Lcm2(); //ZDD \
+ \
+int CtoI_LcmItems() { //ZDD \
+ if( ERROR_MES ) return -1; //ZDD \
+ return LCM_PP.II.item_max; //ZDD \
+} //ZDD \
+ \
+int CtoI_LcmPerm(int k) { //ZDD \
+ if( ERROR_MES ) return -1; //ZDD \
+ return LCM_PP.II.perm[k]; //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmA ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 0); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmC ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 1); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmM ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 2); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmAV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 10); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmCV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 11); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_LcmMV ( char *fname1, char *fname2, int th){ //ZDD \
+ CtoI_Lcm1(fname1, fname2, th, 12); //ZDD \
+ if( !ERROR_MES ) while(CtoI_LcmItems() > BDD_VarUsed()) BDD_NewVar(); //ZDD \
+ return CtoI_Lcm2(); //ZDD \
+} //ZDD \
+ \
+int CtoI_Lcm1 ( char *fname1, char *fname2, int th, int param ) { //ZDD
+
+/PROBLEM PP/d
+
+/ITEMSET \*II = &PP\./c\
+ ITEMSET *II = &LCM_PP.II; //ZDD
+
+/TRSACT \*TT = &PP\./c\
+ TRSACT *TT = &LCM_PP.TT; //ZDD
+
+/SGRAPH \*SG = &PP\./c\
+ SGRAPH *SG = &LCM_PP.SG; //ZDD
+
+/PROBLEM_init (/c\
+ ERROR_MES = 0; //ZDD \
+ PROBLEM_init ( &LCM_PP ); //ZDD
+
+/LCM_read_param (argc/c\
+ switch(param) //ZDD \
+ { //ZDD \
+ case 12: //ZDD \
+ LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ break; //ZDD \
+ case 11: //ZDD \
+ LCM_PP.problem |= PROBLEM_CLOSED; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ break; //ZDD \
+ case 10: //ZDD \
+ LCM_PP.problem |= PROBLEM_FREQSET; //ZDD \
+ II->flag |= ITEMSET_PRE_FREQ; //ZDD \
+ II->flag |= ITEMSET_ALL; //ZDD \
+ break; //ZDD \
+ case 2: //ZDD \
+ LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD \
+ break; //ZDD \
+ case 1: //ZDD \
+ LCM_PP.problem |= PROBLEM_CLOSED; //ZDD \
+ break; //ZDD \
+ case 0: //ZDD \
+ default: //ZDD \
+ LCM_PP.problem |= PROBLEM_FREQSET; //ZDD \
+ II->flag |= ITEMSET_ALL; //ZDD \
+ } //ZDD \
+ LCM_PP.trsact_fname = fname1; //ZDD \
+ LCM_PP.trsact_pfname = fname2; //ZDD \
+ II->frq_lb = (WEIGHT)th; //ZDD
+
+/PROBLEM_init2 (/c\
+ PROBLEM_init2 ( &LCM_PP, PROBLEM_PRINT_SHRINK + PROBLEM_PRINT_FRQ ); //ZDD
+
+/LCM_init (&PP)/c\
+ LCM_init(&LCM_PP); //ZDD \
+ } //ZDD \
+ return 0; //ZDD \
+} //ZDD \
+ \
+CtoI CtoI_Lcm2 () { //ZDD \
+ CtoI F, G; //ZDD \
+ if ( ERROR_MES ) { //ZDD \
+ PROBLEM_end( &LCM_PP ); //ZDD \
+ return CtoI(-1); //ZDD \
+ } //ZDD \
+ else //ZDD \
+ { //ZDD \
+ F = CtoI(0); //ZDD
+
+/if ( ERROR_MES ) return;/c\
+ if ( ERROR_MES ) return CtoI(-1); //ZDD
+/LCM (&PP, TT->T\.clms/c\
+ if ( !ERROR_MES ) G = LCM (&LCM_PP, LCM_PP.TT.T.clms, &LCM_PP.oo, LCM_PP.TT.total_w_org, LCM_PP.TT.total_pw_org); //ZDD \
+ else G = CtoI(0); //ZDD \
+ F = CtoI_Union(F, G); //ZDD
+
+/ITEMSET_last/c\
+ ITEMSET_last_output (&LCM_PP.II); //ZDD
+
+/TT->sc = NULL/c\
+ LCM_PP.TT.sc = NULL; //ZDD
+
+/PROBLEM_end (&PP)/c\
+ PROBLEM_end (&LCM_PP); //ZDD
+
+/return (ERR/c\
+ return F; //ZDD
+
--- /dev/null
+
+int CtoI_Lcm1_ub ( char *fname1, char *fname2, int th, int param, int len_ub ) { //ZDD
+ITEMSET *II = &LCM_PP.II; //ZDD
+TRSACT *TT = &LCM_PP.TT; //ZDD
+SGRAPH *SG = &LCM_PP.SG; //ZDD
+
+ERROR_MES = 0; //ZDD
+PROBLEM_init ( &LCM_PP ); //ZDD
+switch(param) //ZDD
+{ //ZDD
+case 12: //ZDD
+LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD
+II->flag |= ITEMSET_PRE_FREQ; //ZDD
+break; //ZDD
+case 11: //ZDD
+LCM_PP.problem |= PROBLEM_CLOSED; //ZDD
+II->flag |= ITEMSET_PRE_FREQ; //ZDD
+break; //ZDD
+case 10: //ZDD
+LCM_PP.problem |= PROBLEM_FREQSET; //ZDD
+II->flag |= ITEMSET_PRE_FREQ; //ZDD
+II->flag |= ITEMSET_ALL; //ZDD
+break; //ZDD
+case 2: //ZDD
+LCM_PP.problem |= PROBLEM_MAXIMAL; //ZDD
+break; //ZDD
+case 1: //ZDD
+LCM_PP.problem |= PROBLEM_CLOSED; //ZDD
+break; //ZDD
+case 0: //ZDD
+default: //ZDD
+LCM_PP.problem |= PROBLEM_FREQSET; //ZDD
+II->flag |= ITEMSET_ALL; //ZDD
+} //ZDD
+LCM_PP.trsact_fname = fname1; //ZDD
+LCM_PP.trsact_pfname = fname2; //ZDD
+II->frq_lb = (WEIGHT)th; //ZDD
+
+II->ub = len_ub; // ham
+
+if ( ERROR_MES ) return (1);
+ TT->flag |= LOAD_PERM +TRSACT_FRQSORT +LOAD_DECSORT +LOAD_RM_DUP +TRSACT_MAKE_NEW +TRSACT_DELIV_SC +TRSACT_ALLOC_OCC + ((II->flag & ITEMSET_TRSACT_ID)?0: TRSACT_SHRINK) ;
+ if ( II->flag&ITEMSET_RULE ) TT->w_lb = -WEIGHTHUGE; else TT->w_lb = II->frq_lb;
+ SG->flag = LOAD_EDGE;
+PROBLEM_init2 ( &LCM_PP, PROBLEM_PRINT_SHRINK + PROBLEM_PRINT_FRQ ); //ZDD
+
+ if ( !ERROR_MES ){
+LCM_init(&LCM_PP); //ZDD
+} //ZDD
+return 0; //ZDD
+} //ZDD
+
--- /dev/null
+// VSOP Print (SAPPORO-1.25)
+// Shin-ichi MINATO (Jan. 16, 2008)
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <cstring>
+#include "CtoI.h"
+#include "vsop.h"
+#include "ZBDDDG.h"
+using namespace std;
+
+#define LINE 70
+
+BOut::BOut() {
+ _ffp=&cout;
+ _column = 0;
+ _isStdout=true;
+}
+BOut::BOut(char * str) {
+ _fp.open(str);
+ _ffp=&_fp;
+ _column = 0;
+ _isStdout=false;
+}
+BOut::~BOut() {
+ if(_isStdout==false){
+ _fp.close();
+ }
+}
+
+BOut& BOut::operator << (char* str)
+{
+ _column += strlen(str);
+ *_ffp << str;
+ return *this;
+}
+
+void BOut::Delimit()
+{
+ if(_column >= LINE)
+ {
+ _column = 2;
+ *_ffp << "\n ";
+ _ffp->flush();
+ }
+ else
+ {
+ _column++;
+ *_ffp << " ";
+ }
+}
+
+void BOut::Return()
+{
+ _column = 0;
+ *_ffp << "\n";
+ _ffp->flush();
+}
+void BOut::Set(char *str)
+{
+ _ffp->flush();
+ if(_isStdout==false){
+ _fp.close();
+ }
+ _fp.open(str);
+ _ffp=&_fp;
+ _column = 0;
+ _isStdout=false;
+}
+void BOut::Unset()
+{
+ _ffp->flush();
+ if(_isStdout==false){
+ _fp.close();
+ }
+ _ffp=&cout;
+ _column = 0;
+ _isStdout=true;
+}
+
+
+BOut bout;
+
+static int PutNum(CtoI a, int base);
+int PutNum(CtoI a, int base)
+{
+ if(a.TopItem() > 0) a = a.MaxVal();
+ int d = a.TopDigit() / 3 + 14;
+ char* s = new char[d];
+ if(s == 0) return 1;
+
+ int err;
+ if(base == 16) err = a.StrNum16(s);
+ else err = a.StrNum10(s);
+ if(err == 1)
+ {
+ delete[] s;
+ return 1;
+ }
+ int len = strlen(s);
+ bout << s;
+ delete[] s;
+ return 0;
+}
+
+static int Depth;
+static int* S_Var;
+static int PFflag;
+static int PF(CtoI, int);
+static int PF(CtoI a, int base)
+{
+ if(a.IsConst())
+ {
+ if(a.TopDigit() & 1) { bout.Delimit(); bout << "-"; a = -a; }
+ else if(PFflag == 1) { bout.Delimit(); bout << "+"; }
+
+ PFflag = 1;
+ int c1 = (a != 1);
+ if(c1 || Depth == 0)
+ {
+ bout.Delimit();
+ if(PutNum(a, base) == 1) return 1;
+ }
+ for(int i=0; i<Depth; i++)
+ {
+ bout.Delimit();
+ bout << 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) == 1) return 1;
+ Depth--;
+ b = a.Factor0(v);
+ if(b == 0) return 0;
+ if(b == CtoI_Null()) return 1;
+ return PF(b, base);
+}
+
+int PrintCtoI(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+
+ if(a == 0) bout << " 0";
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ S_Var = new int[lev];
+ PFflag = 0;
+ int err = PF(a, 10);
+ delete[] S_Var;
+ if(err == 1)
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ }
+ bout.Return();
+ return 0;
+}
+
+int PrintCtoI_16(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+
+ if(a == 0) bout << " 0";
+ else
+ {
+ int lev = BDD_LevOfVar(a.TopItem());
+ Depth = 0;
+ S_Var = new int[lev];
+ PFflag = 0;
+ int err = PF(a, 16);
+ delete[] S_Var;
+ if(err == 1)
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ }
+ bout.Return();
+ return 0;
+}
+
+int PrintDigital(CtoI a)
+{
+ int d = a.TopDigit();
+ for(int i=d; i>=0; i--)
+ {
+ if(d > 1)
+ {
+ char s[10];
+ sprintf(s, "%3d:", i);
+ bout << s;
+ }
+ if(PrintCtoI(a.Digit(i)) == 1) return 1;
+ }
+ return 0;
+}
+
+int PrintCase(CtoI a)
+{
+ char s[80];
+ while(CtoI_GT(a, 0) != 0)
+ {
+ if(a == CtoI_Null())
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ CtoI b = a.MaxVal();
+ b.StrNum10(s);
+ bout << s << ": ";
+ CtoI c = a.EQ_Const(b);
+ PrintCtoI(c);
+ a = a.FilterElse(c);
+ }
+ while(CtoI_LT(a, 0) != 0)
+ {
+ if(a == CtoI_Null())
+ {
+ bout << "...";
+ bout.Return();
+ return 1;
+ }
+ CtoI b = a.MinVal();
+ b.StrNum10(s);
+ bout << s << ": ";
+ CtoI c = a.EQ_Const(b);
+ PrintCtoI(c);
+ a = a.FilterElse(c);
+ }
+ return 0;
+}
+
+static void PutCode(int, int);
+void PutCode(int num, int digit) // num < 8, digit <=3
+{
+ for(int i=3; i>=0; i--)
+ if(i >= digit) bout << " ";
+ else if((num & (1 << i)) == 0) bout << "0";
+ else bout << "1";
+}
+
+static int MapVar[6];
+
+static int MapNum(CtoI a);
+int MapNum(CtoI a)
+{
+ int ovf = 0;
+ if(a.TopItem() > 0)
+ {
+ a = a.MaxVal();
+ ovf = 1;
+ }
+ int d = a.TopDigit() / 3 + 14;
+ char* s = new char[d];
+ if(s == 0) return 1;
+
+ int err;
+ err = a.StrNum10(s);
+ if(err == 1)
+ {
+ delete[] s;
+ return 1;
+ }
+ int len = strlen(s);
+ if(ovf == 0)
+ {
+ for(int i=0; i<5-len; i++) bout << " ";
+ bout << " " << s;
+ }
+ else
+ {
+ for(int i=0; i<4-len; i++) bout << " ";
+ bout << "(" << s << ")";
+ }
+ delete[] s;
+ return 0;
+}
+
+static int Map(CtoI, int);
+int Map(CtoI a, int dim)
+{
+ if(a == CtoI_Null()) return 1;
+ int x, y;
+ switch(dim)
+ {
+ case 0:
+ if(MapNum(a) == 1) return 1;
+ bout.Return();
+ return 0;
+ case 1:
+ bout << " " << VTable.GetName(MapVar[0]);
+ bout.Return();
+ PutCode(0, 1);
+ bout << " |";
+ if(MapNum(a.Factor0(MapVar[0])) == 1) return 1;
+ bout.Return();
+ PutCode(1, 1);
+ bout << " |";
+ if(MapNum(a.Factor1(MapVar[0])) == 1) return 1;
+ bout.Return();
+ return 0;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ y = dim / 2;
+ x = dim - y;
+ break;
+ default: ;
+ }
+ int mx = 1 << x;
+ int my = 1 << y;
+ for(int i=0; i<y; i++)
+ bout << " " << VTable.GetName(MapVar[i]);
+ bout << " :";
+ for(int i=y; i<dim; i++)
+ bout << " " << VTable.GetName(MapVar[i]);
+ bout.Return();
+ bout << " ";
+ for(int i=0; i<mx; i++)
+ {
+ if(i == 0 || i == 4) bout << " |";
+ int m = i ^ (i >> 1);
+ bout << " ";
+ PutCode(m, x);
+ }
+ bout.Return();
+ for(int j=0; j<my; j++)
+ {
+ if(j == 4)
+ {
+ bout << " |";
+ if(x == 3) bout << " |";
+ bout.Return();
+ }
+ int n = j ^ (j >> 1);
+ PutCode(n, y);
+ n <<= x;
+ for(int i=0; i<mx; i++)
+ {
+ if(i == 0 || i == 4) bout << " |";
+ int m = n | (i ^ (i >> 1));
+ CtoI ax = a;
+ for(int k=0; k<dim; k++)
+ if((m & (1 << (dim-k-1))) == 0)
+ ax = ax.Factor0(MapVar[k]);
+ else ax = ax.Factor1(MapVar[k]);
+ if(MapNum(ax) == 1) return 1;
+ }
+ bout.Return();
+ }
+ return 0;
+}
+
+int MapAll(CtoI a)
+{
+ int i=0;
+ int n = VTable.Used();
+ for(int j=0; j<n; j++)
+ {
+ MapVar[i++] = BDD_VarOfLev(n-j);
+ if(i == 6) break;
+ }
+ return Map(a, i);
+}
+
+int MapSel(CtoI a)
+{
+ int i=0;
+ int n = VTable.Used();
+ for(int j=0; j<n; j++)
+ {
+ int var = BDD_VarOfLev(n-j);
+ if(a == CtoI_Null()) return 1;
+ if(a == a.Factor0(var)) continue;
+ MapVar[i++] = var;
+ if(i == 6) break;
+ }
+ return Map(a, i);
+}
+
+static void PrintD(ZBDDDG *, bddword);
+void PrintD(ZBDDDG* dg, bddword ndx)
+{
+ ZBDDDG_Tag tag, tag2;
+ tag.Set(dg, ndx);
+ bddword ndx0, ndx2;
+ int top;
+ switch(tag.Type())
+ {
+ case ZBDDDG_C0:
+ bout << "0";
+ break;
+ case ZBDDDG_P1:
+ bout << "OR(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ tag2.Set(dg, ndx0);
+ if(tag2.Type() != ZBDDDG_OR)
+ PrintD(dg, ndx0);
+ else
+ {
+ ndx0 = tag2.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ }
+ }
+ bout.Delimit();
+ bout << "1";
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_LIT:
+ top = tag.Func().Top();
+ bout << VTable.GetName(top);
+ break;
+ case ZBDDDG_AND:
+ bout << "AND(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_OR:
+ bout << "OR(";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << ")";
+ break;
+ case ZBDDDG_OTHER:
+ bout << "[";
+ bout.Delimit();
+ ndx0 = tag.TopNdx();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ bout.Delimit();
+ PrintD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ bout.Delimit();
+ bout << "]";
+ break;
+ default:
+ bout << "???";
+ bout.Delimit();
+ break;
+ }
+}
+
+int PrintDecomp(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+ a = a.NonZero();
+ if(a == CtoI_Null()) return 1;
+ ZBDD f = a.GetZBDD();
+ ZBDDDG* dg = new ZBDDDG();
+ if(dg == 0) return 1;
+ bddword ndx = dg->Decomp(f);
+ if(ndx == ZBDDDG_NIL) { delete dg; return 1; }
+
+ PrintD(dg, ndx);
+ bout.Return();
+ delete dg;
+ return 0;
+}
+
+static int PrintDD_N;
+static void PrintDD(ZBDDDG *, bddword);
+void PrintDD(ZBDDDG* dg, bddword ndx)
+{
+ ZBDDDG_Tag tag, tag2;
+ tag.Set(dg, ndx);
+ bddword ndx0, ndx2;
+ char s[20];
+ int top;
+ int n;
+ switch(tag.Type())
+ {
+ case ZBDDDG_C0:
+ bout << "n0 [label=0];";
+ break;
+ case ZBDDDG_P1:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OR];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ tag2.Set(dg, ndx0);
+ if(tag2.Type() != ZBDDDG_OR)
+ PrintDD(dg, ndx0);
+ else
+ {
+ ndx0 = tag2.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag2.NextNdx();
+ }
+ }
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << " [label=1];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+ PrintDD_N++;
+
+ break;
+ case ZBDDDG_LIT:
+ top = tag.Func().Top();
+
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=";
+ bout << VTable.GetName(top);
+ bout << "];";
+ bout.Return();
+
+ break;
+ case ZBDDDG_AND:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=AND];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ case ZBDDDG_OR:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OR];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ case ZBDDDG_OTHER:
+ n = PrintDD_N++;
+ sprintf(s, "n%d", n); bout << s;
+ bout << " [label=OTHER];";
+ bout.Return();
+
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ ndx0 = tag.TopNdx();
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ while(ndx0 != ZBDDDG_NIL)
+ {
+ sprintf(s, "n%d", n); bout << s;
+ bout << " -> ";
+ sprintf(s, "n%d", PrintDD_N); bout << s;
+ bout << ";";
+ bout.Return();
+
+ PrintDD(dg, ndx0);
+ ndx0 = tag.NextNdx();
+ }
+ break;
+ default:
+ bout << "???";
+ break;
+ }
+}
+
+int PrintDecompDot(CtoI a)
+{
+ if(a == CtoI_Null()) return 1;
+ a = a.NonZero();
+ if(a == CtoI_Null()) return 1;
+ ZBDD f = a.GetZBDD();
+ ZBDDDG* dg = new ZBDDDG();
+ if(dg == 0) return 1;
+ bddword ndx = dg->Decomp(f);
+ if(ndx == ZBDDDG_NIL) { delete dg; return 1; }
+
+ bout << "digraph G {";
+ bout.Return();
+ PrintDD_N = 0;
+ PrintDD(dg, ndx);
+ bout << "}";
+ bout.Return();
+ delete dg;
+ return 0;
+}
+
--- /dev/null
+// VSOP - Header (SAPPORO-1.00M)
+// Shin-ichi MINATO (Jun. 22, 2006)
+#include <fstream>
+#define PROMPT "vsop> "
+#define DOCUMENT "vsop.help"
+
+int yyparse();
+
+struct VarEntry;
+
+class VarTable
+{
+ int _used;
+ int _hashsize;
+ VarEntry* _wheel;
+ VarEntry** _index;
+
+ void Enlarge(void);
+ VarEntry* GetEntry(char *);
+public:
+ VarTable(int size = 64);
+ ~VarTable(void);
+ int GetID(char *);
+ char* GetName(int);
+ int GetValue(int);
+ int GetGID(int);
+ void SetB(char *, int);
+ void SetB(char *, int, int);
+ void SetT(char *, int);
+ void SetT0(int, char *);
+ void SetT(char *, int, int);
+ int Used(void);
+};
+
+struct FuncEntry;
+class CtoI;
+
+class FuncTable
+{
+ int _used;
+ int _hashsize;
+ FuncEntry* _wheel;
+
+ void Enlarge(void);
+ FuncEntry* GetEntry(char *);
+public:
+ FuncTable(int size = 256);
+ ~FuncTable(void);
+ int CheckNew(char *);
+ CtoI& GetCtoI(char *);
+ void Set(char *, CtoI &);
+ int Used(void);
+};
+
+class BOut
+{
+ short _column;
+ ostream* _ffp;
+ ofstream _fp;
+ bool _isStdout;
+public:
+ BOut(void);
+ BOut(char * str);
+ ~BOut();
+ BOut& operator <<(char *);
+ void Delimit(void);
+ void Return(void);
+ void Set(char *);
+ void Unset(void);
+};
+
+extern VarTable VTable;
+extern FuncTable FTable;
+extern BOut bout;
+
+extern void yyerror(char *);
+
+extern int PrintCtoI(CtoI);
+extern int PrintCtoI_16(CtoI);
+extern int PrintDigital(CtoI);
+extern int PrintCase(CtoI);
+extern int MapAll(CtoI);
+extern int MapSel(CtoI);
+
+extern int PrintDecomp(CtoI);
+extern int PrintDecompDot(CtoI);
--- /dev/null
+require "rubygems"
+require "zdd_so"
+
+class String
+ alias_method :plus ,:+
+ def +(other)
+ if String == other.class then
+ return ( self.plus(other) )
+ else
+ return (ZDD.itemset(self) + other)
+ end
+ end
+
+ #宣言してからzdd生成(引数がmoduleだった場合"+"とする)
+ def v(val=nil,to="bottom")
+ if ( val.kind_of? Module) then
+ ZDD.symbol(self,nil,"bottom")
+ base = ZDD.itemset(self)
+ return base + val
+ else
+ ZDD.symbol(self,val,to)
+ return ZDD.itemset(self)
+ end
+ end
+end
+
+class Integer
+ def v
+ ZDD.constant(self)
+ end
+end
--- /dev/null
+//lcmのruby拡張
+#include <ruby.h>
+#include <fstream>
+#include <memory>
+#include <stack>
+//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
+#define MAX_LEN 409600
+#define HASH_MAX 4096000
+
+int env_nmax=0;
+bool env_warning = false;
+
+#include "setfunc.cpp"
+
+extern "C"{
+ void Init_zdd_so();
+}
+
+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 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++;
+ }
+}
+
+//----------------------- vsop_csvout -------------------------------
+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;
+}
+/*##vsop_csvout##*/
+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);
+ if(fs.is_open()){
+ CsvoutCtoI(*rmod->cmod,fs);
+ fs.close();
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"file oepn error");
+ }
+ return self;
+}
+//----------------------- vsop_csvout -------------------------------
+
+//----------------------- vsop_hashout -------------------------------
+static int PF_hash(CtoI a, int base,VALUE& hash)
+{
+ if(a.IsConst())
+ {
+ char *valstr;
+ kgAutoPtr2<char> a_ptr0;
+ try{
+ a_ptr0.set(new char[MAX_LEN]);
+ valstr = a_ptr0.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ 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;
+ kgAutoPtr2<char> a_ptr1;
+ try{
+ a_ptr1.set(new char[MAX_LEN]);
+ keystr = a_ptr1.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ *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();
+ 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);
+}
+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;
+}
+
+/*##vsop_hashout##*/
+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;
+}
+//----------------------- vsop_hashout -------------------------------
+
+//----------------------- vsop_each -------------------------------
+static int PF_array_each(CtoI a, VALUE& self)
+{
+ int sign=1;
+ if(a.IsConst())
+ {
+ 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(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);
+ }
+}
+/*##vsop_each##*/
+VALUE vsop_each(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI2Array_each(*rmod->cmod,self);
+ return Qtrue;
+}
+//----------------------- vsop_each -------------------------------
+
+//----------------------- vsop_to_a -------------------------------
+static int PF_array(CtoI a,VALUE& array)
+{
+ if(a.IsConst())
+ {
+ char *valstr;
+ kgAutoPtr2<char> a_ptr0;
+ try{
+ a_ptr0.set(new char[MAX_LEN]);
+ valstr = a_ptr0.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ 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;
+ kgAutoPtr2<char> a_ptr1;
+ try{
+ a_ptr1.set(new char[MAX_LEN]);
+ keystr = a_ptr1.get();
+ }catch(...){
+ rb_raise(rb_eRuntimeError,"memory allocation error");
+ }
+ *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;
+}
+/*##vsop_to_a##*/
+VALUE vsop_to_a(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE array = CtoI2Array(*rmod->cmod);
+
+ return array;
+}
+//----------------------- vsop_to_a -------------------------------
+
+//----------------------- vsop_to_s -------------------------------
+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;
+}
+
+/*##vsop_to_s##*/
+VALUE vsop_to_s(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ VALUE str = CtoI2String(*rmod->cmod);
+ return str;
+}
+//----------------------- vsop_to_s -------------------------------
+
+
+//----------------------- vsop_each_item -------------------------------
+static int PF_itemarray(CtoI a, VALUE& self)
+{
+ int sign=1;
+ if(a.IsConst())
+ {
+ 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);
+ }
+}
+
+/*##vsop_each_item##*/
+VALUE vsop_each_item(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ CtoI2ItemArray(*rmod->cmod,self);
+ return Qtrue;
+}
+//----------------------- vsop_each_item -------------------------------
+
+
+//この値は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;
+}
+
+/*##vsop_delta##*/
+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)
+{
+ 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;
+}
+
+/*##vsop_symbol##*/
+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;
+}
+
+/*##vsop_itemset##*/
+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;
+}
+
+/*##vsop_constant##*/
+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;
+}
+// ------------------------------ パターン長制約を入れたlcm over zdd
+
+VALUE vsop_lcm_nomal_ub(VALUE v1,VALUE v2,VALUE v3,VALUE v4 , VALUE self)
+{
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ CtoI *ctoi_fin;
+ 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 (2nd 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 (5th 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(VALUE v1,VALUE v2,VALUE v3,VALUE v4 ,VALUE v5, VALUE self)
+{
+ if(init_cnt==0){ BDDV_Init(256, env_nmax);}
+ init_cnt++;
+
+ CtoI *ctoi_fin;
+ 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);
+}
+
+/*##vsop_lcm##*/
+VALUE vsop_lcm(int argc, VALUE *argv, VALUE self)
+{
+ VALUE rtnval;
+ if(argc==3){
+ rtnval = vsop_lcm_nomal(argc,argv,self);
+ }
+ else if(argc==4){
+ rtnval = vsop_lcm_order(argc,argv,self);
+ }
+ else if(argc==5){
+ VALUE v1,v2,v3,v4,v5;
+ rb_scan_args(argc, argv,"50",&v1,&v2,&v3,&v4,&v5);
+ if(TYPE(v4)!=T_STRING || strcmp(RSTRING_PTR(v4),"")==0 ){
+ rtnval = vsop_lcm_nomal_ub(v1,v2,v3,v5,self);
+ }
+ else{
+ rtnval = vsop_lcm_order_ub(v1,v2,v3,v4,v5,self);
+ }
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"argument size error ");
+ }
+ return rtnval;
+}
+
+// ------------------------------ パターン長制約を入れたlcm over zdd ここまで 2010/02/28
+
+/*##vsop_same##*/
+ 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;
+ }
+}
+
+/*##vsop_diff##*/
+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;
+ }
+}
+
+/*##vsop_print_size##*/
+VALUE vsop_print_size( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+ int val = rmod->cmod->Size();
+ return INT2NUM(val);
+}
+
+/*##vsop_print_totalsize##*/
+VALUE vsop_print_totalsize(VALUE self){
+ rb_gc();
+ BDD_GC();
+ VALUE rtn = INT2NUM(BDD_Used());
+
+ return rtn;
+}
+
+/*##vsop_print_count##*/
+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 = rb_cstr_to_inum(s, 10, Qfalse);
+ return rtn;
+}
+
+/*##vsop_print_density##*/
+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;
+}
+
+/*##vsop_print_value##*/
+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;
+}
+
+/*##vsop_print_maxcover##*/
+VALUE vsop_print_maxcover(VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+
+ CtoI *ctoi_fin;
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ ctoi_fin = new CtoI(0);
+ rb_raise(rb_eRuntimeError,"08Memory overflow");
+ }
+ if(*ctoitmp == 0){
+ ctoi_fin = new CtoI(0);
+ }
+ else
+ {
+ ZBDD f = ctoitmp -> GetZBDD();
+ if(MaxCost(f)==0){
+ ctoi_fin = new CtoI(1);
+ }
+ else
+ {
+ CtoI ctmp(1);
+ 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)
+ {
+ f = f1;
+ ctmp = ctmp.AffixVar(var);
+ }
+ else f = f0;
+ }
+ ctoi_fin = new CtoI(ctmp);
+ }
+ }
+
+ 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);
+}
+
+/*##vsop_print_maxcost##*/
+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;
+}
+
+/*##vsop_print_mincover##*/
+VALUE vsop_print_mincover( VALUE self){
+ Vsop_Ruby* rmod;
+ Data_Get_Struct(self,Vsop_Ruby,rmod);
+
+ CtoI *ctoi_fin;
+
+ auto_ptr<CtoI> auto_p(new CtoI(*rmod->cmod));
+ CtoI *ctoitmp = auto_p.get();
+
+ *ctoitmp = ctoitmp -> NonZero();
+ if(*ctoitmp == CtoI_Null())
+ {
+ *ctoitmp = 0;
+ ctoi_fin = new CtoI(0);
+ rb_raise(rb_eRuntimeError,"10Memory overflow");
+ }
+ if(*ctoitmp == 0){
+ ctoi_fin = new CtoI(0);
+ }
+ else
+ {
+ ZBDD f = ctoitmp -> GetZBDD();
+ if(MinCost(f)==0){
+ ctoi_fin = new CtoI(1);
+ }
+ else
+ {
+ CtoI ctmp(1);
+ 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)
+ {
+ f = f1;
+ ctmp = ctmp.AffixVar(var);
+ }
+ else f = f0;
+ }
+ ctoi_fin = new CtoI(ctmp);
+ }
+ }
+ 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);
+}
+
+/*##vsop_print_mincost##*/
+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;
+}
+
+/*##vsop_print_decomp##*/
+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;
+}
+
+/*##vsop_print_export##*/
+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;
+}
+
+
+static char* show_use_para[][2]={
+ {"hex","/hex"},
+ {"bit", "/bit"},
+ {"case", "/case"},
+ {"map", "/map"},
+ {"rmap", "/rmap"},
+ {"decomp", "/decomp"},
+ {"",""}
+};
+
+static char* show_notuse_para[]={
+ "size", "count", "density", "value", "maxcover", "maxcost", "mincover",
+ "mincost", "plot","decompd", "imply0","symmetry",
+ "imply", "coimply0", "coimply2", "coimply","export",
+ "/size", "/count", "/density", "/value", "/maxcover",
+ "/maxcost", "/mincover", "/mincost","/plot",
+ "/decompd", "/imply0", "/symmetry", "/imply",
+ "/coimply0", "/coimply2", "/coimply", "/export",""
+};
+
+/*##vsop_show##*/
+VALUE vsop_show(int argc, VALUE *argv, VALUE self){
+ // bit,hex,map,rmap,case,decompのみ動くようにする
+ 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);
+ for(size_t i=0;*show_use_para[i][0]!='\0';i++){
+ if( !strcmp(argtmp,show_use_para[i][0])||
+ !strcmp(argtmp,show_use_para[i][1])){
+ rtnval = vsop_print_arg1(self,show_use_para[i][0]);
+ return rtnval;
+ }
+ }
+ bool output = true;
+ for(const char *p=*show_notuse_para ;*p!='\0';p++){
+ if( !strcmp(argtmp,p)){
+ output=false;
+ break;
+ }
+ }
+ if(output){
+ rtnval = vsop_print_arg1(self,argtmp);
+ return rtnval;
+ }
+ rb_raise(rb_eRuntimeError,"Illegal switch(/bit,/hex,/map,/rmap,/case,/decomp)");
+ }
+ else if(argc == 2)
+ {
+ VALUE v1,v2;
+ rb_scan_args(argc, argv,"20",&v1,&v2);
+ char *argtmp = RSTRING_PTR(v1);
+ for(size_t i=0;*show_use_para[i][0]!='\0';i++){
+ if( !strcmp(argtmp,show_use_para[i][0])||
+ !strcmp(argtmp,show_use_para[i][1])){
+ rtnval = vsop_print_arg2(argc,argv,self);
+ return rtnval;
+ }
+ }
+ rb_raise(rb_eRuntimeError,"parameter error(/bit,/hex,/map,/rmap,/case,/decomp)");
+ }
+ else{
+ rb_raise(rb_eRuntimeError,"number of argument is 0 or 1 or 2");
+ }
+ return rtnval;
+}
+
+/*##vsop_partly##*/
+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);
+}
+
+/*##vsop_const_to_i##*/
+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() {
+/*##zdd##*/
+
+ //環境変数取得
+ 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_iv_set(vsop_main,"@partly", Qfalse );
+
+ //モジュール変数設定
+ 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, "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, "maxweight", RUBY_METHOD_FUNC(vsop_maxval), 0);
+ rb_define_module_function(vsop_main, "minweight", RUBY_METHOD_FUNC(vsop_minval), 0);
+ rb_define_module_function(vsop_main,"totalweight", 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, "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, "cost", RUBY_METHOD_FUNC(vsop_print_value), 0);
+ rb_define_module_function(vsop_main, "maxcover", RUBY_METHOD_FUNC(vsop_print_maxcover), 0);
+ 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), 0);
+ rb_define_module_function(vsop_main, "mincost", RUBY_METHOD_FUNC(vsop_print_mincost), 0);
+ 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);
+
+}
--- /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);
+
+}