diff --git a/CMakeLists.txt b/CMakeLists.txt index 04ff21b..47663a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,7 +28,6 @@ set(TTFPARSER_ROOT ${EXTERNAL_ROOT}/ttf-parser) set(FREETYPE_ROOT ${EXTERNAL_ROOT}/freetype) set(SPIRV_ROOT ${EXTERNAL_ROOT}/SPIRV-Cross) set(ENTT_ROOT ${EXTERNAL_ROOT}/entt) -set(NLOPT_ROOT ${EXTERNAL_ROOT}/nlopt) set(ODEINT_ROOT ${EXTERNAL_ROOT}/odeint) set(THREADPOOL_ROOT ${EXTERNAL_ROOT}/thread-pool) set(ZLIB_ROOT ${EXTERNAL_ROOT}/zlib) @@ -105,6 +104,7 @@ if(MSVC) target_compile_options(Engine PUBLIC /Zi /MP14 /W4 /DEBUG "/WX-") target_sources(Engine INTERFACE $ + $ $ ) install(FILES @@ -174,3 +174,10 @@ install( DESTINATION ${CMAKE_INSTALL_PREFIX} ) + +install( + DIRECTORY + ${CMAKE_SOURCE_DIR}/res + DESTINATION + ${CMAKE_INSTALL_PREFIX} +) \ No newline at end of file diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index bd634d7..d2e776e 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -50,7 +50,7 @@ add_subdirectory(${ENTT_ROOT}) #--------------thread-pool------------------------------ add_subdirectory(${THREADPOOL_ROOT}) -target_compile_options(ThreadPool INTERFACE "/WX-") +target_compile_options(ThreadPool INTERFACE "/W0") #--------------SLang------------------------------ string(TOLOWER release_${CMAKE_PLATFORM} SLANG_CONFIG) diff --git a/external/sdpa/AUTHORS b/external/sdpa/AUTHORS new file mode 100644 index 0000000..bb17bec --- /dev/null +++ b/external/sdpa/AUTHORS @@ -0,0 +1,15 @@ +-------------------------------------------------- +Copyright (C) 1995-2011 SDPA Project +-------------------------------------------------- + +We appreciate your comments, suggestions, and questions about SDP +and/or the SDPA software. We also consider questions such as "I can +not install the SDPA on my computer," "I can not formulate my problem +in SDPA format," "I found a bug in the software," etc. + + +To contact SDPA project, refer the following Web page. +https://sdpa.sourceforge.net/contact.html + +The member list of SDPA project is available there. + diff --git a/external/sdpa/COPYING b/external/sdpa/COPYING new file mode 100644 index 0000000..623b625 --- /dev/null +++ b/external/sdpa/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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. + + 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.) + +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. + + 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. + + 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 + + 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. + + + Copyright (C) + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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) year 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. + + , 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. diff --git a/external/sdpa/ChangeLog b/external/sdpa/ChangeLog new file mode 100644 index 0000000..a56684d --- /dev/null +++ b/external/sdpa/ChangeLog @@ -0,0 +1,10 @@ +SDPA-C 7.3.8 from SDPA-C 6 / 2013-10-21 Makoto Yamashita + * Based on SDPA 7.3.8 + * Employ CHOLMOD for sparse Cholesky factoization + to the variable matrices + * Efficient computation for the Schur complement matrix + * New callable library + * New Matlab/Octave interface + * Multiple-threaded computation + + diff --git a/external/sdpa/INSTALL b/external/sdpa/INSTALL new file mode 100644 index 0000000..bb1a856 --- /dev/null +++ b/external/sdpa/INSTALL @@ -0,0 +1,160 @@ + +SDPA-C 7.3.X Install Manual + +[Copyright (C) 2004-2013 SDPA Project] + +This text explains how to install SDPA-C. +If you have questions on the installation, +please contact us from +http://sdpa.sourceforge.net/contact.html + +The user-manual of SDPA is available for SDPA-C, and can be downloaded at +https://sourceforge.net/projects/sdpa/files/sdpa/sdpa.7.1.1.manual.20080618.pdf/download + +--- index ------------------------------------ + +1. Install the SDPA-C +2. Compile callable-library example [optional] +3. Compile Matlab Interface [optional] +4. Difference from SDPA +5. If you have some trouble + +---------------------------------------------- + + +1. Install the SDPA-C + +(1) Check your environment + +Requirement: wget, git +Recommendation: gcc (>= 4.2), g++ (>= 4.2), gfortran (>=4.2) + +We have checked the compilation on RedHat Linux (version 6) +and Debian (wheezy). +Other C/C++/Fortran compilers than gcc/g++/gfortran may be +available, but we have not tested them. + +(2) Download the SDPA from the SDPA Homepage + +http://sdpa.sourceforge.net/download.html + +You can get the sdpa-c_7.3.X.tar.gz, then unpack the file +$ tar xzf sdpa-c_7.3.X.tar.gz +You will find the directory 'sdpa-c'. +$ cd sdpa-c + +(3) Edit make.inc + +At least you should check 'sdpac_dir'. +In the default setting, sdpac_dir is $(HOME)/sdpa-c. +In other words, the default setting assumes +you unpacked the downloaded file in your home directory. + +(4) Compile SDPA-C + +$ make all +will compile SuiteSparse, MUMPS, OpenBLAS, then SDPA-C. + +If you want compile them step by step, +$ make SuiteSparse +$ make MUMPS +$ make OpenBLAS +$ make sdpa-c + + +(5) Test SDPA-C +Try the following command to execute sdpa + $ cd $HOME/sdpa-c + $ ./sdpa-c +Then you will see message from SDPA and can check command line options. +To solve input dat-s and write its result, + $ ./sdpa example1.dat-s example1.result + +If you specify the number of threads with the SDPA-C, +set OMP_NUM_THREADS environment variable(ex. export OMP_NUM_THREADS=4). + +---------------------------------------------- +2. Compile callable-library example (optional) + +To compile callable-library example, use 'make' command +in 'libexample' directory + $ cd $HOME/sdpa-c/libexample + $ make + +The details of callable-library can be found in SDPA user manual. + +---------------------------------------------- +3. Compile Matlab Interface (optional) + +To compile the Matlab interface, use 'make matlab' command. + $ cd $HOME/sdpa-c + $ make matlab + +If you use Octave instead of Matlab, then + $ cd $HOME/sdpa-c + $ make octave + +Since the usage of this Matlab Interface as SDPA-M 6.2.0, +SDPA-M 6.2.0 manual is very useful. +(https://sourceforge.net/projects/sdpa/files/sdpa-m/sdpamManual.pdf/download) +In addition, the file 'mex/CommandList.txt' summarizes +each command. + + +When you have trouble with SDPA-M(Matlab environment), +the following command will display useful messages. + +$ matlab -Dgdb +[On gdb environment] +(gdb) run -nodisplay +[On Matlab environment] +>> (Call SDPA-M by sdpam or sedumiwrap) +If Matlab aborts, try the following command in gdb environment. +(gdb) where +The command 'where' will display what happened. +To exit gdb environment, +(gdb) quit + +In some case, the segmentation fault may be avoided by +$ export LD_PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/4.4/libgfortran.so:$LD_PRELOAD +$ export LD_PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/4.4/libstdc++.so:$LD_PRELOAD +$ export LD_PRELOAD=/usr/lib/gcc/x86_64-linux-gnu/4.4/libgcc_s.so:$LD_PRELOAD +$ matlab +In particular, when the gcc version is higher than the version Matlab +assumes, Matlab sometimes can not load appropriate shared libraries. +The command above load the libraries before Matlab launches. + +------------------------------------------------------- +4. Deference from SDPA + +(1) Since SDPA-C employs the completion method, which extensively +uses the structural sparsity, the SDPA dense format is not acceptable. +More precisely, example1.dat-s is available while example1.dat is not. + +(2) In the callable library, some function mainly related to the dense +input file are not available. +In addition, the function SDPA::terminate() is renamed as +SDPA::finalize(). +In libexample directory, the difference in example1,2,5.cpp from SDPA +is only terminate() to finalize(). +However, the example3,4,6.cpp in SDPA contained the functions +which are not available in SDPA-C. We removed these examples +from the SDPA-C package. + +(3) param.sdpa is renamed as param.sdpaC. + +(4) The matlab interface only contains the mex functions of SDPA-C. +If you want to read the SDPA sparse format, you should employ +such routines from SDPA. We suggest you add the paths of both SDPA +and SDPA-C to the Matlab search path. + +------------------------------------------------------- +5. If you have some trouble + +If some bugs are found or you encounter some trouble +when you are compiling SDPA, please let us know from +http://sdpa.sourceforge.net/contact.html + +In particular, attaching error messages and/or 'config.log' file +is very useful to let us understand your situation. + diff --git a/external/sdpa/Makefile b/external/sdpa/Makefile new file mode 100644 index 0000000..466d551 --- /dev/null +++ b/external/sdpa/Makefile @@ -0,0 +1,100 @@ + +## This is Makefile for SDPA-C + +## Requirement :: wget, git +## Recommendation :: gcc (>= 4.2), g++ (>=4.2), gfortran (>= 4.2), + +## Before the compilation, examine the file 'make.inc' + +## To compile SDPA-C, 'make all' +## This will compile SuiteSparse, MUMPS, OpenBLAS, then SDPA-C +## To compile mex, 'make matlab' or 'make octave' + +-include make.inc +-include make.obj +.PHONY: SuiteSparse MUMPS OpenBLAS + +all: $(sdpac_exe) + +matlab: all + (cd mex; make DEVELOPEMENT_STAGE=1) + @echo === Add "$(sdpac_dir)/mex" to your Matlab path. === + +octave: all + (cd mex; make DEVELOPEMENT_STAGE=1 COMPILE_ENVIRONMENT=octave) + @echo === Add "$(sdpac_dir)/mex" to your octave path. === + +$(sdpac_exe): SuiteSparse MUMPS OpenBLAS $(sdpac_lib) sdpa_exe.o + $(CXX) $(CXXFLAGS) -o $@ sdpa_exe.o $(sdpac_lib) $(sdpac_all_lib) + +$(sdpac_lib): $(OBJ) + rm -f $@ + ar r $@ $(OBJ) + ranlib $@ + +.cpp.o: + $(CXX) $(CXXFLAGS) -c -o $@ -I. $(sdpac_all_include) \ + -DVERSION=$(SDPAC_VERSION) $< + +SuiteSparse:$(suitesparse_lib) +$(suitesparse_lib): + (cd $(sdpac_dir); \ + rm -rf SuiteSparse; \ + wget http://faculty.cse.tamu.edu/davis/SuiteSparse/SuiteSparse-$(suitesparse_ver).tar.gz; \ + tar xzf SuiteSparse-$(suitesparse_ver).tar.gz; \ + rm -f SuiteSparse-$(suitesparse_ver).tar.gz; ) + (cd $(suitesparse_dir); \ + cd $(suitesparse_dir)/metis-5.1.0; \ + make config cc=$(CC); \ + make ; \ + cp build/*/libmetis/libmetis.a . ) + ( cd $(suitesparse_dir); \ + echo CC = $(CC) >> $(suitesparse_dir)/SuiteSparse_config/SuiteSparse_config.mk; \ + echo CF = $(CFLAGS) -fexceptions >> $(suitesparse_dir)/SuiteSparse_config/SuiteSparse_config.mk; \ + echo CC = $(CC) >> $(suitesparse_dir)/CSparse/Lib/Makefile; \ + cd $(suitesparse_dir); \ + make) + +MUMPS:$(mumps_lib) +$(mumps_lib): + (cd $(sdpac_dir); \ + rm -rf mumps; \ + wget wget http://ftp.de.debian.org/debian/pool/main/m/mumps/$(mumps_tar_file); \ + tar xzf $(mumps_tar_file); \ + rm -f $(mumps_tar_file); \ + mv -f MUMPS_$(mumps_ver)/ $(mumps_dir); \ + cd $(mumps_dir); \ + cp Make.inc/Makefile.inc.generic.SEQ Makefile.inc; \ + echo "CC = " $(CC) >> Makefile.inc; \ + echo "FC = " $(FC) >> Makefile.inc; \ + echo "FL = " $(FC) >> Makefile.inc; \ + echo "OPTC = " $(CFLAGS) >> Makefile.inc; \ + echo "OPTF = " $(FCFLAGS) >> Makefile.inc; \ + echo "OPTL = " $(FCFLAGS) >> Makefile.inc; \ + echo "LPORDDIR = "`pwd`"/PORD/lib/" >> Makefile.inc; \ + echo "IPORDDIR = "`pwd`"/PORD/include/" >> Makefile.inc; \ + make d;) + +OpenBLAS:$(openblas_lib) +$(openblas_lib): + (cd $(sdpac_dir); \ + rm -rf OpenBLAS; \ + git clone git://github.com/xianyi/OpenBLAS; \ + mv -f OpenBLAS $(openblas_dir); \ + cd $(openblas_dir); \ + make NO_WARMUP=1 USE_THREAD=1 USE_OPENMP=1 FC=$(FC) CC=$(CC) libs netlib) + +clean: + rm -rf *~ *.o + @echo "## If you want to clean SuiteSparse, MUMPS, OpenBLAS," + @echo "## then use 'make dist-clean'" + +dist-clean: clean + rm -f $(sdpac_lib) $(sdpac_exe) + (cd $(sdpac_dir); \ + rm -rf SuiteSparse; rm -rf mumps; rm -rf OpenBLAS) + (cd mex; make dist-clean) + +# -include make.head must be the bottom +# otherwise, you need to assign make 'all'. +-include make.head diff --git a/external/sdpa/Makefile.in b/external/sdpa/Makefile.in new file mode 100644 index 0000000..7ac3cee --- /dev/null +++ b/external/sdpa/Makefile.in @@ -0,0 +1,24 @@ +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC +CC = gcc +OPTFLAGS = -O3 -fPIC diff --git a/external/sdpa/Makefile.inc b/external/sdpa/Makefile.inc new file mode 100644 index 0000000..c0742b5 --- /dev/null +++ b/external/sdpa/Makefile.inc @@ -0,0 +1,8 @@ +CC = gcc +FC = gfortran +FL = gfortran +OPTC = -O3 -fPIC +OPTF = -O3 -fPIC +OPTL = -O3 -fPIC +LPORDDIR = /home/makoto/sdpa-c/PORD/lib/ +IPORDDIR = /home/makoto/sdpa-c/PORD/include/ diff --git a/external/sdpa/NEWS b/external/sdpa/NEWS new file mode 100644 index 0000000..c9256a8 --- /dev/null +++ b/external/sdpa/NEWS @@ -0,0 +1,2 @@ +For the latest news on SDPA, please refer to +http://sdpa.sourceforge.net/ diff --git a/external/sdpa/example1.dat-s b/external/sdpa/example1.dat-s new file mode 100644 index 0000000..58bc643 --- /dev/null +++ b/external/sdpa/example1.dat-s @@ -0,0 +1,12 @@ +"Example 1: mDim = 3, nBLOCK = 1, {2}" + 3 = mDIM + 1 = nBLOCK + 2 = bLOCKsTRUCT +48, -8, 20 +0 1 1 1 -11 +0 1 2 2 23 +1 1 1 1 10 +1 1 1 2 4 +2 1 2 2 -8 +3 1 1 2 -8 +3 1 2 2 -2 diff --git a/external/sdpa/example2-1.dat-s b/external/sdpa/example2-1.dat-s new file mode 100644 index 0000000..9fb3f4f --- /dev/null +++ b/external/sdpa/example2-1.dat-s @@ -0,0 +1,70 @@ +5 +1 +7 +1.1 -10.0 6.6 19.0 4.1 +0 1 1 1 1.8 +0 1 2 2 -4.0 +0 1 3 3 -1.4 +0 1 3 4 -3.2 +0 1 4 4 -28.0 +0 1 5 5 15.0 +0 1 5 6 -12.0 +0 1 5 7 2.1 +0 1 6 6 16.0 +0 1 6 7 -3.8 +0 1 7 7 15.0 +1 1 1 1 -4.5 +1 1 2 2 -3.5 +1 1 3 3 0.5 +1 1 3 4 5.2 +1 1 4 4 -5.3 +1 1 5 5 7.8 +1 1 5 6 -2.4 +1 1 5 7 6.0 +1 1 6 6 4.2 +1 1 6 7 6.5 +1 1 7 7 2.1 +2 1 1 1 -0.2 +2 1 2 2 -3.7 +2 1 3 3 1.7 +2 1 3 4 7.0 +2 1 4 4 -9.3 +2 1 5 5 -1.9 +2 1 5 6 -0.9 +2 1 5 7 -1.3 +2 1 6 6 -0.8 +2 1 6 7 -2.1 +2 1 7 7 4.0 +3 1 1 1 -3.3 +3 1 2 2 -4.0 +3 1 3 3 6.3 +3 1 3 4 -7.5 +3 1 4 4 -3.3 +3 1 5 5 0.2 +3 1 5 6 8.8 +3 1 5 7 5.4 +3 1 6 6 3.4 +3 1 6 7 -0.4 +3 1 7 7 7.5 +4 1 1 1 4.8 +4 1 2 2 9.7 +4 1 3 3 -2.4 +4 1 3 4 -2.5 +4 1 4 4 -2.9 +4 1 5 5 3.4 +4 1 5 6 -3.2 +4 1 5 7 -4.5 +4 1 6 6 3.0 +4 1 6 7 -4.8 +4 1 7 7 3.6 +5 1 1 1 6.1 +5 1 2 2 -1.5 +5 1 3 3 -6.5 +5 1 3 4 -5.4 +5 1 4 4 -6.6 +5 1 5 5 6.7 +5 1 5 6 -7.2 +5 1 5 7 -3.6 +5 1 6 6 7.3 +5 1 6 7 -3.0 +5 1 7 7 -1.4 diff --git a/external/sdpa/example2.dat b/external/sdpa/example2.dat new file mode 100644 index 0000000..bc09281 --- /dev/null +++ b/external/sdpa/example2.dat @@ -0,0 +1,54 @@ +*Example 2: +*mDim = 5, nBLOCK = 3, {2,3,-2} + 5 = mDIM + 3 = nBLOCK + 2 3 -2 = bLOCKsTRUCT +{1.1, -10, 6.6 , 19 , 4.1} +{ +{ { -1.4, -3.2 }, + { -3.2,-28 } } +{ { 15, -12, 2.1 }, + {-12, 16, -3.8 }, + { 2.1, -3.8, 15 } } + { 1.8, -4.0 } +} +{ +{ { 0.5, 5.2 }, + { 5.2, -5.3 } } +{ { 7.8, -2.4, 6.0 }, + { -2.4, 4.2, 6.5 }, + { 6.0, 6.5, 2.1 } } + { -4.5, -3.5 } +} +{ +{ { 1.7, 7.0 }, + { 7.0, -9.3 } } +{ {-1.9, -0.9, -1.3 }, + {-0.9, -0.8, -2.1 }, + {-1.3, -2.1, 4.0 } } + {-0.2, -3.7 } +} +{ +{ { 6.3, -7.5 }, + {-7.5, -3.3 } } +{ { 0.2, 8.8, 5.4 }, + { 8.8, 3.4, -0.4 }, + { 5.4, -0.4, 7.5 } } + {-3.3, -4.0 } +} +{ +{ { -2.4, -2.5 }, + { -2.5, -2.9 } } +{ { 3.4, -3.2, -4.5 }, + { -3.2, 3.0, -4.8 }, + { -4.5, -4.8, 3.6 } } + { 4.8 , 9.7 } +} +{ +{ { -6.5, -5.4 }, + { -5.4, -6.6 } } +{ { 6.7, -7.2, -3.6 }, + { -7.2, 7.3, -3.0 }, + { -3.6, -3.0, -1.4 } } + { 6.1, -1.5 } +} diff --git a/external/sdpa/example2.dat-s b/external/sdpa/example2.dat-s new file mode 100644 index 0000000..cdf8bf3 --- /dev/null +++ b/external/sdpa/example2.dat-s @@ -0,0 +1,72 @@ +*Example 2: +*mDim = 5, nBLOCK = 3, {2,3,-2} + 5 = mDIM + 3 = nBLOCK + 2 3 -2 = bLOCKsTRUCT +1.1, -10, 6.6 , 19 , 4.1 +0 1 1 1 -1.4 +0 1 1 2 -3.2 +0 1 2 2 -28 +0 2 1 1 15 +0 2 1 2 -12 +0 2 1 3 2.1 +0 2 2 2 16 +0 2 2 3 -3.8 +0 2 3 3 15 +0 3 1 1 1.8 +0 3 2 2 -4.0 +1 1 1 1 0.5 +1 1 1 2 5.2 +1 1 2 2 -5.3 +1 2 1 1 7.8 +1 2 1 2 -2.4 +1 2 1 3 6.0 +1 2 2 2 4.2 +1 2 2 3 6.5 +1 2 3 3 2.1 +1 3 1 1 -4.5 +1 3 2 2 -3.5 +2 1 1 1 1.7 +2 1 1 2 7.0 +2 1 2 2 -9.3 +2 2 1 1 -1.9 +2 2 1 2 -0.9 +2 2 1 3 -1.3 +2 2 2 2 -0.8 +2 2 2 3 -2.1 +2 2 3 3 4.0 +2 3 1 1 -0.2 +2 3 2 2 -3.7 +3 1 1 1 6.3 +3 1 1 2 -7.5 +3 1 2 2 -3.3 +3 2 1 1 0.2 +3 2 1 2 8.8 +3 2 1 3 5.4 +3 2 2 2 3.4 +3 2 2 3 -0.4 +3 2 3 3 7.5 +3 3 1 1 -3.3 +3 3 2 2 -4.0 +4 1 1 1 -2.4 +4 1 1 2 -2.5 +4 1 2 2 -2.9 +4 2 1 1 3.4 +4 2 1 2 -3.2 +4 2 1 3 -4.5 +4 2 2 2 3.0 +4 2 2 3 -4.8 +4 2 3 3 3.6 +4 3 1 1 4.8 +4 3 2 2 9.7 +5 1 1 1 -6.5 +5 1 1 2 -5.4 +5 1 2 2 -6.6 +5 2 1 1 6.7 +5 2 1 2 -7.2 +5 2 1 3 -3.6 +5 2 2 2 7.3 +5 2 2 3 -3.0 +5 2 3 3 -1.4 +5 3 1 1 6.1 +5 3 2 2 -1.5 diff --git a/external/sdpa/libexample/Makefile b/external/sdpa/libexample/Makefile new file mode 100644 index 0000000..a7af784 --- /dev/null +++ b/external/sdpa/libexample/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# List of examples for callable-library +# +# example1.cpp: Solve example1.dat-s using inputElements +# example2.cpp: Solve example2.dat using inputElements +# example5.cpp: Solve problems reading from file +# +############################################################# + +.PHONY: all lib clean cleanall distclean +.SUFFIXES: .exe + +# after "make install", you can find +# 'make.inc' in 'share/sdpa' sub-directory under the installed directory +# For example +# make MAKE_INCLUDE_DIR=/usr/share/sdpa +# or +# make MAKE_INCLUDE_DIR=/usr/local/share/sdpa + +MAKE_INCLUDE_DIR=.. +-include ${MAKE_INCLUDE_DIR}/make.inc +# after "make install", you can find +# 'make.inc' in 'share/sdpa' sub-directory under the installed directory +# For example +# make MAKE_INCLUDE_DIR=/usr/share/sdpa +# or +# make MAKE_INCLUDE_DIR=/usr/local/share/sdpa + + +SRC = $(wildcard example?.cpp) +EXE = $(subst .cpp,.exe,$(SRC)) + +all: ${EXE} + +%.exe: %.o + ${CXX} ${CXXFLAGS} -o $@ $< ${sdpac_dir}/${sdpac_lib} ${sdpac_all_lib} +.cpp.o: + ${CXX} -c ${CXXFLAGS} \ + -I${sdpac_dir} ${sdpac_all_include} \ + -o $@ $< +clean: + rm -f *.o *~ +cleanall: clean + rm -f *.exe +dist-clean: cleanall diff --git a/external/sdpa/libexample/example1.cpp b/external/sdpa/libexample/example1.cpp new file mode 100644 index 0000000..9512d60 --- /dev/null +++ b/external/sdpa/libexample/example1.cpp @@ -0,0 +1,227 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +// Here is the start of ``example1.cpp'' + +#include +#include +#include + +/* +example1.dat: + +"Example 1: mDim = 3, nBLOCK = 1, {2}" + 3 = mDIM + 1 = nBLOCK + 2 = bLOCKsTRUCT +{48, -8, 20} +{ {-11, 0}, { 0, 23} } +{ { 10, 4}, { 4, 0} } +{ { 0, 0}, { 0, -8} } +{ { 0, -8}, {-8, -2} } +*/ + +void printVector(double* ele, int dim, char* printFormat, + FILE* fpout); +void printMatrix(double* ele, int dim, char* printFormat, + FILE* fpout); +void printDimacsError(double dimacs_error[7],char* printFormat, + FILE* fpout); + +int main () +{ + SDPA::printSDPAVersion(stdout); + SDPA Problem1; + Problem1.setDisplay(stdout); + + // All parameteres are renewed + Problem1.setParameterType(SDPA::PARAMETER_DEFAULT); + + // If necessary, each parameter can be set independently + + // Problem1.setParameterMaxIteration(100); + // Problem1.setParameterEpsilonStar(1.0e-7); + // Problem1.setParameterLambdaStar(1.0e+2); + // Problem1.setParameterOmegaStar(2.0); + // Problem1.setParameterLowerBound(-1.0e+5); + // Problem1.setParameterUppwerBound(1.0e+5); + // Problem1.setParameterBetaStar(0.1); + // Problem1.setParameterBetaBar(0.2); + // Problem1.setParameterGammaStar(0.9); + // Problem1.setParameterEpsilonDash(1.0e-7); + // Problem1.setParameterPrintXVec((char*)"%+8.3e" ); + // Problem1.setParameterPrintXMat((char*)"%+8.3e" ); + // Problem1.setParameterPrintYMat((char*)"%+8.3e" ); + // Problem1.setParameterPrintInformation((char*)"%+10.16e"); + + Problem1.printParameters(stdout); + + int mDIM = 3; + int nBlock = 1; + Problem1.inputConstraintNumber(mDIM); + Problem1.inputBlockNumber(nBlock); + Problem1.inputBlockSize(1,2); + Problem1.inputBlockType(1,SDPA::SDP); + + Problem1.initializeUpperTriangleSpace(); + + Problem1.inputCVec(1,48); + Problem1.inputCVec(2,-8); + Problem1.inputCVec(3,20); + + Problem1.inputElement(0, 1, 1, 1, -11); + Problem1.inputElement(0, 1, 2, 2, 23); + + Problem1.inputElement(1, 1, 1, 1, 10); + Problem1.inputElement(1, 1, 1, 2, 4); + + Problem1.inputElement(2, 1, 2, 2, -8); + + Problem1.inputElement(3, 1, 1, 2, -8); + Problem1.inputElement(3, 1, 2, 2, -2); + + Problem1.initializeUpperTriangle(); + Problem1.initializeSolve(); + + // if necessary, dump input data and initial point + // Problem1.writeInputSparse((char*)"tmp.dat-s",(char*)"%+8.3e"); + // Problem1.writeInitSparse((char*)"tmp.ini-s",(char*)"%+8.3e"); + + Problem1.solve(); + + fprintf(stdout, "\nStop iteration = %d\n", + Problem1.getIteration()); + char phase_string[30]; + Problem1.getPhaseString(phase_string); + fprintf(stdout, "Phase = %s\n", phase_string); + fprintf(stdout, "objValPrimal = %+10.6e\n", + Problem1.getPrimalObj()); + fprintf(stdout, "objValDual = %+10.6e\n", + Problem1.getDualObj()); + fprintf(stdout, "p. feas. error = %+10.6e\n", + Problem1.getPrimalError()); + fprintf(stdout, "d. feas. error = %+10.6e\n\n", + Problem1.getDualError()); + + + fprintf(stdout, "xVec = \n"); + // Problem1.printResultXVec(); + printVector(Problem1.getResultXVec(), + Problem1.getConstraintNumber(), (char*)"%+8.3e", + stdout); + + fprintf(stdout, "xMat = \n"); + // Problem1.printResultXMat(); + for (int l=0; l - ) / (1 + || + ||)]\n"); + fprintf(fpout, "err6 = "); + fprintf(fpout, printFormat, dimacs_error[6]); + fprintf(fpout, " [ / (1 + || + ||)]\n"); + fprintf(fpout, "\n"); +} + diff --git a/external/sdpa/libexample/example2.cpp b/external/sdpa/libexample/example2.cpp new file mode 100644 index 0000000..4c36415 --- /dev/null +++ b/external/sdpa/libexample/example2.cpp @@ -0,0 +1,411 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +// Here is the start of ``example1.cpp'' + +#include +#include +#include + +/* +*Example 2: +*mDim = 5, nBLOCK = 3, {2,3,-2} + 5 = mDIM + 3 = nBLOCK + 2 3 -2 = bLOCKsTRUCT +{1.1, -10, 6.6 , 19 , 4.1} +{ +{ { -1.4, -3.2 }, + { -3.2,-28 } } +{ { 15, -12, 2.1 }, + {-12, 16, -3.8 }, + { 2.1, -3.8, 15 } } + { 1.8, -4.0 } +} +{ +{ { 0.5, 5.2 }, + { 5.2, -5.3 } } +{ { 7.8, -2.4, 6.0 }, + { -2.4, 4.2, 6.5 }, + { 6.0, 6.5, 2.1 } } + { -4.5, -3.5 } +} +{ +{ { 1.7, 7.0 }, + { 7.0, -9.3 } } +{ {-1.9, -0.9, -1.3 }, + {-0.9, -0.8, -2.1 }, + {-1.3, -2.1, 4.0 } } + {-0.2, -3.7 } +} +{ +{ { 6.3, -7.5 }, + {-7.5, -3.3 } } +{ { 0.2, 8.8, 5.4 }, + { 8.8, 3.4, -0.4 }, + { 5.4, -0.4, 7.5 } } + {-3.3, -4.0 } +} +{ +{ { -2.4, -2.5 }, + { -2.5, -2.9 } } +{ { 3.4, -3.2, -4.5 }, + { -3.2, 3.0, -4.8 }, + { -4.5, -4.8, 3.6 } } + { 4.8 , 9.7 } +} +{ +{ { -6.5, -5.4 }, + { -5.4, -6.6 } } +{ { 6.7, -7.2, -3.6 }, + { -7.2, 7.3, -3.0 }, + { -3.6, -3.0, -1.4 } } + { 6.1, -1.5 } +} +*/ + +void printVector(double* ele, int dim, char* printFormat, + FILE* fpout); +void printMatrix(double* ele, int dim, char* printFormat, + FILE* fpout); +void printDimacsError(double dimacs_error[7],char* printFormat, + FILE* fpout); + +int main () +{ + SDPA::printSDPAVersion(stdout); + SDPA Problem1; + Problem1.setDisplay(stdout); + + // All parameteres are renewed + Problem1.setParameterType(SDPA::PARAMETER_DEFAULT); + // Problem1.printParameters(stdout); + + int mDIM = 5; + int nBlock = 3; + Problem1.inputConstraintNumber(mDIM); + Problem1.inputBlockNumber(nBlock); + // bLOCKsTRUCT :: 2(SDP) 3(SDP) -2(LP) + Problem1.inputBlockSize(1,2); + Problem1.inputBlockSize(2,3); + Problem1.inputBlockSize(3,-2); + Problem1.inputBlockType(1,SDPA::SDP); + Problem1.inputBlockType(2,SDPA::SDP); + Problem1.inputBlockType(3,SDPA::LP); + + Problem1.initializeUpperTriangleSpace(); + + //cVECT = {1.1, -10, 6.6 , 19 , 4.1} + Problem1.inputCVec(1,1.1); + Problem1.inputCVec(2,-10); + Problem1.inputCVec(3,6.6); + Problem1.inputCVec(4,19); + Problem1.inputCVec(5,4.1); + + // --------- Input F_0 -------------------- + + // 1st block + // { { -1.4, -3.2}, + // { -3.2, -28} } + + Problem1.inputElement(0, 1, 1, 1, -1.4); + Problem1.inputElement(0, 1, 1, 2, -3.2); + Problem1.inputElement(0, 1, 2, 2, -28); + + // 2nd block + // { { 15, -12, 2.1 }, + // {-12, 16, -3.8 }, + // { 2.1, -3.8, 15 } } + + Problem1.inputElement(0, 2, 1, 1, 15); + Problem1.inputElement(0, 2, 1, 2, -12); + Problem1.inputElement(0, 2, 1, 3, 2.1); + Problem1.inputElement(0, 2, 2, 2, 16); + Problem1.inputElement(0, 2, 2, 3,-3.8); + Problem1.inputElement(0, 2, 3, 3, 15); + + // 3rd block + // { 1.8, -4.0 } + Problem1.inputElement(0, 3, 1, 1, 1.8); + Problem1.inputElement(0, 3, 2, 2,-4.0); + + // --------- Input F_1 -------------------- + + // 1st block + // { { 0.5, 5.2}, + // { 5.2, -5.3} } + + Problem1.inputElement(1, 1, 1, 1, 0.5); + Problem1.inputElement(1, 1, 1, 2, 5.2); + Problem1.inputElement(1, 1, 2, 2,-5.3); + + // 2nd block + // { { 7.8, -2.4, 6.0 }, + // {-2.4, 4.2, 6.5 }, + // { 6.0, 6.5, 2.1 } } + + Problem1.inputElement(1, 2, 1, 1, 7.8); + Problem1.inputElement(1, 2, 1, 2,-2.4); + Problem1.inputElement(1, 2, 1, 3, 6.0); + Problem1.inputElement(1, 2, 2, 2, 4.2); + Problem1.inputElement(1, 2, 2, 3, 6.5); + Problem1.inputElement(1, 2, 3, 3, 2.1); + + // 3rd block + // { -4.5, -3.5 } + Problem1.inputElement(1, 3, 1, 1, -4.5); + Problem1.inputElement(1, 3, 2, 2, -3.5); + + // --------- Input F_2 -------------------- + + // 1st block + // { { 1.7, 7.0}, + // { 7.0,-9.3} } + + Problem1.inputElement(2, 1, 1, 1, 1.7); + Problem1.inputElement(2, 1, 1, 2, 7.0); + Problem1.inputElement(2, 1, 2, 2, -9.3); + + // 2nd block + // { {-1.9, -0.9, -1.3 }, + // {-0.9, -0.8, -2.1 }, + // {-1.3, -2.1, 4.0 } } + + Problem1.inputElement(2, 2, 1, 1, -1.9); + Problem1.inputElement(2, 2, 1, 2, -0.9); + Problem1.inputElement(2, 2, 1, 3, -1.3); + Problem1.inputElement(2, 2, 2, 2, -0.8); + Problem1.inputElement(2, 2, 2, 3, -2.1); + Problem1.inputElement(2, 2, 3, 3, 4.0); + + // 3rd block + // { -0.2, -3.7 } + Problem1.inputElement(2, 3, 1, 1, -0.2); + Problem1.inputElement(2, 3, 2, 2, -3.7); + + // --------- Input F_3 -------------------- + + // 1st block + // { { 6.3, -7.5}, + // { -7.5, -3.3} } + + Problem1.inputElement(3, 1, 1, 1, 6.3); + Problem1.inputElement(3, 1, 1, 2, -7.5); + Problem1.inputElement(3, 1, 2, 2, -3.3); + + // 2nd block + // { { 0.2, 8.8, 5.4 }, + // { 8.8, 3.4, -0.4 }, + // { 5.4, -0.4, 7.5 } } + + Problem1.inputElement(3, 2, 1, 1, 0.2); + Problem1.inputElement(3, 2, 1, 2, 8.8); + Problem1.inputElement(3, 2, 1, 3, 5.4); + Problem1.inputElement(3, 2, 2, 2, 3.4); + Problem1.inputElement(3, 2, 2, 3, -0.4); + Problem1.inputElement(3, 2, 3, 3, 7.5); + + // 3rd block + // { -3.3, -4.0 } + Problem1.inputElement(3, 3, 1, 1, -3.3); + Problem1.inputElement(3, 3, 2, 2, -4.0); + + // --------- Input F_4 -------------------- + + // 1st block + // { { -2.4, -2.5}, + // { -2.5, -2.9} } + + Problem1.inputElement(4, 1, 1, 1, -2.4); + Problem1.inputElement(4, 1, 1, 2, -2.5); + Problem1.inputElement(4, 1, 2, 2, -2.9); + + // 2nd block + // { { 3.4, -3.2, -4.5 }, + // { -3.2, 3.0, -4.8 }, + // { -4.5, -4.8, 3.6 } } + + Problem1.inputElement(4, 2, 1, 1, 3.4); + Problem1.inputElement(4, 2, 1, 2, -3.2); + Problem1.inputElement(4, 2, 1, 3, -4.5); + Problem1.inputElement(4, 2, 2, 2, 3.0); + Problem1.inputElement(4, 2, 2, 3, -4.8); + Problem1.inputElement(4, 2, 3, 3, 3.6); + + // 3rd block + // { 4.8, 9.7 } + Problem1.inputElement(4, 3, 1, 1, 4.8); + Problem1.inputElement(4, 3, 2, 2, 9.7); + + // --------- Input F_5 -------------------- + + // 1st block + // { { -6.5, -5.4}, + // { -5.4, -6.6} } + + Problem1.inputElement(5, 1, 1, 1, -6.5); + Problem1.inputElement(5, 1, 1, 2, -5.4); + Problem1.inputElement(5, 1, 2, 2, -6.6); + + // 2nd block + // { { 6.7, -7.2, -3.6 }, + // { -7.2, 7.3, -3.0 }, + // { -3.6, -3.0, -1.4 } } + + Problem1.inputElement(5, 2, 1, 1, 6.7); + Problem1.inputElement(5, 2, 1, 2, -7.2); + Problem1.inputElement(5, 2, 1, 3, -3.6); + Problem1.inputElement(5, 2, 2, 2, 7.3); + Problem1.inputElement(5, 2, 2, 3, -3.0); + Problem1.inputElement(5, 2, 3, 3, -1.4); + + // 3rd block + // { 6.1, -1.5 } + Problem1.inputElement(5, 3, 1, 1, 6.1); + Problem1.inputElement(5, 3, 2, 2,-1.5); + + Problem1.initializeUpperTriangle(); + Problem1.initializeSolve(); + + // if necessary, dump input data and initial point + // Problem1.writeInputSparse((char*)"tmp.dat-s",(char*)"%+8.3e"); + // Problem1.writeInitSparse((char*)"tmp.ini-s",(char*)"%+8.3e"); + + Problem1.solve(); + + fprintf(stdout, "\nStop iteration = %d\n", + Problem1.getIteration()); + char phase_string[30]; + Problem1.getPhaseString(phase_string); + fprintf(stdout, "Phase = %s\n", phase_string); + fprintf(stdout, "objValPrimal = %+10.6e\n", + Problem1.getPrimalObj()); + fprintf(stdout, "objValDual = %+10.6e\n", + Problem1.getDualObj()); + fprintf(stdout, "p. feas. error = %+10.6e\n", + Problem1.getPrimalError()); + fprintf(stdout, "d. feas. error = %+10.6e\n\n", + Problem1.getDualError()); + + + fprintf(stdout, "xVec = \n"); + // Problem1.printResultXVec(); + printVector(Problem1.getResultXVec(), + Problem1.getConstraintNumber(), (char*)"%+8.3e", + stdout); + + fprintf(stdout, "xMat = \n"); + // Problem1.printResultXMat(); + for (int l=0; l - ) / (1 + || + ||)]\n"); + fprintf(fpout, "err6 = "); + fprintf(fpout, printFormat, dimacs_error[6]); + fprintf(fpout, " [ / (1 + || + ||)]\n"); + fprintf(fpout, "\n"); +} + diff --git a/external/sdpa/libexample/example5.cpp b/external/sdpa/libexample/example5.cpp new file mode 100644 index 0000000..c43173a --- /dev/null +++ b/external/sdpa/libexample/example5.cpp @@ -0,0 +1,55 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +// Here is the start of ``example5.cpp'' + +#include +#include +#include + +int main(int argc, char** argv) +{ + if (argc != 4) { + fprintf(stderr, "%s [Input] [Output] [Param] \n", argv[0]); + exit(EXIT_FAILURE); + } + + SDPA Problem1; + FILE* fpresult; + if ((fpresult = fopen(argv[2],"w")) == NULL) { + fprintf(stderr, "Cannot Open %s \n", argv[2]); + } + Problem1.setResultFile(fpresult); + + // fpresult records which file is read from argv[3] + Problem1.readParameter(argv[3],fpresult); + // Note that readParameter should be called before readInput + // Otherwise initial point cannot be decided by lambdaStar + Problem1.readInput(argv[1],fpresult); + + Problem1.initializeSolve(); + + // All results and intermediate log are written into fpresult + Problem1.solve(); + + fclose(fpresult); + Problem1.finalize(); + exit(0); +} diff --git a/external/sdpa/libexample/gmon.out b/external/sdpa/libexample/gmon.out new file mode 100644 index 0000000..cc2191d Binary files /dev/null and b/external/sdpa/libexample/gmon.out differ diff --git a/external/sdpa/libexample/param.sdpaC b/external/sdpa/libexample/param.sdpaC new file mode 100644 index 0000000..a9ec655 --- /dev/null +++ b/external/sdpa/libexample/param.sdpaC @@ -0,0 +1,15 @@ +100 unsigned int maxIteration; +1.0E-7 double 0.0 < epsilonStar; +1.0E2 double 0.0 < lambdaStar; +2.0 double 1.0 < omegaStar; +-1.0E5 double lowerBound; +1.0E5 double upperBound; +0.1 double 0.0 <= betaStar < 1.0; +0.3 double 0.0 <= betaBar < 1.0, betaStar <= betaBar; +0.9 double 0.0 < gammaStar < 1.0; +1.0E-7 double 0.0 < epsilonDash; +%+8.3e char* xPrint (default %+8.3e, NOPRINT skips printout) +%+8.3e char* XPrint (default %+8.3e, NOPRINT skips printout) +%+8.3e char* YPrint (default %+8.3e, NOPRINT skips printout) +%+10.16e char* infPrint (default %+10.16e, NOPRINT skips printout) + diff --git a/external/sdpa/make.head b/external/sdpa/make.head new file mode 100644 index 0000000..7d745a3 --- /dev/null +++ b/external/sdpa/make.head @@ -0,0 +1,30 @@ +sdpa_block.o: sdpa_block.cpp sdpa_block.h sdpa_include.h sdpa_right.h \ + sdpa_tool.h +sdpa_call.o: sdpa_call.cpp sdpa_call.h sdpa_io.h sdpa_block.h \ + sdpa_include.h sdpa_right.h sdpa_tool.h sdpa_parts.h sdpa_dataset.h \ + sdpa_struct.h sdpa_linear.h +sdpa_chordal.o: sdpa_chordal.cpp sdpa_chordal.h sdpa_dataset.h \ + sdpa_include.h sdpa_right.h sdpa_tool.h sdpa_struct.h sdpa_block.h +sdpa_dataset.o: sdpa_dataset.cpp sdpa_dataset.h sdpa_include.h \ + sdpa_right.h sdpa_tool.h sdpa_struct.h sdpa_block.h sdpa_parts.h \ + sdpa_linear.h sdpa_newton.h sdpa_chordal.h +sdpa_dpotrf.o: sdpa_dpotrf.cpp sdpa_include.h sdpa_right.h sdpa_tool.h \ + sdpa_algebra.h +sdpa_exe.o: sdpa_exe.cpp +sdpa_io.o: sdpa_io.cpp sdpa_io.h sdpa_block.h sdpa_include.h sdpa_right.h \ + sdpa_tool.h sdpa_parts.h sdpa_dataset.h sdpa_struct.h sdpa_linear.h +sdpa_linear.o: sdpa_linear.cpp sdpa_linear.h sdpa_struct.h sdpa_include.h \ + sdpa_right.h sdpa_tool.h sdpa_block.h sdpa_dataset.h sdpa_dpotrf.h \ + sdpa_algebra.h +sdpa_newton.o: sdpa_newton.cpp sdpa_newton.h sdpa_chordal.h \ + sdpa_dataset.h sdpa_include.h sdpa_right.h sdpa_tool.h sdpa_struct.h \ + sdpa_block.h sdpa_parts.h sdpa_linear.h sdpa_algebra.h +sdpa_parts.o: sdpa_parts.cpp sdpa_parts.h sdpa_include.h sdpa_right.h \ + sdpa_tool.h sdpa_dataset.h sdpa_struct.h sdpa_block.h sdpa_linear.h \ + sdpa_newton.h sdpa_chordal.h +sdpa_solve.o: sdpa_solve.cpp sdpa_call.h sdpa_linear.h sdpa_struct.h \ + sdpa_include.h sdpa_right.h sdpa_tool.h sdpa_block.h sdpa_io.h \ + sdpa_parts.h sdpa_dataset.h +sdpa_struct.o: sdpa_struct.cpp sdpa_struct.h sdpa_include.h sdpa_right.h \ + sdpa_tool.h sdpa_block.h sdpa_algebra.h sdpa_linear.h sdpa_dataset.h +sdpa_tool.o: sdpa_tool.cpp sdpa_tool.h sdpa_right.h diff --git a/external/sdpa/make.inc b/external/sdpa/make.inc new file mode 100644 index 0000000..1bdb9ef --- /dev/null +++ b/external/sdpa/make.inc @@ -0,0 +1,62 @@ +######################################################### +# Edit below accordingly your environment +######################################################### + +# The base directory of SDPA-C +sdpac_dir = $(HOME)/sdpa-c + +# The compilers +CC = gcc +CXX = g++ +FC = gfortran + +# The compiler options +# To generate mex files, you should not remove '-fPIC' from FLAGS +# When you use OpenBLAS, you should not remove '-DOPENBLAS' from CXXFLAGS +CFLAGS = -O3 -fPIC +CXXFLAGS = -O3 -fPIC -DOPENBLAS +FCFLAGS = -O3 -fPIC + + +######################################################### +# Usually, you do not have to edit below +######################################################### + +SDPAC_VERSION = \"7.3.8\" +sdpac_lib = libsdpa-c.a +sdpac_exe = sdpa-c + +## do not add '/' to the end of suitesparse_dir +suitesparse_dir = $(sdpac_dir)/SuiteSparse +suitesparse_include = -I$(suitesparse_dir)/CHOLMOD/Include \ + -I$(suitesparse_dir)/SuiteSparse_config +suitesparse_lib = $(suitesparse_dir)/CHOLMOD/Lib/libcholmod.a \ + $(suitesparse_dir)/CCOLAMD/Lib/libccolamd.a \ + $(suitesparse_dir)/COLAMD/Lib/libcolamd.a \ + $(suitesparse_dir)/CAMD/Lib/libcamd.a \ + $(suitesparse_dir)/AMD/Lib/libamd.a \ + $(suitesparse_dir)/metis-5.1.0/libmetis.a \ + $(suitesparse_dir)/SuiteSparse_config/libsuitesparseconfig.a +suitesparse_ver = 5.1.2 + +## do not add '/' to the end of mumps_dir +mumps_dir = $(sdpac_dir)/mumps +mumps_include = -I$(mumps_dir)/include +mumps_lib = $(mumps_dir)/lib/libdmumps.a \ + $(mumps_dir)/lib/libmumps_common.a \ + $(mumps_dir)/lib/libpord.a \ + $(mumps_dir)/libseq/libmpiseq.a +mumps_ver = 5.1.2 +mumps_tar_file = mumps_${mumps_ver}.orig.tar.gz + +## do not add '/' to the end of openblas_dir +openblas_dir = $(sdpac_dir)/OpenBLAS +openblas_lib = $(openblas_dir)/libopenblas.a + +openmp_lib = -lgomp -lpthread +fortran_lib = -lgfortran +realtime_lib = -lrt + +sdpac_all_include = $(suitesparse_include) $(mumps_include) +sdpac_all_lib = $(suitesparse_lib) $(mumps_lib) $(openblas_lib) \ + $(openmp_lib) $(fortran_lib) $(realtime_lib) diff --git a/external/sdpa/mex/CommandList.txt b/external/sdpa/mex/CommandList.txt new file mode 100644 index 0000000..b62cf21 --- /dev/null +++ b/external/sdpa/mex/CommandList.txt @@ -0,0 +1,60 @@ +This is a short list for SDPA-M command. + +(1) read_data.m +>> [mDIM,nBLOCK,bLOCKsTRUCT,c,F] = read_data('example1.dat-s'); +will read 'example1.dat-s' into the SDPA-M structures. + +(2) paramC.m +>> OPTION=paramC; +will prepare default parameter. You can change the parameter +by this OPTION structure. + +(3) sdpam.m +>> [objVal,x,X,Y,INFO] = sdpam(mDIM,nBLOCK,bLOCKsTRUCT,c,F); +or +>> [objVal,x,X,Y,INFO] = sdpam(mDIM,nBLOCK,bLOCKsTRUCT,c,F,OPTION); +will solve the SDP. + +(4) gensdpafile.m +>> gensdpafile('myexample.dat-s',mDIM,nBLOCK,bLOCKsTRUCT,c,F); +will output the SDPA-M structure into 'myexample.dat-s'. + +(5) initial_point.m +>> [x0,X0,Y0] = initial_point('example1.ini-s', mDIM, nBLOCK, bLOCKsTRUCT); +will read an initial point from 'example1.ini-s'. +You need to prepare mDIM, nBLOCK, bLOCKsTRUCT by read_data.m + +(6) SDPAToSedumi.m +>> [At,b,c,K,blockStruct] = SDPAToSedumi('example1.dat-s'); +will read 'example1.dat-s' into SeDuMi structures with +an additional structure 'blockStruct'. + +(7) sedumiwrap.m +>> [x,y,info]=sedumiwrap(A,b,c,K,pars,OPTION); +will solve the SDP given in SeDuMi strucutres. +The 5th argument 'pars' will be ignored +and the 6th argument can be prepared by param.m + +(8) SedumiToSDPA.m +>> SedumiToSDPA('myexample.dat-s',A,b,c,K,'%8.16e'); +will output SeDuMi structures into 'myexample.dat-s'. +'%8.16' determines the output style by printf-format. + +(9) read_output.m +>> [objVal,x,X,Y,INFO] = read_output('example1.result',mDIM,nBLOCK,bLOCKsTRUCT); +will read the result file generated by SDPA. +If you solve 'example1.dat-s' by +$ ./sdpa example1.dat-s example1.result +then this result can be read by +>> [mDIM,nBLOCK,bLOCKsTRUCT,c,F] = read_data('example1.dat-s'); +>> [objVal,x,X,Y,INFO] = read_output('example1.result',mDIM,nBLOCK,bLOCKsTRUCT); + +(10) read_outputSedumi.m +>> [x,y,info] = read_outputSedumi('example1.result',m,K); +will read the result file generated by SDPA. +If you solve 'example1.dat-s' by +$ ./sdpa example1.dat-s example1.result +then this result can be read by +>> [At,b,c,K,blockStruct] = SDPAToSedumi('example1.dat-s'); +>> [x,y,info] = read_outputSedumi('example1.result',m,K); + diff --git a/external/sdpa/mex/Makefile b/external/sdpa/mex/Makefile new file mode 100644 index 0000000..bfb4d0c --- /dev/null +++ b/external/sdpa/mex/Makefile @@ -0,0 +1,131 @@ +# +# SDPA-M: $Revision: 7.3 $ +# +# For Matlab +# $ make +# For Octave +# $ make COMPILE_ENVIRONMENT=octave + +# after "make install", you can find +# 'make.inc' in 'share/sdpa' sub-directory under the installed directory +# For example +# make MAKE_INCLUDE_DIR=/usr/share/sdpa +# or +# make MAKE_INCLUDE_DIR=/usr/local/share/sdpa +# In addition, for Octave, you should try +# make MAKE_INCLUDE_DIR=/usr/local/share/sdpa COMPILE_ENVIRONMENT=octave + + +# To compile with mingw, the following command is a sample. +# Your need to modify directory names and compiler names. +# make MEX="i586-mingw32msvc-g++ -shared" COMPILE_ENVIRONMENT=octave \ +# PRINTF_INT_STYLE=-DPRINTF_INT_STYLE=\\\"%zd\\\" \ +# OUTPUT_FORMAT="-o \$@.mexw32" \ +# MATLAB_INCLUDE="-Imatlab-extern/include" \ +# MATLAB_LIBS="-I/matlab-extern/microsoft/libmx.lib -I/matlab-extern/microsoft/libmex.lib" \ + + +# for only SDPA-Project members +# set DEVELOPEMENT_STAGE=1 to compile without 'make install' +# For example +# make MAKE_INCLUDE_DIR=../etc DEVELOPEMENT_STAGE=1 +# In addition, for Octave, you should try +# make MAKE_INCLUDE_DIR=../etc DEVELOPEMENT_STAGE=1 COMPILE_ENVIRONMENT=octave + +# This file is a component of SDPA +# Copyright (C) 2004-2013 SDPA Project + +# 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 + +MAKE_INCLUDE_DIR=.. +-include ${MAKE_INCLUDE_DIR}/make.inc +# after "make install", you can find +# 'make.inc' in 'share/sdpa' sub-directory under the installed directory +# For example +# make MAKE_INCLUDE_DIR=/usr/share/sdpa +# or +# make MAKE_INCLUDE_DIR=/usr/local/share/sdpa + +MEX = mex +DEF_FPIC = -fPIC + +CXXFLAGSOPTIONS = CXXFLAGS="-Wall -fPIC" -O -DNDEBUG CC=${CC} CXX=${CXX} +LARGEARRAYOPTION = -largeArrayDims + +SDPA_INCLUDE = -I${SDPA_DIR}/include +ifeq ($(DEVELOPEMENT_STAGE),1) + SDPA_INCLUDE = -I.. + SDPA_LIB = ../libsdpa-c.a +endif + +PRINTF_INT_STYLE = -DPRINTF_INT_STYLE=\\\"%zd\\\" +# Output format is usually automatically set by mex command. +OUTPUT_FORMAT = + +ifeq ($(COMPILE_ENVIRONMENT),octave) + MEX = CC=${CC} CXX=${CXX} mkoctfile --mex + CXXFLAGSOPTIONS = + LARGEARRAYOPTION = + PRINTF_INT_STYLE = -DPRINTF_INT_STYLE=\\\"%d\\\" +endif + +ALL_OPTION = ${CXXFLAGSOPTIONS} ${LARGEARRAYOPTION} ${PRINTF_INT_STYLE} + +all: mexsdpaC mexSedumiWrapC +# all: mexSedumiWrap + +mexBinaryCheck: + @echo "---------------------------------------------" + @echo "Mex Compilation Start " + @echo "---------------------------------------------" + @if [ -f $(MEX) ]; then \ + echo "---------------------------------------------" ;\ + echo " We use " ;\ + echo " " $(MEX) ;\ + echo " for Mex compilaton " ;\ + echo "---------------------------------------------" ;\ + else \ + echo "---------------------------------------------" ;\ + echo "Automatic search is failed, " ;\ + echo " Set the full path for mex command mannually " ;\ + echo " in "`pwd`"/Makekefile" ;\ + echo " and try 'make' in `pwd` " ;\ + echo "---------------------------------------------" ;\ + false ;\ + fi + +mexsdpaC: + ${MEX} ${ALL_OPTION} \ + ${OUTPUT_FORMAT} \ + ${SDPA_INCLUDE} ${sdpac_all_include} \ + mexsdpaC.cpp mexFprintf.c \ + ${SDPA_LIB} ${sdpac_all_lib} + +mexSedumiWrapC: + ${MEX} ${ALL_OPTION} \ + ${OUTPUT_FORMAT} \ + ${SDPA_INCLUDE} ${sdpac_all_include} \ + mexSedumiWrapC.cpp mexFprintf.c \ + ${SDPA_LIB} ${sdpac_all_lib} + +# clean all generated files +clean: + rm -f *~ *.o +dist-clean: clean + rm -f mexsdpaC.mex* mexSedumiWrapC.mex* + +# +# End of File +# diff --git a/external/sdpa/mex/mexFprintf.c b/external/sdpa/mex/mexFprintf.c new file mode 100644 index 0000000..7d57758 --- /dev/null +++ b/external/sdpa/mex/mexFprintf.c @@ -0,0 +1,116 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include +#include +#include +#include + +#include + + +#define BUF_LENGTH 4096 + +int fprintf(FILE *stream, const char *format, ...) +{ + va_list arg; + va_start(arg,format); + int return_size = 0; + if (stream == stdout) { + char tmp_buf[BUF_LENGTH]; + vsprintf(tmp_buf,format,arg); + #if 0 + printf("tmp_buf = %s",tmp_buf); + #endif + mexPrintf(tmp_buf); + mexEvalString("drawnow;"); /* to dump string.*/ + return_size = strlen(tmp_buf); + if ( return_size >= BUF_LENGTH ) { + mexPrintf("Too Long Message To PrintOut " + "(some part might be truncated)"); + } + } + else { + return_size = vfprintf(stream,format,arg); + } + va_end(arg); + return return_size; +} + +static int internal_fprintf(FILE *stream, const char *format, ...) +{ + va_list arg; + va_start(arg,format); + int return_size = 0; + return_size = vfprintf(stream,format,arg); + va_end(arg); + return return_size; +} + +size_t fwrite(const void *ptr, size_t size, size_t nmemb, + FILE *stream) +{ + #if 1 + fprintf(stream,"%s",(const char*)ptr); + #else + // internal_fprintf does not work well here + internal_fprintf(stream, (const char*) internal_fprintf); + #endif + return 1; +} + +int fputc(int c, FILE* fp) +{ + if (fp == stdout) { + mexPrintf("%c",(unsigned char)c); + } + else { + internal_fprintf(fp,"%c",c); + /* fprintf(fp,"%c ",c);*/ + } + return c; +} + +#ifdef __GNUC__ +/*Only GNU, to avoid + warning: 'noreturn' function does return +*/ +static void internal_exit() __attribute__ ((noreturn)); +extern void mexErrMsgTxt(const char*) __attribute__ ((noreturn)); + void exit() __attribute__ ((noreturn)); + void abort() __attribute__ ((noreturn)); +#endif + +static void internal_exit() +{ + mexWarnMsgTxt("SDPA-C exits with some error."); + mexWarnMsgTxt("Matlab should be reboot to clear up memory space."); + mexErrMsgTxt("SDPA-C exits with some error."); +} + +void exit(int status) +{ + internal_exit(); +} +void abort(void) +{ + internal_exit(); +} diff --git a/external/sdpa/mex/mexSedumiWrapC.cpp b/external/sdpa/mex/mexSedumiWrapC.cpp new file mode 100644 index 0000000..ce5d073 --- /dev/null +++ b/external/sdpa/mex/mexSedumiWrapC.cpp @@ -0,0 +1,655 @@ +/* + * This file is a component of SDPA + * Copyright (C) 2004-2013 SDPA Project + * + * 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 + * + * SDPA-M: 7.3 + * mexsdpa.cpp + */ + +#include +/* + * SDPA header files + */ +#include +#include +using namespace sdpa; + +extern void _main(); + +void sdpasolver(mxArray* At_ptr, mxArray* b_ptr, mxArray* c_ptr, + mxArray* K_ptr, mxArray* OPTION_ptr, + mxArray* x_ptr, mxArray* y_ptr, + mxArray* info_ptr) +{ + time_t ltime; + time(<ime); + char string_time[1024]; + strcpy(string_time,ctime(<ime)); + string_time[strlen(string_time)-1]='\0'; + + SDPA sdpa; + + int maxIteration = 0; + double param = 0.0; + /* mxArray pointer */ + mxArray *field_ptr = NULL; + int nSymmChk = 0; + int nDimacs = 0; + + /* strings for phase value */ + const char *szPhase[] = { + "noINFO", "pFEAS", "dFEAS", "pdFEAS", "pdINF", + "pFEAS_dINF", "pINF_dFEAS", "pdOPT", "pUNBD", "dUNBD"}; + + /* output file */ + char *outfile = NULL; + FILE *fp = NULL; + FILE *fpResult = NULL; + int nOutfile = 0; + + mwSize mDIM; + mwSize nBLOCK; + + /* temporary variables */ + mwIndex k; + int size; + mwSize mwsize; + double *tmp_ptr = NULL; + char* tmpPrint = NULL; + + TimeStart(SDPA_START); + TimeStart(SDPA_CONVERT_START); + + /*** Set SDPA parameters by OPTIONS ***/ + /* Max Iteration */ + field_ptr = mxGetField(OPTION_ptr, 0, "maxIteration"); + if( field_ptr != NULL ){ + maxIteration = (int)mxGetScalar(field_ptr); + // mexPrintf("maxIteration = %d\n",maxIteration); + sdpa.setParameterMaxIteration(maxIteration); + } + /* epsilonStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "epsilonStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterEpsilonStar(param); + } + /* lambdaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "lambdaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterLambdaStar(param); + } + /* omegaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "omegaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterOmegaStar(param); + } + /* lowerBound */ + field_ptr = mxGetField(OPTION_ptr, 0, "lowerBound"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterLowerBound(param); + } + /* upperBound */ + field_ptr = mxGetField(OPTION_ptr, 0, "upperBound"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterUpperBound(param); + } + /* betaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "betaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterBetaStar(param); + } + /* betaBar */ + field_ptr = mxGetField(OPTION_ptr, 0, "betaBar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterBetaBar(param); + } + /* gammaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "gammaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterGammaStar(param); + } + /* epsilonDash */ + field_ptr = mxGetField(OPTION_ptr, 0, "epsilonDash"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterEpsilonDash(param); + } + /* xPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "xPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintXVec(tmpPrint); + mxFree(tmpPrint); + } + /* XPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "XPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintXMat(tmpPrint); + mxFree(tmpPrint); + } + /* YPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "YPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintYMat(tmpPrint); + mxFree(tmpPrint); + } + /* infPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "infPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintInformation(tmpPrint); + mxFree(tmpPrint); + } + + + /* isSymmetric */ + field_ptr = mxGetField(OPTION_ptr, 0, "isSymmetric"); + if( field_ptr != NULL ){ + nSymmChk = (int)mxGetScalar(field_ptr); + } + /* isDimacs */ + field_ptr = mxGetField(OPTION_ptr, 0, "isDimacs"); + if( field_ptr != NULL ){ + nDimacs = (int)mxGetScalar(field_ptr); + } + /* print */ + field_ptr = mxGetField(OPTION_ptr, 0, "print"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + if (mwsize == 1) { + // mexPrintf("display is NULL\n"); + fp = NULL; + } + else { + outfile = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, outfile, mwsize); + if( strncmp("display", outfile, mwsize - 1) == 0 ){ + fp = stdout; + } else if( strncmp("no", outfile, mwsize - 1) == 0 ){ + fp = NULL; + } else { + fp = fopen(outfile, "at"); + if( fp == NULL ){ + mexPrintf("Failed to open %s\n", outfile); + fp = stdout; + } else { + nOutfile = 1; + } + } + mxFree(outfile); + } + } else { + /* default setting is displaying information to stdout */ + fp = stdout; + } + sdpa.setDisplay(fp); + + /* resultFile */ + field_ptr = mxGetField(OPTION_ptr, 0, "resultFile"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + if (mwsize == 1) { + // mexPrintf("resultFile is NULL\n"); + } + else { + outfile = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, outfile, mwsize); + if ( strncmp("no", outfile, mwsize - 1) == 0 ) { + mexPrintf("resultFile is NULL\n"); + } + else { + fpResult = fopen(outfile, "w"); + if ( fpResult == NULL ) { + mexPrintf("Failed to open %s\n", outfile); + mexPrintf("Skip the detail file\n"); + } else { + sdpa.setResultFile(fpResult); + } + } + mxFree(outfile); + } + } + + if (fp) { + fprintf(fp,"SDPA-C start at [%s]\n",string_time); + } + if (fpResult) { + fprintf(fpResult,"SDPA-C start at [%s]\n",string_time); + } + + if (nDimacs != 0) { + if (sdpa.judgeDimacsAvailability() == false) { + if (fp) { + fprintf(fp, "Dimacs will be skipped by XPrint and YPrint parameter.\n"); + } + if (fpResult) { + fprintf(fpResult, "Dimacs will be skipped by XPrint and YPrint parameter.\n"); + } + nDimacs = 0; + } + } + + /* NumThreads */ + field_ptr = mxGetField(OPTION_ptr, 0, "NumThreads"); + if( field_ptr != NULL ){ + sdpa.setNumThreads((int)mxGetScalar(field_ptr)); + } + + /*** initialize SDPA class members ***/ + /* mDIM */ + mDIM = mxGetN(At_ptr); + sdpa.inputConstraintNumber(mDIM); + /* nBLOCK */ + nBLOCK = 0; + mwSize K_l = 0; + int isK_l = 0; // 1 (K_l > 0) or 0 (K_l == 0) + field_ptr = mxGetField(K_ptr, 0, "l"); + if (field_ptr != NULL) { + K_l = (mwSize)((mxGetPr(field_ptr))[0]); + #if 0 + mexPrintf("K_l = %zd\n", K_l); + #endif + if (K_l > 0) { + isK_l = 1; + nBLOCK++; + } + } + mwSize* K_s = NULL; + mwSize* K_sdpConeStart = NULL; + int K_sdpNoCones = 0; + field_ptr = mxGetField(K_ptr, 0, "s"); + if (field_ptr != NULL) { + K_sdpNoCones = (int) mxGetM(field_ptr); + K_s = (mwSize*) mxCalloc(K_sdpNoCones, sizeof(mwSize)); + K_sdpConeStart = (mwSize*) mxCalloc(K_sdpNoCones+1, sizeof(mwSize)); + K_sdpConeStart[0] = 0; + for (int l=0; l 0) { + sdpa.inputBlockSize(1, K_l); + sdpa.inputBlockType(1, SDPA::LP); + } + for (int l=0; l 0) { + size = sdpa.getBlockSize(1); + tmp_ptr = sdpa.getResultYMat(1); + for (int index = 0; index < size; ++index) { + x[index] = tmp_ptr[index]; + } + } + for (int l=0; l +/* + * SDPA header files + */ +#include + +extern void _main(); + +void sdpasolver(double *mDIM_ptr, + double *nBLOCK_ptr, + double *bLOCKsTRUCT_ptr, + double *c_ptr, + mxArray *F_ptr, + double *x0_ptr, + mxArray *X0_ptr, + mxArray *Y0_ptr, + mxArray *OPTION_ptr, + int IniPt, + double *objVal_ptr, + double *x_ptr, + mxArray *X_ptr, + mxArray *Y_ptr, + mxArray *INFO_ptr) +{ + time_t ltime; + time(<ime); + char string_time[1024]; + strcpy(string_time,ctime(<ime)); + string_time[strlen(string_time)-1]='\0'; + + SDPA sdpa; + + int maxIteration = 0; + double param = 0.0; + /* mxArray pointer */ + mxArray *field_ptr = NULL; + mxArray *cell_ptr = NULL; + + int nSymmChk = 0; + int nDimacs = 0; + + /* strings for phase value */ + const char *szPhase[] = { + "noINFO", "pFEAS", "dFEAS", "pdFEAS", "pdINF", + "pFEAS_dINF", "pINF_dFEAS", "pdOPT", "pUNBD", "dUNBD"}; + + /* output file */ + char *outfile = NULL; + FILE *fp = NULL; + FILE *fpResult = NULL; + int nOutfile = 0; + + mwSize mDIM; + mwSize nBLOCK; + + /* temporary variables */ + mwIndex i,j,k,l; + int size; + mwSize mwsize; + mwIndex idx, startidx, endidx; + mwSize sizeM, sizeN; + mwIndex *subscript = NULL; + mwIndex *dims = NULL; + int cell_index = 0; + mwIndex *ir_ptr = NULL; + mwIndex *jc_ptr = NULL; + double *tmp_ptr = NULL; + double *result_ptr = NULL; + char* tmpPrint = NULL; + + /*** Set SDPA parameters by OPTIONS ***/ + /* Max Iteration */ + field_ptr = mxGetField(OPTION_ptr, 0, "maxIteration"); + if( field_ptr != NULL ){ + maxIteration = (int)mxGetScalar(field_ptr); + sdpa.setParameterMaxIteration(maxIteration); + } + /* epsilonStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "epsilonStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterEpsilonStar(param); + } + /* lambdaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "lambdaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterLambdaStar(param); + } + /* omegaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "omegaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterOmegaStar(param); + } + /* lowerBound */ + field_ptr = mxGetField(OPTION_ptr, 0, "lowerBound"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterLowerBound(param); + } + /* upperBound */ + field_ptr = mxGetField(OPTION_ptr, 0, "upperBound"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterUpperBound(param); + } + /* betaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "betaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterBetaStar(param); + } + /* betaBar */ + field_ptr = mxGetField(OPTION_ptr, 0, "betaBar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterBetaBar(param); + } + /* gammaStar */ + field_ptr = mxGetField(OPTION_ptr, 0, "gammaStar"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterGammaStar(param); + } + /* epsilonDash */ + field_ptr = mxGetField(OPTION_ptr, 0, "epsilonDash"); + if( field_ptr != NULL ){ + param = *mxGetPr(field_ptr); + sdpa.setParameterEpsilonDash(param); + } + /* xPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "xPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintXVec(tmpPrint); + mxFree(tmpPrint); + } + /* XPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "XPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintXMat(tmpPrint); + mxFree(tmpPrint); + } + /* YPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "YPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintYMat(tmpPrint); + mxFree(tmpPrint); + } + /* infPrint */ + field_ptr = mxGetField(OPTION_ptr, 0, "infPrint"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + tmpPrint = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, tmpPrint, mwsize); + sdpa.setParameterPrintInformation(tmpPrint); + mxFree(tmpPrint); + } + + /* isSymmetric */ + field_ptr = mxGetField(OPTION_ptr, 0, "isSymmetric"); + if( field_ptr != NULL ){ + nSymmChk = (int)mxGetScalar(field_ptr); + } + /* isDimacs */ + field_ptr = mxGetField(OPTION_ptr, 0, "isDimacs"); + if( field_ptr != NULL ){ + nDimacs = (int)mxGetScalar(field_ptr); + } + /* print */ + field_ptr = mxGetField(OPTION_ptr, 0, "print"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + if (mwsize == 1) { + // mexPrintf("display is NULL\n"); + fp = NULL; + } + else { + outfile = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, outfile, mwsize); + if( strncmp("display", outfile, mwsize - 1) == 0 ){ + fp = stdout; + } else if( strncmp("no", outfile, mwsize - 1) == 0 ){ + fp = NULL; + } else { + fp = fopen(outfile, "at"); + if( fp == NULL ){ + mexPrintf("Failed to open %s\n", outfile); + fp = stdout; + } else { + nOutfile = 1; + } + } + mxFree(outfile); + } + } else { + /* default setting is displaying information to stdout */ + fp = stdout; + } + sdpa.setDisplay(fp); + + /* resultFile */ + field_ptr = mxGetField(OPTION_ptr, 0, "resultFile"); + if( field_ptr != NULL ){ + mwsize = mxGetM(field_ptr) * mxGetN(field_ptr) + 1; + if (mwsize == 1) { + // mexPrintf("resultFile is NULL\n"); + } + else { + outfile = (char*)mxCalloc(mwsize, sizeof(char)); + mxGetString(field_ptr, outfile, mwsize); + fpResult = fopen(outfile, "w"); + if( fpResult == NULL ){ + mexPrintf("Failed to open %s\n", outfile); + mexPrintf("Skip the detail file\n"); + } else { + sdpa.setResultFile(fpResult); + } + mxFree(outfile); + } + } + + if (fp) { + fprintf(fp,"SDPA-C start at [%s]\n",string_time); + } + if (fpResult) { + fprintf(fpResult,"SDPA-C start at [%s]\n",string_time); + } + + if (nDimacs) { + if (sdpa.judgeDimacsAvailability() == false) { + if (fp) { + fprintf(fp, "Dimacs will be skipped by XPrint and YPrint parameter.\n"); + } + if (fpResult) { + fprintf(fpResult, "Dimacs will be skipped by XPrint and YPrint parameter.\n"); + } + } + } + + + /* NumThreads */ + field_ptr = mxGetField(OPTION_ptr, 0, "NumThreads"); + if( field_ptr != NULL ){ + sdpa.setNumThreads((int)mxGetScalar(field_ptr)); + } + + /*** initialize SDPA class members ***/ + /* mDIM */ + mDIM = (mwSize)(*mDIM_ptr); + sdpa.inputConstraintNumber(mDIM); + /* nBLOCK */ + nBLOCK = (mwSize)(*nBLOCK_ptr); + sdpa.inputBlockNumber(nBLOCK); + /* bLOCKsTRUCT */ + for(i = 0; i < nBLOCK; i++){ + int bs = (int)(bLOCKsTRUCT_ptr[i]); + sdpa.inputBlockSize(i+1,bs); + if (bs < 0 || bs == 1) { + sdpa.inputBlockType(i+1,SDPA::LP); + } + else { + sdpa.inputBlockType(i+1,SDPA::SDP); + } + } + /* Execute initializeUpperTriangleSpace() */ + sdpa.initializeUpperTriangleSpace(); + /* cVECT */ + for(i = 0; i < mDIM; i++){ + sdpa.inputCVec(i+1, c_ptr[i]); + } + + /*** Count NonZeroNumber in coefficience matrices ***/ + // Do nothing for SDPA 7 + + /*** Set coefficience matrices value ***/ + subscript = (mwIndex*)mxCalloc(2,sizeof(mwIndex)); + dims = (mwIndex*)mxGetDimensions(F_ptr); + for(l = 0; l < dims[0]; l++){ + for(k = 0; k < dims[1]; k++){ + subscript[0]=l; subscript[1]=k; + cell_index = mxCalcSingleSubscript(F_ptr, 2, subscript); + cell_ptr = mxGetCell(F_ptr, cell_index); + // mxGetDimensions at the next line is redundant, + // but this is necessary to octave + dims = (mwIndex*)mxGetDimensions(F_ptr); + if( cell_ptr == NULL || mxIsEmpty(cell_ptr) ){ + /* If the cell is empty, we assume this cell as zero matrix */ + continue; + } + sizeM = mxGetM(cell_ptr); + sizeN = mxGetN(cell_ptr); + tmp_ptr = mxGetPr(cell_ptr); + if( mxIsSparse(cell_ptr) ){ + /* Sparse Matrix */ + ir_ptr = mxGetIr(cell_ptr); + jc_ptr = mxGetJc(cell_ptr); + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + sdpa.inputElement( k, l+1, j+1, j+1, tmp_ptr[startidx]); + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + endidx = jc_ptr[sizeN]; + for(idx = 0; idx < endidx; idx++){ + i = ir_ptr[idx]; + sdpa.inputElement( k, l+1, i+1, i+1, tmp_ptr[idx]); + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + for(idx = startidx; idx < endidx; idx++){ + i = ir_ptr[idx]; + if( i <= j ){ + sdpa.inputElement( k, l+1, i+1, j+1, tmp_ptr[idx]); + } + } + } + } + } else { + /* Dense Matrix */ + if( sdpa.getBlockType(l+1)==SDPA::SDP ){ + /* Full Matrix */ + for(j = 0; j < sizeN; j++){ + for(i = 0; i < sizeM; i++){ + if( i <= j ){ + if( tmp_ptr[j * sizeN + i] != 0 ){ + sdpa.inputElement(k, l+1, i+1, j+1, + tmp_ptr[j * sizeN + i]); + } + } + } + } + } else { + /* Diagonal Matrix */ + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j] != 0 ){ + sdpa.inputElement( k, l+1, j+1, j+1, tmp_ptr[j]); + } + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + for(i = 0; i < sizeM; i++){ + if( tmp_ptr[i] != 0 ){ + sdpa.inputElement( k, l+1, i+1, i+1, tmp_ptr[i]); + } + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j * sizeN + j] != 0 ){ + sdpa.inputElement( k, l+1, j+1, j+1, + tmp_ptr[j * sizeN + j]); + } + } + } + } + } + } + } + + /*** Check the consistence of F, c ***/ + if( nSymmChk ){ + sdpa.initializeUpperTriangle(true); + } + else { + sdpa.initializeUpperTriangle(false); + } + + /*** Check initial point ***/ + if( IniPt == 1 ){ + rMessage("Initial point is ignored in SDPA-C."); + #if 0 + sdpa.setInitPoint(true); + /* initial value for xVec */ + for(k = 0; k < mDIM; k++){ + sdpa.inputInitXVec( k+1, x0_ptr[k]); + } + /* initial value for XMat */ + cell_index = 0; + for(l = 0; l < nBLOCK; l++){ + cell_ptr = mxGetCell(X0_ptr, cell_index); + if( cell_ptr == NULL || mxIsEmpty(cell_ptr) ){ + /* If the cell is empty, we assume this cell as zero matrix */ + continue; + } + sizeM = mxGetM(cell_ptr); + sizeN = mxGetN(cell_ptr); + tmp_ptr = mxGetPr(cell_ptr); + if( mxIsSparse(cell_ptr) ){ + /* Sparse Matrix */ + ir_ptr = mxGetIr(cell_ptr); + jc_ptr = mxGetJc(cell_ptr); + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + sdpa.inputInitXMat(l+1, j+1, j+1, tmp_ptr[startidx]); + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + endidx = jc_ptr[sizeN]; + for(idx = 0; idx < endidx; idx++){ + i = ir_ptr[idx]; + sdpa.inputInitXMat(l+1, i+1, i+1, tmp_ptr[idx]); + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + for(idx = startidx; idx < endidx; idx++){ + i = ir_ptr[idx]; + if( i <= j ){ + sdpa.inputInitXMat( l+1, i+1, j+1, tmp_ptr[idx]); + } + } + } + } + } else { + /* Dense Matrix */ + if( sdpa.getBlockType(l+1) == SDPA::SDP ){ + /* Full Matrix */ + for(j = 0; j < sizeN; j++){ + for(i = 0; i < sizeM; i++){ + if( i <= j ){ + if( tmp_ptr[j * sizeN + i] != 0 ){ + sdpa.inputInitXMat( l+1, i+1, j+1, + tmp_ptr[j * sizeN + i]); + } + } + } + } + } else { + /* Diagonal Matrix */ + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j] != 0 ){ + sdpa.inputInitXMat( l+1, j+1, j+1, tmp_ptr[j]); + } + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + for(i = 0; i < sizeM; i++){ + if( tmp_ptr[i] != 0 ){ + sdpa.inputInitXMat( l+1, i+1, i+1, tmp_ptr[i]); + } + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j * sizeN + j] != 0 ){ + sdpa.inputInitXMat( l+1, j+1, j+1, + tmp_ptr[j * sizeN + j]); + } + } + } + } + } + cell_index++; + } + /* initial value for YMat */ + cell_index = 0; + for(l = 0; l < nBLOCK; l++){ + cell_ptr = mxGetCell(Y0_ptr, cell_index); + if( cell_ptr == NULL || mxIsEmpty(cell_ptr) ){ + /* If the cell is empty, we assume this cell as zero matrix */ + continue; + } + sizeM = mxGetM(cell_ptr); + sizeN = mxGetN(cell_ptr); + tmp_ptr = mxGetPr(cell_ptr); + if( mxIsSparse(cell_ptr) ){ + /* Sparse Matrix */ + ir_ptr = mxGetIr(cell_ptr); + jc_ptr = mxGetJc(cell_ptr); + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + sdpa.inputInitYMat( l+1, j+1, j+1, tmp_ptr[startidx]); + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + endidx = jc_ptr[sizeN]; + for(idx = 0; idx < endidx; idx++){ + i = ir_ptr[idx]; + sdpa.inputInitYMat( l+1, i+1, i+1, tmp_ptr[idx]); + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + startidx = jc_ptr[j]; + endidx = jc_ptr[j+1]; + if( startidx == endidx ){ continue; } + for(idx = startidx; idx < endidx; idx++){ + i = ir_ptr[idx]; + if( i <= j ){ + sdpa.inputInitYMat( l+1, i+1, j+1, tmp_ptr[idx]); + } + } + } + } + } else { + /* Dense Matrix */ + if( sdpa.getBlockType(l+1) == SDPA::SDP ){ + /* Full Matrix */ + for(j = 0; j < sizeN; j++){ + for(i = 0; i < sizeM; i++){ + if( i <= j ){ + if( tmp_ptr[j * sizeN + i] != 0 ){ + sdpa.inputInitYMat( l+1, i+1, j+1, + tmp_ptr[j * sizeN + i]); + } + } + } + } + } else { + /* Diagonal Matrix */ + if( sizeM == 1 && sizeN != 1 ){ + /* Row Vector Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j] != 0 ){ + sdpa.inputInitYMat( l+1, j+1, j+1, tmp_ptr[j]); + } + } + } else if( sizeM != 1 && sizeN == 1 ){ + /* Column Vector Case */ + for(i = 0; i < sizeM; i++){ + if( tmp_ptr[i] != 0 ){ + sdpa.inputInitYMat( l+1, i+1, i+1, tmp_ptr[i]); + } + } + } else { + /* Matrix Case */ + for(j = 0; j < sizeN; j++){ + if( tmp_ptr[j * sizeN + j] != 0 ){ + sdpa.inputInitYMat( l+1, j+1, j+1, + tmp_ptr[j * sizeN + j]); + } + } + } + } + } + cell_index++; + } + #endif + } + /*** Solve SDP ***/ + sdpa.initializeSolve(); + sdpa.solve(); + /*** Dimacs Error Information ****/ + if (nDimacs != 0) { + field_ptr = mxCreateNumericMatrix(6,1,mxDOUBLE_CLASS,mxREAL); + double dimacs_error[7]; + sdpa.getDimacsError(dimacs_error); + double* dimacs_store = mxGetPr(field_ptr); + if (sdpa.judgeDimacsAvailability() == false) { + for (int i=0; i<=6; i++) { + dimacs_store[i] = 0.0; + } + } + else { + for (int i=1; i<=6; i++) { + dimacs_store[i-1] = dimacs_error[i]; + } + } + mxSetField(INFO_ptr, 0, "dimacs", field_ptr); + } + /**** Set output values to arguments ****/ + /* Optimal value of Primal objective */ + objVal_ptr[0] = sdpa.getPrimalObj(); + /* Optimal value of Dual objective */ + objVal_ptr[1] = sdpa.getDualObj(); + /* Optimal value for xVec */ + tmp_ptr = sdpa.getResultXVec(); + if( tmp_ptr != NULL ){ + for(k = 0; k < mDIM; k++){ + x_ptr[k] = tmp_ptr[k]; + } + } + /* Optimal value for XMat */ + cell_index = 0; + result_ptr = sdpa.getResultXMat(1); + if (result_ptr == NULL) { + rMessage("XMat is not computed by XPrint, and XMat will be empty matrix."); + } + for(l = 0; l < nBLOCK; l++){ + result_ptr = sdpa.getResultXMat(l+1); + if (result_ptr == NULL) { + cell_ptr = mxCreateDoubleMatrix(0, 0, mxREAL); + mxSetCell(X_ptr, cell_index++, mxDuplicateArray(cell_ptr)); + continue; + } + size = sdpa.getBlockSize(l+1); + if( sdpa.getBlockType(l+1) == SDPA:: SDP){ + sizeM = size; + sizeN = size; + } else { + sizeM = 1; + sizeN = abs(size); + } + cell_ptr = mxCreateDoubleMatrix(sizeM, sizeN, mxREAL); + tmp_ptr = mxGetPr(cell_ptr); + idx = 0; + result_ptr = sdpa.getResultXMat(l+1); + if( size >= 0 ){ + for(j = 0; j < sizeN; j++){ + for(i = 0; i < sizeM; i++){ + tmp_ptr[idx++] = result_ptr[j + sizeN * i]; + } + } + } else { + for(idx = 0; idx < sizeN; idx++){ + tmp_ptr[idx] = result_ptr[idx]; + } + } + mxSetCell(X_ptr, cell_index++, mxDuplicateArray(cell_ptr)); + } + /* Optimal value for YMat */ + result_ptr = sdpa.getResultYMat(1); + if (result_ptr == NULL) { + rMessage("YMat is not computed by YPrint, and YMat will be empty matrix."); + } + cell_index = 0; + for(l = 0; l < nBLOCK; l++){ + result_ptr = sdpa.getResultYMat(l+1); + if (result_ptr == NULL) { + cell_ptr = mxCreateDoubleMatrix(0, 0, mxREAL); + mxSetCell(Y_ptr, cell_index++, mxDuplicateArray(cell_ptr)); + continue; + } + size = sdpa.getBlockSize(l+1); + if( sdpa.getBlockType(l+1) == SDPA:: SDP){ + sizeM = size; + sizeN = size; + } else { + sizeM = 1; + sizeN = abs(size); + } + cell_ptr = mxCreateDoubleMatrix(sizeM, sizeN, mxREAL); + tmp_ptr = mxGetPr(cell_ptr); + idx = 0; + result_ptr = sdpa.getResultYMat(l+1); + if( size >= 0 ){ + for(j = 0; j < sizeN; j++){ + for(i = 0; i < sizeM; i++){ + tmp_ptr[idx++] = result_ptr[j + sizeN * i]; + } + } + } else { + for(idx = 0; idx < sizeN; idx++){ + tmp_ptr[idx] = result_ptr[idx]; + } + } + mxSetCell(Y_ptr, cell_index++, mxDuplicateArray(cell_ptr)); + } + /* Phase information */ + field_ptr = mxCreateString(szPhase[sdpa.getPhaseValue()]); + mxSetField(INFO_ptr, 0, "phasevalue", field_ptr); + /* Iteration */ + field_ptr = mxCreateNumericMatrix(1,1,mxDOUBLE_CLASS,mxREAL); + *mxGetPr(field_ptr) = (double)sdpa.getIteration(); + mxSetField(INFO_ptr, 0, "iteration", field_ptr); + /* close output file */ + time(<ime); + strcpy(string_time,ctime(<ime)); + string_time[strlen(string_time)-1]='\0'; + if (fp) { + fprintf(fp,"SDPA-C end at [%s]\n",string_time); + } + if (fpResult) { + fprintf(fpResult,"SDPA-C end at [%s]\n",string_time); + } + + if( nOutfile ){ + fclose(fp); + } + if (fpResult != NULL) { + fclose(fpResult); + } + /*** Free allocated memory ****/ + mxFree(subscript); + sdpa.finalize(); + + return; +} + +/* + * Matlab gateway function + */ +void mexFunction(int nlhs, mxArray *plhs[], + int nrhs, const mxArray *prhs[]) +{ + /* Decleration of variables */ + + double + *mDIM_ptr, + *nBLOCK_ptr, + *bLOCKsTRUCT_ptr, + *c_ptr, + *x_ptr, + *objVal_ptr, + *x0_ptr; + + mxArray + *F_ptr, + *X_ptr, + *Y_ptr, + *X0_ptr, + *Y0_ptr, + *OPTION_ptr, + *INFO_ptr; + + int IniPt; + + const char *fnames[] = { + "phasevalue", + "iteration", + "dimacs", + "cpusec" + }; + + /* + * check arguments + */ + if( nrhs != 9 ){ + mexErrMsgTxt("Input arguments must be 9."); + } + + /* Get the pointer of input variables */ + mDIM_ptr = mxGetPr(prhs[0]); + nBLOCK_ptr = mxGetPr(prhs[1]); + bLOCKsTRUCT_ptr = mxGetPr(prhs[2]); + c_ptr = mxGetPr(prhs[3]); + F_ptr = (mxArray*)prhs[4]; + x0_ptr = mxGetPr(prhs[5]); + X0_ptr = (mxArray*)prhs[6]; + Y0_ptr = (mxArray*)prhs[7]; + OPTION_ptr = (mxArray*)prhs[8]; + + if( mxIsEmpty(prhs[5]) /* x0 */ + || mxIsEmpty(prhs[6]) /* X0 */ + || mxIsEmpty(prhs[7]) /* Y0 */ + ){ + /* nouse of Initial Point*/ + IniPt = 0; + } else { + /* use of Initial Point */ + IniPt = 1; + /* check of argument dimensions */ + /* if(*mDIM_ptr != mxGetM(prhs[5]) || !mxIsDouble(prhs[5])) + mexErrMsgTxt("x0 must be (mDIM x 1) column vector of double"); + if( *nBLOCK_ptr != sizeM_X0 || 1 != sizeN_X0 || !mxIsCell(prhs[6])) + mexErrMsgTxt("X0 must be (nBLOCK x 1) cell array"); + if( *nBLOCK_ptr != sizeM_Y0 || 1 != sizeN_Y0 || !mxIsCell(prhs[7])) + + mexErrMsgTxt("Y0 must be (nBLOCK x 1) cell array");*/ + } + /* Create cellarrays for the output variables */ + plhs[0] = mxCreateDoubleMatrix(1,2,mxREAL); + plhs[1] = mxCreateDoubleMatrix((int) *mDIM_ptr,1,mxREAL); + plhs[2] = mxCreateCellMatrix((int) *nBLOCK_ptr,1); + plhs[3] = mxCreateCellMatrix((int) *nBLOCK_ptr,1); + plhs[4] = mxCreateStructMatrix(1,1,4,fnames); + + //Get the pointer of output variables + objVal_ptr = mxGetPr(plhs[0]); + x_ptr = mxGetPr(plhs[1]); + X_ptr = plhs[2]; + Y_ptr = plhs[3]; + INFO_ptr = plhs[4]; + + /* Call sdpasolver here */ + sdpasolver(mDIM_ptr, + nBLOCK_ptr, + bLOCKsTRUCT_ptr, + c_ptr, + F_ptr, + x0_ptr, + X0_ptr, + Y0_ptr, + OPTION_ptr, + IniPt, + objVal_ptr, + x_ptr, + X_ptr, + Y_ptr, + INFO_ptr); + + return; +} + +/* + * End of File + */ diff --git a/external/sdpa/mex/paramC.m b/external/sdpa/mex/paramC.m new file mode 100644 index 0000000..1242c13 --- /dev/null +++ b/external/sdpa/mex/paramC.m @@ -0,0 +1,233 @@ +function OPTION=paramC(OPTION) +% +% Create SDPA-C parameters. +% If there is no argument, default parameters are returned. +% +% OPTION=paramC % for default parameter +% or +% OPTION=paramC(field1,value1,field2,value2,....) +% +% +% - field?: string : field name +% - value?: numeric or string : +% +% +% - OPTION: structure data: each field is as follows: +% * maxIteration : The maximum number of iterations. +% * epsilonStar : The accuracy of an approximate optimal solution +% for primal and dual SDP. +% * lambdaStar : An initial point. +% * omegaStar : The search region for an optimal solution. +% * lowerBound : Lower bound of the minimum objective value of +% the primal SDP. +% * upperBound : Upper bound of the maximum objective value of +% the dual SDP +% * betaStar : The parameter for controlling the search direction +% if the current point is feasible. +% * betaBar : The parameter for controlling the search direction +% if the current point is infeasible. +% * gammaStar : A reduction factor for the primal and dual step +% lengths. +% * epsilonDash : The relative accuracy of an approximate optimal +% solution between primal and dual SDP. +% * isSymmetric : The flag for the checking the symmetricity of input +% matrices. (0 => no check, 1=> check) +% * isDimacs : The flag to compute DIMACS ERROR +% (0 => no computation, 1=> computation) +% * xPrint : (default %+8.3e, NOPRINT skips printout) +% * XPrint : (default %+8.3e, NOPRINT skips printout) +% * YPrint : (default %+8.3e, NOPRINT skips printout) +% * infPrint : (default %+10.16e, NOPRINT skips printout) +% * print : Destination of file output. the default setting is +% stdout by 'display'. +% If print is set 'no' or empty, no message +% is print out +% * resultFile : Destination of detail file output +% * NumThreads : Number of Threads for internal computation + +% This file is a component of SDPA +% Copyright (C) 2004-2013 SDPA Project +% +% 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 +% +% SDPA-M: $Revision: 6.2 $ +% $Id: param.m,v 6.2 2005/05/28 02:36:40 drophead Exp $ + +% create default OPTION +OPTION0.maxIteration = 100; +OPTION0.epsilonStar = 1.0E-7; +OPTION0.lambdaStar = 1.0E2; +OPTION0.omegaStar = 2.0; +OPTION0.lowerBound = -1.0E5; +OPTION0.upperBound = 1.0E5; +OPTION0.betaStar = 0.1; +OPTION0.betaBar = 0.3; +OPTION0.gammaStar = 0.9; +OPTION0.epsilonDash = 1.0E-7; +OPTION0.isSymmetric = 0; +OPTION0.isDimacs = 0; +OPTION0.xPrint = '%+8.3e'; +OPTION0.XPrint = '%+8.3e'; +OPTION0.YPrint = '%+8.3e'; +OPTION0.infPrint = '%+16.10e'; +OPTION0.print = 'display'; +OPTION0.resultFile = ''; +try + OPTION0.NumThreads = maxNumCompThreads; % Max Avialable Number +catch + fprintf(['Function maxNumCompThreads is not found, NumThreads ' ... + 'is set as 1.\n']); + OPTION0.NumThreads = 1; +end + + +OPTION0.aggConeSize = []; + +if (nargin == 0) || isempty(OPTION) + OPTION = OPTION0; + return +else + if ~isfield(OPTION,'maxIteration') + OPTION.maxIteration=OPTION0.maxIteration; + elseif ~isnumeric(OPTION.maxIteration) + error('OPTION.maxIteration must be numeric.'); + end + % + if ~isfield(OPTION,'epsilonStar') + OPTION.epsilonStar=OPTION0.epsilonStar; + elseif ~isnumeric(OPTION.epsilonStar) + error('epsilonStar must be numeric.'); + end + % + if ~isfield(OPTION,'lambdaStar') + OPTION.lambdaStar=OPTION0.lambdaStar; + elseif ~isnumeric(OPTION.lambdaStar) + error('OPTION.lambdaStar must be numeric.'); + end + % + if ~isfield(OPTION,'omegaStar') + OPTION.omegaStar=OPTION0.omegaStar; + elseif ~isnumeric(OPTION.omegaStar) + error('OPTION.omegaStar must be numeric.'); + end + % + if ~isfield(OPTION,'lowerBound') + OPTION.lowerBound=OPTION0.lowerBound; + elseif ~isnumeric(OPTION.lowerBound) + error('OPTION.lowerBound must be numeric.'); + end + % + if ~isfield(OPTION,'upperBound') + OPTION.upperBound=OPTION0.upperBound; + elseif ~isnumeric(OPTION.upperBound) + error('OPTION.upperBound must be numeric.'); + end + % + if ~isfield(OPTION,'betaStar') + OPTION.betaStar=OPTION0.betaStar; + elseif ~isnumeric(OPTION.betaStar) + error('OPTION.beaStar must be numeric.'); + end + % + if ~isfield(OPTION,'betaBar') + OPTION.betaBar=OPTION0.betaBar; + elseif ~isnumeric(OPTION.betaBar) + error('OPTION.betaBar must be numeric.'); + end + % + if ~isfield(OPTION,'gammaStar') + OPTION.gammaStar=OPTION0.gammaStar; + elseif ~isnumeric(OPTION.gammaStar) + error('OPTION.gammaStar must be numeric.'); + end + % + if ~isfield(OPTION,'epsilonDash') + OPTION.epsilonDash=OPTION0.epsilonDash; + elseif ~isnumeric(OPTION.epsilonDash) + error('OPTION.epsilonDash must be numeric.'); + end + % + if isfield(OPTION,'searchDir') + disp('Parameter *searchDir* is no longer supported.'); + disp('HRVW/KSH/M is automatically used.'); + end + % + if ~isfield(OPTION,'isSymmetric') + OPTION.isSymmetric=OPTION0.isSymmetric; + elseif ~isnumeric(OPTION.isSymmetric) || ((OPTION.isSymmetric~=0) && (OPTION.isSymmetric~=1)) + error('OPTION.isSymmetric must be 0 or 1.'); + end + % + if ~isfield(OPTION,'isDimacs') + OPTION.isDimacs=OPTION0.isDimacs; + elseif ~isnumeric(OPTION.isDimacs) || ((OPTION.isDimacs~=0) && (OPTION.isDimacs~=1)) + error('OPTION.isDimacs must be 0 or 1.'); + end + % + if ~isfield(OPTION,'XPrint') + OPTION.XPrint=OPTION0.XPrint; + elseif ~ischar(OPTION.XPrint) + error('OPTION.XPrint must be string.'); + end + % + if ~isfield(OPTION,'YPrint') + OPTION.YPrint=OPTION0.YPrint; + elseif ~ischar(OPTION.YPrint) + error('OPTION.YPrint must be string for printf.'); + end + % + if ~isfield(OPTION,'infPrint') + OPTION.infPrint=OPTION0.infPrint; + elseif ~ischar(OPTION.infPrint) + error('OPTION.infPrint must be string for printf.'); + end + % + if isfield(OPTION,'print') && ... + (isempty(OPTION.print) || length(OPTION.print) == 0) + OPTION.print = 'no'; + end + if ~isfield(OPTION,'print') + OPTION.print=OPTION0.print; + elseif ~ischar(OPTION.print) + disp('*** OPTION.print must be string for FILE. ***'); + disp(' "display" is for stdout.'); + disp(' "no" or empty is for skip message.'); + disp(' filename is filename in which message will be written.'); + error('*** OPTION.print must be string for FILE. ***'); + end + % + if ~isfield(OPTION,'resultFile') || isempty(OPTION.resultFile) + OPTION.resultFile=OPTION0.resultFile; + elseif ~ischar(OPTION.resultFile) + error('OPTION.resultFile must be string.'); + end + % + if ~isfield(OPTION,'NumThreads') + OPTION.NumThreads=OPTION0.NumThreads; + elseif ~isnumeric(OPTION.NumThreads) + error('OPTION.NumThreads must be positive integer.'); + end + + if ~isfield(OPTION,'aggConeSize') + OPTION.aggConeSize = OPTION0.aggConeSize; + elseif (~isempty(OPTION.aggConeSize)) && ... + ((~isnumeric(OPTION.aggConeSize)) || (OPTION.aggConeSize <=0)) + error('OPTION.aggConeSize must be a positive integer.'); + end +end + +return + +% End of File diff --git a/external/sdpa/mex/sdpamC.m b/external/sdpa/mex/sdpamC.m new file mode 100644 index 0000000..09d9e35 --- /dev/null +++ b/external/sdpa/mex/sdpamC.m @@ -0,0 +1,81 @@ +function [objVal,x,X,Y,INFO]=sdpamC(mDIM,nBLOCK,bLOCKsTRUCT,c,F,... + x0,X0,Y0,OPTION) +% +% Compute the solution of standard SDP. +% Since some of input arguments are optional, sdpam can be +% overloaded as below. +% +% [objVal,x,X,Y,INFO] = sdpamC(mDIM,nBLOCK,bLOCKsTRUCT,c,F, +% x0,X0,Y0,OPTION); +% +% +% - mDIM : integer ; number of primal variables +% - nBLOCK : integer ; number of blocks of F +% - bLOCKsTRUCT: vector ; represetns the block structure of F +% - c : vector ; coefficient vector +% - F : cell array; coefficient matrices +% - x0,X0,Y0 : cell array; initial point +% (NOTE: In SDPA-C, initial point is ignored.) +% - OPTION : structure ; options +% +% +% - objVal: [objValP objValD]; optimal value of P and D +% - x : vector ; optimal solution +% - X,Y : cell arrray ; optimal solutions +% - INFO : structure ; infomation of the solution +% + +% This file is a component of SDPA +% Copyright (C) 2004-2013 SDPA Project +% +% 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 +% +% SDPA-M: $Revision: 6.2 $ +% $Id: sdpam.m,v 6.2 2005/05/28 02:36:40 drophead Exp $ + +t = cputime; + +if (nargin < 5 || nargin > 9) + error('incorrect number of input arguments') +elseif nargin == 5 + % make initial points empty + x0=[];X0=[];Y0=[]; + % load default parameters + OPTION=paramC; + % solve by SDPA + [objVal,x,X,Y,INFO]=mexsdpaC(mDIM,nBLOCK,bLOCKsTRUCT,... + c,F,x0,X0,Y0,OPTION); +elseif nargin == 6 + % use OPTION given by arguments + OPTION=paramC(x0); + % make initial points empty + x0=[];X0=[];Y0=[]; + [objVal,x,X,Y,INFO]=mexsdpaC(mDIM,nBLOCK,bLOCKsTRUCT,... + c,F,x0,X0,Y0,OPTION); +elseif nargin == 8 + % load default parameters + OPTION=paramC; + %solve by SDPA + [objVal,x,X,Y,INFO]=mexsdpaC(mDIM,nBLOCK,bLOCKsTRUCT,... + c,F,x0,X0,Y0,OPTION); +elseif nargin == 9 + OPTION=paramC(OPTION); + % solve by SDPA + [objVal,x,X,Y,INFO]=mexsdpaC(mDIM,nBLOCK,bLOCKsTRUCT,... + c,F,x0,X0,Y0,OPTION); +end +INFO.cpusec = cputime-t; + +% End of File diff --git a/external/sdpa/mex/sedumiwrapC.m b/external/sdpa/mex/sedumiwrapC.m new file mode 100644 index 0000000..47431d2 --- /dev/null +++ b/external/sdpa/mex/sedumiwrapC.m @@ -0,0 +1,382 @@ +function [x,y,info]=sedumiwrapC(A,b,c,K,pars,OPTION); + +% +% SeDuMi wrapper for SDPA +% +% [x,y,info]=sedumiwrapC(A,b,c,K,pars,OPTION); +% or +% [x,y,info]=sedumiwrapC(A,b,c,K); % with SDPA-M default parameter +% +% Note : +% 'A', in each SDP block, only upper triangle part is used. +% 'K' can include only 'f'(free) 'l'(linear) 's'(SDP) cones. +% 'pars' information is NOT used (just for SeDuMi compatibility) +% 'OPTION' is option structure for SDPA-M (for details, try 'help param') +% 'info' information is based on SDPA-M +% +% This file is a component of SDPA +% Copyright (C) 2004-2013 SDPA Project +% +% 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 +% +% SDPA-M: $Revision: 7.3 $ + + +t = cputime; + +fprintf('-SeDuMi Wrapper for SDPA-C Start-\n'); + +if (nargin < 4 || nargin > 6) + error('incorrect number of input arguments') +end +if nargin >= 5 + if isfield(OPTION,'print') && ~isempty(OPTION.print) + fprintf('Note: pars information [5th argument] is not used\n'); + end +end +if nargin < 6 + OPTION = paramC; +else + OPTION = paramC(OPTION); +end + +if isfield(K,'q') && ~isempty(K.q) + error('Current Wrapper cannot handle K.q'); +end + +if isfield(K,'r') && ~isempty(K.r) + error('Current Wrapper cannot handle K.r'); +end + +if size(b,2) ~= 1 + % fprintf('Transposing b to a column vector'); + b = b'; +end +if size(b,2) ~= 1 + error('b must be a vector'); +end + +if size(c,2) ~= 1 + % fprintf('Transposing c to a column vector\n'); + c = c'; +end +if size(c,2) ~= 1 + error('c must be a vector'); +end + +%%%%% +% Constructing at least one SDP cone if necesary +if (~isfield(K,'s')) || (isempty(K.s)) + [K] = LPtoLP_SDP(K); +end +%%%%% + +totalLength = 0; +Kf = 0; +if isfield(K,'f') && ~isempty(K.f) + totalLength = totalLength + K.f; + Kf = K.f; +end +if isfield(K,'l') && ~isempty(K.l) + totalLength = totalLength + K.l; +else + K.l = 0; +end +if isfield(K,'s') && ~isempty(K.s) + if size(K.s,2) ~= 1 + % fprintf('Transposing K.s to a column vector\n'); + K.s = K.s'; + end + Ks = sum(K.s .* K.s); + totalLength = totalLength + Ks; +else + error('Cannot handle empty K.s'); +end +m = size(b,1); +n = size(c,1); + +[mA,nA] = size(A); +if (m~=mA || n~=nA) && (m~=nA || n~=mA) + fprintf('Inconsistent Size of A,b,c\n'); + fprintf('size(A) = [%d,%d], size(b) = %d, size(c) = %d\n',... + mA,nA, m,n); + error('Cannot continue...'); +end + +if (n~=totalLength) + fprintf('Inconsistent Size of c and K\n'); + fprintf('size(c) = %d, totalSize(K) = %d\n',... + n, totalLength); + error('Cannot continue...'); +end + +if ~issparse(A) + if isfield(OPTION,'print') && ~isempty(OPTION.print) + fprintf('Converting A from dense to sparse\n'); + end + A = sparse(A); +end + +if issparse(b) + % fprintf('Converting b from sparse to dense\n'); + b = full(b); +end + +if ~issparse(c) + % fprintf('Converting c from dense to sparse\n'); + c = sparse(c); +end + +if issparse(K.s) + % fprintf('Converting K.s from sparse to dense\n'); + K.s = full(K.s); +end + +if Kf ~= 0 + if isfield(OPTION,'print') && ~isempty(OPTION.print) + fprintf(['Free Variables are divided into positive and ' ... + 'negative part of LP cone\n']); + end + Af = A(:,1:Kf); + Kl = K.l; + Al = A(:,Kf+1:Kf+Kl); + As = A(:,Kf+Kl+1:Kf+Kl+Ks); + Anew = [Af, -Af, Al, As]; + + cf = c(1:Kf); + cl = c(Kf+1:Kf+Kl); + cs = c(Kf+Kl+1:Kf+Kl+Ks); + cnew = [cf; -cf; cl; cs]; + + Knew.l = 2*Kf + Kl; + Knew.s = K.s; + + A = Anew; + c = cnew; + K = Knew; + + clear Af; + clear Al; + clear As; + clear Anew; + clear cf; + clear cl; + clear cs; + clear cnew; + clear Knew; +end + +if isfield(K,'s') && ~isempty(K.s) + if size(K.s,2) ~= 1 + K.s = Ks'; + end +end + +%%%%% +% Aggregating small SDP cones into larger SDP cones +aggSW = 0; +minNoSDPcones = 3; +if (isfield(OPTION,'aggConeSize')) && (~isempty(OPTION.aggConeSize)) && (isnumeric(OPTION.aggConeSize)) && ... + ((OPTION.aggConeSize > 0)) && (length(K.s') > minNoSDPcones) && (length(find(K.s' < OPTION.aggConeSize)) > minNoSDPcones) + fprintf('OPTION.aggConeSize = %d\n',OPTION.aggConeSize) + K0 = K; + aggSW = 1; + [A,c,K1] = aggSDPcones(A,c,K,OPTION.aggConeSize); + A = sparse(A); + c = sparse(c); + K = K1; +end +%%%%% + + +% A should be transposed when passed to mex +[mA,nA] = size(A); +if mA ~= K.l + sum(K.s.*K.s) + A = A'; +end +% fprintf('size(A) = (%d,%d)\n',size(A,2),size(A,1)); +% fprintf('length(K.s) = %d\n',length(K.s)); + +[x,y,info] = mexSedumiWrapC(A,b,c,K,OPTION); + +%%%%% +% Retrieving the origianl primal SDP cone variables +if aggSW == 1 + if (isfield(K,'l')) && (~isempty(K.l)) && (K.l > 0) + xSDP = x(K.l+1:size(x,1),1); + xLP = x(1:K.l,1); + [xSDP] = mexDisAggSDPsol(xSDP,K0.s,K1.s); + x = [xLP; xSDP]; + else + [x] = mexDisAggSDPsol(x,K0.s,K1.s); + end +end +%%%%% + +if Kf ~=0 + xlength = size(x); + xnew = x(1:Kf) - x(Kf+1:Kf+Kf); + xnew = [xnew; x(Kf+Kf+1:xlength)]; + x = xnew; +end + +info.cpusec = cputime-t; +% if isfield(OPTION,'print') && ~isempty(OPTION.print) + fprintf('-SeDuMi Wrapper for SDPA-C End-\n'); +% end + +% End of File + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [K] = LPtoLP_SDP(K) + +if isfield(K,'q') && ~isempty(K.q) + error('Current Wrapper cannot handle K.q'); +end + +if isfield(K,'r') && ~isempty(K.r) + error('Current Wrapper cannot handle K.r'); +end + +if isfield(K,'s') && ~isempty(K.s) + return; +elseif ~isfield(K,'l') || isempty(K.l) + error('Both LP and SDP cones are empty, so the problem can not be solved'); +else + K.l = K.l-1; + if K.l == 0 + K.l = []; + end + K.s = 1; +end + +return + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function [A1,c1,K1] = aggSDPcones(A,c,K0,aggConeSize) +% +% [A1,c1,K1] = aggSDPcones(A,c,K0,aggConeSize) +% Input : SeDuMi format +% aggConeSize : the block size into which small blocks are converted +% Output: Sedumi format with larger SDP cone matrices +% + +if (size(K0.s,2) > 1) + K0.s = K0.s'; +end + +if size(A,1) > size(A,2) + A = A'; +end +% if size(c,1) < size(c,2) +% c = c'; +% end +[m,n] = size(A); +% +if ~isfield(K0,'f') || isempty(K0.f) + fDim = 0; +else + fDim = K0.f; +end +% +if ~isfield(K0,'l') || isempty(K0.l) + ellDim = 0; +else + ellDim = K0.l; +end +% +if ~isfield(K0,'q') + qDim = 0; +else + if size(K0.q,1) > size(K0.q,2) + K0.q = K0.q'; % a row vector + end + qDim = sum(K0.q); +end +% +if ~isfield(K0,'s') || isempty(K0.s) + K1 = K0; + A1 = A; + c1 = c; + return +else + if size(K0.s,2) > size(K0.s,1) + K0.s = K0.s'; % a column vector + end + sDim = sum(K0.s .* K0.s); +end + +nonSDim = fDim+ellDim+qDim; +if nonSDim == 0 + cNonSDP = []; + AnonSDP = []; + c0SDP = c; + A0SDP = A; +else + cNonSDP = c(1:nonSDim,1); + AnonSDP = A(:,1:nonSDim); + c0SDP = c(nonSDim+1:n,1); + A0SDP = A(:,nonSDim+1:n); +end + +K1s = []; +coneSize = 0; +for p=1:length(K0.s) + if (K0.s(p) > aggConeSize) + if coneSize > 0 + K1s = [K1s; coneSize; K0.s(p)]; + coneSize = 0; + else + K1s = [K1s; K0.s(p)]; + coneSize = 0; + end + elseif ((coneSize + K0.s(p) > aggConeSize)) + K1s = [K1s; coneSize]; + coneSize = K0.s(p); + elseif ((coneSize + K0.s(p) == aggConeSize)) + K1s = [K1s; coneSize + K0.s(p)]; + coneSize = 0; + else + coneSize = coneSize + K0.s(p); + end +end +if (coneSize > 0) + K1s = [K1s; coneSize]; +end + +K0s = K0.s; % K0.s is a column vector +K1 = K0; +K1.s = K1s; % K1s is a column vector + +tStart = tic; +% C0SDP, K0s and K1s need to be clolumn vector +[A1SDP,c1SDP] = mexAggSDPcones(A0SDP,c0SDP',K0s,K1s); +tElapsed = toc(tStart); +fprintf('Original SDP: the max cone size, the number of cones = %3d, %3d\n',full(max(K0.s)),length(K0.s)); +fprintf('Transformed SDP: the max cone size, the number of cones = %3d, %3d\n',full(max(K1.s)),length(K1.s)); +% fprintf('Elapsed time for transformation = %6.2e\n',tElapsed); + +c1SDP = c1SDP'; + +A1 = sparse([AnonSDP, A1SDP]); +c1 = sparse([cNonSDP;c1SDP]); + +% checkData(A1,b1,c1,K1); + +% sedumi(A1,b1,c1,K1); + +return + + diff --git a/external/sdpa/param.sdpaC b/external/sdpa/param.sdpaC new file mode 100644 index 0000000..a9ec655 --- /dev/null +++ b/external/sdpa/param.sdpaC @@ -0,0 +1,15 @@ +100 unsigned int maxIteration; +1.0E-7 double 0.0 < epsilonStar; +1.0E2 double 0.0 < lambdaStar; +2.0 double 1.0 < omegaStar; +-1.0E5 double lowerBound; +1.0E5 double upperBound; +0.1 double 0.0 <= betaStar < 1.0; +0.3 double 0.0 <= betaBar < 1.0, betaStar <= betaBar; +0.9 double 0.0 < gammaStar < 1.0; +1.0E-7 double 0.0 < epsilonDash; +%+8.3e char* xPrint (default %+8.3e, NOPRINT skips printout) +%+8.3e char* XPrint (default %+8.3e, NOPRINT skips printout) +%+8.3e char* YPrint (default %+8.3e, NOPRINT skips printout) +%+10.16e char* infPrint (default %+10.16e, NOPRINT skips printout) + diff --git a/external/sdpa/sdpa_algebra.h b/external/sdpa/sdpa_algebra.h new file mode 100644 index 0000000..72804f2 --- /dev/null +++ b/external/sdpa/sdpa_algebra.h @@ -0,0 +1,153 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/* sdpa_algebra.h + +LAPACK+BLAS definitions wrapper + +Define macros to mangle the given C identifier (in lower and upper +case), which must not contain underscores, for linking with Fortran. + +*/ + +#ifndef __sdpa_algebra_h__ +#define __sdpa_algebra_h__ + +#define FC_RET_I int +#define FC_RET_D double + +#if defined(__APPLE__) // Dirty... +#define FC_FUNC(name,NAME) name ## _ +#endif + + +#define FC_FUNC(name,NAME) name ## _ // for SDPA-C temporary + +#define dtrsm_fc FC_FUNC (dtrsm, DTRSM) +#define dsyrk_fc FC_FUNC (dsyrk, DSYRK) +#define dcopy_fc FC_FUNC (dcopy, DCOPY) +#define daxpy_fc FC_FUNC (daxpy, DAXPY) +#define dgemm_fc FC_FUNC (dgemm, DGEMM) +#define dgemv_fc FC_FUNC (dgemv, DGEMV) +#define dscal_fc FC_FUNC (dscal, DSCAL) +#define dtrsv_fc FC_FUNC (dtrsv, DTRSV) +#define dtrmv_fc FC_FUNC (dtrmv, DTRMV) +#define ddot_fc FC_FUNC (ddot, DDOT) +#define dtrmm_fc FC_FUNC (dtrmm, DTRMM) +#define ilaenv_fc FC_FUNC (ilaenv, ILAENV) +#define dsteqr_fc FC_FUNC (dsteqr, DSTEQR) +#define dsyev_fc FC_FUNC (dsyev, DSYEV) +#define dpotrf_fc FC_FUNC (dpotrf, DPORTRF) + + +extern "C" +{ +// BLAS + FC_RET_I dtrsm_fc + (char* side, char* uplo, char* trans, char* diag, + int* M, int* N, + double* alpha, + double* A, int* lda, + double* B, int* ldb, int side_len, + int uplo_len, int trans_len, int diag_len); + + FC_RET_I dsyrk_fc + (char* uplo, char* trans, int* N, int* K, + double* alpha, + double* A, int* lda, + double* beta, + double* C, int* ldc, int uplo_len, int trans_len); + + FC_RET_I dcopy_fc + (int* N, + double* X, int* incX, + double* Y, int* incY); + + FC_RET_I daxpy_fc + (int* N, + double* alpha, + double* X, int* incX, + double* Y, int* incY); + + FC_RET_I dgemm_fc + (char* transA, char* transB, int* M, int* N, int* K, + double* alpha, + double* A, int* lda, + double* B, int* ldb, + double* beta, + double* C, int* ldc, int transA_len, int transB_len); + + FC_RET_I dgemv_fc + (char* trans, int* M, int* N, + double* alpha, + double* A, int* lda, + double* X, int* incX, + double* beta, + double* Y, int* incY, int trans_len); + + FC_RET_I dscal_fc + (int* N, + double* alpha, + double* X, int* incX); + + FC_RET_I dtrsv_fc + (char* uplo, char* trans, char* diag, int* N, + double* A, int* lda, + double* X, int* incX, int uplo_len, + int trans_len, int diag_len); + + FC_RET_I dtrmv_fc + (char* uplo, char *trans, char* diag, int *N, + double *A, int *lda, + double *X, int *incX, int uplo_len, int trans_len, int diag_len); + + FC_RET_D ddot_fc + (int* N, double* X, int* incX, double* Y, int* incY); + + FC_RET_I dtrmm_fc + (char* side, char* uplo, char* trans, char* diag, + int* M, int* N, + double* alpha, + double* A, int* lda, + double* B, int* ldb, int side_len, int uplo_len, + int trans_len, int diag_len); + +// LAPACK + + FC_RET_I ilaenv_fc + (int *ispec, char *name, char *opts, int *n1, + int *n2, int *n3, int *n4, int name_len, int opts_len); + + FC_RET_I dsteqr_fc + (char *compz, int *n, double *d, + double *e, double *z, int *ldz, double *work, + int *info, int compz_len); + + FC_RET_I dsyev_fc + (char *jobz, char *uplo, int *n, double *a, + int *lda, double *w, double *work, int *lwork, + int *info, int jobz_len, int uplo_len); + + FC_RET_I dpotrf_fc + (char *uplo, int *n, double *a, int *lda, + int *info, int uplo_len); +} + +#endif // __sdpa_algebra_h__ diff --git a/external/sdpa/sdpa_block.cpp b/external/sdpa/sdpa_block.cpp new file mode 100644 index 0000000..fd44c77 --- /dev/null +++ b/external/sdpa/sdpa_block.cpp @@ -0,0 +1,140 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_block.h" + +namespace sdpa { + +BlockStruct::BlockStruct() +{ + nBlock = 0; + blockStruct = NULL; + blockNumber = NULL; + blockType = NULL; + SDP_nBlock = 0; + SDP_blockStruct = NULL; + LP_nBlock = 0; +} + +BlockStruct::~BlockStruct() +{ + finalize(); +} + +void BlockStruct::initialize(int nBlock) +{ + this->nBlock = nBlock; + NewArray(blockStruct,int,nBlock); + NewArray(blockType, BlockType, nBlock); + NewArray(blockNumber,int,nBlock); + SDP_nBlock = 0; + SDP_blockStruct = NULL; + LP_nBlock = 0; +} + +void BlockStruct::finalize() +{ + DeleteArray(blockStruct); + DeleteArray(blockNumber); + DeleteArray(blockType); + DeleteArray(SDP_blockStruct); +} + +void BlockStruct::makeInternalStructure() +{ + SDP_nBlock = 0; + LP_nBlock = 0; + for (int l=0; lDisplay = Display; +} + +void SDPA::setResultFile(FILE* fpout) +{ + this->fpout = fpout; +} + +void SDPA::setNumThreads(int NumThreads) +{ + newton.setNumThreads(Display,fpout,NumThreads); +} + +SDPA::ParameterType SDPA::getParameterType() +{ + return typeParameter; +} + +int SDPA::getParameterMaxIteration() +{ + return param.maxIteration; +} +double SDPA::getParameterEpsilonStar() +{ + return param.epsilonStar; +} +double SDPA::getParameterLambdaStar() +{ + return param.lambdaStar; +} +double SDPA::getParameterOmegaStar() +{ + return param.omegaStar; +} +double SDPA::getParameterLowerBound() +{ + return param.lowerBound; +} +double SDPA::getParameterUpperBound() +{ + return param.upperBound; +} +double SDPA::getParameterBetaStar() +{ + return param.betaStar; +} +double SDPA::getParameterBetaBar() +{ + return param.betaBar; +} +double SDPA::getParameterGammaStar() +{ + return param.gammaStar; +} +double SDPA::getParameterEpsilonDash() +{ + return param.epsilonDash; +} +char* SDPA::getParameterPrintXVec() +{ + return param.xPrint; +} +char* SDPA::getParameterPrintXMat() +{ + return param.XPrint; +} +char* SDPA::getParameterPrintYMat() +{ + return param.YPrint; +} +char* SDPA::getParameterPrintInformation() +{ + return param.infPrint; +} +FILE* SDPA::getDisplay() +{ + return Display; +} +FILE* SDPA::getResultFile() +{ + return fpout; +} +bool SDPA::getInitPoint() +{ + return isInitPoint; +} + +int SDPA::getNumThreads() +{ + return newton.NUM_THREADS; +} + +void SDPA::inputConstraintNumber(int m) +{ + this->m = m; +} + +void SDPA::inputBlockNumber(int nBlock) +{ + this->nBlock = nBlock; + bs.initialize(nBlock); +} + +void SDPA::inputBlockSize(int l, int size) +{ + bs.blockStruct[l-1] = size; +} + +void SDPA::inputBlockType(int l, ConeType coneType) +{ + if (coneType == SDPA::SDP) { + bs.blockType[l-1] = BlockStruct::btSDP; + } + if (coneType == SDPA::LP) { + bs.blockType[l-1] = BlockStruct::btLP; + } +} + +void SDPA::inputCVec(int k, double value) +{ + if (k > m || k <= 0) { + rError("k exceeds ConstraintNumber or " + "k is less than or equal to zero :: m= " + << m << " : k= " << k); + + } + inputData.b.ele[k-1] = value; +} + +void SDPA::inputElement(int k, int l, int i, int j, double value, + bool inputCheck) +{ + if (inputCheck) { + if (k > m || k < 0) { + rError ("k exceeds ConstraintNumber or " + "k is less than zero :: m= " + << m << " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + if (l > nBlock || l <= 0) { + rError ("l exceeds nBlock or " + "l is less than or equal to zero :: nBlock= " + << nBlock << " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + int dim = bs.blockStruct[l-1]; + if (i > dim || i <= 0) { + rError ("i exceeds dimension of the block or " + "i is less than or equal to zero :: dim= " + << dim << " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + if (j > dim || j <= 0) { + rError ("j exceeds dimension of the block or " + "j is less than or equal to zero :: dim= " + << dim << " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + if (bs.blockType[l-1] == BlockStruct::btSDP) { + if (i > j) { + rMessage("Swap i and j [Only Upper Triangle]" + " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + } + if (bs.blockType[l-1] == BlockStruct::btLP) { + if (i!=j) { + rError("i should be j in LP block" + " : k= " << k << " : l= " << l + << " : i= " << i << " : j= " << j); + } + } + } + + if (i > j) { + int tmp = i; i = j; j = tmp; + } + + LIJV* indexLIJv; + NewArray(indexLIJv,LIJV,1); + indexLIJv[0].SDPl = -1; + indexLIJv[0].LPl = -1; + indexLIJv[0].i = i; + indexLIJv[0].j = j; + indexLIJv[0].value = value; + + if (bs.blockType[l-1] == BlockStruct::btSDP) { + int l2 = bs.blockNumber[l-1]; + indexLIJv[0].SDPl = l2; + NonZeroElements[k].push_back(indexLIJv); + } else if (bs.blockType[l-1] == BlockStruct::btLP) { + int l2 = bs.blockNumber[l-1]; + indexLIJv[0].LPl = l2+i-1; + NonZeroElements[k].push_back(indexLIJv); + } + // NonZeroElements[k].push_back(indexLIJv); +} + +void SDPA::inputInitXVec(int k, double value) +{ + rError("This routine is not available in SDPA-C"); +} + +void SDPA::inputInitXMat(int l, int i, int j, double value) +{ + rError("This routine is not available in SDPA-C"); +} + +void SDPA::inputInitYMat(int l, int i, int j, double value) +{ + rError("This routine is not available in SDPA-C"); +} + + +void SDPA::initializeUpperTriangleSpace() +{ + bs.makeInternalStructure(); + NewArray(NonZeroElements,vector,m+1); + inputData.initialize(m, bs); + + // In SDPA-C, currentPt.initialize will be called later + // currentPt.initialize(m, bs, param.lambdaStar, com); +} + + +void SDPA::printNonZeroElements(FILE* fp) +{ + for (int k=0; k<=m; ++k) { + int size = NonZeroElements[k].size(); + for (int index = 0; index= 0) { + fprintf(fp,"%d, %d(S), %d, %d, ",k,SDPl,i,j); + } + if (LPl >= 0) { + fprintf(fp,"%d, %d(L), %d, %d, ",k,LPl,i,j); + } + fprintf(fp,param.infPrint,value); + fprintf(fp,"\n"); + } + } +} + +void SDPA::checkNonZeroElements() +{ + TimeStart(FILE_CHECK_START1); + for (int k=0; k<=m; ++k) { + int size = NonZeroElements[k].size(); + for (int index = 0; indexLP_sp_index[index2]); + } + printf("\n"); + rMessage("SDP blocks = "); + for (int index2 = 0; index2 < SDP_sp_nBlock; ++index2) { + printf(" %d", target->SDP_sp_index[index2]); + } + printf("\n"); + #endif + target->initializeInputVector(); + } + LP_blockCount.clear(); + SDP_blockCount.clear(); +} + +void SDPA::setNonZeroElements() +{ + for (int k=0; k0) { + target = &inputData.A[k-1]; + scale = 1.0; + } + int length = NonZeroElements[k].size(); + for (int index1 = 0; index1 < length; ++index1) { + LIJV* oneData = NonZeroElements[k].at(index1); + if (oneData[0].LPl >= 0) { + target->setElement_LP(oneData[0].LPl, oneData[0].value*scale); + } + if (oneData[0].SDPl >= 0) { + target->setElement_SDP(oneData[0].SDPl, + oneData[0].i-1, oneData[0].j-1, + oneData[0].value*scale); + } + } + } + + double v1 = 0; // dummy initialize + double v2 = 0; // dummy initialize + inputData.C.sortInputVector(); + int check_l = 0, check_i = 0, check_j = 0; + double check_v1 = 0, check_v2 = 0; + inputData.C.checkInputDataStructure(check_l, check_i, check_j, + check_v1, check_v2); + inputData.C.makeInternalStructure(); + if (check_l>=0) { + printf("***** invalid data ******\n"); + printf("F[0]:%d-th SDP block:[%d, %d]-th element has more than one input\n", + check_l+1, check_i+1, check_j+1); + rError("Stop due to input error\n"); + } + for (int k=0; k=0) { + printf("***** invalid data ******\n"); + printf("F[%d]:%d-th SDP block:[%d, %d]-th element has more than one input\n", + k+1, check_l+1, check_i+1, check_j+1); + rError("Stop due to input error\n"); + } + } + + #if 0 + rMessage("************** Read finished, internal data is from here."); + rMessage("C = -------------------------"); + inputData.C.display(); + for (int k=0; k nBlock || l <= 0) { + rError ("l exceeds nBlock or " + "l is less than or equal to zero :: nBlock= " + << nBlock << " : l= " << l); + } + if (bs.blockType[l-1] == BlockStruct::btSDP) { + int l2 = bs.blockNumber[l-1]; + return currentPt.finalZ.SDP_block[l2].de_ele; + } + else if (bs.blockType[l-1] == BlockStruct::btLP) { + int start = bs.blockNumber[l-1]; + return ¤tPt.finalZ.LP_block[start]; + } + return NULL; +} + +double* SDPA::getResultYMat(int l) +{ + if (IO::judgeXmake(param) == false) { + return NULL; + } + if (l > nBlock || l <= 0) { + rError ("l exceeds nBlock or " + "l is less than or equal to zero :: nBlock= " + << nBlock << " : l= " << l); + } + if (bs.blockType[l-1] == BlockStruct::btSDP) { + int l2 = bs.blockNumber[l-1]; + return currentPt.finalX.SDP_block[l2].de_ele; + } + else if (bs.blockType[l-1] == BlockStruct::btLP) { + int start = bs.blockNumber[l-1]; + return ¤tPt.finalX.LP_block[start]; + } + return NULL; +} + +double SDPA::getPrimalObj() +{ + // Note reverse primal-dual + return -solveInfo.objValDual; +} + +double SDPA::getDualObj() +{ + // Note reverse primal-dual + return -solveInfo.objValPrimal; +} + +double SDPA::getPrimalError() +{ + // Note reverse primal-dual + return currentRes.normDual; +} + +double SDPA::getDualError() +{ + // Note reverse primal-dual + return currentRes.normPrimal; +} + +double SDPA::getDigits() +{ + double mean = (fabs(solveInfo.objValPrimal) + + fabs(solveInfo.objValDual)) / 2.0; + double PDgap = getDualityGap(); + double digits = -log10(fabs(PDgap/mean)); + return digits; +} + +int SDPA::getIteration() +{ + return pIteration; +} + +double SDPA::getMu() +{ + return mu.current; +} + +double SDPA::getDualityGap() +{ + double PDgap = fabs(solveInfo.objValPrimal + - solveInfo.objValDual); + return PDgap; +} + +SDPA::PhaseType SDPA::getPhaseValue() +{ + // Note reverse primal-dual + switch (phase.value) { + case SolveInfo::noINFO : return noINFO ; break; + case SolveInfo::pFEAS : return pFEAS ; break; + case SolveInfo::dFEAS : return dFEAS ; break; + case SolveInfo::pdFEAS : return pdFEAS ; break; + case SolveInfo::pdINF : return pdINF ; break; + case SolveInfo::pFEAS_dINF: return pINF_dFEAS; break; + case SolveInfo::pINF_dFEAS: return pFEAS_dINF; break; + case SolveInfo::pdOPT : return pdOPT ; break; + case SolveInfo::pUNBD : return dUNBD ; break; + case SolveInfo::dUNBD : return pUNBD ; break; + default: break; + } + return noINFO; +} + +void SDPA::getPhaseString(char* str) +{ + switch (phase.value) { + case SolveInfo::noINFO : strcpy(str,(char *)"noINFO "); break; + case SolveInfo::pFEAS : strcpy(str,(char *)"pFEAS "); break; + case SolveInfo::dFEAS : strcpy(str,(char *)"dFEAS "); break; + case SolveInfo::pdFEAS : strcpy(str,(char *)"pdFEAS "); break; + case SolveInfo::pdINF : strcpy(str,(char *)"pdINF "); break; + case SolveInfo::pFEAS_dINF: strcpy(str,(char *)"pFEAS_dINF"); break; + case SolveInfo::pINF_dFEAS: strcpy(str,(char *)"pINF_dFEAS"); break; + case SolveInfo::pdOPT : strcpy(str,(char *)"pdOPT "); break; + case SolveInfo::pUNBD : strcpy(str,(char *)"pUNBD "); break; + case SolveInfo::dUNBD : strcpy(str,(char *)"dUNBD "); break; + default: + strcpy(str,(char *)"phase error"); + break; + } + return; +} + +double SDPA::getSolveTime() +{ + return com.TotalTime; +} + +int SDPA::getConstraintNumber() +{ + return m; +} + +int SDPA::getBlockNumber() +{ + return nBlock; +} + +int SDPA::getBlockSize(int l) +{ + if (l<=0 || l>nBlock) { + rMessage("out of range : getBlockSize " + ": l = " << l + << " should be between 1 and nBlock " << nBlock); + } + return bs.blockStruct[l-1]; +} + +SDPA::ConeType SDPA::getBlockType(int l) +{ + if (l<=0 || l>nBlock) { + rMessage("out of range : getBlockSize " + ": l = " << l + << " should be between 1 and nBlock " << nBlock); + } + switch (bs.blockType[l-1]) { + case BlockStruct::btSDP : return SDPA::SDP ; + case BlockStruct::btLP : return SDPA::LP ; + } + rError("Type Error in getBlockType "); + return SDPA::SDP; // dummy return +} + +void SDPA::getDimacsError(double* DimacsError) +{ + if (judgeDimacsAvailability() == false) { + return; + } + IO::computeDimacs(DimacsError, solveInfo, currentRes, + currentPt, inputData); +} + +void SDPA::printDimacsError(double* DimacsError, char* printFormat, + FILE* fpout) +{ + if (judgeDimacsAvailability() == false) { + return; + } + IO::printDimacs(DimacsError,printFormat,fpout); +} + +void SDPA::printDimacsEasy(FILE* fpout) +{ + double dimacs_error[7]; + currentPt.makeFinalSolution(true, true, bs); + getDimacsError(dimacs_error); + printf("Dimacs = "); + for (int dd=1; dd<7; ++dd) { + printf("%.3e ", dimacs_error[dd]); + } + printf("\n"); +} + + +void SDPA::printResultXVec(FILE* fp) +{ + // Note reverse primal-dual + currentPt.cholmodSpace.yVec.display(fp,1.0,param.xPrint); +} + +void SDPA::printResultXMat(FILE* fp) +{ + if (IO::judgeZmake(param) == false) { + fprintf(fp, "Result XMat is not computed.\n"); + return; + } + // Note reverse primal-dual + currentPt.finalZ.displaySolution(bs,fp,param.XPrint); +} + +void SDPA::printResultYMat(FILE* fp) +{ + if (IO::judgeXmake(param) == false) { + fprintf(fp, "Result YMat is not computed.\n"); + return; + } + // Note reverse primal-dual + currentPt.finalX.displaySolution(bs,fp,param.YPrint); +} + +void SDPA::printComputationTime(FILE* fp) +{ + com.display(fp); +} + +void SDPA::printParameters(FILE* fp) +{ + param.display(fp); +} + +bool SDPA::judgeDimacsAvailability() // for only SDPA-C +{ + bool Xmake = IO::judgeXmake(param); + bool Zmake = IO::judgeZmake(param); + if (Xmake == false || Zmake == false) { + return false; + } + return true; +} + +void SDPA::printSDPAVersion(FILE* fp) +{ + if (fp) { + fprintf(fp,"%s\n",(char*)sdpa_right); + } +} + +void SDPA::readInput(char* filename, FILE* fpout) +{ + TimeStart(FILE_READ_START1); + FILE* fpinput = NULL; + if ((fpinput = fopen(filename,"r")) == NULL) { + rError("Cannot Open Data File " << filename); + } + #if 0 + if (fpout){ + fprintf(fpout,"data is %s ", filename); + fprintf(fpout," : sparse\n"); + } + #endif + + char titleAndComment[LengthOfBuffer]; + IO::read(fpinput,fpout,m,titleAndComment); + IO::read(fpinput,nBlock); + bs.initialize(nBlock); + IO::read(fpinput,bs); + bs.makeInternalStructure(); + inputData.initialize(m, bs); + IO::read(fpinput, inputData.b); + IO::read(fpinput, m, bs, inputData); + // inputData.initialize_index(); + fclose(fpinput); + TimeEnd(FILE_READ_END1); + com.FileRead += TimeCal(FILE_READ_START1, + FILE_READ_END1); + com.TotalTime += TimeCal(FILE_READ_START1, + FILE_READ_END1); + return; +} + +void SDPA::readParameter(char* filename, FILE* fpout) +{ + FILE* fp = NULL; + if ((fp=fopen(filename,"r"))==NULL) { + rError("Cannot Open parameter File " << filename); + } + param.readFile(fp); + fclose(fp); + return; +} + +void SDPA::finalize() +{ + bs.finalize(); + inputData.finalize(); + chordal.finalize(); + newton.finalize(); + currentPt.finalize(); + initPt_xMat.finalize(); + initPt_zMat.finalize(); + currentRes.finalize(); + alpha.finalize(); +} + + +void SDPA::copyCurrentToInit() +{ + // This function is only compatibility with SDPA. + rMessage("The function SDPA::copyCurrentToInit() does nothing in SDPA-C"); + return; +} + +void SDPA::setKappa(double KAPPA) +{ + this->KAPPA = KAPPA; +} + diff --git a/external/sdpa/sdpa_call.h b/external/sdpa/sdpa_call.h new file mode 100644 index 0000000..544d9e6 --- /dev/null +++ b/external/sdpa/sdpa_call.h @@ -0,0 +1,256 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*-------------------------------------------------- + sdpa_call.h +--------------------------------------------------*/ + +/*************************************************** + In this header file, + Do NOT use 'using namespace sdpa;'. + Otherwise, if users define their OWN 'sdpa' namespace, + it would be trouble. +***************************************************/ + + +#ifndef __sdpa_call_h__ +#define __sdpa_call_h__ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* The class list is generated by the following command + $ grep class *.h | grep -v \; | grep -v SDPA | tr ':' ' ' | \ + awk '{print $2 " " $3 ";"}' +*/ + +namespace sdpa { + class BlockStruct; + class Chordal; + class Solutions; + class InputData; + class Residuals; + class IO; + class Lal; + class Newton; + class ComputeTime; + class Parameter; + class StepLength; + class DirectionParameter; + class Switch; + class AverageComplementarity; + class RatioInitResCurrentRes; + class SolveInfo; + class Phase; + class Vector; + class BlockVector; + class SparseMatrix; + class DenseMatrix; + class SparseLinearSpace; + class DenseLinearSpace; + class Time; + + class LIJV + { + public: + int SDPl,LPl,i,j; + double value; + }; +}; + +class SDPA +{ +public: + + enum PhaseType {noINFO, pFEAS,dFEAS,pdFEAS,pdINF, + pFEAS_dINF,pINF_dFEAS,pdOPT,pUNBD,dUNBD}; + enum ParameterType {PARAMETER_DEFAULT, + PARAMETER_UNSTABLE_BUT_FAST, + PARAMETER_STABLE_BUT_SLOW}; + + enum ConeType {SDP, SOCP, LP}; + // SOCP is not implemented in the current version. + + enum SparseType {AUTO, SPARSE, DENSE}; + // SparseType is only for compatiblity with SDPA7 + // In SDPA-C, this always must be SPARSE. + // enum SparseType {AUTO, SPARSE, DENSE}; + // when AUTO is set, the type is analyzed by the file extenstion. + + SDPA(); + ~SDPA(); + + void setParameterType(ParameterType type = PARAMETER_DEFAULT); + void setParameterMaxIteration(int maxIteration); + void setParameterEpsilonStar (double epsilonStar); + void setParameterLambdaStar (double lambdaStar); + void setParameterOmegaStar (double omegaStar); + void setParameterLowerBound (double lowerBound); + void setParameterUpperBound (double upperBound); + void setParameterBetaStar (double betaStar); + void setParameterBetaBar (double betaBar); + void setParameterGammaStar (double gammaStar); + void setParameterEpsilonDash (double epsilonDash); + + void setParameterPrintXVec(char* xPrint); + void setParameterPrintXMat(char* XPrint); + void setParameterPrintYMat(char* YPrint); + void setParameterPrintInformation(char* infPrint); + + void setDisplay(FILE* Display = stdout); + void setResultFile(FILE* fpout = stdout); + + void setNumThreads(int NumThreads=0); + + ParameterType getParameterType(); + int getParameterMaxIteration(); + double getParameterEpsilonStar (); + double getParameterLambdaStar (); + double getParameterOmegaStar (); + double getParameterLowerBound (); + double getParameterUpperBound (); + double getParameterBetaStar (); + double getParameterBetaBar (); + double getParameterGammaStar (); + double getParameterEpsilonDash (); + + char* getParameterPrintXVec(); + char* getParameterPrintXMat(); + char* getParameterPrintYMat(); + char* getParameterPrintInformation(); + + FILE* getDisplay(); + FILE* getResultFile(); + bool getInitPoint(); + + int getNumThreads(); + + void inputConstraintNumber(int m); + void inputBlockNumber(int nBlock); + void inputBlockSize(int l, int size); + void inputBlockType(int l, ConeType coneType); + void inputCVec(int k, double value); + void inputElement(int k, int l, int i, int j, double value, + bool inputCheck = false); + void inputInitXVec(int k, double value); + void inputInitXMat(int l, int i, int j, double value); + void inputInitYMat(int l, int i, int j, double value); + + void initializeUpperTriangleSpace(); + void initializeUpperTriangle(bool inputTwiceCheck = false); + void initializeSolve(); + + void solve(); + + double* getResultXVec(); + double* getResultXMat(int l); + double* getResultYMat(int l); + double getPrimalObj(); + double getDualObj(); + double getPrimalError(); + double getDualError(); + double getDigits(); + int getIteration(); + double getMu(); + double getDualityGap(); + PhaseType getPhaseValue(); + void getPhaseString(char* str); + double getSolveTime(); + + int getConstraintNumber(); + int getBlockNumber(); + int getBlockSize(int l); + ConeType getBlockType(int l); + + void getDimacsError(double* DimacsError); + void printDimacsError(double* DimacsError, char* printFormat, + FILE* fp = stdout); + + void printResultXVec(FILE* fp = stdout); + void printResultXMat(FILE* fp = stdout); + void printResultYMat(FILE* fp = stdout); + void printComputationTime(FILE* fp = stdout); + void printParameters(FILE* fp = stdout); + + bool judgeDimacsAvailability(); // for only SDPA-C + + static void printSDPAVersion(FILE* fp = stdout); + + void readInput(char* filename, FILE* fpout = NULL); + void readParameter(char* filename, FILE* fpout = NULL); + void writeInputSparse(char* filename, char* printFormat); + void writeInitSparse(char* filename, char* printFormat); + + void finalize(); + void copyCurrentToInit(); + + // setKappa is for only SDPA developers + void setKappa(double KAPPA); + + // // for debugging, private is replaced by public + // public: +private: + double KAPPA; + int m; + int nBlock; + FILE* Display; + FILE* fpout; + bool isInitPoint; + ParameterType typeParameter; + + int pIteration; + + sdpa::ComputeTime com; + sdpa::Parameter param; + sdpa::BlockStruct bs; + sdpa::InputData inputData; + sdpa::Newton newton; + sdpa::Chordal chordal; + sdpa::Solutions currentPt; + sdpa::DenseLinearSpace initPt_xMat; + sdpa::DenseLinearSpace initPt_zMat; + sdpa::Residuals currentRes; + sdpa::StepLength alpha; + sdpa::DirectionParameter beta; + sdpa::Switch reduction; + sdpa::AverageComplementarity mu; + sdpa::RatioInitResCurrentRes theta; + sdpa::SolveInfo solveInfo; + sdpa::Phase phase; + + + // temporary space to store + // upper trianguler part non-zeros. + vector * NonZeroElements; + void printNonZeroElements(FILE* fpout = stdout); + void checkNonZeroElements(); + void setNonZeroBlockStruct(); + void setNonZeroElements(); + + void printDimacsEasy(FILE* fpout = stdout); // heavy but for each iteration +}; + +#endif // __sdpa_call_h__ diff --git a/external/sdpa/sdpa_chordal.cpp b/external/sdpa/sdpa_chordal.cpp new file mode 100644 index 0000000..96ea8dd --- /dev/null +++ b/external/sdpa/sdpa_chordal.cpp @@ -0,0 +1,557 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include + +#define PrintSparsity 1 +#define PLUS_ADJUST_DIAGONAL (1.0e-10) + // #define PLUS_ADJUST_DIAGONAL (m*1.0e-10) + + // For debug +#define FORCE_SCHUR_DENSE 0 +#define FORCE_SCHUR_SPARSE 0 + +#include "sdpa_chordal.h" +#define MUMPS_JOB_INIT -1 +#define MUMPS_JOB_END -2 +#define MUMPS_JOB_ANALYSIS 1 +#define MUMPS_JOB_FACTORIZE 2 +#define MUMPS_JOB_SOLVE 3 +#define MUMPS_USE_COMM_WORLD (-987654) + +namespace sdpa { + +Chordal::Chordal() +{ + mumps_usage = false; + sparse_bMat_ptr = NULL; + best = 0; +} + +Chordal::~Chordal() +{ + finalize(); +} + +void Chordal::initialize(SparseMatrix* sparse_bMat_ptr) +{ + // condition of sparse computation + // m_threshold < mDim, + // b_threshold < nBlock, + // aggregate_threshold >= aggrigated sparsity ratio + // extend_threshold >= extended sparsity ratio + m_threshold = 100; + b_threshold = 5; + aggregate_threshold = 0.70; + extend_threshold = 0.80; + +#if FORCE_SCHUR_DENSE // DENSE computation for debugging + m_threshold = 10000000; + b_threshold = 1000000; + aggregate_threshold = 0.0; + extend_threshold = 0.0; +#endif +#if FORCE_SCHUR_SPARSE // SPARSE computation for debugging + m_threshold = 0; + b_threshold = 0; + aggregate_threshold = 2.0; + extend_threshold = 2.0; +#endif + // initialize by assuming Schur would be DENSE + best = SELECT_DENSE; + + this->sparse_bMat_ptr = sparse_bMat_ptr; + + // initialize MUMPS + mumps_id.job = MUMPS_JOB_INIT; + mumps_id.comm_fortran = MUMPS_USE_COMM_WORLD; + // rank 0 process participates factorizations + mumps_id.par = 1; + // Only symmetric positive definite matricies + mumps_id.sym = 1; + // No OUTPUTS + mumps_id.icntl[1-1] = -1; + mumps_id.icntl[2-1] = -1; + mumps_id.icntl[3-1] = -1; + mumps_id.icntl[4-1] = 0; + + // MUMPS selects ordering automatically + mumps_id.icntl[7-1] = SELECT_MUMPS_BEST; + // for Minumum Degree Ordering + // mumps_id.icntl[7-1] = 0; + + dmumps_c(&mumps_id); + mumps_usage = true; + +} + +void Chordal::finalize() +{ + if (mumps_usage == true) { + mumps_id.job = MUMPS_JOB_END; + dmumps_c(&mumps_id); + mumps_usage = false; + } + if (sparse_bMat_ptr) { + sparse_bMat_ptr->finalize(); + } + sparse_bMat_ptr = NULL; +} + +// merge array1 to array2 +void Chordal::mergeArray(int na1, int* array1, int na2, int* array2) +{ + + int ptr = na1 + na2 - 1; + int ptr1 = na1-1; + int ptr2 = na2-1; + int idx1, idx2; + + while ((ptr1 >= 0) || (ptr2 >= 0)){ + + if (ptr1 >= 0){ + idx1 = array1[ptr1]; + } else { + idx1 = -1; + } + if (ptr2 >= 0 ){ + idx2 = array2[ptr2]; + } else { + idx2 = -1; + } + if (idx1 > idx2){ + array2[ptr] = idx1; + ptr1--; + } else { + array2[ptr] = idx2; + ptr2--; + } + ptr--; + + } + + // error check + if (ptr != -1){ + rMessage("Chordal::mergeArray:: program bug"); + } +} + +void Chordal::catArray(int na1, int* array1, int na2, int* array2) +{ + int ind1 = 0; + for (int index=0; index initialize(m,m,SparseMatrix::SPARSE, + nz,SparseMatrix::DSarrays); + sparse_bMat_ptr -> NonZeroCount = nz; + int indexNZ = 0; + for (j=0; j row_index[indexNZ] = tmp[j][index_i]+1; + sparse_bMat_ptr -> column_index[indexNZ] = j+1; + sparse_bMat_ptr -> sp_ele[indexNZ] = 0.0; + indexNZ++; + } + } + + DeleteArray(counter); + for (j=0; jNonZeroCount; + mumps_id.irn = sparse_bMat_ptr->row_index; + mumps_id.jcn = sparse_bMat_ptr->column_index; + mumps_id.a = sparse_bMat_ptr->sp_ele; + + // sparse_bMat_ptr->display(); + // rMessage("m = " << m); + // rMessage("NonZeroCount = " << sparse_bMat_ptr->NonZeroCount); + + // No OUTPUTS for analysis + mumps_id.icntl[1-1] = -1; + mumps_id.icntl[2-1] = -1; + mumps_id.icntl[3-1] = -1; + mumps_id.icntl[4-1] = 0; + // strcpy(mumps_id.write_problem,"write_problem"); + dmumps_c(&mumps_id); + double lower_nonzeros = (double)mumps_id.infog[20-1]; + // if lower_nonzeros is greater than 1.0e+6, + // the value infog[20-1] is lower_nonzeros*(-1)/(1.0e+6). + // we need to adjust the value. + if (lower_nonzeros < 0) { + lower_nonzeros *= (-1.0e+6); + } + #if 0 + rMessage("lower_nonzeros = " << lower_nonzeros); + rMessage("Schur density = " << lower_nonzeros/((m+1)*m/2)*100 << "%" ); + #endif + + if (mumps_id.infog[1-1] != 0) { + rError("MUMPS ERROR " << mumps_id.infog[1-1]); + } + return lower_nonzeros; +} + +void Chordal::ordering_bMat(int m, int nBlock, + InputData& inputData, + FILE* Display, FILE* fpOut) +{ + best = SELECT_MUMPS_BEST; + #if 0 + if ((m <= m_threshold)||(nBlock <= b_threshold)) { + best = SELECT_DENSE; + return; + } + #else + if (m <= m_threshold) { + best = SELECT_DENSE; + return; + } + #endif + + #if 1 + for (int b=0; b m * sqrt(aggregate_threshold)){ + best = SELECT_DENSE; + return; + } + } + for (int b=0; b m * sqrt(aggregate_threshold)){ + best = SELECT_DENSE; + return; + } + } + #endif + + makeGraph(inputData,m); + // Here, we initialize sparse_bMat + + int NonZeroAggregate = sparse_bMat_ptr->NonZeroCount*2-m; + if (NonZeroAggregate > aggregate_threshold * (double)m * (double) m) { + best = SELECT_DENSE; + return; + } + + double lowerExtended = analysisAndcountLowerNonZero(m); + double NonZeroExtended = lowerExtended*2 - m; + double overM2 = 1.0/((double)m*(double)m)*100.0; +#if PrintSparsity + /* print sparsity information */ + if (Display) { + + #if 0 + fprintf(Display,"dense matrix :\t\t\t%14d elements\n", m*m); + fprintf(Display,"aggregate sparsity pattern :\t\t\t%14d elements\n", + NonZeroAggregate); + fprintf(Display,"extended sparsity pattern :\t\t\t%14d elements\n", + (int)NonZeroExtended); + fprintf(Display,"Schur density = %.8lf%%\n", + (double)NonZeroExtended*overM2); + fprintf(Display,"Fill in = %e%%\n", + (double)(NonZeroExtended-NonZeroAggregate)*overM2); + fprintf(Display, "Estimated FLOPs for elimation process = %e\n", + mumps_id.rinfog[1-1]); + fprintf(Display, + "Maximum Processor Memory Requirement = %d MB = %.2lf GB\n", + mumps_id.infog[16-1],(double)mumps_id.infog[16-1]/1024); + fprintf(Display, + "Total Processors Memory Requirement = %d MB = %.2lf GB\n", + mumps_id.infog[17-1],(double)mumps_id.infog[17-1]/1024); + #else + fprintf(Display, "Full Schur Elements %ld, %.2e\n", + (long int)((double)m*m),(double)m*m); + fprintf(Display, "Agg %d (%.2e%%)->Ext %d (%.2e%%)" + " [Fill %d (%.2e%%)]\n", + NonZeroAggregate, + (double)NonZeroAggregate*overM2, + (int)NonZeroExtended, + (double)NonZeroExtended*overM2, + (int)(NonZeroExtended-NonZeroAggregate), + (double)(NonZeroExtended-NonZeroAggregate)*overM2); + fprintf(Display, "Est FLOPs Elim = %.2e:", + mumps_id.rinfog[1-1]); + fprintf(Display, + "MaxMem = %dMB = %.2lfGB:", + mumps_id.infog[16-1],(double)mumps_id.infog[16-1]/1024); + fprintf(Display, + "TotMem = %dMB = %.2lfGB\n", + mumps_id.infog[17-1],(double)mumps_id.infog[17-1]/1024); + #endif + } + if (fpOut) { + #if 0 + fprintf(fpOut,"dense matrix :\t\t\t%14d elements\n", m*m); + fprintf(fpOut,"aggregate sparsity pattern :\t\t\t%14d elements\n", + NonZeroAggregate); + fprintf(fpOut,"extended sparsity pattern :\t\t\t%14d elements\n", + (int)NonZeroExtended); + fprintf(fpOut,"Schur density = %.8lf%%\n", + (double)NonZeroExtended*overM2); + fprintf(fpOut,"Fill in = %e%%\n", + (double)(NonZeroExtended-NonZeroAggregate)*overM2); + fprintf(fpOut, "Estimated FLOPS for elimation process = %e\n", + mumps_id.rinfog[1-1]); + fprintf(fpOut, + "Maximum Processor Memory Requirement = %d MB = %.2lf GB\n", + mumps_id.infog[16-1],(double)mumps_id.infog[16-1]/1024); + fprintf(fpOut, + "Total Processors Memory Requirement = %d MB = %.2lf GB\n", + mumps_id.infog[17-1],(double)mumps_id.infog[17-1]/1024); + #else + fprintf(fpOut, "Full Schur Elements Number %ld, %.2e\n", + (long int)((double)m*m),(double)m*m); + fprintf(fpOut, "Agg %d (%.2e%%)->Ext %d (%.2e%%)" + " [Fill %d (%.2e%%)]\n", + NonZeroAggregate, + (double)NonZeroAggregate*overM2, + (int)NonZeroExtended, + (double)NonZeroExtended*overM2, + (int)(NonZeroExtended-NonZeroAggregate), + (double)(NonZeroExtended-NonZeroAggregate)*overM2); + fprintf(fpOut, "Est FLOPs Elim = %.2e:", + mumps_id.rinfog[1-1]); + fprintf(fpOut, + "MaxMem = %dMB = %.2lfGB:", + mumps_id.infog[16-1],(double)mumps_id.infog[16-1]/1024); + fprintf(fpOut, + "TotMem = %dMB = %.2lfGB\n", + mumps_id.infog[17-1],(double)mumps_id.infog[17-1]/1024); + #endif + } +#endif + + + + if (NonZeroExtended > extend_threshold * m * m){ + best = SELECT_DENSE; + } + + double sparse_cost = mumps_id.rinfog[1-1] * 1.15; + double dense_cost = 1.0/3.0 * (double)m * (double)m * (double) m; + double sd_ratio = 0.85; + // The ratio of (dense/sparse) + // estimated by BbRosenB10.dat-s + #if 0 + rMessage("sparse_cost = " << sparse_cost + << " : dense_cost = " << dense_cost + << " : dense_cost * sd_ratio = " + << (dense_cost * sd_ratio)); + #endif + + #if !FORCE_SCHUR_SPARSE + if (sparse_cost > dense_cost * sd_ratio) { + best = SELECT_DENSE; + } + #endif +} + +bool Chordal::factorizeSchur(int m, int* diagonalIndex, + FILE* Display, FILE* fpOut) +{ + // I need to adjust Schur before factorization + // to loose Numerical Error Condition + double adjustSize = PLUS_ADJUST_DIAGONAL; + for (int i=0; isp_ele[diagonalIndex[i]] += adjustSize; + } + + mumps_id.job = MUMPS_JOB_FACTORIZE; + mumps_id.a = sparse_bMat_ptr->sp_ele; + dmumps_c(&mumps_id); + bool isSuccess = SDPA_SUCCESS; + while (mumps_id.infog[1-1] == -9) { + #if 0 + rMessage("mumps icntl(14) = " << mumps_id.icntl[14-1]); + rMessage("mumps icntl(23) = " << mumps_id.icntl[23-1]); + #endif + if (Display) { + fprintf(Display,"MUMPS needs more memory space. Trying ANALYSIS phase once more\n"); + } + if (fpOut) { + fprintf(fpOut, "MUMPS needs more memory space. Trying ANALYSIS phase once more\n"); + } + mumps_id.icntl[14-1] += 20; // More 20% working memory space + analysisAndcountLowerNonZero(m); + mumps_id.job = MUMPS_JOB_FACTORIZE; + dmumps_c(&mumps_id); + } + if (mumps_id.infog[1-1] < 0) { + isSuccess = SDPA_FAILURE; + if (mumps_id.infog[1-1] == -10) { + rMessage("Cholesky failed by NUMERICAL ERROR"); + rMessage("There are some possibilities."); + rMessage("1. SDPA finalizes due to inaccuracy of numerical error"); + rMessage("2. The input problem may not have (any) interior-points"); + rMessage("3. Input matrices are linearly dependent"); + } + else { + rMessage("Cholesky failed with Error Code " + << mumps_id.infog[1-1]); + } + } + return isSuccess; +} + +bool Chordal::solveSchur(Vector& rhs) +{ + mumps_id.job = MUMPS_JOB_SOLVE; + mumps_id.rhs = rhs.ele; + dmumps_c(&mumps_id); + return SDPA_SUCCESS; +} + +} // end of namespace 'sdpa' + diff --git a/external/sdpa/sdpa_chordal.h b/external/sdpa/sdpa_chordal.h new file mode 100644 index 0000000..8febad5 --- /dev/null +++ b/external/sdpa/sdpa_chordal.h @@ -0,0 +1,84 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +/*----------------------------------------- + sdpa_chordal.h +-----------------------------------------*/ + +#ifndef __sdpa_chordal_h__ +#define __sdpa_chordal_h__ + +#include "sdpa_dataset.h" +#include + +#define SELECT_MUMPS_BEST 7 // MUMPS selects automatically when 7 +#define SELECT_DENSE -1 // This value must be minus + +namespace sdpa { + +class Chordal { +public: + + // condition of sparse computation + // m_threshold < mDim, + // b_threshold < nBlock, + // aggregate_threshold >= aggrigated sparsity ratio + // extend_threshold >= extended sparsity ratio + int m_threshold; + int b_threshold; + double aggregate_threshold; + double extend_threshold; + + int best; +/* indicates the used ordering method */ + /* -1: dense computation */ + /* 7: sparse computation by MUMPS */ + + SparseMatrix* sparse_bMat_ptr; + DMUMPS_STRUC_C mumps_id; + bool mumps_usage; + + + Chordal(void); + ~Chordal(); + void initialize(SparseMatrix* sparse_bMat_ptr); + void finalize(); + + // merge array1 to array2 + void mergeArray(int na1, int* array1, int na2, int* array2); + void catArray(int na1, int* array1, int na2, int* array2); + void slimArray(int i, int length, int* array, int& slimedLength); + + void makeGraph(InputData& inputData, int m); + + void ordering_bMat(int m, int nBlock, + InputData& inputData, FILE* Display, + FILE* fpOut); + double analysisAndcountLowerNonZero(int m); + bool factorizeSchur(int m, int* diagonalIndex, + FILE* Display, FILE* fpOut); + bool solveSchur(Vector& rhs); + +}; + +} // end of namespace 'sdpa' + +#endif // __sdpa_chordal_h__ diff --git a/external/sdpa/sdpa_dataset.cpp b/external/sdpa/sdpa_dataset.cpp new file mode 100644 index 0000000..708f065 --- /dev/null +++ b/external/sdpa/sdpa_dataset.cpp @@ -0,0 +1,557 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_dataset.h" +#include "sdpa_parts.h" +#include "sdpa_linear.h" +#include "sdpa_newton.h" + +namespace sdpa { + +Solutions::Solutions() +{ + initialize(); +} + +Solutions::~Solutions() +{ + finalize(); +} + +void Solutions::initialize() +{ + nDim = 0; + mDim = 0; +} + +void Solutions::initialize(int m, BlockStruct& bs) +{ + mDim = m; + nDim = 0; + for (int l=0; l \n"); + cholmodSpace.display(fpout, printFormat); + fprintf(fpout, "order =========> \n"); + order.display(fpout, printFormat); + rMessage("Solutions @ end @@@@@@@@@@@@@@@@@@@@@@"); +} + +void Solutions::makeFinalSolution(bool Xmake, bool Zmake, + BlockStruct& bs) +{ + if (Xmake == true) { + cholmodSpace.getCholesky(order); + finalX.initialize(bs); + for (int l=0; l ret) { + ret = tmp; + } + } + return ret; +} + +double Residuals::computeMaxNorm(cholmod_sparse* rD) +{ + double ret = 0.0; + for (int index1=0; index1nzmax; ++index1) { + const double tmp = fabs(((double*)rD->x)[index1]); + if (tmp > ret) { + ret = tmp; + } + } + return ret; +} + +void Residuals::update(CholmodSpace& cholmodSpace) +{ + // p[k] = b[k] - A[k].X; + normPrimal = computeMaxNorm(cholmodSpace.rp); + + double tmpNorm = 0.0; + for (int l = 0; l < cholmodSpace.LP_nBlock; ++l) { + double tmp2 = fabs(cholmodSpace.LP_rD[l]); + if (tmp2 > tmpNorm) { + tmpNorm = tmp2; + } + } + for (int l = 0; l < cholmodSpace.SDP_nBlock; ++l) { + double tmp2 = computeMaxNorm(cholmodSpace.SDP_block[l].rD); + if (tmp2 > tmpNorm) { + tmpNorm = tmp2; + } + } + normDual = tmpNorm; +} + +void Residuals::copyToInit() +{ + initNormPrimal = normPrimal; + initNormDual = normDual; + centerNorm = 0.0; +} + +void Residuals::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout," initial.normPrimal = %8.3e\n", + initNormPrimal); + fprintf(fpout," initial.normDual = %8.3e\n", + initNormDual); + fprintf(fpout," currentRes.normPrimal = %8.3e\n", + normPrimal); + fprintf(fpout," currentRes.normDual = %8.3e\n", + normDual); +} + + + +} // end of namespace 'sdpa' + diff --git a/external/sdpa/sdpa_dataset.h b/external/sdpa/sdpa_dataset.h new file mode 100644 index 0000000..a37786e --- /dev/null +++ b/external/sdpa/sdpa_dataset.h @@ -0,0 +1,135 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#ifndef __sdpa_detaset_h__ +#define __sdpa_detaset_h__ + +#include "sdpa_include.h" +#include "sdpa_struct.h" + +namespace sdpa { + +class Newton; + +class Solutions; +class InputData; +class Residuals; + +class ComputeTime; +class Parameter; +class StepLength; +class DirectionParameter; +class Switch; +class RatioInitResCurrentRes; +class SolveInfo; +class Phase; +class AverageComplementarity; + + +class Solutions +{ +public: + int nDim; + int mDim; + + CholmodSpace cholmodSpace; + OrderingSpace order; + + DenseLinearSpace finalX; + DenseLinearSpace finalZ; + + Solutions(); + ~Solutions(); + void initialize(); + void initialize(int m, BlockStruct& bs); + void finalize(); + + void makeCliques(BlockStruct& bs, InputData& inputData); + void setInitialPoint(BlockStruct&bs, double lambda); + + bool update(StepLength& alpha, ComputeTime& com); + void display(FILE* fpout=stdout, char* printFormat = P_FORMAT); + + void makeFinalSolution(bool Xmake, bool Zmake, + BlockStruct& bs); +}; + +class InputData +{ +public: + Vector b; + CompSpace C; + CompSpace* A; + + // nBLock : number of block + // nConstraint[k]: number of nonzero matrix in k-th block + // When A[i].block[k] is nonzero matrix, for t, + // i <-> constraint[k][t] + // A[i].block[k] <-> A[i].sp_block[blockIndex[k][t]] + int SDP_nBlock; int* SDP_nConstraint; + int** SDP_constraint; int** SDP_blockIndex; + int LP_nBlock; int* LP_nConstraint; + int** LP_constraint; int** LP_blockIndex; + + InputData(); + ~InputData(); + void initialize(int m, BlockStruct& bs); + void finalize(); + void initialize_bVec(int m); + void initialize_index_SDP(); + void initialize_index_LP(); + void initialize_index(); + + void assignAgg(CholmodSpace& cholmodSpace); + void assignBlockIndex(OrderingSpace& order); + + void display(FILE* fpout=stdout); + void display_index(FILE* fpout=stdout); +}; + +class Residuals +{ +public: + double initNormPrimal; + double initNormDual; + double normPrimal; + double normDual; + double centerNorm; + + Residuals(); + ~Residuals(); + + void initialize(); + void finalize(); + + static double computeMaxNorm(Vector& primalVec); + static double computeMaxNorm(cholmod_sparse* rD); + + void update(CholmodSpace& cholmodSpace); + void copyToInit(); + void display(FILE* fpout = stdout); + +}; + + +} // end of namespace 'sdpa' + +#endif // __sdpa_dataset_h__ diff --git a/external/sdpa/sdpa_dpotrf.cpp b/external/sdpa/sdpa_dpotrf.cpp new file mode 100644 index 0000000..4144881 --- /dev/null +++ b/external/sdpa/sdpa_dpotrf.cpp @@ -0,0 +1,274 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*----------------------------------------------- + rsdpa_dpotrf.cpp + modification of ATL_dpotrfL + for dealing with numerical error + in diagonal elements. + + int rATL_dpotrfL(int N, double *A,int lda) + + modified by Makoto Yamshita 2002.07.11 +-----------------------------------------------*/ +#define POTRF_NONZERO (1.0e-14) +#define POTRF_ASSIGN (1.0e+100) +#define POTRF_LIMIT (-1.0e-6) + +/* + * Automatically Tuned Linear Algebra Software v3.4.0 + * (C) Copyright 1999 R. Clint Whaley + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions, and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the ATLAS group or the names of its contributers may + * not be used to endorse or promote products derived from this + * software without specific written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ATLAS GROUP OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + + + +#include "sdpa_include.h" +#include "sdpa_algebra.h" +#if 0 +#define CHOLESKY_ADJUST(val) rMessage("Choleksy adjust from " << val << " to " << POTRF_NONZERO); +#else +#define CHOLESKY_ADJUST(val) ; +#endif + +namespace sdpa { + +extern "C" { +static int potrf4(double* A,const int n) +{ + double* A1 = A+n+1; + double* A2 = A1+n+1; + double* A3 = A2+n+1; + double L11 = *A; + double L21 = A[1], L22 = *A1; + double L31 = A[2], L32 = A1[1], L33 = *A2; + double L41 = A[3], L42 = A1[2], L43 = A2[1], L44 = *A3; + + if (L11 < POTRF_LIMIT) { + return 1; + } + if (L11 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L11); + L11 = POTRF_ASSIGN; + } + + *A = L11 = sqrt(L11); + L11 = 1.0/L11; + L21 *= L11; + L31 *= L11; + L41 *= L11; + + L22 -= L21*L21; + if (L22 < POTRF_LIMIT) { + return 2; + } + if (L22 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L22); + L22 = POTRF_ASSIGN; + } + *A1 = L22 = sqrt(L22); + L22 = 1.0/L22; + L32 = (L32 - L31*L21)*L22; + L42 = (L42 - L41*L21)*L22; + + L33 -= L31*L31 + L32*L32; + if (L33 < POTRF_LIMIT) { + return 3; + } + if (L33 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L33); + L33 = POTRF_ASSIGN; + } + *A2 = L33 = sqrt(L33); + L43 = (L43-L41*L31-L42*L32)/L33; + L44 -= L41*L41 + L42*L42 + L43*L43; + if (L44 < POTRF_LIMIT) { + return 4; + } + if (L44 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L44); + L44 = POTRF_ASSIGN; + } + *A3 = sqrt(L44); + + A[1] = L21; + A[2] = L31; A1[1] = L32; + A[3] = L41; A1[2] = L42; A2[1] = L43; + return 0; +} + +static int potrf3(double* A,const int n) +{ + double* A1 = A+n+1; + double* A2 = A1+n+1; + double L11 = *A; + double L21 = A[1], L22 = *A1; + double L31 = A[2], L32 = A1[1], L33 = *A2; + + if (L11 < POTRF_LIMIT) { + return 1; + } + if (L11 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L11); + L11 = POTRF_ASSIGN; + } + + *A = L11 = sqrt(L11); + L11 = 1.0/L11; + L21 *= L11; + L31 *= L11; + + L22 -= L21*L21; + if (L22 < POTRF_LIMIT) { + return 2; + } + if (L22 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L22); + L22 = POTRF_ASSIGN; + } + L22 = sqrt(L22); + L32 = (L32 - L31*L21)/L22; + + L33 -= L31*L31 + L32*L32; + if (L33 < POTRF_LIMIT) { + return 3; + } + if (L33 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L33); + L33 = POTRF_ASSIGN; + } + *A2 = sqrt(L33); + + A[1] = L21; *A1 = L22; + A[2] = L31; A1[1] = L32; + return 0; +} + +static int potrf2(double* A,const int n) +{ + double* A1 = A+n+1; + double L11 = *A; + double L21 = A[1], L22 = *A1; + + if (L11 < POTRF_LIMIT) { + return 1; + } + if (L11 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L11); + L11 = POTRF_ASSIGN; + } + + *A = L11 = sqrt(L11); + L21 /= L11; + L22 -= L21*L21; + if (L22 < POTRF_LIMIT) { + return 2; + } + if (L22 < POTRF_NONZERO) { + CHOLESKY_ADJUST(L22); + L22 = POTRF_ASSIGN; + } + *A = L11; + A[1] = L21; *A1 = sqrt(L22); + + return 0; +} + +int rATL_dpotrfL(int N, double *A,int lda) +{ + double *An, *Ar; + int Nleft, Nright, ierr; + + if (N > 4) { + Nleft = N >> 1; +#if 0 + int nb = ilaenv_fc(&IONE, "DPOTRF", "L", &N, + &IMONE,&IONE, &IMONE, strlen("DPOTRF"), strlen("L")); + if (Nleft > nb<<1) Nleft = (Nleft/nb)*nb; +#endif +#if 0 + if (Nleft > 64) { + Nleft = 64; + } +#endif + Nright = N - Nleft; + ierr = rATL_dpotrfL(Nleft, A,lda); + if (!ierr) { + Ar = A + Nleft; + An = Ar + lda * Nleft; + dtrsm_fc ((char *)"R",(char *)"L",(char *)"T",(char *)"N", + &Nright,&Nleft,&DONE,A,&lda, + Ar, &lda, strlen("R"),strlen("L"), + strlen("T"),strlen("N")); + dsyrk_fc ((char *)"L",(char *)"N",&Nright,&Nleft,&DMONE, + Ar, &lda, &DONE,An,&lda,strlen("L"),strlen("N")); + ierr = rATL_dpotrfL(Nright, An,lda); + if (ierr) return(ierr+Nleft); + } + else return(ierr); + } + else if (N==4) return(potrf4(A,lda)); + else if (N==3) return(potrf3(A,lda)); + else if (N==2) return(potrf2(A,lda)); + else if (N==1) { + if (*A < POTRF_LIMIT) { + return 1; + } + if (*A < POTRF_NONZERO) { + CHOLESKY_ADJUST(*A); + *A = POTRF_ASSIGN; + } + *A = sqrt(*A); + } + return(0); +} + +void rdpotrfl_(int* N, double *A,int* lda,int* info) +{ + *info = rATL_dpotrfL(*N,A,*lda); +} + +}; // end of extern "C" + +} // end of namespace 'sdpa' diff --git a/external/sdpa/sdpa_dpotrf.h b/external/sdpa/sdpa_dpotrf.h new file mode 100644 index 0000000..586887d --- /dev/null +++ b/external/sdpa/sdpa_dpotrf.h @@ -0,0 +1,43 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*----------------------------------------------- + rsdpa_dpotrf.cpp + modification of ATL_dpotrfL + int rATL_dpotrfL(int N, double *A,int lda) + $Id: rsdpa_dpotrf.h,v 1.2 2004/09/01 06:34:12 makoto Exp $ +-----------------------------------------------*/ + +#ifndef __sdpa_dpotrf_h__ +#define __sdpa_dpotrf_h__ + +namespace sdpa { + +#ifdef __cplusplus +extern "C" int rATL_dpotrfL(int N, double *A,int lda); +#else +extern int rATL_dpotrfL(int N, double *A,int lda); +#endif + +} // end of namespace 'sdpa' + +#endif // __sdpa_dpotrf_h__ + + diff --git a/external/sdpa/sdpa_exe.cpp b/external/sdpa/sdpa_exe.cpp new file mode 100644 index 0000000..c8c63c3 --- /dev/null +++ b/external/sdpa/sdpa_exe.cpp @@ -0,0 +1,360 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include +#include +#include +using namespace sdpa; + +#define USER_PARAMETER_FILE ((char *)"./param.sdpaC") +#define DEFAULT_PARAMETER_FILE ((char *)"/usr/share/sdpa/param.sdpaC") +// PARAMETER_FILE is decided by the following priority +// 1: The file assigned by '-p' option of 'option type 2'. +// For 'option type1', this is skipped. +// 2: USER_PARAMETER_FILE +// For 'option type2', this is skipped. +// 3: DEFAULT_PARAMETER_FILE +// 4: Default parameter +static void message(char* argv0) +{ + cout << endl; + cout << "*** Please assign data file and output file.***" << endl; + cout << endl; + cout << "---- option type 1 ------------" << endl; + cout << argv0 <<" SparseDataFile OutputFile" + " [-pt parameters] [-dimacs] [-numThreads numThreads]"<< endl; + cout << "parameters = 0 default, 1 fast (unstable)," + " 2 slow (stable)" << endl; + cout << " -dimacs : printout dimacs information incurring additional computation cost " << endl; + cout << " -numThreads: Number of pthreads for internal computation" << endl; + cout << "example1-1: " << argv0 + << " example1.dat-s example1.result" << endl; + cout << "example1-2: " << argv0 + << " example1.dat-s example1.result -pt 2" << endl; + cout << "example1-3: " << argv0 + << " example1.dat-s example1.result -dimacs" << endl; + cout << "example1-4: " << argv0 + << " example1.dat-s example1.result -numThreads 4" << endl; + + cout << endl; + cout << "---- option type 2 ------------" << endl; + cout << argv0 << " [option filename]+ " << endl; + cout << " -ds : data sparse " << endl; + cout << " -o : output :: -p : parameter " << endl; + cout << " -pt : parameters , 0 default, 1 fast (unstable)" << endl; + cout << " 2 slow (stable) " << endl; + cout << " -dimacs : printout dimacs information incurring additional computation cost " << endl; + cout << " -numThreads: Number of pthreads for internal computation" << endl; + cout << "example2-1: " << argv0 + << " -ds example1.dat-s -o example1.result " + << "-p param.sdpaC" << endl; + cout << "example2-2: " << argv0 + << " -ds example1.dat-s -o example1.result " + << "-pt 2" << endl; + cout << "example2-3: " << argv0 + << " -ds example1.dat-s -o example1.result " + << "-dimacs" << endl; + cout << "example2-4: " << argv0 + << " -ds example1.dat-s -o example1.result " + << "-numThreads 4" << endl; + + cout << endl; + cout << "---- option type 3 ------------" << endl; + cout << argv0 << " --version " << endl; + cout << " to print out version and exit." << endl; + + cout << endl << endl; + cout << "PARAMETER_FILE is decided by the following priority" << endl; + cout << " 1: The file assigned by '-p' option of 'option type 2'." << endl; + cout << " For 'option type1', this is skipped." << endl; + cout << " 2: " << USER_PARAMETER_FILE << endl; + cout << " For 'option type2', this is skipped." << endl; + cout << " 3: " << DEFAULT_PARAMETER_FILE << endl; + cout << " 4: Default parameter" << endl; + exit(1); +} + +static void argumentAnalysis(SDPA& Problem1, + int argc, char** argv, + char*& inputFileName, + char*& resultFileName, + char*& paramFileName, + SDPA::ParameterType& parameterType, + bool& isDimacs, int& numThreads) +{ + if (argc == 1) { + message(argv[0]); + } + if (strcmp(argv[1],"--version") == 0) { + fprintf(stdout,"====\n"); + fprintf(stdout,"SDPA-C (SemiDefinite Programming Algorithm with Completion) %s\n",sdpa_version); + fprintf(stdout," %s\n",sdpa_right); + fprintf(stdout,"====\n"); + exit(0); + } + if (argv[1][0] == '-') { + // rsdpa argument + + for (int index = 0; index < argc; ++index) { + char* target = argv[index]; + if (strcmp(target,"-dd")==0 && index+1 < argc) { + fprintf(stdout,"*** Dense Data is NOT supported ***\n"); + inputFileName = argv[index+1]; + inputFileName = NULL; + // isInputSparse = SDPA::DENSE; + index++; + continue; + } + if (strcmp(target,"-ds")==0 && index+1 < argc) { + inputFileName = argv[index+1]; + // isInputSparse = SDPA::SPARSE; + continue; + } + if (strcmp(target,"-o")==0 && index+1 < argc) { + resultFileName = argv[index+1]; + index++; + continue; + } + if (strcmp(target,"-p")==0 && index+1 < argc) { + paramFileName = argv[index+1]; + index++; + continue; + } + if (strcmp(target,"-dimacs")==0) { + isDimacs = true; + continue; + } + if (strcmp(target,"-pt")==0 && index+1 < argc) { + int tmp = atoi(argv[index+1]); + switch (tmp) { + case 0: + parameterType = SDPA::PARAMETER_DEFAULT; + break; + case 1: + parameterType = SDPA::PARAMETER_UNSTABLE_BUT_FAST; + break; + case 2: + parameterType = SDPA::PARAMETER_STABLE_BUT_SLOW; + break; + default: + parameterType = SDPA::PARAMETER_DEFAULT; + } + index++; + paramFileName = NULL; + continue; + } + if (strcmp(target,"-numThreads")==0 && index+1 < argc) { + numThreads = atoi(argv[index+1]); + index++; + continue; + } + } + } + else { // SDPA argument + inputFileName = argv[1]; + int len = strlen(inputFileName); + if (inputFileName[len-1] == 's' + && inputFileName[len-2] == '-') { + } + else { + fprintf(stdout, "File may not be Sparse SDPA format. \n"); + fprintf(stdout, "The file extension must be 'dat-s'. \n"); + inputFileName = NULL; + } + + resultFileName = argv[2]; + + paramFileName = USER_PARAMETER_FILE; + + for (int index=3; index +#include +#include +#include +#include +#include + +using namespace std; + +#define SDPA_SUCCESS true +#define SDPA_FAILURE false + + + +// for CHOLMOD routine +#define TRUE 1 +#define FALSE 0 + +#include "sdpa_tool.h" +// #include "sdpa_algebra.h" + +#endif // __sdpa_include_h__ diff --git a/external/sdpa/sdpa_io.cpp b/external/sdpa/sdpa_io.cpp new file mode 100644 index 0000000..7974606 --- /dev/null +++ b/external/sdpa/sdpa_io.cpp @@ -0,0 +1,1155 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_io.h" +#include "sdpa_linear.h" +#include +#include + +namespace sdpa { + +void IO::read(FILE* fpData, FILE* fpout, int& m, char* str) +{ + while (true) { + volatile int dummy=0; dummy++;//for gcc-3.3 bug + fgets(str,lengthOfString,fpData); + if (str[0]=='*' || str[0]=='"') { + fprintf(fpout,"%s",str); + } else { + sscanf(str,"%d",&m); + break; + } + } +} + +void IO::read(FILE* fpData, int & nBlock) +{ + fscanf(fpData,"%d",&nBlock); +} + +void IO::read(FILE* fpData, BlockStruct& bs) +{ + for (int l=0; l 0 ) { + bs.blockType[l] = BlockStruct::btSDP; + } + if (bs.blockStruct[l] < 0 ) { + bs.blockType[l] = BlockStruct::btLP; + } + } +} + +void IO::read(FILE* fpData, Vector& b) +{ + for (int k=0; k 0) { + // if y[0] locates the first charcter in fpData + // then we need the following line + yVec.ele[k] = -tmp; + // rMessage("yVec.ele[" << k << "] = " << -tmp); + k++; + } + for (; k* readData; + NewArray(readData, vector, m+1); + + while (true) { + lineNumber++; + if (fscanf(fpData,"%*[^0-9+-]%d",&k)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&l)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&i)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&j)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%lf",&value)<=0) { + break; + } + + #if 0 + rMessage("Data " << k << "," << l << "," + << i << "," << j << "," << value); + #endif + + IO::LIJV* oneData; + NewArray(oneData, IO::LIJV, 1); + oneData[0].SDPl = -1; // -1 means empty here + oneData[0].LPl = -1; + oneData[0].i = i-1; + oneData[0].j = j-1; + oneData[0].value = value; + + if (bs.blockType[l-1] == BlockStruct::btSDP) { + int l2 = bs.blockNumber[l-1]; + oneData[0].SDPl = l2; + readData[k].push_back(oneData); + } else if (bs.blockType[l-1] == BlockStruct::btLP) { + if (i!=j) { + printf("******** invalid data line %d, %d, %d, %d, %e ***\n", + k,l,i,j,value); + printf("Line number [%d] in 5-element-lines is invalid\n", lineNumber); + printf("Check your input file\n"); + printf("Note: -1000 may appear in the above invalid report line if the corresponding place is not read correctly.\n"); + + rError("IO::initializeLinearSpace"); + } + int l2 = bs.blockNumber[l-1]; + oneData[0].LPl = l2+i-1; + readData[k].push_back(oneData); + } else { + printf("******** invalid data line %d, %d, %d, %d, %e ***\n", + k,l,i,j,value); + printf("Line number [%d] in 5-element-lines is invalid\n", lineNumber); + printf("Check your input file\n"); + printf("Note: -1000 may appear in the above invalid report line if the corresponding place is not read correctly.\n"); + rError("io::read not valid blockType"); + } + }// end of 'while (true)' + + vector LP_blockCount; + vector SDP_blockCount; + for (int k=0; k= 0) { + LP_blockCount.push_back(oneData[0].LPl); + } + if (oneData[0].SDPl >= 0) { + SDP_blockCount.push_back(oneData[0].SDPl); + } + } + sort(LP_blockCount.begin(), LP_blockCount.end()); + sort(SDP_blockCount.begin(), SDP_blockCount.end()); + int LP_sp_nBlock = 0; + int SDP_sp_nBlock = 0; + int LP_old_block = -1; + int SDP_old_block = -1; + const int LP_length = LP_blockCount.size(); + const int SDP_length = SDP_blockCount.size(); + for (int index1 = 0; index1 < LP_length; ++index1) { + if (LP_blockCount[index1] != LP_old_block) { + LP_old_block = LP_blockCount[index1]; + LP_sp_nBlock++; + } + } + for (int index1 = 0; index1 < SDP_length; ++index1) { + if (SDP_blockCount[index1] != SDP_old_block) { + SDP_old_block = SDP_blockCount[index1]; + SDP_sp_nBlock++; + } + } + + CompSpace* target = &inputData.C; + if (k>0) { + target = &inputData.A[k-1]; + } + target->initialize(LP_sp_nBlock, SDP_sp_nBlock); + int index_t = 0; + LP_old_block = -1; + for (int index1 = 0; index1 < LP_length; ++index1) { + const int current_block = LP_blockCount[index1]; + if (current_block != LP_old_block) { + target->LP_sp_index[index_t] = current_block; + LP_old_block = current_block; + index_t++; + } + } + index_t = 0; + SDP_old_block = -1; + for (int index1 = 0; index1 < SDP_length; ++index1) { + const int current_block = SDP_blockCount[index1]; + if (current_block != SDP_old_block) { + target->SDP_sp_index[index_t] = current_block; + SDP_old_block = current_block; + target->SDP_sp_block[index_t].nRow = bs.SDP_blockStruct[current_block]; + target->SDP_sp_block[index_t].nCol = bs.SDP_blockStruct[current_block]; + index_t++; + } + } + #if 0 + rMessage("LP blocks = "); + for (int index2 = 0; index2 < LP_sp_nBlock; ++index2) { + printf(" %d", target->LP_sp_index[index2]); + } + printf("\n"); + rMessage("SDP blocks = "); + for (int index2 = 0; index2 < SDP_sp_nBlock; ++index2) { + printf(" %d", target->SDP_sp_index[index2]); + } + printf("\n"); + #endif + target->initializeInputVector(); + } + LP_blockCount.clear(); + SDP_blockCount.clear(); + + for (int k=0; k0) { + target = &inputData.A[k-1]; + scale = 1.0; + } + int length = readData[k].size(); + for (int index1 = 0; index1 < length; ++index1) { + IO::LIJV* oneData = readData[k].at(index1); + if (oneData[0].LPl >= 0) { + target->setElement_LP(oneData[0].LPl, oneData[0].value*scale); + } + if (oneData[0].SDPl >= 0) { + target->setElement_SDP(oneData[0].SDPl, + oneData[0].i, oneData[0].j, + oneData[0].value*scale); + } + DeleteArray(oneData); + } + } + DeleteArray(readData); + + double v1 = 0; // dummy initialize + double v2 = 0; // dummy initialize + inputData.C.sortInputVector(); + inputData.C.checkInputDataStructure(l, i, j, v1, v2); + inputData.C.makeInternalStructure(); + if (l>=0) { + printf("***** invalid data ******\n"); + printf("F[0]:%d-th SDP block:[%d, %d]-th element has more than one input\n", + l+1, i+1, j+1); + rError("Stop due to input error\n"); + } + for (int k=0; k=0) { + printf("***** invalid data ******\n"); + printf("F[%d]:%d-th SDP block:[%d, %d]-th element has more than one input\n", + k+1, l+1, i+1, j+1); + rError("Stop due to input error\n"); + } + } + + #if 0 + rMessage("************** Read finished, internal data is from here."); + rMessage("C = -------------------------"); + inputData.C.display(); + for (int k=0; k* SDP_index; + NewArray(SDP_index,vector,m+1); + vector* SOCP_index; + NewArray(SOCP_index,vector,m+1); + vector* LP_index; + NewArray(LP_index,vector,m+1); + + // for SDP + int SDP_sp_nBlock; + int* SDP_sp_index; + int* SDP_sp_blockStruct; + int* SDP_sp_NonZeroNumber; + NewArray(SDP_sp_index,int,bs.SDP_nBlock); + NewArray(SDP_sp_blockStruct,int,bs.SDP_nBlock); + NewArray(SDP_sp_NonZeroNumber,int,bs.SDP_nBlock); + // for SOCP + int SOCP_sp_nBlock; + int* SOCP_sp_blockStruct; + int* SOCP_sp_index; + int* SOCP_sp_NonZeroNumber; + // for LP + int LP_sp_nBlock; + int* LP_sp_index; + NewArray(LP_sp_index,int,bs.LP_nBlock); + + if (isDataSparse) { + int i,j,k,l; + i=j=k=l = -1000; // dummy initialize + double value; + value = -1000; + int lineNumber = 0; + while (true) { + lineNumber++; + if (fscanf(fpData,"%*[^0-9+-]%d",&k)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&l)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&i)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%d",&j)<=0) { + break; + } + if (fscanf(fpData,"%*[^0-9+-]%lf",&value)<=0) { + break; + } + + if (bs.blockType[l-1] == BlockStruct::btSDP) { + int l2 = bs.blockNumber[l-1]; + SDP_index[k].push_back(l2); + } else if (bs.blockType[l-1] == BlockStruct::btLP) { + if (i!=j){ + printf("******** invalid data line %d, %d, %d, %d, %e ***\n", + k,l,i,j,value); + printf("Line number [%d] in 5-element-lines is invalid\n", lineNumber); + printf("Check your input file\n"); + printf("Note: -1000 may appear in the above invalid report line if the corresponding place is not read correctly.\n"); + + rError("IO::initializeLinearSpace"); + } + int l2 = bs.blockNumber[l-1]; + LP_index[k].push_back(l2+i-1); + } else { + printf("******** invalid data line %d, %d, %d, %d, %e ***\n", + k,l,i,j,value); + printf("Line number [%d] in 5-element-lines is invalid\n", lineNumber); + printf("Check your input file\n"); + printf("Note: -1000 may appear in the above invalid report line if the corresponding place is not read correctly.\n"); + rError("io::read not valid blockType"); + } + }// end of 'while (true)' + + } else { // isDataSparse == false + + // constant matrix + for (int l=0; lncol; + for (int j=0; j < ncol; ++j) { + const int start_row = ((int*)rD->p)[j]; + const int end_row = ((int*)rD->p)[j+1]; + for (int i_index = start_row; i_index < end_row; ++i_index) { + const int i = (( int*)rD->i)[i_index]; + const double value = ((double*)rD->x)[i_index]; + if (i==j) { + d_norm += value * value; + } + else { + d_norm += 2.0 * value * value; + } + } + } + } + d_norm = sqrt(d_norm); + + double x_min = 1.0e+50; + double z_min = 1.0e+50; + DenseLinearSpace& finalX = currentPt.finalX; + DenseLinearSpace& finalZ = currentPt.finalZ; + + for (int l=0; l < finalX.LP_nBlock; ++l) { + if (x_min > finalX.LP_block[l]) { + x_min = finalX.LP_block[l]; + } + } + for (int l=0; l < finalZ.LP_nBlock; ++l) { + if (z_min > finalZ.LP_block[l]) { + z_min = finalZ.LP_block[l]; + } + } + + for (int l=0; l < finalX.SDP_nBlock; ++l) { + DenseMatrix& xMat = finalX.SDP_block[l]; + int nDim = xMat.nRow; + DenseMatrix workMatrix; + workMatrix.copyFrom(xMat); + Vector eigenVec; + eigenVec.initialize(nDim); + Vector workVec; + workVec.initialize(3*nDim-1); + Lal::getMinEigenValue(workMatrix, eigenVec, workVec); + + for (int i=0; i eigenVec.ele[i]) { + x_min = eigenVec.ele[i]; + } + } + } + + + for (int l=0; l < finalZ.SDP_nBlock; ++l) { + DenseMatrix& zMat = finalZ.SDP_block[l]; + int nDim = zMat.nRow; + DenseMatrix workMatrix; + workMatrix.copyFrom(zMat); + Vector eigenVec; + eigenVec.initialize(nDim); + Vector workVec; + workVec.initialize(3*nDim-1); + Lal::getMinEigenValue(workMatrix, eigenVec, workVec); + + for (int i=0; i eigenVec.ele[i]) { + z_min = eigenVec.ele[i]; + } + } + } + + + #if 0 + printf("b1:%e\n",b1); + printf("c1:%e\n",c1); + printf("p_norm:%e\n",p_norm); + printf("d_norm:%e\n",d_norm); + printf("x_min:%e\n",x_min); + printf("z_min:%e\n",z_min); + #endif + + double ctx = solveInfo.objValPrimal; + double bty = solveInfo.objValDual; + double xtz = 0.0; + Lal::let(xtz,'=',currentPt.finalX,'.',currentPt.finalZ); + + for (int i=0; i<=6; ++i) { + dimacs_error[i] = 0.0; + } + + rMessage("x_min, z_min"); + printf("x_min = %.2e, z_min = %.2e\n", x_min, z_min); + + dimacs_error[1] = p_norm / (1+b1); + dimacs_error[2] = max( 0.0, - x_min / (1+b1)); + dimacs_error[3] = d_norm / (1+c1); + dimacs_error[4] = max( 0.0, - z_min / (1+c1)); + dimacs_error[5] = (ctx - bty) / (1 + fabs(ctx) + fabs(bty)); + dimacs_error[6] = xtz / (1 + fabs(ctx) + fabs(bty)); +} + +void IO::printDimacs(double* DimacsError,char* printFormat, + FILE* fpout) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout, "\n"); + fprintf(fpout, "* DIMACS_ERRORS * \n"); + fprintf(fpout, "err1 = "); + fprintf(fpout, printFormat, DimacsError[1]); + fprintf(fpout, " [||Ax-b|| / (1+||b||_1)]\n"); + fprintf(fpout, "err2 = "); + fprintf(fpout, printFormat, DimacsError[2]); + fprintf(fpout, " [max(0, -lambda(x)/(1+||b||_1))]\n"); + fprintf(fpout, "err3 = "); + fprintf(fpout, printFormat, DimacsError[3]); + fprintf(fpout, " [||A^Ty + z - c || / (1+||c||_1)]\n"); + fprintf(fpout, "err4 = "); + fprintf(fpout, printFormat, DimacsError[4]); + fprintf(fpout, " [max(0, -lambda(z)/(1+||c||_1))]\n"); + fprintf(fpout, "err5 = "); + fprintf(fpout, printFormat, DimacsError[5]); + fprintf(fpout, " [( - ) / (1 + || + ||)]\n"); + fprintf(fpout, "err6 = "); + fprintf(fpout, printFormat, DimacsError[6]); + fprintf(fpout, " [ / (1 + || + ||)]\n"); + fprintf(fpout, "\n"); +} + + +bool IO::judgeXmake(Parameter& param) +{ +#if REVERSE_PRIMAL_DUAL + if (strcmp(param.YPrint,NO_P_FORMAT) == 0) { + return false; + } +#else + if (strcmp(param.XPrint,NO_P_FORMAT) == 0) { + return false; + } +#endif + return true; +} + +bool IO::judgeZmake(Parameter& param) +{ +#if REVERSE_PRIMAL_DUAL + if (strcmp(param.XPrint,NO_P_FORMAT) == 0) { + return false; + } +#else + if (strcmp(param.YPrint,NO_P_FORMAT) == 0) { + return false; + } +#endif + return true; +} + + +void IO::printSolution(BlockStruct& bs, Solutions& currentPt, + Parameter& param, FILE* fpout, bool Xmake, bool Zmake) +{ + if (fpout != NULL) { + #if REVERSE_PRIMAL_DUAL + fprintf(fpout,"xVec = \n"); + currentPt.cholmodSpace.yVec.display(fpout,1.0,param.xPrint); + fprintf(fpout,"xMat = \n"); + currentPt.finalZ.displaySolution(bs,fpout,param.XPrint); + fprintf(fpout,"yMat = \n"); + currentPt.finalX.displaySolution(bs,fpout,param.YPrint); + #else + fprintf(fpout,"xMat = \n"); + currentPt.finalX.displaySolution(bs,fpout,param.XPrint); + fprintf(fpout,"yVec = \n"); + currentPt.cholmodSpace.yVec.display(fpout,1.0,param.xPrint); + fprintf(fpout,"zMat = \n"); + currentPt.finalZ.displaySolution(bs,fpout,param.YPrint); + #endif + } +} + +} // end of namespace 'sdpa' diff --git a/external/sdpa/sdpa_io.h b/external/sdpa/sdpa_io.h new file mode 100644 index 0000000..231e205 --- /dev/null +++ b/external/sdpa/sdpa_io.h @@ -0,0 +1,118 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#ifndef __sdpa_io_h__ +#define __sdpa_io_h__ + +#define lengthOfString 256 + +#include "sdpa_block.h" +#include "sdpa_parts.h" + +namespace sdpa { + +class IO +{ +public: + static void read(FILE* fpData, FILE* fpout, int& m, char* str); + static void read(FILE* fpData, int& nBlock); + static void read(FILE* fpData, BlockStruct& bs); + static void read(FILE* fpData, Vector& b); + static void read(FILE* fpData, DenseLinearSpace& xMat, + Vector& yVec, DenseLinearSpace& zMat, + BlockStruct& bs, bool inputSparse); + static void read(FILE* fpData, int m, + BlockStruct& bs, + InputData& inputData, bool isDataSparse); + static void read(FILE* fpData, int m, + BlockStruct& bs, InputData& inputData); + + // read data is first introduced into this class + class LIJV + { + public: + int SDPl,LPl,i,j; + double value; + }; + + + // 2008/02/27 kazuhide nakata + // without LP_ANonZeroCount + static void setBlockStruct(FILE* fpData, InputData& inputData, + int m, BlockStruct& bs, + long position, bool isDataSparse); + + // 2008/02/27 kazuhide nakata + // without LP_ANonZeroCount + static void setElement(FILE* fpData, InputData& inputData, int m, + BlockStruct& bs, + long position, bool isDataSparse); + + static void printHeader(FILE* fpout, FILE* Display); + + static void printOneIteration(int pIteration, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + SolveInfo& solveInfo, + StepLength& alpha, + DirectionParameter& beta, + FILE* fpout, + FILE* Display); + + static void printLastInfo(int pIteration, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + SolveInfo& solveInfo, + StepLength& alpha, + DirectionParameter& beta, + Residuals& currentRes, + Phase & phase, + Solutions& currentPt, + InputData& inputData, + double cputime, + ComputeTime& com, + Parameter& param, + FILE* fpout, + FILE* Display, + bool printTime = true); + + static void computeDimacs(double* dimacs_error, + SolveInfo& solveInfo, + Residuals& currentRes, + Solutions& currentPt, + InputData& inputData); + + static void printDimacs(double* dimacs_error, + char* printFormat, + FILE* fpout); + + static bool judgeXmake(Parameter& param); + static bool judgeZmake(Parameter& param); + + static void printSolution(BlockStruct& bs, Solutions& currentPt, + Parameter& param, FILE* fpout, + bool Xmake, bool Zmake); + +}; + +} // end of namespace 'sdpa' + +#endif // __sdpa_io_h__ diff --git a/external/sdpa/sdpa_linear.cpp b/external/sdpa/sdpa_linear.cpp new file mode 100644 index 0000000..56531f6 --- /dev/null +++ b/external/sdpa/sdpa_linear.cpp @@ -0,0 +1,2959 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_linear.h" +#include "sdpa_dataset.h" +#include "sdpa_dpotrf.h" +#include "sdpa_algebra.h" + +namespace sdpa { + +double Lal::getMinEigen(DenseMatrix& lMat, + DenseMatrix& xMat, + DenseMatrix& Q, + Vector& out, Vector& b, Vector& r, + Vector& q, Vector& qold, + Vector& w, Vector& tmp, + Vector& diagVec, Vector& diagVec2, + Vector& workVec, char charTranspose) +{ + double alpha,beta,value; + double min = 1.0e+51, min_old = 1.0e+52; + double error = 1.0e+10; + + int nDim = xMat.nRow; + int k = 0, kk = 0; + + diagVec.initialize(1.0e+50); + diagVec2.setZero(); + q.setZero(); + r.initialize(1.0); + beta = sqrt((double)nDim); // norm of "r" + + // nakata 2004/12/12 + while (k 1.0e-16 + && ( k<20 || + fabs(min-min_old) > (1.0e-5)*fabs(min)+(1.0e-8) + // && (fabs(min-min_old) > (1.0e-3)*fabs(min)+(1.0e-6) + || fabs(error*beta) > (1.0e-2)*fabs(min)+(1.0e-6) ) + ) { + // rMessage("k = " << k); + qold.copyFrom(q); + value = 1.0/beta; + Lal::let(q,'=',r,'*',&value); + + if (charTranspose == 'N') { + // w = (lMat^T)*q + w.copyFrom(q); + dtrmv_fc ((char *)"Lower",(char *)"Transpose", + (char *)"NotUnit",&nDim, + lMat.de_ele,&nDim,w.ele,&IONE, + strlen("Lower"), strlen("Transpose"),strlen("NotUnit")); + Lal::let(tmp,'=',xMat,'*',w); + w.copyFrom(tmp); + dtrmv_fc ((char *)"Lower",(char *)"NoTranspose", + (char *)"NotUnit",&nDim, + lMat.de_ele,&nDim,w.ele,&IONE, + strlen("Lower"), strlen("NoTranspose"),strlen("NotUnit")); + // w = lMat*xMat*(lMat^T)*q + // rMessage("w = "); + // w.display(); + } + else if (charTranspose == 'T') { + // w = lMat*q + w.copyFrom(q); + dtrmv_fc ((char *)"Lower",(char *)"NoTranspose", + (char *)"NotUnit",&nDim, + lMat.de_ele,&nDim,w.ele,&IONE, + strlen("Lower"), strlen("NoTranspose"),strlen("NotUnit")); + Lal::let(tmp,'=',xMat,'*',w); + w.copyFrom(tmp); + dtrmv_fc ((char *)"Lower",(char *)"Transpose", + (char *)"NotUnit",&nDim, + lMat.de_ele,&nDim,w.ele,&IONE, + strlen("Lower"), strlen("Transpose"),strlen("NotUnit")); + // w = lMat^T*xMat*lMat*q + // rMessage("w = "); + // w.display(); + } + else { + rError("code bug, charTranspose should be 'N' or 'T'"); + } + + Lal::let(alpha,'=',q,'.',w); + diagVec.ele[k] = alpha; + Lal::let(r,'=',w,'-',q,&alpha); + Lal::let(r,'=',r,'-',qold,&beta); + // rMessage("r = "); + // r.display(); + + if ( kk>=sqrt((double)k) || k==nDim-1 || k>sqrt((double)nDim+9) ) { + kk = 0; + out.copyFrom(diagVec); + b.copyFrom(diagVec2); + out.ele[nDim-1] = diagVec.ele[k]; + b.ele[nDim-1] = 0.0; + + // rMessage("out = "); + // out.display(); + // rMessage("b = "); + // b.display(); + + int info; + int kp1 = k+1; + dsteqr_fc ((char *)"I_withEigenvalues",&kp1,out.ele,b.ele, + Q.de_ele, &Q.nRow, workVec.ele, &info, + strlen("I_withEigenvalues")); + if (info < 0) { + rError(" rLanczos :: bad argument " << -info + << " Q.nRow = " << Q.nRow + << ": nDim = " << nDim + << ": kp1 = " << kp1); + } else if (info > 0) { + rMessage(" rLanczos :: cannot converge " << info); + break; + } + + // rMessage("out = "); + // out.display(); + // rMessage("Q = "); + // Q.display(); + + min_old = min; + #if 0 + min = 1.0e+50; + error = 1.0e+10; + for (int i=0; iout.ele[i]){ + min = out.ele[i]; + error = Q.de_ele[k+Q.nCol*i]; + } + } + #else + // out have eigen values with ascending order. + min = out.ele[0]; + error = Q.de_ele[k]; + #endif + + } // end of 'if ( kk>=sqrt(k) ...)' + // printf("\n"); + + Lal::let(value,'=',r,'.',r); + beta = sqrt(value); + diagVec2.ele[k] = beta; + ++k; + ++kk; + } // end of while + // rMessage("k = " << k); + return min - fabs(error*beta); +} + +double Lal::getMinEigenValue(DenseMatrix& aMat, + Vector& eigenVec, + Vector& workVec) +{ + // aMat is rewritten. + // aMat must be symmetric. + // eigenVec is the space of eigen values + // and needs memory of length aMat.nRow + // workVec is temporary space and needs + // 3*aMat.nRow-1 length memory. + int N = aMat.nRow; + int LWORK, info; + LWORK = 3*N-1; + // "N" means that we need not eigen vectors + // "L" means that we refer only lower triangular. + dsyev_fc((char *)"NonVectors",(char *)"Lower",&N,aMat.de_ele,&N, + eigenVec.ele,workVec.ele,&LWORK,&info, + strlen("NonVectors"), strlen("Lower")); + if (info!=0) { + if (info < 0) { + rMessage("getMinEigenValue:: info is mistaken " << info); + } else { + rMessage("getMinEigenValue:: cannot decomposition"); + } + exit(0); + return 0.0; + } + return eigenVec.ele[0]; +} + +double Lal::getMinEigenValue(CholmodMatrix& cholmodMatrix) +{ + cholmod_factor* Lz = cholmodMatrix.Lz; + cholmod_sparse* dZ = cholmodMatrix.dZ; + cholmod_common& common = cholmodMatrix.common; + const int nDIM = cholmodMatrix.nDim; + Vector rVect(nDIM); + Vector qVect(nDIM); + Vector qoldVect(nDIM); + Vector wVect(nDIM); + Vector diagVect(nDIM); + Vector diag2Vect(nDIM); + + if (nDIM == 1) { + // this block should be handled as an LP block + rError("code bug"); + } + int i,j,k; + double alpha,beta,tmp,min=1.0e51,min_old = 1.0e52; + double sig,max,mid; + + k = 0; + for (i=0; i 1.0e-16) && + ((fabs(min - min_old) > 1.0e-4 * fabs(min) + 1.0e-8))) { + qoldVect.copyFrom(qVect); + tmp = 1.0 / beta; + Lal::let(qVect,'=',rVect,'*',&tmp); + + + // wVect = Lz^{-1} * dZ * Lz^{-T} * qVect + double* b_z_ele = (double*) cholmodMatrix.b_z->x; + for (i=0; ix; + for (i=0; i sqrt((double)nDIM)+20)|| + (beta < 1.0e-16)||(3 * k >= sqrt((double)nDIM+20))) { + min_old = min; + min = diagVect.ele[0] - fabs(diag2Vect.ele[0]); + max = diagVect.ele[0] + fabs(diag2Vect.ele[0]); + for ( i = 1; i < k ; i++ ) { + tmp = diagVect.ele[i] + - fabs(diag2Vect.ele[i-1]) - fabs(diag2Vect.ele[i]); + if (min > tmp) + min = tmp; + tmp = diagVect.ele[i] + + fabs(diag2Vect.ele[i-1]) + fabs(diag2Vect.ele[i]); + if (max < tmp) + max = tmp; + } + tmp = diagVect.ele[k] - fabs(diag2Vect.ele[k-1]); + if (min > tmp) + min = tmp; + tmp = diagVect.ele[k] + fabs(diag2Vect.ele[k-1]); + if (max < tmp) + max = tmp; + + for (i = 0; i < 20;i++) { + // printf("i = %d min = %lf max = %lf\n", i, min, max); + mid = (max + min) / 2.0; + sig = diagVect.ele[0] - mid; + for (j = 1;j <= k;j++) { + if (sig <= 0.0) + break; + tmp = sig; + sig = (diagVect.ele[j] - mid) - diag2Vect.ele[j-1] * diag2Vect.ele[j-1] / tmp; + } + if (sig <= 0.0) + max = mid; + else + min = mid; + } + } + k++; + // printf("%d : %e %e %e\n",k,fabs(min - min_old),fabs(min),beta); + } + return min; +} + + + +double Lal::getOneNorm(Vector& b) +{ + double ret = 0.0; + int nDim = b.nDim; + for (int k=0; k= *n) { + // Here is point. + rdpotf2_(uplo, n, a, lda, info); + } else { + for (int j = 0; j < *n; j += nb) { + int jb = min(nb,*n- j); + dsyrk_fc((char *)"Lower", (char *)"No transpose", &jb, + &j, &DMONE, &a[j], lda, + &DONE, &a[j+nRow*j], lda, + strlen("Lower"), strlen("No transpose")); + // Here is point. + rdpotf2_((char *)"Lower", &jb, &a[j+nRow*j], lda, info); + if (*info != 0) { + *info = *info + j - 1; + return 0; + } + if (j + jb <= *n-1) { + int i = *n - j - jb; + dgemm_fc((char *)"No transpose", (char *)"Transpose", &i, &jb, + &j, &DMONE, &a[j + jb], lda, &a[j], lda, + &DONE, &a[(j + jb)+nRow*j], lda, + strlen("No transpose"), strlen("Transpose")); + dtrsm_fc((char *)"Right", (char *)"Lower", + (char *)"Transpose", (char *)"Non-unit", + &i, &jb, &DONE, &a[j+nRow*j], lda, + &a[(j + jb)+nRow*j], lda, + strlen("Right"), strlen("Lower"), + strlen("Transpose"), strlen("Non-unit")); + } + } + } + return 0; +} + + +bool Lal::choleskyFactorWithAdjust(DenseMatrix& aMat) +{ + int info=0; +#if 1 + // aMat.display(); + TimeStart(START1); + info = rATL_dpotrfL(aMat.nRow, aMat.de_ele,aMat.nRow); + TimeEnd(END1); + // rMessage("Schur colesky ::" << TimeCal(START1,END1)); + // aMat.display(); +#elif 1 + dpotrf_fc("Lower",&aMat.nRow,aMat.de_ele,&aMat.nRow, + &info,strlen("Lower")); +#else + rdpotrf_("Lower",&aMat.nRow,aMat.de_ele,&aMat.nRow,&info); +#endif + if (info < 0) { + rMessage("cholesky argument is wrong " << -info); + } else if (info > 0) { + rMessage("cholesky miss condition :: not positive definite" + << " :: info = " << info); + rMessage("There are some possibilities."); + rMessage("1. SDPA finalizes due to inaccuracy of numerical error"); + rMessage("2. The input problem may not have (any) interior-points"); + rMessage("3. Input matrices are linearly dependent"); + return SDPA_FAILURE; + } + return SDPA_SUCCESS; +#if 0 + double ZERO_DETECT = 1.0e-3; + double NONZERO = 1.0e-7; + // no idea version + // if Cholesky factorization failed, then exit soon. + int info = 1; // info == 0 means success + int start = 0; + while (start NONZERO*mishi) { + // rMessage(" migi*migi > NONZERO*mishi "); + migi = sqrt(NONZERO*mishi) * 0.99; + shita = sqrt(NONZERO*mishi) * 0.99; + } + } + } + rMessage("cholesky adjust position " << start); + } + if (info < 0) { + rError("argument is something wrong " << info); + } + return SDPA_SUCCESS; +#endif +} + +bool Lal::solveSystems(Vector& xVec, + DenseMatrix& aMat, Vector& bVec) +{ + // aMat must have done Cholesky factorized. + if (aMat.nCol!=xVec.nDim || aMat.nRow!=bVec.nDim + || aMat.nRow!=aMat.nCol) { + rError("solveSystems:: different memory size"); + } + xVec.copyFrom(bVec); + dtrsv_fc((char *)"Lower", (char *)"NoTranspose", (char *)"NonUnit", + &aMat.nRow, aMat.de_ele, &aMat.nCol, xVec.ele,&IONE, + strlen("Lower"), strlen("NoTranspose"), strlen("NonUnit")); + dtrsv_fc((char *)"Lower", (char *)"Transpose", (char *)"NonUnit", + &aMat.nRow, aMat.de_ele, &aMat.nCol, xVec.ele,&IONE, + strlen("Lower"), strlen("Transpose"), strlen("NonUnit")); + return SDPA_SUCCESS; +} + +// nakata 2004/12/01 +bool Lal::solveSystems(Vector& xVec, + SparseMatrix& aMat, Vector& bVec) +{ +#define TUNEUP 0 +#if TUNEUP + if (aMat.nCol!=xVec.nDim || aMat.nRow!=bVec.nDim + || aMat.nRow!=aMat.nCol) { + printf("A.row:%d A.col:%d x.row:%d b.row:%d\n", + aMat.nCol,aMat.nRow,xVec.nDim ,bVec.nDim); + rError("solveSystems(sparse):: different memory size"); + } + int length; + int amari,shou,counter; + + switch(aMat.type) { + case SparseMatrix::SPARSE: +#endif + // Attension: in SPARSE case, only half elements + // are stored. And bMat must be DENSE case. + // rMessage("aMat.NonZeroCount == " << aMat.NonZeroCount); + xVec.copyFrom(bVec); +#if TUNEUP + + shou = aMat.NonZeroCount / 4; + amari = aMat.NonZeroCount % 4; + int i,j; + double value; + + for (int index=0; indexx)[agg_index] += value*(*scalar); + } + } +} + +void Lal::plus(CholmodSpace& retMat, + CompSpace& aMat, + double* scalar) +{ + if (scalar == NULL) { + scalar = &DONE; + } + + for (int l_index=0; l_index < aMat.LP_sp_nBlock; ++l_index) { + const double value = aMat.LP_sp_block[l_index]; + const int l = aMat.LP_sp_index[l_index]; + if (l < 0 || l>=retMat.LP_nBlock) { + rError("Code bug"); + } + retMat.LP_Z[l] += value * (*scalar); + } + + for (int l_index=0; l_index < aMat.SDP_sp_nBlock; ++l_index) { + const int l = aMat.SDP_sp_index[l_index]; + Lal::plus(retMat.SDP_block[l], aMat.SDP_sp_block[l_index], scalar); + } +} + +bool Lal::getSymmetrize(DenseLinearSpace& aMat) +{ + bool total_judge = SDPA_SUCCESS; + // for SDP + for (int l=0; lA) = retMat(Cholmod->A) + aMat*(*scalar); + static void plus(CholmodMatrix& retMat, + CompMatrix& aMat, + double* scalar = NULL); + + // retMat(Cholmod->A) = retMat(Cholmod->A) + aMat*(*scalar); + static void plus(CholmodSpace& retMat, + CompSpace& aMat, + double* scalar = NULL); + + // ret = a '*' (*scalar) + static bool let(DenseLinearSpace& retMat, const char eq, + DenseLinearSpace& aMat, const char op, + double* scalar = NULL); + + // ret = a '+' '-' b*(*scalar) + static bool let(DenseLinearSpace& retMat, const char eq, + DenseLinearSpace& aMat, const char op, + DenseLinearSpace& bMat, double* scalar = NULL); + + // ret = a '+' '-' b*(*scalar) + static bool let(DenseLinearSpace& retMat, const char eq, + SparseLinearSpace& aMat, const char op, + DenseLinearSpace& bMat, double* scalar = NULL); + + // ret = a '+' '-' '*' b*(*scalar) + static bool let(DenseLinearSpace& retMat, const char eq, + DenseLinearSpace& aMat, const char op, + SparseLinearSpace& bMat, double* scalar = NULL); + + // ret = inner_product(a,b) // op = '.' + static bool let(double& ret, const char eq, + DenseLinearSpace& aMat, const char op, + DenseLinearSpace& bMat); + + // ret = inner_product(a,b) // op = '.' + static bool let(double& ret, const char eq, + SparseLinearSpace& aMat, const char op, + DenseLinearSpace& bMat); + + // ret = inner_product(a,b) // op = '.' + static bool let(double& ret, const char eq, + DenseLinearSpace& aMat, const char op, + SparseLinearSpace& bMat); + + + //======================================================================= + // for SDPA-C + //======================================================================= + + static void getInnerProduct(double& ret, + CompMatrix& A, + CliqueMatrix& X, + OrderingMatrix& order); + + static void getInnerProduct(double& ret, + cholmod_sparse* Z, + CliqueMatrix& X, + OrderingMatrix& order, + int* Z_blockNumber, int* Z_blockIndex); + + static void getInnerProduct(double& ret, + CompSpace& A, + CliqueSpace& X, + OrderingSpace& order); + + static void getInnerProduct(double& ret, + CompMatrix& A, + double* aVec, + double* bVec); + + static void getInnerProduct(double& ret, + cholmod_sparse* A, + double* aVec, + double* bVec); + + +}; + +} // end of namespace 'sdpa' + +#endif // __sdpa_linear_h__ diff --git a/external/sdpa/sdpa_newton.cpp b/external/sdpa/sdpa_newton.cpp new file mode 100644 index 0000000..584755f --- /dev/null +++ b/external/sdpa/sdpa_newton.cpp @@ -0,0 +1,1889 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_newton.h" +#include "sdpa_parts.h" +#include "sdpa_linear.h" +#include "sdpa_algebra.h" + +namespace sdpa { + +pthread_mutex_t Newton::job_mutex = PTHREAD_MUTEX_INITIALIZER; +int Newton::Column_Number = 0; +int Newton::Column_NumberDx = 0; + + +Newton::Newton() +{ + // Caution: if SDPA doesn't use sparse bMat, + // following variables are indefinite. + this->SDP_nBlock = -1; + SDP_number = NULL; SDP_location_sparse_bMat = NULL; + SDP_constraint1 = NULL; SDP_constraint2 = NULL; + SDP_blockIndex1 = NULL; SDP_blockIndex2 = NULL; + this->LP_nBlock = -1; + LP_number = NULL; LP_location_sparse_bMat = NULL; + LP_constraint1 = NULL; LP_constraint2 = NULL; + LP_blockIndex1 = NULL; LP_blockIndex2 = NULL; + + diagonalIndex = NULL; + NUM_THREADS = 1; +} + +Newton::Newton(int m, BlockStruct& bs) +{ + initialize(m, bs); +} + +Newton::~Newton() +{ + finalize(); +} + +void Newton::initialize(int m, BlockStruct& bs) +{ + gVec.initialize(m); + + SDP_nBlock = bs.SDP_nBlock; + LP_nBlock = bs.LP_nBlock; + + bMat_type = DENSE; + // Caution: if SDPA doesn't use sparse bMat, + // following variables are indefinite. + this->SDP_nBlock = -1; + SDP_number = NULL; SDP_location_sparse_bMat = NULL; + SDP_constraint1 = NULL; SDP_constraint2 = NULL; + SDP_blockIndex1 = NULL; SDP_blockIndex2 = NULL; + this->LP_nBlock = -1; + LP_number = NULL; LP_location_sparse_bMat = NULL; + LP_constraint1 = NULL; LP_constraint2 = NULL; + LP_blockIndex1 = NULL; LP_blockIndex2 = NULL; + + diagonalIndex = NULL; +} + +void Newton::finalize() +{ + + if (bMat_type == SPARSE){ + + if (SDP_location_sparse_bMat && SDP_constraint1 && SDP_constraint2 + && SDP_blockIndex1 && SDP_blockIndex2) { + for (int l=0; l 1){ + if (sparse_bMat.row_index[target] < ii+1){ + begin = target; + target = (begin + end) / 2; + } else if (sparse_bMat.row_index[target] > ii+1){ + end = target; + target = (begin + end) / 2; + } else if (sparse_bMat.row_index[target] == ii+1) { + t = target; + break; + } + } + if (t == -1){ + if (sparse_bMat.row_index[begin] == ii+1){ + t = begin; + } else if (sparse_bMat.row_index[end] == ii+1){ + t = end; + } else { + #if 0 + int m = sparse_bMat.nRow; + rMessage("Trouble ii = " << ii << " jj = " << j << " m = " << m); + for (int k = 0; k startTmp; + + for (int k1=0; k1%d ", index1,startTmp[index1]); + } + #endif + } //for l lth block +} + +void Newton::make_aggrigateIndex_LP(InputData& inputData) +{ + LP_nBlock = inputData.LP_nBlock; + NewArray(LP_number,int,LP_nBlock); + + // memory allocate for aggrigateIndex + NewArray(LP_constraint1,int*,LP_nBlock); + NewArray(LP_constraint2,int*,LP_nBlock); + NewArray(LP_blockIndex1,int*,LP_nBlock); + NewArray(LP_blockIndex2,int*,LP_nBlock); + NewArray(LP_location_sparse_bMat,int*,LP_nBlock); + NewArray(LP_nStartIndex2, int, LP_nBlock); + NewArray(LP_startIndex2, int*, LP_nBlock); + + for (int l=0; l startTmp; + + for (int k1=0; k1l; + const int m = targ->m; + const double target_mu = targ->target_mu; + const int thread_num = targ->thread_num; + InputData& inputData = *(targ->addr_inputData); + CholmodMatrix& cholmodMatrix = *(targ->addr_cholmodMatrix); + DenseMatrix& bMat = *(targ->addr_bMat); + Vector& gVec = *(targ->addr_gVec); + Phase& phase = *(targ->addr_phase); + CompSpace* A = inputData.A; + const int nDim = cholmodMatrix.nDim; + cholmod_common& common = cholmodMatrix.common; + + const int SDP_nConstraintl = inputData.SDP_nConstraint[l]; + int* SDP_constraintl = inputData.SDP_constraint[l]; + int* SDP_blockIndexl = inputData.SDP_blockIndex[l]; + + + // for multi-threads computing work space + cholmod_dense* b_x1; + cholmod_dense* b_z1; + b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + double* b_x = (double*)(b_x1->x); + double* b_z = (double*)(b_z1->x); + + cholmod_factor* Lz = cholmodMatrix.Lz; + cholmod_factor* Lx = cholmodMatrix.Lx; + int k1 = 0; // dummy initialize + while (1) { + pthread_mutex_lock(&job_mutex); + k1 = Column_Number; + Column_Number++; + pthread_mutex_unlock(&job_mutex); + if (k1>=SDP_nConstraintl) { + break; + } + + int j = SDP_constraintl[k1]; + int jb = SDP_blockIndexl[k1]; + // rMessage("j = " << j << " : jb = " << jb); + CompMatrix& Aj = A[j].SDP_sp_block[jb]; + + const int nCol = Aj.nzColumn; + double gj1 = 0.0; + double gj2 = 0.0; + for (int k_index = 0; k_index < nCol; ++k_index) { + const int k = Aj.column_index[k_index]; + // rMessage("k = " << k << ", k_index = " << k_index); + // rMessage("j = " << j << " : jb = " << jb); + for (int index1=0;index1 < nDim; ++index1) { + b_z[index1] = 0.0; + } + const int i_start = Aj.column_start[k_index]; + const int i_end = Aj.column_start[k_index+1]; + for (int i_index = i_start; i_index < i_end; ++i_index) { + const int i2 = Aj.row_index[i_index]; + b_z[i2] = Aj.ele[i_index]; + } + + cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common); + cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common); + cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common); + double* x_z = (double*)(x_z1->x); + + for (int index1=0;index1 < nDim; ++index1) { + b_x[index1] = 0.0; + } + b_x[k] = 1.0; + + cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common); + cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common); + cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common); + cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common); + double* x_x = (double*)(x_x1->x); +#if 0 + rMessage("Aj = "); Aj.display(); + rMessage(" b_x = "); + CholmodMatrix::display_dense(cholmodMatrix.b_x1); + rMessage(" x_x = "); + CholmodMatrix::display_dense(cholmodMatrix.x_x1); + rMessage(" b_z = "); + CholmodMatrix::display_dense(cholmodMatrix.b_z1); + rMessage(" x_z = "); + CholmodMatrix::display_dense(cholmodMatrix.x_z1); + // rMessage(" rD = "); + // CholmodMatrix::display_sparse(cholmodMatrix.rD); +#endif + + double gadd = 0.0; + if (phase.value == SolveInfo::pFEAS + || phase.value == SolveInfo::noINFO) { + Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z); + } + // rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k); + gj1 += gadd; + gj2 += x_z[k]; + for (int k2=k1; k2l; + const int m = targ->m; + const double target_mu = targ->target_mu; + const int thread_num = targ->thread_num; + InputData& inputData = *(targ->addr_inputData); + CholmodMatrix& cholmodMatrix = *(targ->addr_cholmodMatrix); + SparseMatrix& sparse_bMat = *(targ->addr_sparse_bMat); + Vector& gVec = *(targ->addr_gVec); + Phase& phase = *(targ->addr_phase); + Newton& newton = *(targ->addr_newton); + CompSpace* A = inputData.A; + const int nDim = cholmodMatrix.nDim; + cholmod_common& common = cholmodMatrix.common; + + int* SDP_constraint1l = newton.SDP_constraint1[l]; + int* SDP_blockIndex1l = newton.SDP_blockIndex1[l]; + int* SDP_constraint2l = newton.SDP_constraint2[l]; + int* SDP_blockIndex2l = newton.SDP_blockIndex2[l]; + int* SDP_startIndex2l = newton.SDP_startIndex2[l]; + const int SDP_nStartIndex2l = newton.SDP_nStartIndex2[l]; + int* SDP_location_sparse_bMatl = newton.SDP_location_sparse_bMat[l]; + + // for multi-threads computing work space + cholmod_dense* b_x1; + cholmod_dense* b_z1; + b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + double* b_x = (double*)(b_x1->x); + double* b_z = (double*)(b_z1->x); + + cholmod_factor* Lz = cholmodMatrix.Lz; + cholmod_factor* Lx = cholmodMatrix.Lx; + + int index2 = 0; // dummy initialize + while (1) { + pthread_mutex_lock(&job_mutex); + index2 = Column_Number++; + pthread_mutex_unlock(&job_mutex); + if (index2 >= SDP_nStartIndex2l) { + break; + } + const int start_iter = SDP_startIndex2l[index2]; + const int end_iter = SDP_startIndex2l[index2+1]; + int j = SDP_constraint2l[start_iter]; + int jb = SDP_blockIndex2l[start_iter]; + CompMatrix& Aj = A[j].SDP_sp_block[jb]; + + const int nCol = Aj.nzColumn; + double gj1 = 0.0; + double gj2 = 0.0; + for (int k_index = 0; k_index < nCol; ++k_index) { + const int k = Aj.column_index[k_index]; + for (int index1=0;index1 < nDim; ++index1) { + b_z[index1] = 0.0; + } + const int i_start = Aj.column_start[k_index]; + const int i_end = Aj.column_start[k_index+1]; + for (int i_index = i_start; i_index < i_end; ++i_index) { + const int i2 = Aj.row_index[i_index]; + b_z[i2] = Aj.ele[i_index]; + } + cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common); + cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common); + cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common); + double* x_z = (double*)(x_z1->x); + for (int index1=0;index1 < nDim; ++index1) { + b_x[index1] = 0.0; + } + b_x[k] = 1.0; + + cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common); + cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common); + cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common); + cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common); + double* x_x = (double*)(x_x1->x); + +#if 0 + rMessage(" x_x = "); + CholmodMatrix::display_dense(cholmodMatrix.x_x); + rMessage(" x_z = "); + CholmodMatrix::display_dense(cholmodMatrix.x_z); + rMessage(" rD = "); + CholmodMatrix::display_sparse(cholmodMatrix.rD); +#endif + + double gadd = 0.0; + if (phase.value == SolveInfo:: pFEAS + || phase.value == SolveInfo::noINFO) { + Lal::getInnerProduct(gadd, cholmodMatrix.rD, x_x, x_z); + // rMessage("gj1 = " << gadd << " : gj2 = " << x_z[k] << " : k = " << k); + } + gj1 += gadd; + gj2 += x_z[k]; + + for (int iter = start_iter; iter < end_iter; ++iter) { + int i = SDP_constraint1l[iter]; + int ib = SDP_blockIndex1l[iter]; + CompMatrix& Ai = A[i].SDP_sp_block[ib]; + double Badd = 0.0; + Lal::getInnerProduct(Badd, Ai, x_x, x_z); + sparse_bMat.sp_ele[SDP_location_sparse_bMatl[iter]] += Badd; + } + cholmod_free_dense(&b2,&common); + cholmod_free_dense(&x_z2,&common); + cholmod_free_dense(&b_x2,&common); + cholmod_free_dense(&x_x3,&common); + cholmod_free_dense(&x_x2,&common); + cholmod_free_dense(&x_x1,&common); + cholmod_free_dense(&x_z1,&common); + } // end of 'for (int k_index)' + gVec.ele[j] += (gj1 - target_mu * gj2); + } // end of 'for (int index2, aka j)' + cholmod_free_dense(&b_x1,&common); + cholmod_free_dense(&b_z1,&common); + +} + + + +void Newton::Make_bMatgVec(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com) +{ + TimeStart(START3); + gVec.copyFrom(inputData.b); + if (bMat_type == SPARSE){ + // set sparse_bMat zero + sdpa_dset(sparse_bMat.NonZeroCount, 0.0, sparse_bMat.sp_ele, 1); + #if 0 + compute_bMatgVec_sparse(inputData, currentPt, currentRes, mu, beta, + phase, com); + #else + compute_bMatgVec_sparse_threads(inputData, currentPt, currentRes, mu, beta, + phase, com); + #endif + } else { + bMat.setZero(); + #if 0 + compute_bMatgVec_dense(inputData, currentPt, currentRes, mu, beta, + phase, com); + #else + compute_bMatgVec_dense_threads(inputData, currentPt, currentRes, mu, beta, + phase, com); + #endif + } + + #if 0 + // display_index(); + rMessage("bMat = "); + if (bMat_type == DENSE) { + bMat.display(); + } + else { + sparse_bMat.display(); + } + rMessage("gVec = "); + gVec.display(); + #endif + TimeEnd(END3); + com.makebMatgVec += TimeCal(START3,END3); +} + +bool Newton::compute_DyVec(Newton::WHICH_DIRECTION direction, + int m, + InputData& inputData, + Chordal& chordal, + Solutions& currentPt, + ComputeTime& com, + FILE* Display, FILE* fpOut) +{ + if (direction == PREDICTOR) { + TimeStart(START3_2); + + if (bMat_type == SPARSE){ + bool ret = chordal.factorizeSchur(m, diagonalIndex, Display, fpOut); + if (ret == SDPA_FAILURE) { + return SDPA_FAILURE; + } + } else { + bool ret = Lal::choleskyFactorWithAdjust(bMat); + if (ret == SDPA_FAILURE) { + return SDPA_FAILURE; + } + } + // rMessage("Cholesky of bMat = "); + // bMat.display(); + // sparse_bMat.display(); + TimeEnd(END3_2); + com.choleskybMat += TimeCal(START3_2,END3_2); + } + // bMat is already cholesky factorized. + + + Vector& DyVec = currentPt.cholmodSpace.dyVec; + + TimeStart(START4); + if (bMat_type == SPARSE){ + DyVec.copyFrom(gVec); + chordal.solveSchur(DyVec); + } else { + Lal::let(DyVec,'=',bMat,'/',gVec); + } + TimeEnd(END4); + com.solve += TimeCal(START4,END4); + // rMessage("DyVec = "); + // DyVec.display(); + return SDPA_SUCCESS; +} + +void Newton::compute_DzMat(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + Phase& phase, + ComputeTime& com) +{ + TimeStart(START_SUMDZ); + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + CompSpace* A = inputData.A; + + for (int l=0; lnzmax; + for (int index1 = 0; index1 < length; ++index1) { + ((double*)(dZ->x))[index1] = 0.0; + } + } + + const int m = cholmodSpace.dyVec.nDim; + for (int k=0; kx))[agg_index] -= Akl.ele[i]*dyk; + } + } + } + } // end of 'for (int k=0; knzmax; + for (int index1 = 0; index1 < length; ++index1) { + ((double*)(dZ->x))[index1] += ((double*)(rD->x))[index1]; + } + } + } + TimeEnd(END_SUMDZ); + com.sumDz += TimeCal(START_SUMDZ,END_SUMDZ); +} + +void Newton::compute_DxMat(Solutions& currentPt, + AverageComplementarity& mu, + DirectionParameter& beta, + ComputeTime& com) +{ + TimeStart(START_DX); + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + OrderingSpace& orderingSpace = currentPt.order; + const double target_mu = beta.value * mu.current; + for (int l=0; lx); + b_z[k] = 1.0; + cholmodMatrix.solveByZ(); + double* x_z = (double*)(cholmodMatrix.x_z->x); + // x_z is now Zinv[*k] + + double one[2] = {1.0, 0.0}; + double zero[2] = {0.0, 0.0} ; + int transpose = 0; // 0 means no transpose + double* b_x = (double*)(cholmodMatrix.b_x->x); + cholmod_sdmult(dZ, transpose, one, zero, cholmodMatrix.x_z, + cholmodMatrix.b_x, &common); + cholmodMatrix.solveByX(); + double* x_x = (double*)(cholmodMatrix.x_x->x); + + for (int i=0; il; + const int thread_num = tDX->thread_num; + const double target_mu = tDX->target_mu; + CholmodMatrix& cholmodMatrix = *(tDX->addr_cholmodMatrix); + OrderingMatrix& order = *(tDX->addr_order); + + const int nDim = cholmodMatrix.nDim; + cholmod_factor* Lz = cholmodMatrix.Lz; + cholmod_factor* Lx = cholmodMatrix.Lx; + cholmod_sparse* dZ = cholmodMatrix.dZ; + cholmod_common& common = cholmodMatrix.common; + CliqueMatrix& clique_dX = cholmodMatrix.clique_dX; + + cholmod_dense* b_x1; + cholmod_dense* b_z1; + b_x1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + b_z1 = cholmod_allocate_dense(nDim,1,nDim,CHOLMOD_REAL, + &common); + double* b_x = (double*)(b_x1->x); + double* b_z = (double*)(b_z1->x); + + int k = 0; // dummy initialize + + while (1) { + pthread_mutex_lock(&job_mutex); + k = Column_NumberDx; + Column_NumberDx++; + pthread_mutex_unlock(&job_mutex); + if (k >= nDim) { + break; + } + for (int index1=0;index1 < nDim; ++index1) { + b_z[index1] = 0.0; + } + b_z[k] = 1.0; + cholmod_dense* b2 = cholmod_solve(CHOLMOD_P, Lz, b_z1, &common); + cholmod_dense* x_z2 = cholmod_solve(CHOLMOD_LDLt, Lz, b2, &common); + cholmod_dense* x_z1 = cholmod_solve(CHOLMOD_Pt, Lz, x_z2, &common); + double* x_z = (double*)(x_z1->x); + + // x_z is now Zinv[*k] + + double one[2] = {1.0, 0.0}; + double zero[2] = {0.0, 0.0} ; + int transpose = 0; // 0 means no transpose + cholmod_sdmult(dZ, transpose, one, zero, x_z1, + b_x1, &common); + + cholmod_dense* b_x2 = cholmod_solve(CHOLMOD_P, Lx, b_x1, &common); + cholmod_dense* x_x3 = cholmod_solve(CHOLMOD_L, Lx, b_x2, &common); + cholmod_dense* x_x2 = cholmod_solve(CHOLMOD_Lt,Lx, x_x3, &common); + cholmod_dense* x_x1 = cholmod_solve(CHOLMOD_Pt, Lx, x_x2, &common); + double* x_x = (double*)(x_x1->x); + + + for (int i=0; inzmax; + for (int index1 = 0; index1 < length; ++index1) { + ((double*)(rDs[l]->x))[index1] = -((double*)(Z->x))[index1] -((double*)(dZ->x))[index1]; + } + } + for (int l_index=0; l_index < C.SDP_sp_nBlock; ++l_index) { + const int l = C.SDP_sp_index[l_index]; + CompMatrix& Cl = C.SDP_sp_block[l_index]; + cholmod_sparse* rD = rDs[l]; + for (int j_index = 0; j_indexx))[agg_index] += Cl.ele[i]; + } + } + } + for (int k=0; kx))[agg_index] -= Akl.ele[i]*(yk+dyk); + } + } + } + } + for (int l=0; lnzmax; + for (int index1 = 0; index1 < length; ++index1) { + double value = ((double*)(rDs[l]->x))[index1]; + sum += value*value; + } + } + for (int l=0; l + +#define SparseCholesky 1 + +namespace sdpa { + +class Newton; + +class Solutions; +class InputData; +class Residuals; + +class ComputeTime; +class Parameter; +class StepLength; +class DirectionParameter; +class Switch; +class RatioInitResCurrentRes; +class SolveInfo; +class Phase; +class AverageComplementarity; + + + +class Newton +{ +public: + enum bMat_Sp_De {SPARSE, DENSE}; + bMat_Sp_De bMat_type; + + SparseMatrix sparse_bMat; + DenseMatrix bMat; // the coefficent of Schur complement + Vector gVec; // the right hand side of Schur complement + + // Caution: + // if SDPA doesn't use sparse bMat, following variables are indefinite. + // + // nBlock : number of block + // nConstraint[k]: number of combination of nonzero matrices in k-th block + // when A[k].block[i] and A[k].block[j] are nonzero matrices, + // i <-> constraint1[k][t] + // j <-> constraint2[k][t] + // A[k].block[i] <-> A[k].sp_block[blockIndex1[k][t]] + // A[k].block[j] <-> A[k].sp_block[blockIndex2[k][t]] + // B_{ij} <-> sparse_bMat.sp_ele[location_sparse_bMat[k][t]] + int SDP_nBlock; int* SDP_number; + int** SDP_constraint1; int** SDP_constraint2; + int** SDP_blockIndex1; int** SDP_blockIndex2; + int** SDP_location_sparse_bMat; + int* SDP_nStartIndex2; // start new j&jb from this index + int** SDP_startIndex2; // start new j&jb from this index + int LP_nBlock; int* LP_number; + int** LP_constraint1; int** LP_constraint2; + int** LP_blockIndex1; int** LP_blockIndex2; + int** LP_location_sparse_bMat; + int* LP_nStartIndex2; // start new j&jb from this index + int** LP_startIndex2; // start new j&jb from this index + + // from index of aggrigate sparsity pattern to index of sparse_bMat + // B_{ii} <-> sparse_bMat[diagonalIndex[i]] + int* diagonalIndex; + // B_{ij} for all i is between diagonalIndex[j] and rowStartIndex[j+1] + + Newton(); + Newton(int m, BlockStruct& bs); + ~Newton(); + + void initialize(int m, BlockStruct& bs); + + void finalize(); + + void initialize_dense_bMat(int m); + // 2008/03/12 kazuhide nakata + void initialize_sparse_bMat(int m); + // 2008/03/12 kazuhide nakata + void initialize_bMat(int m, Chordal& chordal, InputData& inputData, + FILE* Display, FILE* fpOut); + + int binarySearchIndex(int i, int j); + void make_aggrigateIndex_SDP(InputData& inputData); + void make_aggrigateIndex_LP(InputData& inputData); + void make_aggrigateIndex(InputData& inputData); + + enum WHICH_DIRECTION {PREDICTOR, CORRECTOR}; + + void compute_bMatgVec_dense(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com); + + static pthread_mutex_t job_mutex; + static int Column_Number; + static int Column_NumberDx; + + void compute_bMatgVec_dense_threads(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com); + static void* compute_bMatgVec_dense_threads_SDP(void* arg); + + void compute_bMatgVec_sparse(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com); + + void compute_bMatgVec_sparse_threads(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com); + + static void* compute_bMatgVec_sparse_threads_SDP(void* arg); + + void Make_bMatgVec(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Phase& phase, + ComputeTime& com); + + bool compute_DyVec(Newton::WHICH_DIRECTION direction, + int m, + InputData& inputData, + Chordal& chordal, + Solutions& currentPt, + ComputeTime& com, + FILE* Display, FILE* fpOut); + + void compute_DzMat(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + Phase& phase, + ComputeTime& com); + + void compute_DxMat(Solutions& currentPt, + AverageComplementarity& mu, + DirectionParameter& beta, + ComputeTime& com); + + void compute_DxMat_threads(Solutions& currentPt, + AverageComplementarity& mu, + DirectionParameter& beta, + ComputeTime& com); + + static void* compute_DxMat_threads_SDP(void* arg); + + bool Mehrotra(WHICH_DIRECTION direction, + int m, + InputData& inputData, + Chordal& chordal, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Switch& reduction, + Phase& phase, + ComputeTime& com, + FILE* Display, FILE* fpOut); + + void checkDirection(int m, InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + DirectionParameter& beta, + Switch& reduction, + Phase& phase, + ComputeTime& com, + FILE* Display, FILE* fpOut); + + void display(FILE* fpout=stdout); + void display_index(FILE* fpout=stdout); + void display_sparse_bMat(FILE* fpout=stdout); + + int NUM_THREADS; + void setNumThreads(FILE* Display, FILE* fpOut, int NumThreads=0); +}; + +typedef struct _thread_arg { + int l; + int m; + double target_mu; + int thread_num; + InputData* addr_inputData; + CholmodMatrix* addr_cholmodMatrix; + DenseMatrix* addr_bMat; + Vector* addr_gVec; + Phase* addr_phase; + +} thread_arg_t; + +typedef struct _thread_arg_s { + int l; + int m; + double target_mu; + int thread_num; + InputData* addr_inputData; + CholmodMatrix* addr_cholmodMatrix; + SparseMatrix* addr_sparse_bMat; + Vector* addr_gVec; + Phase* addr_phase; + Newton* addr_newton; + +} thread_arg_s; + +typedef struct _thread_DX { + int l; + int thread_num; + double target_mu; + CholmodMatrix* addr_cholmodMatrix; + OrderingMatrix* addr_order; +} thread_DX_t; + + +} // end of namespace 'sdpa' + +#endif // __sdpa_newton_h__ diff --git a/external/sdpa/sdpa_parts.cpp b/external/sdpa/sdpa_parts.cpp new file mode 100644 index 0000000..1ea8627 --- /dev/null +++ b/external/sdpa/sdpa_parts.cpp @@ -0,0 +1,1314 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_parts.h" +#include "sdpa_linear.h" +#include "sdpa_newton.h" + +namespace sdpa { + +ComputeTime::ComputeTime() +{ + Predictor = 0.0; + Corrector = 0.0; + + StepPredictor = 0.0; + StepCorrector = 0.0; + + xMatTime = 0.0; + zMatTime = 0.0; + xMatzMatTime = 0.0; + invzMatTime = 0.0; + + EigxMatTime = 0.0; + EigzMatTime = 0.0; + EigxMatzMatTime = 0.0; + + makebMat = 0.0; + B_DIAG = 0.0; + B_F1 = 0.0; + B_F2 = 0.0; + B_F3 = 0.0; + B_PRE = 0.0; + + makebMatgVec = 0.0; + makerMat = 0.0; + choleskybMat = 0.0; + + solve = 0.0; + sumDz = 0.0; + makedX = 0.0; + symmetriseDx = 0.0; + makedXdZ = 0.0; + updateRes = 0.0; + + MainLoop = 0.0; + FileRead = 0.0; + FileCheck = 0.0; + FileChange= 0.0; + TotalTime = 0.0; +} + +ComputeTime::~ComputeTime() +{ + // Nothing needs. +} + + +void ComputeTime::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout,"\n"); + #if 0 + if (TotalTime <= 0.0) { + return; + } + #endif + fprintf(fpout, " Time(sec) "); + fprintf(fpout," Ratio(%% : MainLoop) \n"); + fprintf(fpout, " Predictor time = %f, %f\n", + Predictor, Predictor/MainLoop*100.0); + fprintf(fpout, " Corrector time = %f, %f\n", + Corrector, Corrector/MainLoop*100.0); + fprintf(fpout, " Make bMat time = %f, %f\n", + makebMat, makebMat/MainLoop*100.0); + fprintf(fpout, " Make bDia time = %f, %f\n", + B_DIAG,B_DIAG/MainLoop*100.0); + fprintf(fpout, " Make bF1 time = %f, %f\n", + B_F1,B_F1/MainLoop*100.0); + fprintf(fpout, " Make bF2 time = %f, %f\n", + B_F2,B_F2/MainLoop*100.0); + fprintf(fpout, " Make bF3 time = %f, %f\n", + B_F3,B_F3/MainLoop*100.0); + fprintf(fpout, " Make bPRE time = %f, %f\n", + B_PRE,B_PRE/MainLoop*100.0); + fprintf(fpout, " Make rMat time = %f, %f\n", + makerMat, makerMat/MainLoop*100.0); + fprintf(fpout, " Make bMatgVec = %f, %f\n", + makebMatgVec, makebMatgVec/MainLoop*100.0); + fprintf(fpout, " Cholesky bMat = %f, %f\n", + choleskybMat, choleskybMat/MainLoop*100.0); + fprintf(fpout, " Ste Pre time = %f, %f\n", + StepPredictor, StepPredictor/MainLoop*100.0); + fprintf(fpout, " Ste Cor time = %f, %f\n", + StepCorrector, StepCorrector/MainLoop*100.0); + fprintf(fpout, " solve = %f, %f\n", + solve, solve/MainLoop*100.0); + fprintf(fpout, " sumDz = %f, %f\n", + sumDz, sumDz/MainLoop*100.0); + fprintf(fpout, " makedX = %f, %f\n", + makedX, makedX/MainLoop*100.0); + fprintf(fpout, " symmetriseDx = %f, %f\n", + symmetriseDx, symmetriseDx/MainLoop*100.0); + fprintf(fpout, " makedXdZ = %f, %f\n", + makedXdZ, makedXdZ/MainLoop*100.0); + fprintf(fpout, " xMatTime = %f, %f\n", + xMatTime, xMatTime/MainLoop*100.0); + fprintf(fpout, " zMatTime = %f, %f\n", + zMatTime, zMatTime/MainLoop*100.0); + fprintf(fpout, " invzMatTime = %f, %f\n", + invzMatTime, invzMatTime/MainLoop*100.0); + fprintf(fpout, " xMatzMatTime = %f, %f\n", + xMatzMatTime, xMatzMatTime/MainLoop*100.0); + fprintf(fpout, " EigxMatTime = %f, %f\n", + EigxMatTime, EigxMatTime/MainLoop*100.0); + fprintf(fpout, " EigzMatTime = %f, %f\n", + EigzMatTime, EigzMatTime/MainLoop*100.0); + fprintf(fpout, " EigxMatzMatTime = %f, %f\n", + EigxMatzMatTime, EigxMatzMatTime/MainLoop*100.0); + fprintf(fpout, " updateRes = %f, %f\n", + updateRes, updateRes/MainLoop*100.0); + double total_eigen = EigxMatTime + EigzMatTime + EigxMatzMatTime; + fprintf(fpout, " EigTime = %f, %f\n", + total_eigen, total_eigen/MainLoop*100.0); + double sub_total_bMat = MainLoop - makebMat; + fprintf(fpout, " sub_total_bMat = %f, %f\n", + sub_total_bMat, sub_total_bMat/MainLoop*100.0); + fprintf(fpout, " Main Loop = %f, %f\n", + MainLoop, MainLoop/MainLoop*100.0); + fprintf(fpout, " File Check = %f, %f\n", + FileCheck, FileCheck/MainLoop*100.0); + fprintf(fpout, " File Change = %f, %f\n", + FileChange, FileChange/MainLoop*100.0); + fprintf(fpout, " File Read = %f, %f\n", + FileRead, FileRead/MainLoop*100.0); + fprintf(fpout, " Total = %f, %f\n", + TotalTime, TotalTime/MainLoop*100.0); + fprintf(fpout, "\n"); + + return; +} + +//------------------------------------------------------------- + +Parameter::Parameter() +{ + // setDefaultParameter(); +} +Parameter::Parameter(FILE* parameterFile) +{ + readFile(parameterFile); +} + +Parameter::~Parameter() +{ + // Nothings needs. +} + +void Parameter::setDefaultParameter(Parameter::parameterType type) +{ + if (type == PARAMETER_STABLE_BUT_SLOW) { + maxIteration = 1000; + epsilonStar = 1.0e-7; + lambdaStar = 1.0e+4; + omegaStar = 2.0; + lowerBound = -1.0e+5; + upperBound = 1.0e+5; + betaStar = 0.1; + betaBar = 0.5; + gammaStar = 0.8; + epsilonDash = 1.0e-7; + } + else if (type == PARAMETER_UNSTABLE_BUT_FAST) { + maxIteration = 100; + epsilonStar = 1.0e-7; + lambdaStar = 1.0e+2; + omegaStar = 2.0; + lowerBound = -1.0e+5; + upperBound = 1.0e+5; + betaStar = 0.01; + betaBar = 0.02; + gammaStar = 0.95; + epsilonDash = 1.0e-7; + } + else { + maxIteration = 100; + epsilonStar = 1.0e-7; + lambdaStar = 1.0e+2; + omegaStar = 2.0; + lowerBound = -1.0e+5; + upperBound = 1.0e+5; + betaStar = 0.1; + betaBar = 0.3; + gammaStar = 0.9; + epsilonDash = 1.0e-7; + } + strcpy(xPrint,xPRINT_DEFAULT); + strcpy(XPrint,XPRINT_DEFAULT); + strcpy(YPrint,YPRINT_DEFAULT); + strcpy(infPrint,infPRINT_DEFAULT); +} + +char Parameter::xPRINT_DEFAULT[PRINT_DEFAULT_LENGTH] = "%+8.3e"; +char Parameter::XPRINT_DEFAULT[PRINT_DEFAULT_LENGTH] = "%+8.3e"; +char Parameter::YPRINT_DEFAULT[PRINT_DEFAULT_LENGTH] = "%+8.3e"; +char Parameter::infPRINT_DEFAULT[PRINT_DEFAULT_LENGTH] = "%+10.16e"; + +void Parameter::readFile(FILE* parameterFile) +{ + fscanf(parameterFile,"%d%*[^\n]",&maxIteration); + fscanf(parameterFile,"%lf%*[^\n]",&epsilonStar); + fscanf(parameterFile,"%lf%*[^\n]",&lambdaStar); + fscanf(parameterFile,"%lf%*[^\n]",&omegaStar); + fscanf(parameterFile,"%lf%*[^\n]",&lowerBound); + fscanf(parameterFile,"%lf%*[^\n]",&upperBound); + fscanf(parameterFile,"%lf%*[^\n]",&betaStar); + fscanf(parameterFile,"%lf%*[^\n]",&betaBar); + fscanf(parameterFile,"%lf%*[^\n]",&gammaStar); + fscanf(parameterFile,"%lf%*[^\n]",&epsilonDash); + fscanf(parameterFile,"%s %*[^\n]",xPrint); + fscanf(parameterFile,"%s %*[^\n]",XPrint); + fscanf(parameterFile,"%s %*[^\n]",YPrint); + fscanf(parameterFile,"%s %*[^\n]",infPrint); + if (strcmp(xPrint,NO_P_FORMAT)!=0 && xPrint[0]!='%') { + rMessage("Strange xPrint[" << xPrint << "]" + " migh cause trouble when printing x"); + } + if (strcmp(XPrint,NO_P_FORMAT)!=0 && XPrint[0]!='%') { + rMessage("Strange XPrint[" << XPrint << "]" + " migh cause trouble when printing X."); + } + if (strcmp(YPrint,NO_P_FORMAT)!=0 && YPrint[0]!='%') { + rMessage("Strange YPrint[" << YPrint << "]" + " migh cause trouble when printing Y."); + } + if (strcmp(infPrint,NO_P_FORMAT)!=0 && infPrint[0]!='%') { + rMessage("Strange infPrint[" << infPrint << "]" + " migh cause trouble when printing information."); + } +} + + +void Parameter::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (strcmp(printFormat,NO_P_FORMAT) == 0) { + fprintf(fpout,"%s\n",NO_P_FORMAT); + return; + } + fprintf(fpout, "** Parameters **\n"); + fprintf(fpout, "maxIteration = %d\n",maxIteration); + fprintf(fpout, "epsilonStar = "); + fprintf(fpout, printFormat, epsilonStar ); + fprintf(fpout, "\n"); + fprintf(fpout, "lambdaStar = "); + fprintf(fpout, printFormat, lambdaStar ); + fprintf(fpout, "\n"); + fprintf(fpout, "omegaStar = "); + fprintf(fpout, printFormat, omegaStar ); + fprintf(fpout, "\n"); + fprintf(fpout, "lowerBound = "); + fprintf(fpout, printFormat, lowerBound); + fprintf(fpout, "\n"); + fprintf(fpout, "upperBound = "); + fprintf(fpout, printFormat, upperBound); + fprintf(fpout, "\n"); + fprintf(fpout, "betaStar = "); + fprintf(fpout, printFormat, betaStar ); + fprintf(fpout, "\n"); + fprintf(fpout, "betaBar = "); + fprintf(fpout, printFormat, betaBar ); + fprintf(fpout, "\n"); + fprintf(fpout, "gammaStar = "); + fprintf(fpout, printFormat, gammaStar ); + fprintf(fpout, "\n"); + fprintf(fpout, "epsilonDash = "); + fprintf(fpout, printFormat, epsilonDash ); + fprintf(fpout, "\n"); + #if 1 + fprintf(fpout, "xPrint = %s \n", xPrint ); + fprintf(fpout, "XPrint = %s \n", XPrint ); + fprintf(fpout, "YPrint = %s \n", YPrint ); + fprintf(fpout, "infPrint = %s \n", infPrint ); + #endif + return; +} + +//---------------------------------------------------------- + +StepLength::StepLength() +{ + primal = 0.0; + dual = 0.0; + +} + +StepLength::~StepLength() +{ + finalize(); +} + + +void StepLength::initialize(double alphaP, double alphaD) +{ + primal = alphaP; + dual = alphaD; +} + +void StepLength::finalize() +{ + // Nothing needs. +} + +double StepLength::minBlockVector(BlockVector& aVec) +{ + int nBlock = aVec.nBlock; + double ret = aVec.ele[0].ele[0]; + double tmp; + int size = aVec.ele[0].nDim; + for (int j=1; j1.0) { + primal = 1.0; + } + if (dual>1.0) { + dual = 1.0; + } + + +} + + +void StepLength::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + + fprintf(fpout,"alpha.primal = %8.3e\n",primal); + fprintf(fpout,"alpha.dual = %8.3e\n",dual); +} + +//------------------------------------------------- +DirectionParameter::DirectionParameter(double betaStar) +{ + initialize(betaStar); +} + +DirectionParameter::~DirectionParameter() +{ + // Nothing needs. +} + +void DirectionParameter::initialize(double betaStar) +{ + value = betaStar; +} + +void DirectionParameter::Predictor(Phase& phase, + Switch& reduction, + Parameter& param) +{ + const double nu = 2.0; + if (phase.value == SolveInfo::pdFEAS) { + value = param.betaStar; + } else { + value = param.betaBar; + if (reduction.switchType==Switch::AFFINE) { + value = nu; + } + } +} + +void DirectionParameter::Centering() +{ + value = 1.0; +} + +void DirectionParameter:: +MehrotraCorrector(Phase& phase, StepLength& alpha, + Solutions& currentPt, + AverageComplementarity& mu, Parameter& param) +{ + int nDim = currentPt.nDim; + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + + // Lal::let(uMatzMat,'=',newton.DxMat,'.',currentPt.zMat); + // Lal::let(xMatvMat,'=',currentPt.xMat,'.',newton.DzMat); + // Lal::let(uMatvMat,'=',newton.DxMat,'.',newton.DzMat); + double uMatzMat = 0.0; + double xMatvMat = 0.0; + double uMatvMat = 0.0; + for (int l=0; l 1.0) { + value = 1.0; + } + } else { + if (value < param.betaBar) { + value = param.betaBar; + } + } + // rMessage("MehrotraCorrector : " << value); +} + +void DirectionParameter::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout,"beta.value = %8.3e\n",value); +} + +//--------------------------------------------------- + +Switch::Switch(SwitchType switchType) +{ + initialize(switchType); +} + +Switch::~Switch() +{ + // Nothing needs. +} + +void Switch::initialize(SwitchType switchType) +{ + this->switchType = switchType; +} + +void Switch::MehrotraPredictor(Phase& phase) +{ + if (phase.value==SolveInfo::noINFO + || phase.value==SolveInfo::pFEAS + || phase.value==SolveInfo::dFEAS) { + // At least one of primal or dual is infeasible. + switchType = CENTERING; + } else { + switchType = AFFINE; + } +} + +void Switch::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + + if (switchType == CENTERING) { + fprintf(fpout,"reduction.switchType == CENTERING\n"); + } else { + fprintf(fpout,"reduction.switchType == AFFINE\n"); + } +} + +// ---------------------------------------- + +AverageComplementarity::AverageComplementarity(double lambdaStar) +{ + initialize(lambdaStar); +} + +AverageComplementarity::~AverageComplementarity() +{ + // Nothing needs. +} + +void AverageComplementarity::initialize(double lambdaStar) +{ + initial = lambdaStar*lambdaStar; + current = initial; + // rMessage("initial average = " << initial); +} + +void AverageComplementarity::update(Solutions& currentPt) +{ + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + int nDim = cholmodSpace.LP_nBlock; + current = 0.0; + for (int l=0; l param.epsilonDash * 1.0e-2) { + primal = currentRes.normPrimal / currentRes.initNormPrimal; + } + else { + primal = 0.0; + } + if (currentRes.initNormDual + > param.epsilonDash * 1.0e-2) { + dual = currentRes.normDual / currentRes.initNormDual; + } + else { + dual = 0.0; + } +} + +void RatioInitResCurrentRes::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + + fprintf(fpout,"theta.primal = %8.3e\n",primal); + fprintf(fpout,"theta.dual = %8.3e\n",dual); +} + +//--------------------------------------------------- + +SolveInfo::SolveInfo() +{ + rho = 0.0; + etaPrimal = 0.0; + etaDual = 0.0; + objValPrimal = 0.0; + objValDual = 0.0; +} + +SolveInfo::SolveInfo(InputData& inputData, Solutions& currentPt, + double mu0, double omegaStar) +{ + initialize(inputData,currentPt,mu0,omegaStar); +} + +SolveInfo::~SolveInfo() +{ + // Nothing needs. +} + +void SolveInfo::initialize(InputData& inputData, Solutions& currentPt, + double mu0, double omegaStar) +{ + int nDim = currentPt.nDim; + Vector& b = inputData.b; + CompSpace& C = inputData.C; + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + + rho = 1.0; + etaPrimal = omegaStar * nDim * mu0; + etaDual = omegaStar * nDim * mu0; + cholmodSpace.getInnerProductAX(objValPrimal, C, currentPt.order); + #if 0 + C.display(); + cholmodSpace.display(); + rMessage("objValPrimal = " << objValPrimal); + #endif + Lal::let(objValDual,'=',b,'.',cholmodSpace.yVec); +} + +void SolveInfo::update(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + Parameter& param) +{ + CholmodSpace& cholmodSpace = currentPt.cholmodSpace; + + // Lal::let(objValPrimal,'=',C,'.',currentPt.xMat); + objValPrimal = 0.0; + cholmodSpace.getInnerProductAX(objValPrimal, inputData.C, currentPt.order); + Lal::let(objValDual,'=',inputData.b,'.',cholmodSpace.yVec); + + int nDim = cholmodSpace.LP_nBlock; + for (int l=0; lncol; + for (int j=0; j < ncol; ++j) { + const int diag_row = ((int*)Z->p)[j]; + x0zMat += ((double*)Z->x)[diag_row]; + } + } + x0zMat *= lambda; + + // Lal::let(xMatz0,'=',currentPt.xMat,'.',initPt_zMat); + double xMatz0 = 0.0; + for (int l=0; l accuracy + && currentRes.normDual <= accuracy) { + rho = primal*x0zMat + / ((primal+(1.0-primal)*omega)*etaDual + xMatzMat); + } + + // primal is feasible and dual is infeasible + if (currentRes.normPrimal <= accuracy + && currentRes.normDual > accuracy) { + rho = dual*xMatz0 + / ((dual+(1.0-dual)*omega)* etaPrimal + xMatzMat); + } + + // primal and dual are infeasible + if (currentRes.normPrimal > accuracy + && currentRes.normDual > accuracy) { + rho = (dual*xMatz0+primal*x0zMat) + / ((primal*dual + + omega *(primal*(1.0-dual) + (1.0-primal)*dual))* x0z0 + + xMatzMat); + } + // rMessage("eta Primal = " << etaPrimal); + // rMessage("eta Dual = " << etaDual); +} + +// 2007/09/13 kazuhide nakata +// print information of ObjVal, residual, gap, complementarity +// b^T y + R \bullet X = value, norm(r), norm(Z) +// C \bullet X + r^T y = value, norm(R), norm(X) +// gap gap, mu * nDim +void SolveInfo::check(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + Parameter& param) +{ + rMessage("This function is not implemented in SDPA-C"); + #if 0 + double tmp,tmp1p,tmp1d,tmp2p,tmp2d,tmp3p,tmp3d,tmp4,tmp5p,tmp5d; + + Lal::let(tmp,'=',inputData.b,'.',currentPt.yVec); + tmp1p = - tmp; + printf("Primal: %9.1e",tmp1p); + Lal::let(tmp,'=',currentRes.dualMat,'.',currentPt.xMat); + tmp2p = -tmp; + printf(" + %9.1e",tmp2p); + tmp3p = tmp1p + tmp2p; + printf(" = %9.1e",tmp3p); + printf(", residual:%-9.1e",currentRes.normDualMat); + tmp5p = currentRes.computeMaxNorm(currentPt.zMat); + printf(" norm:%-9.1e\n",tmp5p); + + Lal::let(tmp,'=',inputData.C,'.',currentPt.xMat); + tmp1d = - tmp; + printf("Dual: %9.1e",tmp1d); + Lal::let(tmp,'=',currentRes.primalVec,'.',currentPt.yVec); + tmp2d = -tmp; + printf(" + %9.1e",tmp2d); + tmp3d = tmp1d + tmp2d; + printf(" = %9.1e",tmp3d); + printf(", residual:%-9.1e", currentRes.normPrimalVec); + tmp5d = currentRes.computeMaxNorm(currentPt.xMat); + printf(" norm:%-9.1e\n",tmp5d); + + tmp4 = tmp1p - tmp1d; + printf("P-D: %9.1e",tmp4); + tmp4 = tmp3p - tmp3d; + printf(" %9.1e",tmp4); + tmp4 = mu.current * currentPt.nDim; + printf(", mu * n:%-9.1e\n",tmp4); + + #endif +} + + +void SolveInfo::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + + fprintf(fpout,"rSolveInfo.rho = %8.3e\n",rho); + fprintf(fpout,"rSolveInfo.etaPrimal = %8.3e\n",etaPrimal); + fprintf(fpout,"rSolveInfo.etaDual = %8.3e\n",etaDual); + fprintf(fpout,"rSolveInfo.objValPrimal = %8.3e\n",objValPrimal); + fprintf(fpout,"rSolveInfo.objValDual = %8.3e\n",objValDual); +} + +// ---------------------------------------------------- + +Phase::Phase() +{ + nDim = 0; + value = SolveInfo::noINFO; +} + +Phase::~Phase() +{ + // Nothing needs. +} + +bool Phase::initialize(Residuals& currentRes, + SolveInfo& solveInfo, + Parameter& param, int nDim) +{ + this->nDim = nDim; + return updateCheck(currentRes, solveInfo, param); +} + +bool Phase::updateCheck(Residuals& currentRes, + SolveInfo& solveInfo, + Parameter& param) +{ + const double NONZERO = 1.0e-6; + double accuracy = param.epsilonDash; + value = SolveInfo::noINFO; + + if (currentRes.normPrimal <= accuracy) { + if (currentRes.normDual <= accuracy) { + value = SolveInfo::pdFEAS; + } else { + value = SolveInfo::pFEAS; + } + } + if (value==SolveInfo::noINFO + && currentRes.normDual <= accuracy) { + value = SolveInfo::dFEAS; + } + if (value==SolveInfo::pdFEAS) { + double mean = (fabs(solveInfo.objValPrimal)+ + fabs(solveInfo.objValDual)) / 2.0; + double PDgap = fabs(solveInfo.objValPrimal - solveInfo.objValDual); + + double dominator; + if (mean < 1.0) { + dominator = 1.0; + } else { + dominator = mean; + } + #if 0 + rMessage("PDgap = " << PDgap); + rMessage("dominator = " << dominator); + rMessage("PDgap/dominator = " << PDgap/dominator); + #endif + if (PDgap/dominator <= param.epsilonStar) { + value = SolveInfo::pdOPT; + return false; + } + } + if (value == SolveInfo::noINFO + && solveInfo.rho > 1.0+NONZERO) { + rMessage("pdINF criteria"); + value = SolveInfo::pdINF; + return false; + } + if (value == SolveInfo::pFEAS) { + #if REVERSE_PRIMAL_DUAL + if (solveInfo.objValPrimal<=-param.upperBound) { + rMessage("pUNBD criteria"); + value = SolveInfo::pUNBD; + return false; + } + #else + if (solveInfo.objValPrimal<=param.lowerBound) { + rMessage("pdINF criteria"); + value = SolveInfo::pUNBD; + return false; + } + #endif + if (solveInfo.rho > 1.0+NONZERO) { + rMessage("pFEAS_dINF criteria"); + value = SolveInfo::pFEAS_dINF; + return false; + } + } + + if (value == SolveInfo::dFEAS) { + #if REVERSE_PRIMAL_DUAL + if (solveInfo.objValDual>=-param.lowerBound) { + rMessage("dUNBD criteria"); + value = SolveInfo::dUNBD; + return false; + } + #else + if (solveInfo.objValDual>=param.upperBound) { + rMessage("dUNBD criteria"); + value = SolveInfo::dUNBD; + return false; + } + #endif + if (solveInfo.rho > 1.0+NONZERO) { + rMessage("pINF_dFEAD criteria"); + value = SolveInfo::pINF_dFEAS; + return false; + } + } + #if 0 + rMessage("phase ="); + display(); + #endif + return true; +} + +void Phase::reverse() +{ + #if REVERSE_PRIMAL_DUAL + switch (value) { + case SolveInfo::noINFO : ; break; + case SolveInfo::pFEAS : value = SolveInfo::dFEAS ; break; + case SolveInfo::dFEAS : value = SolveInfo::pFEAS ; break; + case SolveInfo::pdFEAS : ; break; + case SolveInfo::pdINF : ; break; + case SolveInfo::pFEAS_dINF: value = SolveInfo::pINF_dFEAS; break; + case SolveInfo::pINF_dFEAS: value = SolveInfo::pFEAS_dINF; break; + case SolveInfo::pdOPT : ; break; + case SolveInfo::pUNBD : value = SolveInfo::dUNBD ; break; + case SolveInfo::dUNBD : value = SolveInfo::pUNBD ; break; + default: break; + } + #else + // do nothing + #endif +} + + +void Phase::display(FILE* fpout) +{ + if (fpout == NULL) { + return; + } + char* str; + switch (value) { + case SolveInfo::noINFO : str = (char *)"noINFO "; break; + case SolveInfo::pFEAS : str = (char *)"pFEAS "; break; + case SolveInfo::dFEAS : str = (char *)"dFEAS "; break; + case SolveInfo::pdFEAS : str = (char *)"pdFEAS "; break; + case SolveInfo::pdINF : str = (char *)"pdINF "; break; + case SolveInfo::pFEAS_dINF: str = (char *)"pFEAS_dINF"; break; + case SolveInfo::pINF_dFEAS: str = (char *)"pINF_dFEAS"; break; + case SolveInfo::pdOPT : str = (char *)"pdOPT "; break; + case SolveInfo::pUNBD : str = (char *)"pUNBD "; break; + case SolveInfo::dUNBD : str = (char *)"dUNBD "; break; + default: + str = (char *)"phase error"; + rMessage("rPhase:: phase error"); + break; + } + fprintf(fpout,"phase.value = %s\n",str); +} + +} // end of namespace 'sdpa' + diff --git a/external/sdpa/sdpa_parts.h b/external/sdpa/sdpa_parts.h new file mode 100644 index 0000000..6bd91f8 --- /dev/null +++ b/external/sdpa/sdpa_parts.h @@ -0,0 +1,269 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#ifndef __sdpa_parts_h__ +#define __sdpa_parts_h__ + +#include "sdpa_include.h" +#include "sdpa_dataset.h" + +namespace sdpa { + +class Newton; + +class Solutions; +class InputData; +class Residuals; + +class ComputeTime; +class Parameter; +class StepLength; +class DirectionParameter; +class Switch; +class RatioInitResCurrentRes; +class SolveInfo; +class Phase; +class AverageComplementarity; + + +class ComputeTime +{ +public: + double Predictor; + double Corrector; + double StepPredictor; + double StepCorrector; + double xMatTime; + double zMatTime; + double invzMatTime; + double xMatzMatTime; + double EigxMatTime; + double EigzMatTime; + double EigxMatzMatTime; + double makerMat; + double makebMat; + double B_DIAG; + double B_F1; + double B_F2; + double B_F3; + double B_PRE; + double makebMatgVec; + double choleskybMat; + double solve; + double sumDz; + double makedX; + double symmetriseDx; + double makedXdZ; + double updateRes; + double MainLoop; + double FileRead; + double FileCheck; + double FileChange; + double TotalTime; + ComputeTime(); + ~ComputeTime(); + void display(FILE* fpout=stdout); +}; + +class Parameter +{ +public: + enum parameterType {PARAMETER_DEFAULT, + PARAMETER_UNSTABLE_BUT_FAST, + PARAMETER_STABLE_BUT_SLOW}; + int maxIteration; + double epsilonStar; + double lambdaStar; + double omegaStar; + double lowerBound; + double upperBound; + double betaStar; + double betaBar; + double gammaStar; + double epsilonDash; + #define PRINT_DEFAULT_LENGTH 30 + static char xPRINT_DEFAULT[PRINT_DEFAULT_LENGTH]; + static char XPRINT_DEFAULT[PRINT_DEFAULT_LENGTH]; + static char YPRINT_DEFAULT[PRINT_DEFAULT_LENGTH]; + static char infPRINT_DEFAULT[PRINT_DEFAULT_LENGTH]; + char xPrint[PRINT_DEFAULT_LENGTH]; + char XPrint[PRINT_DEFAULT_LENGTH]; + char YPrint[PRINT_DEFAULT_LENGTH]; + char infPrint[PRINT_DEFAULT_LENGTH]; + Parameter(); + Parameter(FILE* parameterFile); + ~Parameter(); + void setDefaultParameter(parameterType type + = PARAMETER_DEFAULT); + void readFile(FILE* parameterFile); + void display(FILE* fpout=stdout, char* printFormat=infPRINT_DEFAULT); +}; + +class StepLength +{ +public: + + double primal; + double dual; + StepLength(); + StepLength(double alphaP, double alphaD, int nBlock, + int* blockStruct); + ~StepLength(); + void initialize(double alphaP, double alphaD); + void finalize(); + + static double minBlockVector(BlockVector& aVec); + + void computeStepLength(Solutions& currentPt, + ComputeTime& com); + void MehrotraPredictor(InputData& inputData, + Solutions& currentPt, + Phase& phase, + Switch& reduction, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + Parameter& param, + ComputeTime& com); + void Centering(Solutions& currentPt, + Parameter& param, + ComputeTime& com); + void display(FILE* fpout = stdout); +}; + +class DirectionParameter +{ +public: + double value; + DirectionParameter(double betaStar=0.0); + ~DirectionParameter(); + void initialize(double betaStar=0.0); + + void Predictor(Phase& phase, Switch& reduction, + Parameter& param); + void Centering(); + void MehrotraCorrector(Phase& phase, StepLength& alpha, + Solutions& currentPt, + AverageComplementarity& mu, + Parameter& param); + void display(FILE* fpout = stdout); +}; + +class Switch +{ +public: + enum SwitchType {CENTERING,AFFINE}; // {ON,OFF} + SwitchType switchType; + + Switch(SwitchType switchType=CENTERING); + ~Switch(); + void initialize(SwitchType switchType=CENTERING); + + void MehrotraPredictor(Phase& phase); + void display(FILE* fpout = stdout); + +}; + +class AverageComplementarity +{ +public: + double initial; + double current; + AverageComplementarity(double lambdaStar = 0.0); + ~AverageComplementarity(); + void initialize(double lambdaStar = 0.0); + void update(Solutions& currentPt); + void display(FILE* fpout = stdout); +}; + +class RatioInitResCurrentRes +{ +public: + double primal; + double dual; + + RatioInitResCurrentRes(); + ~RatioInitResCurrentRes(); + + void initialize(Parameter& param, Residuals& currentRes); + + void update(Switch& reduction, StepLength& alpha); + void update_exact(Residuals& currentRes, Parameter& param); + void display(FILE* fpout = stdout); +}; + +class SolveInfo +{ +public: + enum phaseType { noINFO,pFEAS,dFEAS,pdFEAS,pdINF,pFEAS_dINF, + pINF_dFEAS,pdOPT,pUNBD,dUNBD}; + + double rho; + double etaPrimal; + double etaDual; + double objValPrimal; + double objValDual; + + SolveInfo(); + SolveInfo(InputData& inputData, Solutions& currentPt, + double mu0, double omegaStar); + ~SolveInfo(); + + void initialize(InputData& inputData, Solutions& currentPt, + double mu0, double omegaStar); + + void update(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + Parameter& param); + // check mu, gap, feasibility 2007/09/13 + void check(InputData& inputData, + Solutions& currentPt, + Residuals& currentRes, + AverageComplementarity& mu, + RatioInitResCurrentRes& theta, + Parameter& param); + void display(FILE* fpout = stdout); +}; + +class Phase +{ +public: + int nDim; + SolveInfo::phaseType value; + + Phase(); + ~Phase(); + + bool initialize(Residuals& currentRes, + SolveInfo& solveInfo, + Parameter& param, int nDim); + bool updateCheck(Residuals& currentRes, + SolveInfo& solveInfo, + Parameter& param); + void reverse(); + void display(FILE* fpout = stdout); +}; + +} // end of namespace 'sdpa' + +#endif // __sdpa_parts_h__ diff --git a/external/sdpa/sdpa_right.h b/external/sdpa/sdpa_right.h new file mode 100644 index 0000000..bf1ccd0 --- /dev/null +++ b/external/sdpa/sdpa_right.h @@ -0,0 +1,45 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*-------------------------------------------------- + sdpa_right.h +--------------------------------------------------*/ + +#ifndef __sdpa_right_h__ +#define __sdpa_right_h__ + +/*------------------------------------------ + Version Code Name + + SDPA 6 : Rosemary/2003Aug + SDPA 7 : Margaret/2008Feb + +------------------------------------------*/ + +static const char sdpa_right[] = + "SDPA7 (Margaret/since 2008Feb) has been developed by SDPA Project."; +#ifdef VERSION +// VERSION is set by configure script +static const char sdpa_version[] = VERSION; +#else +// static const char sdpa_version[] = "7"; +#endif + +#endif // __sdpa_right_h__ diff --git a/external/sdpa/sdpa_solve.cpp b/external/sdpa/sdpa_solve.cpp new file mode 100644 index 0000000..a9c9ce8 --- /dev/null +++ b/external/sdpa/sdpa_solve.cpp @@ -0,0 +1,259 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*-------------------------------------------------- + sdpa_solve.cpp +--------------------------------------------------*/ + +#include "sdpa_call.h" +#include "sdpa_linear.h" +#include "sdpa_io.h" +using namespace sdpa; + +void SDPA::initializeSolve() +{ + TimeStart(FILE_CHANGE_START1); + TimeEnd(FILE_CHANGE_END1); + com.FileChange += TimeCal(FILE_CHANGE_START1, + FILE_CHANGE_END1); + com.TotalTime += TimeCal(FILE_CHANGE_START1, + FILE_CHANGE_END1); + inputData.initialize_index(); + // rMessage("inputData = "); inputData.display(); + currentPt.initialize(m, bs); + currentPt.makeCliques(bs, inputData); + // rMessage("order = "); currentPt.order.display(); + currentPt.order.displayStatistics(Display, currentPt.cholmodSpace); + currentPt.order.displayStatistics(fpout, currentPt.cholmodSpace); + currentPt.setInitialPoint(bs, param.lambdaStar); + inputData.assignAgg(currentPt.cholmodSpace); + inputData.assignBlockIndex(currentPt.order); + currentPt.cholmodSpace.assignBlockIndex(currentPt.order); + // rMessage("currentPt.initial = "); currentPt.display(); + newton.initialize(m,bs); + int nBlock2 = bs.SDP_nBlock + bs.LP_nBlock; + chordal.initialize(&newton.sparse_bMat); + chordal.ordering_bMat(m, nBlock2, inputData, Display, fpout); + newton.initialize_bMat(m, chordal, inputData, Display, fpout); + + mu.initialize(param.lambdaStar); + TimeStart(UPDATE_START); + currentPt.cholmodSpace.computeResiduals(inputData, currentPt.order); + TimeEnd(UPDATE_END); + com.updateRes += TimeCal(UPDATE_START,UPDATE_END); + // currentPt.cholmodSpace.display(); + // inputData.display(); + currentRes.initialize(); + currentRes.update(currentPt.cholmodSpace); + currentRes.copyToInit(); + // rMessage("currentRes = "); currentRes.display(); + beta.initialize(param.betaStar); + theta.initialize(param, currentRes); + solveInfo.initialize(inputData, currentPt, mu.initial, + param.omegaStar); + phase.initialize(currentRes, solveInfo, param, currentPt.nDim); + // writeInputSparse((char*)"tmp.dat-s",(char*)"%+8.3e"); +} + +void SDPA::solve() +{ + pIteration = 0; + TimeStart(MAIN_LOOP_START1); + IO::printHeader(fpout,Display); + while (phase.updateCheck(currentRes, solveInfo, param) + && pIteration < param.maxIteration) { + // Mehrotra's Predictor + TimeEnd(THIS_ITERATION_TIME); + #if 0 + rMessage("++ " << pIteration << " turn ++ with " + << TimeCal(MAIN_LOOP_START1, THIS_ITERATION_TIME) + << " seconds in main loop"); + #endif + + TimeStart(MEHROTRA_PREDICTOR_START1); + // set variable of Mehrotra + reduction.MehrotraPredictor(phase); + beta.Predictor(phase, reduction, param); + // rMessage("reduction = "); reduction.display(); + // rMessage("phase = "); phase.display(); + // rMessage("beta.predictor.value = " << beta.value); + // rMessage(" mu = " << mu.current); + // rMessage("currentPt = "); currentPt.display(); + // rMessage("currentRes = "); currentRes.display(); + // inputData.display(); + + bool isSuccessCholesky; + isSuccessCholesky = newton.Mehrotra(Newton::PREDICTOR, + m, inputData, chordal, + currentPt, currentRes, + mu, beta, reduction, + phase, com, + Display, fpout); + if (isSuccessCholesky == false) { + break; + } + #if 0 + newton.checkDirection(m, inputData, currentPt, currentRes, + mu, beta, reduction, phase, com, Display, fpout); + #endif + // rMessage("order = "); currentPt.order.display(); + // rMessage("currentPt.cholmodSpace = "); currentPt.cholmodSpace.display(); + + TimeEnd(MEHROTRA_PREDICTOR_END1); + com.Predictor += TimeCal(MEHROTRA_PREDICTOR_START1, + MEHROTRA_PREDICTOR_END1); + + TimeStart(STEP_PRE_START1); + + alpha.MehrotraPredictor(inputData, currentPt, phase, reduction, + mu, theta, param, com); + // rMessage("alpha predictor = "); alpha.display(); + + TimeStart(STEP_PRE_END1); + com.StepPredictor += TimeCal(STEP_PRE_START1,STEP_PRE_END1); + + // rMessage("alphaStar = " << param.alphaStar); + IO::printOneIteration(pIteration, mu, theta, solveInfo, + alpha, beta, fpout, Display); + + if (currentPt.update(alpha,com)==false) { + // if step length is too short, + // we finish algorithm + rMessage("cannot move"); + pIteration++; + break; + } + // rMessage("currentPt = "); + // currentPt.display(); + + // rMessage("updated"); + const double old_mu = mu.current; + theta.update(reduction,alpha); + // rMessage("theta = "); theta.display(); + // rMessage("Before mu update"); + mu.update(currentPt); + // rMessage("mu = "); mu.display(); + currentPt.cholmodSpace.computeResiduals(inputData, currentPt.order); + currentRes.update(currentPt.cholmodSpace); + // rMessage("currentPt = "); currentPt.display(); + theta.update_exact(currentRes, param); + // rMessage("theta.exact = "); theta.display(); + solveInfo.update(inputData, currentPt, currentRes, mu, theta, param); + + // printDimacsEasy(); + pIteration++; + // rMessage("currentPt = "); currentPt.display(); + // rMessage("No Centering"); continue; + // Centering + if ((alpha.primal < 0.3) + ||(alpha.dual < 0.3) + ||((phase.value == SolveInfo::pdFEAS) + &&(old_mu * 0.5 < mu.current))) { + + TimeStart(CORRECTOR_START1); + reduction.MehrotraPredictor(phase); + #if 1 + beta.Centering(); + #else + beta.MehrotraCorrector(phase, alpha, currentPt, mu, param); + rMessage("beta = "); beta.display(); + #endif + isSuccessCholesky = newton.Mehrotra(Newton::PREDICTOR, + m, inputData, chordal, + currentPt, currentRes, + mu, beta, reduction, + phase, com, + Display, fpout); + if (isSuccessCholesky == false) { + break; + } + TimeEnd(CORRECTOR_END1); + com.Corrector += TimeCal(CORRECTOR_START1, CORRECTOR_END1); + TimeStart(CORRECTOR_STEP_START1); + #if 0 + newton.checkDirection(m, inputData, currentPt, currentRes, + mu, beta, reduction, phase, com, Display, fpout); + #endif + alpha.Centering(currentPt, param, com); + TimeEnd(CORRECTOR_STEP_END1); + com.StepCorrector += TimeCal(CORRECTOR_STEP_START1, + CORRECTOR_STEP_END1); + + IO::printOneIteration(pIteration, mu, theta, solveInfo, + alpha, beta, fpout, Display); + + if (currentPt.update(alpha,com)==false) { + // if step length is too short, + // we finish algorithm + rMessage("cannot move"); + pIteration++; + break; + } + + theta.update(reduction,alpha); + mu.update(currentPt); + currentPt.cholmodSpace.computeResiduals(inputData, currentPt.order); + currentRes.update(currentPt.cholmodSpace); + theta.update_exact(currentRes, param); + solveInfo.update(inputData, currentPt, currentRes, mu, theta, param); + // printDimacsEasy(); + pIteration++; + } + } // end of MAIN_LOOP + + if (pIteration == param.maxIteration) { + rMessage("maxIteration is reached"); + } + TimeEnd(MAIN_LOOP_END1); + + com.MainLoop = TimeCal(MAIN_LOOP_START1, + MAIN_LOOP_END1); + com.TotalTime += com.MainLoop; + currentRes.update(currentPt.cholmodSpace); +#if REVERSE_PRIMAL_DUAL + Lal::let(currentPt.cholmodSpace.yVec, + '=',currentPt.cholmodSpace.yVec,'*',&DMONE); + phase.reverse(); +#endif + IO::printLastInfo(pIteration, mu, theta, solveInfo, alpha, beta, + currentRes, phase, currentPt, + inputData, com.TotalTime, com, + param, fpout, Display); + bool Xmake = IO::judgeXmake(param); + bool Zmake = IO::judgeZmake(param); + currentPt.makeFinalSolution(Xmake, Zmake, bs); + IO::printSolution(bs, currentPt, param, fpout, Xmake, Zmake); + // com.display(fpout); + + if (Display) { + fprintf(Display, " main loop time = %.6f\n",com.MainLoop); + fprintf(Display, " total time = %.6f\n",com.TotalTime); + fprintf(Display, "file check time = %.6f\n",com.FileCheck); + fprintf(Display, "file change time = %.6f\n",com.FileChange); + fprintf(Display, "file read time = %.6f\n",com.FileRead); + } + if (fpout) { + fprintf(fpout, " main loop time = %.6f\n",com.MainLoop); + fprintf(fpout, " total time = %.6f\n",com.TotalTime); + fprintf(fpout, " file check time = %.6f\n",com.FileCheck); + fprintf(fpout, " file change time = %.6f\n",com.FileChange); + fprintf(fpout, " file read time = %.6f\n",com.FileRead); + } +} diff --git a/external/sdpa/sdpa_struct.cpp b/external/sdpa/sdpa_struct.cpp new file mode 100644 index 0000000..0e1d13f --- /dev/null +++ b/external/sdpa/sdpa_struct.cpp @@ -0,0 +1,3642 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ + +#include "sdpa_struct.h" +#include "sdpa_algebra.h" +#include "sdpa_linear.h" +#include "sdpa_dataset.h" + +#include + +namespace sdpa{ + +Vector::Vector() +{ + initialize(); +} + +Vector::Vector(int nDim, double value) +{ + initialize(); + initialize(nDim,value); +} + +Vector::~Vector() +{ + finalize(); +} + +void Vector::initialize() +{ + nDim = 0; + ele = NULL; +} + +void Vector::initialize(int nDim, double value) +{ + // rMessage("Vector initialize"); + if (nDim<=0) { + rError("Vector:: nDim is nonpositive"); + } + + if (this->nDim!=nDim && ele != NULL) { + DeleteArray(ele); + } + this->nDim = nDim; + if (ele == NULL) { + NewArray(ele,double,nDim); + } + sdpa_dset(nDim,value,ele,IONE); +} + +void Vector::initialize(double value) +{ + if (ele==NULL) { + NewArray(ele,double,nDim); + } + sdpa_dset(nDim,value,ele,IONE); +} + +void Vector::finalize() +{ + DeleteArray(ele); +} + +void Vector::setZero() +{ + initialize(0.0); +} + +void Vector::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (strcmp(printFormat,NO_P_FORMAT) == 0) { + fprintf(fpout,"%s\n",NO_P_FORMAT); + return; + } + fprintf(fpout,"{"); + for (int j=0; j0) { + fprintf(fpout,printFormat,ele[nDim-1]); + fprintf(fpout,"}\n"); + } else { + fprintf(fpout," }\n"); + } +} + +void Vector::display(FILE* fpout,double scalar, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (strcmp(printFormat,NO_P_FORMAT) == 0) { + fprintf(fpout,"%s\n",NO_P_FORMAT); + return; + } + fprintf(fpout,"{"); + for (int j=0; j0) { + fprintf(fpout,printFormat,ele[nDim-1]*scalar); + fprintf(fpout,"}\n"); + } else { + fprintf(fpout," }\n"); + } +} + +bool Vector::copyFrom(Vector& other) +{ + if (this == &other) { + return SDPA_SUCCESS; + } + if (other.nDim<=0) { + rError("Vector:: nDim is nonpositive"); + } + if (nDim != other.nDim) { + DeleteArray(ele); + } + nDim = other.nDim; + if (ele==NULL) { + NewArray(ele,double,nDim); + } + dcopy_fc(&nDim,other.ele,&IONE,ele,&IONE); + return SDPA_SUCCESS; +} + +BlockVector::BlockVector() +{ + nBlock = 0; + blockStruct = NULL; + ele = NULL; +} + +BlockVector::BlockVector(BlockStruct& bs, double value) +{ + initialize(bs.SDP_nBlock,bs.SDP_blockStruct,value); +} + +BlockVector::BlockVector(int nBlock, int* blockStruct, + double value) +{ + initialize(nBlock,blockStruct,value); +} + +BlockVector::~BlockVector() +{ + finalize(); +} + +void BlockVector::initialize(BlockStruct& bs, double value) +{ + initialize(bs.SDP_nBlock,bs.SDP_blockStruct,value); +} + +void BlockVector::initialize(int nBlock, int* blockStruct, + double value) +{ + // rMessage("BlockVector initialize"); + if (nBlock<=0) { + rError("BlockVector:: nBlock is nonpositive"); + } + this->nBlock = nBlock; + NewArray(this->blockStruct,int,nBlock); + for (int l=0; lblockStruct[l] = blockStruct[l]; + } + + NewArray(ele,Vector,nBlock); + for (int l=0; l0 && blockStruct && ele) { + for (int l=0; l=0) { + for (int l=0; l0 && blockStruct && ele) { + for (int l=0; l0 && blockStruct && ele) { + for (int l=0; lnRow = nRow; + this->nCol = nCol; + this->type = type; + this->DataStruct = DataStruct; + + int length; + switch(type) { + case SPARSE: + this->NonZeroNumber = NonZeroNumber; + this->NonZeroCount = 0; + this->NonZeroEffect = 0; + if (NonZeroNumber > 0) { + if (DataStruct == DSarrays) { + NewArray(row_index,int,NonZeroNumber); + NewArray(column_index,int,NonZeroNumber); + NewArray(sp_ele,double,NonZeroNumber); + if (row_index==NULL || column_index==NULL + || sp_ele==NULL) { + rError("SparseMatrix:: memory exhausted"); + } + } + else { + NewArray(DataS, SparseElement, NonZeroNumber); + if (DataS == NULL) { + rError("SparseElement:: memory exhausted"); + } + } + } + break; + case DENSE: + this->NonZeroNumber = nRow*nCol; + this->NonZeroCount = nRow*nCol; + this->NonZeroEffect = nRow*nCol; + NewArray(de_ele,double,NonZeroNumber); + if (de_ele==NULL) { + rError("SparseMatrix:: memory exhausted"); + } + length = nRow*nCol; + sdpa_dset(length,DZERO,de_ele,IONE); + // all elements are 0. + break; + } +} + +void SparseMatrix::finalize() +{ + DeleteArray(de_ele); + if (DataStruct == DSarrays) { + DeleteArray(row_index); + DeleteArray(column_index); + DeleteArray(sp_ele); + } + else { + DeleteArray(DataS); + } +} + +void SparseMatrix::display(FILE* fpout, char* printFormat) +{ + int i, j; + double value; + if (fpout == NULL) { + return; + } + if (strcmp(printFormat,NO_P_FORMAT) == 0) { + fprintf(fpout,"%s\n",NO_P_FORMAT); + return; + } + switch(type) { + case SPARSE: + fprintf(fpout,"{"); + for (int index=0; index1) { + fprintf(fpout," {"); + } + for (int j=0; j1) { + fprintf(fpout," }\n"); + } else { + fprintf(fpout,"\n"); + } + break; + } +} + +bool SparseMatrix::copyFrom(SparseMatrix& other) +{ + if (type != other.type || nRow != other.nRow + || nCol != other.nCol) { + this->~SparseMatrix(); + initialize(other.nRow,other.nCol,other.type, + NonZeroNumber); + NonZeroCount = other.NonZeroCount; + NonZeroEffect = other.NonZeroEffect; + int length; + switch(type) { + case SPARSE: + for (int index = 0; index NonZeroNumber) { + rError("SparseMatrix:: cannot store over NonZeroNumber"); + // the number of Diagonal elements equals nCol. + } + NonZeroCount = nCol; + NonZeroEffect = nCol; + for (int index=0; index< NonZeroCount; ++index) { + #if DATA_CAPSULE + DataS[index].vRow = index; + DataS[index].vCol = index; + DataS[index].vEle = scalar; + #else + row_index[index] = index; + column_index[index] = index; + sp_ele[index] = scalar; + #endif + } + break; + case DENSE: + length = nRow*nCol; + sdpa_dset(length,DZERO,de_ele,IONE); + step = nCol+1; + sdpa_dset(nCol,scalar,de_ele,step); + // only diagonal elements are set the value of scalar. + break; + } +} + +bool SparseMatrix::sortSparseIndex(int& i, int& j) +{ + // if this matrix is not symmetric, + // return the index(i,j) whose values are not symmetric. + i = -1; + j = -1; + const double tolerance = 1.0e-8; + switch(type) { + case SPARSE: + // Make matrix as Upper Triangluar + for (int i1=0; i1tmpj) { + DataS[i1].vRow = tmpj; + DataS[i1].vCol = tmpi; + } +#else + int tmpi = row_index[i1]; + int tmpj = column_index[i1]; + if (tmpi>tmpj) { + row_index [i1] = tmpj; + column_index[i1] = tmpi; + } +#endif + } + // simple sort + for (int i1=0; i1 tolerance) { + // Here must not be symmetric + if (i<0 || j<0) { + i = DataS[i1].vRow; + j = DataS[i1].vCol; + } + } + // remove redudunt + for (int i2 = i1+1; i2 tolerance) { + // Here must not be symmetric + if (i<0 || j<0) { + i = row_index [i1]; + j = column_index[i1]; + } + } + // remove redudunt + for (int i2 = i1+1; i2 tolerance) { + return SDPA_FAILURE; + } + } + } + break; + } + return SDPA_SUCCESS; +} + +DenseMatrix::DenseMatrix() +{ + initialize(); +} + +void DenseMatrix::initialize() +{ + nRow = 0; + nCol = 0; + de_ele = NULL; +} + +DenseMatrix::~DenseMatrix() +{ + finalize(); +} + +void DenseMatrix::initialize(int nRow, int nCol) +{ + // rMessage("DenseMatrix::initialize"); + + DenseMatrix(); + if (nRow<=0 || nCol<=0) { + rError("DenseMatrix:: Dimensions are nonpositive"); + } + int old_length = this->nRow*this->nCol; + this->nRow = nRow; + this->nCol = nCol; + + int length; + length = nRow*nCol; + if (de_ele != NULL && old_length!=length) { + DeleteArray(de_ele); + } + if (de_ele==NULL) { + NewArray(de_ele,double,length); + } + sdpa_dset(length,DZERO,de_ele,IONE); +} + +void DenseMatrix::finalize() +{ + DeleteArray(de_ele); +} + +void DenseMatrix::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout,"{"); + for (int i=0; i1) { + fprintf(fpout," {"); + } + for (int j=0; j1) { + fprintf(fpout," }\n"); + } else { + fprintf(fpout,"\n"); + } +} + +bool DenseMatrix::copyFrom(SparseMatrix& other) +{ + int length; + switch(other.type) { + case SparseMatrix::SPARSE: + DeleteArray(de_ele); + nRow = other.nRow; + nCol = other.nCol; + NewArray(de_ele,double,nRow*nCol); + length = nRow*nCol; + sdpa_dset(length,DZERO,de_ele,IONE); + for (int index = 0; index 0){ + SDP_sp_nBlock++; + } + } + if (SDP_sp_nBlock > 0){ + NewArray(SDP_sp_index,int,SDP_sp_nBlock); + NewArray(SDP_sp_block,SparseMatrix,SDP_sp_nBlock); + } + counter = 0; + for (int l=0; l 0){ + SDP_sp_index[counter] = l; + int size = SDP_blockStruct[l]; + SDP_sp_block[counter].initialize(size,size,SparseMatrix::SPARSE, + SDP_NonZeroNumber[l]); + counter++; + } + } + + + // for SOCP +#if 0 + for (int l=0; l 0){ + SOCP_sp_nBlock++; + } + } + if (SOCP_sp_nBlock > 0){ + NewArray(SOCP_sp_index,int,SOCP_sp_nBLock); + NewArray(SOCP_sp_block,SparseMatrix,SOCP_sp_nBLock); + } + counter = 0; + for (int l=0; l 0){ + SOCP_sp_index[counter] = l; + int size = SOCP_blockStruct[l]; + SOCP_sp_block[counter].initialize(size,size,SparseMatrix::SPARSE, + SOCP_NonZeroNumber[l]); + counter++; + } + } +#endif + + // for LP + for (int l=0; l 0){ + NewArray(LP_sp_index,int,LP_sp_nBlock); + NewArray(LP_sp_block,double,LP_sp_nBlock); + } + counter = 0; + for (int l=0; lSDP_sp_nBlock = SDP_sp_nBlock; + if (SDP_sp_nBlock > 0){ + NewArray(this->SDP_sp_index,int,SDP_sp_nBlock); + NewArray(this->SDP_sp_block,SparseMatrix,SDP_sp_nBlock); + } + for (int l=0; lSDP_sp_index[l] = SDP_sp_index[l]; + int size = SDP_sp_blockStruct[l]; + SDP_sp_block[l].initialize(size,size,SparseMatrix::SPARSE, + SDP_sp_NonZeroNumber[l]); + } + + // for SOCP +#if 0 + this->SOCP_sp_nBlock = SOCP_sp_nBlock; + if (SOCP_sp_nBlock > 0){ + NewArray(this->SOCP_sp_index,int,SOCP_sp_nBlock); + NewArray(this->SOCP_sp_block,SparseMatrix,SOCP_sp_nBlock); + } + for (int l=0; lSOCP_sp_index[l] = SOCP_sp_index[l]; + int size = SOCP_sp_blockStruct[l]; + SOCP_sp_block[l].initialize(size,size,SparseMatrix::SPARSE, + SOCP_sp_NonZeroNumber[l]); + } +#endif + + // for LP + this->LP_sp_nBlock = LP_sp_nBlock; + if (LP_sp_nBlock > 0){ + NewArray(this->LP_sp_index,int,LP_sp_nBlock); + NewArray(this->LP_sp_block,double,LP_sp_nBlock); + } + for (int l=0; lLP_sp_index[l] = LP_sp_index[l]; + } +} + +void SparseLinearSpace::finalize() +{ + // for SDP + if (SDP_sp_block && SDP_sp_index && SDP_sp_nBlock>=0) { + for (int l=0; l=0) { + for (int l=0; l=0) { + DeleteArray(LP_sp_block); + DeleteArray(LP_sp_index); + } +} + +void SparseLinearSpace::changeToDense(bool forceChange) +{ + if (SDP_sp_nBlock>0 && SDP_sp_index && SDP_sp_block) { + for (int l=0; l0 && SOCP_sp_index && SOCP_sp_block) { + for (int l=0; l0 && SDP_sp_index && SDP_sp_block) { + fprintf(fpout,"SDP part{\n"); + for (int l=0; l0 && SOCP_sp_index && SOCP_sp_block) { + fprintf(fpout,"SOCP part{\n"); + for (int l=0; l0 && LP_sp_index && LP_sp_block) { + fprintf(fpout,"LP part{\n"); + for (int l=0; l 0 && SDP_sp_index==NULL ) { + NewArray(SDP_sp_index,int,SDP_sp_nBlock); + for (int l=0; l 0 && SDP_sp_block==NULL ) { + NewArray(SDP_sp_block,SparseMatrix,SDP_sp_nBlock); + } + total_judge = SDPA_SUCCESS; + for (int l=0; l 0 && SOCP_sp_index==NULL) { + NewArray(SOCP_sp_index,int,SOCP_sp_nBlock); + for (int l=0; l 0 && SOCP_sp_block==NULL) { + NewArray(SOCP_sp_block,SparseMatrix,SOCP_sp_nBlock); + } + total_judge = SDPA_SUCCESS; + for (int l=0; l 0 && LP_sp_index==NULL) { + NewArray(LP_sp_index,int,LP_sp_nBlock); + for (int l=0; l 0 && LP_sp_block==NULL) { + NewArray(LP_sp_block,double,LP_sp_nBlock); + } + total_judge = SDPA_SUCCESS; + for (int l=0; l= SDP_sp_block[l].NonZeroNumber){ + rError("SparseLinearSpace::setElement NonZeroCount >= NonZeroNumber"); + } + if ((i >= SDP_sp_block[l].nRow) || (j >= SDP_sp_block[l].nCol)){ + rError("out of range in input data"); + } + + // set element + int count = SDP_sp_block[l].NonZeroCount; + #if DATA_CAPSULE + SDP_sp_block[l].DataS[count].vRow = i; + SDP_sp_block[l].DataS[count].vCol = j; + SDP_sp_block[l].DataS[count].vEle = ele; + #else + SDP_sp_block[l].row_index[count] = i; + SDP_sp_block[l].column_index[count] = j; + SDP_sp_block[l].sp_ele[count] = ele; + #endif + SDP_sp_block[l].NonZeroCount++; + if (i==j){ + SDP_sp_block[l].NonZeroEffect++; + } else { + SDP_sp_block[l].NonZeroEffect += 2; + } + +} + +void SparseLinearSpace::setElement_SOCP(int block, int i, int j, + double ele) +{ + rError("DenseLinearSpace:: current version does not support SOCP"); +} + +void SparseLinearSpace::setElement_LP(int block, double ele) +{ + int l; + + for (l=0; l0 && SDP_sp_index && SDP_sp_block) { + for (int l=0; l0 && SOCP_sp_index && SOCP_sp_block) { + for (int l=0; l0 && LP_sp_index && LP_sp_block) { + for (int l=0; l0 && SDP_sp_index && SDP_sp_block) { + for (int l=0; l0 && SOCP_sp_index && SOCP_sp_block) { + for (int l=0; l0 && LP_sp_index && LP_sp_block) { + for (int l=0; l0 && SDP_sp_index && SDP_sp_block) { + for (int l_in=0; l_in0 && SOCP_sp_index && SOCP_sp_block) { + for (int l_in=0; l_inSDP_nBlock = bs.SDP_nBlock; + this->LP_nBlock = bs.LP_nBlock; + SDP_block = NULL; + LP_block = NULL; + // rMessage("DenseLinearSpace::initialize"); + if (SDP_nBlock + LP_nBlock <= 0) { + rError("DenseLinearSpace:: SDP + LP Block is nonpositive"); + } + + // for SDP + if (SDP_nBlock<0) { + rError("DenseLinearSpace:: SDP_nBlock is negative"); + } + if (SDP_nBlock > 0) { + NewArray(SDP_block,DenseMatrix,SDP_nBlock); + } + for (int l=0; l0) { + SDP_block[l].initialize(size,size); + } else { + rError("DenseLinearSpace:: SDP size is nonpositive"); + } + } + + // for LP + if (LP_nBlock<0) { + rError("DenseLinearSpace:: LP_nBlock is negative"); + } + if (LP_nBlock > 0) { + NewArray(LP_block,double,LP_nBlock); + } + for (int l=0; l0) { + for (int l=0; l0) { + for (int l=0; l0) { + DeleteArray(LP_block); + } +} + +void DenseLinearSpace::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (strcmp(printFormat,NO_P_FORMAT) == 0) { + fprintf(fpout,"%s\n",NO_P_FORMAT); + return; + } + if (SDP_nBlock>0 && SDP_block) { + fprintf(fpout,"SDP part{\n"); + for (int l=0; l0 && SOCP_block) { + fprintf(fpout,"SOCP part{\n"); + for (int l=0; l0 && LP_block) { + fprintf(fpout,"LP part{\n"); + for (int l=0; l 0) { + fprintf(fpout,printFormat,LP_block[start+size-1]); + fprintf(fpout,"}\n"); + } else { + fprintf(fpout," }\n"); + } + } else { + rError("io::displayDenseLinearSpaceLast not valid blockType"); + } + } + fprintf(fpout,"}\n"); +} + +bool DenseLinearSpace::copyFrom(DenseLinearSpace& other) +{ + if (this == &other) { + return SDPA_SUCCESS; + } + + if (other.SDP_nBlock+other.LP_nBlock<=0) { + rError("DenseLinearSpace:: SDP + LP Block is nonpositive"); + } + bool total_judge = SDPA_SUCCESS; + + // for SDP + if (other.SDP_nBlock<0) { + rError("DenseLinearSpace:: SDP_nBlock is negative"); + } + if (SDP_nBlock!=other.SDP_nBlock) { + DeleteArray(SDP_block); + } + SDP_nBlock = other.SDP_nBlock; + if (SDP_nBlock > 0 && SDP_block == NULL) { + NewArray(SDP_block,DenseMatrix,SDP_nBlock); + } + for (int l=0; l 0) && (LP_block == NULL)) { + LP_block = new double[LP_nBlock]; + if (LP_block==NULL) { + rError("DenseLinearSpace:: memory exhausted"); + } + } + for (int l=0; l= SDP_nBlock){ + rError("out of range in input data"); + } + if ((i >= SDP_block[block].nRow) || (j >= SDP_block[block].nCol)){ + rError("out of range in input data"); + } + + int nCol = SDP_block[block].nCol; + SDP_block[block].de_ele[i + j * nCol] = ele; + SDP_block[block].de_ele[j + i * nCol] = ele; +} + +void DenseLinearSpace::setElement_SOCP(int block, int i, int j, + double ele) +{ + rError("DenseLinearSpace:: current version does not support SOCP"); +} + +void DenseLinearSpace::setElement_LP(int block, double ele) +{ + // check range + if (block >= LP_nBlock){ + rError("out of range in input data"); + } + LP_block[block] = ele; +} + +void DenseLinearSpace::setZero() +{ + // for SDP + if (SDP_nBlock>0 && SDP_block) { + for (int l=0; l0 && LP_block) { + for (int l=0; l0 && SDP_block) { + for (int l=0; l0 && LP_block) { + for (int l=0; lsize(); + for (int index = 0; index < size; ++index) { + DeleteArray(inputVector->at(index)); + } + } + DeleteArray(inputVector); + nRow = 0; + nCol = 0; + nzColumn = 0; + NNZ = 0; + lowerNNZ = 0; + nzColumn_diag = 0; + nzColumn_nondiag = 0; +} + +CompMatrix::~CompMatrix() +{ + finalize(); +} + +void CompMatrix::initializeInputVector() +{ + NewArray(inputVector,vector,1); +} + +void CompMatrix::setElement(int i, int j, double v) +{ + CompMatrix::inputIJV* ele; + NewArray(ele, inputIJV, 1); + ele[0].i = i; + ele[0].j = j; + ele[0].v = v; + inputVector->push_back(ele); + + // both upper and lower triangular are assigned + if (i!=j) { + CompMatrix::inputIJV* ele2; + NewArray(ele2, inputIJV, 1); + ele2[0].i = j; + ele2[0].j = i; + ele2[0].v = v; + inputVector->push_back(ele2); + } +} + +void CompMatrix::sortInputVector() +{ + const int size = inputVector->size(); + + // to make sort easier, (i,j) information is wrapped into (i) + for (int index = 0; index < size; ++index) { + CompMatrix::inputIJV* ele = inputVector->at(index); + ele->i = ele->i + (ele->j)*nRow; + } + sort(inputVector->begin(), inputVector->end(), + CompMatrix::compareIJV); + for (int index = 0; index < size; ++index) { + CompMatrix::inputIJV* ele = inputVector->at(index); + ele->i = ele->i - (ele->j)*nRow; + } +} + +bool CompMatrix::compareIJV(CompMatrix::inputIJV* a, + CompMatrix::inputIJV* b) +{ + // sort by [i + j*nRow] (now this value is inserted in i) + // that is, sort by column-wise + if (a->i < b-> i) { + return true; + } + else if (a->i > b-> i){ + return false; + } + return false; // a==b +} + +void CompMatrix::checkInputDataStructure(int& i, int& j, double& v1, double& v2) +{ + // if correct, minus numbers are assigned to (i,j) + // otherwise, the index of duplicate values are assigned to (i,j) + i = -100; + j = -100; + v1 = 0.0; + v2 = 0.0; + + const int size = inputVector->size(); + if (size == 0) { + return; + } + CompMatrix::inputIJV* ele = inputVector->at(0); + for (int index = 1; index < size; ++index) { + CompMatrix::inputIJV* eleNext = inputVector->at(index); + #if 0 + printf("ele[%d] => i=%d, j=%d, v=%lf\n", + index-1, ele->i, ele->j, ele->v); + printf("eleNext[%d] => i=%d, j=%d, v=%lf\n", + index, eleNext->i, eleNext->j, eleNext->v); + #endif + if (ele->i == eleNext->i && ele->j == eleNext->j) { + i = ele->i; + j = ele->j; + v1 = ele->v; + v2 = eleNext->v; + return; + } + ele = eleNext; + } +} + +void CompMatrix::makeInternalStructure() +{ + // this routine should be called after checkInputVector + + NNZ = inputVector->size(); + // rMessage("NNZ = " << NNZ); + nzColumn = 0; + int oldColumn = -1; + for (int index = 0; index < NNZ; ++index) { + CompMatrix::inputIJV* ele1 = inputVector->at(index); + const int currentColumn = ele1->j; + if (currentColumn != oldColumn) { + nzColumn++; + oldColumn = currentColumn; + } + } + NewArray(column_index, int, nzColumn); + NewArray(column_start, int, nzColumn+1); + NewArray(diag_index, int, nzColumn); + NewArray(row_index, int, NNZ); + NewArray(agg_index, int, NNZ); + NewArray(blockNumber, int, NNZ); + NewArray(blockIndex, int, NNZ); + NewArray(ele, double, NNZ); + + for (int index1=0; index1 < nzColumn; ++index1) { + diag_index[index1] = -1; // -1 means "not assiged" + } + for (int index1=0; index1 < NNZ; ++index1) { + agg_index[index1] = -1; // -1 means "not assiged" + } + + column_start[nzColumn] = NNZ; + oldColumn = -1; + lowerNNZ = 0; + int columnIndex = -1; // this should be -1 precisely + for (int index1=0; index1 < NNZ; ++index1) { + CompMatrix::inputIJV* ele1 = inputVector->at(index1); + #if 0 + rMessage("i = " << ele1->i << ": j = " << ele1->j + << ": value = " << ele1->v); + #endif + const int currentColumn = ele1->j; + if (currentColumn != oldColumn) { + columnIndex++; + column_index[columnIndex] = currentColumn; + column_start[columnIndex] = index1; + oldColumn = currentColumn; + } + if (diag_index[columnIndex] == -1 && ele1->i >= ele1->j) { + diag_index[columnIndex] = index1; + } + if (diag_index[columnIndex] >= 0) { + lowerNNZ++; + } + row_index[index1] = ele1->i; + ele[index1] = ele1->v; + DeleteArray(ele1); + } + DeleteArray(inputVector); + effectiveNzColumn = nzColumn; + for (int ncol = 0; ncol < nzColumn; ++ncol) { + if (diag_index[ncol] == -1) { // only upper part + effectiveNzColumn--; + } + } + + nzColumn_diag = 0; + nzColumn_nondiag = 0; + for (int ncol = 0; ncol < nzColumn; ++ncol) { + if (diag_index[ncol] == -1) { + continue; + } + const int j = column_index[ncol]; + if (row_index[diag_index[ncol]] == j) { + nzColumn_diag++; + } + else { + nzColumn_nondiag++; + } + } + NewArray(column_diag_index, int, nzColumn_diag); + NewArray(column_nondiag_index, int, nzColumn_nondiag); + + nzColumn_diag = 0; + nzColumn_nondiag = 0; + for (int ncol = 0; ncol < nzColumn; ++ncol) { + if (diag_index[ncol] == -1) { + continue; + } + const int j = column_index[ncol]; + if (row_index[diag_index[ncol]] == j) { + column_diag_index[nzColumn_diag] = ncol; + nzColumn_diag++; + } + else { + column_nondiag_index[nzColumn_nondiag] = ncol; + nzColumn_nondiag++; + } + } +} + +void CompMatrix::assignAgg(CholmodMatrix& cholmodMatrix) +{ + cholmod_sparse* Z = cholmodMatrix.Z; + // agg_index in Aggregate-matrix is already computed in indexAgg + for (int ncol = 0; ncol < nzColumn; ++ncol) { + const int j = column_index[ncol]; + if (diag_index[ncol] < 0) { + continue; + } + // column_index of aggregate should contain all columns + const int agg_start = ((int*)Z->p)[j]; + const int agg_end = ((int*)Z->p)[j+1]; + int index2 = agg_start; + // only lower elements will have valid agg_index + for (int index1 = diag_index[ncol]; + index1 < column_start[ncol+1]; ++index1) { + const int i = row_index[index1]; + // Next 'while' must find target, + // because Aggregate must contain this information + while (i != ((int*)Z->i)[index2]) { + index2++; + } + agg_index[index1] = index2; + } + } +} + +void CompMatrix::assignBlockIndex(OrderingMatrix& order) +{ + for (int j_index = 0; j_index < nzColumn; ++j_index) { + int j = column_index[j_index]; + const int row_start = column_start[j_index]; + const int row_end = column_start[j_index+1]; + for (int i_index = row_start; i_index < row_end; ++i_index) { + const int i = row_index[i_index]; + order.getIndex(i,j,blockNumber[i_index],blockIndex[i_index]); + } + } +} + + +CompSpace::CompSpace() +{ + initialize(); +} + +CompSpace::~CompSpace() +{ + finalize(); +} + +void CompSpace::initialize() +{ + LP_sp_nBlock = 0; + SDP_sp_nBlock = 0; + LP_sp_index = NULL; + SDP_sp_index = NULL; + LP_sp_block = NULL; + SDP_sp_block = NULL; + NNZ = 0; + lowerNNZ = 0; +} + +void CompSpace::initialize(int LP_sp_nBlock, + int SDP_sp_nBlock) +{ + initialize(); + this->LP_sp_nBlock = LP_sp_nBlock; + this->SDP_sp_nBlock = SDP_sp_nBlock; + if (LP_sp_nBlock > 0) { + NewArray(this->LP_sp_index, int, LP_sp_nBlock); + NewArray(this->LP_sp_block, double, LP_sp_nBlock); + } + if (SDP_sp_nBlock > 0) { + NewArray(this->SDP_sp_index, int, SDP_sp_nBlock); + NewArray(this->SDP_sp_block, CompMatrix, SDP_sp_nBlock); + } +} + +void CompSpace::finalize() +{ + for (int index = 0; index < SDP_sp_nBlock; ++index) { + SDP_sp_block[index].finalize(); + } + DeleteArray(LP_sp_index); + DeleteArray(SDP_sp_index); + DeleteArray(LP_sp_block); + DeleteArray(SDP_sp_block); + + LP_sp_nBlock = 0; + SDP_sp_nBlock = 0; +} + +void CompSpace::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + + // fprintf(fpout, "Display start \n"); + fprintf(fpout, "== LP block== LP_sp_nBlock = %d\n", LP_sp_nBlock); + for (int index1=0; index1 < LP_sp_nBlock; ++index1) { + fprintf(fpout, "[%d,%d] = ", LP_sp_index[index1], LP_sp_index[index1]); + fprintf(fpout, printFormat, LP_sp_block[index1]); + fprintf(fpout, "\n"); + } + fprintf(fpout, "==SDP block== SDP_sp_nBlock = %d\n", SDP_sp_nBlock); + for (int index1=0; index1 < SDP_sp_nBlock; ++index1) { + fprintf(fpout, "-- %d-th(%d-th in full) block --\n", + index1, SDP_sp_index[index1]); + SDP_sp_block[index1].display(fpout, printFormat); + } + // fprintf(fpout, "Display end \n"); +} + +void CompSpace::initializeInputVector() +{ + for (int index=0; index < SDP_sp_nBlock; ++index) { + SDP_sp_block[index].initializeInputVector(); + } +} + +void CompSpace::setElement_LP(int i, double v) +{ + int index = 0; + for (index=0; index < LP_sp_nBlock; ++index) { + if (i == LP_sp_index[index]) { + break; + } + } + if (index == LP_sp_nBlock) { + rError("Out of LP_sp_nBlock :: code bug"); + } + LP_sp_block[index] = v; +} + +void CompSpace::setElement_SDP(int l, int i, int j, double v) +{ + int index1 = 0; + for (index1=0; index1 < SDP_sp_nBlock; ++index1) { + if (l == SDP_sp_index[index1]) { + break; + } + } + if (index1 == SDP_sp_nBlock) { + rError("Out of SDP_sp_nBlock :: code bug"); + } + SDP_sp_block[index1].setElement(i,j,v); +} + +void CompSpace::sortInputVector() +{ + for (int l=0; l < SDP_sp_nBlock; ++l) { + SDP_sp_block[l].sortInputVector(); + } +} + +void CompSpace::makeInternalStructure() +{ + NNZ = LP_sp_nBlock; + lowerNNZ = LP_sp_nBlock; + for (int l=0; l < SDP_sp_nBlock; ++l) { + SDP_sp_block[l].makeInternalStructure(); + NNZ += SDP_sp_block[l].NNZ; + lowerNNZ += SDP_sp_block[l].lowerNNZ; + } +} + + +void CompSpace::checkInputDataStructure(int& l, int& i, int& j, + double& v1, double& v2) +{ + for (l=0; l=0) { + // found error + l = SDP_sp_index[l]; + return; + } + } + l = -100; // to indicate correctness, l is set to minus +} + +void CompSpace::assignAgg(CholmodSpace& Aggregate) +{ + for (int l=0; lnBlock = nBlock; + NewArray(this->blockStruct, int, nBlock); + NewArray(ele, DenseMatrix, nBlock); + for (int index1=0; index1 < nBlock; ++index1) { + this->blockStruct[index1] = blockStruct[index1]; + ele[index1].initialize(blockStruct[index1], blockStruct[index1]); + } +} + +void CliqueMatrix::finalize() +{ + if (nBlock > 0) { + DeleteArray(blockStruct); + for (int index = 0; index < nBlock; ++index) { + ele[index].finalize(); + } + DeleteArray(ele); + } +} + +void CliqueMatrix::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + + fprintf(fpout, "CliqueMatrix::display nBlock = %d\n", nBlock); + for (int index = 0; index < nBlock; ++index) { + fprintf(fpout, "%d-th block\n", index); + ele[index].display(fpout, printFormat); + } + fprintf(fpout, "CliqueMatrix::display end \n", nBlock); +} + +void CliqueMatrix::setZero() +{ + for (int index = 0; index < nBlock; ++index) { + ele[index].setZero(); + } +} + +void CliqueMatrix::setIdentity(double scalar) +{ + for (int index1 = 0; index1 < nBlock; ++index1) { + ele[index1].setIdentity(scalar); + } +} + + +CliqueSpace::CliqueSpace() +{ + initialize(); +} + +CliqueSpace::~CliqueSpace() +{ + finalize(); +} + +void CliqueSpace::initialize() +{ + LP_nBlock = 0; + SDP_nBlock = 0; + LP_block = NULL; + SDP_block = NULL; +} + +void CliqueSpace::initialize(BlockStruct& bs, + OrderingSpace& order) +{ + int LP_nBlock = bs.LP_nBlock; + int SDP_nBlock = bs.SDP_nBlock; + this->LP_nBlock = LP_nBlock; + this->SDP_nBlock = SDP_nBlock; + NewArray(LP_block, double, LP_nBlock); + NewArray(SDP_block, CliqueMatrix, SDP_nBlock); + for (int l=0; lSDP_block[l].initialize(orderMatrix.nClique, + orderMatrix.cliqueSize); + } +} + +void CliqueSpace::finalize() +{ + if (LP_nBlock > 0) { + DeleteArray(LP_block); + LP_nBlock = 0; + } + if (SDP_nBlock > 0) { + for (int index = 0; index < SDP_nBlock; ++index) { + SDP_block[index].finalize(); + } + DeleteArray(SDP_block); + SDP_nBlock = 0; + } +} + +void CliqueSpace::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + fprintf(fpout, "== LP Part, LP_nBlock = %d ==\n", LP_nBlock); + for (int index=0; index < LP_nBlock; ++index) { + fprintf(fpout, printFormat, LP_block[index]); + } + fprintf(fpout, "== SDP Part, SDP_nBlock = %d ==\n", SDP_nBlock); + for (int index=0; index < SDP_nBlock; ++index) { + SDP_block[index].display(fpout, printFormat); + } +} + +void CliqueSpace::setZero() +{ + for (int l=0; lnDim = nDim; +} + +void OrderingMatrix::finalize() +{ + if (nClique > 0) { + DeleteArray(cliqueSize); + for (int index1 = 0; index1Perm, do not delete Perm here + DeleteArray(ReversePerm); + + if (dXtNonzeros != NULL) { + for (int index1 = 0; index1 < nDim; ++index1) { + DeleteArray(dXtIndex[index1]); + DeleteArray(dXtClique[index1]); + DeleteArray(dXtBlock[index1]); + } + DeleteArray(dXtIndex); + DeleteArray(dXtClique); + DeleteArray(dXtBlock); + DeleteArray(dXtNonzeros); + } +} + +void OrderingMatrix::getIndex(int i, int j, int& blockNumber, int& blockIndex) +{ + // A(i,j) = APerm(iPerm,jPerm) + int iPerm = ReversePerm[i]; + int jPerm = ReversePerm[j]; + + // Find the clique which has both iPerm & jPerm + // If this fails, it means a bug. + + // Find iPerm & jPerm from the last clique to the first clique + // The last clique has more elements, so it should be + // accessed as many time as possible. + + // Lower-triangular, that is, iPerm >= jPerm + if (iPerm < jPerm) { + int tmpPerm = iPerm; + iPerm = jPerm; + jPerm = tmpPerm; + } + + int iIndex = -1; // dummy initialize + int jIndex = -1; // dummy initialize + int cIndex = nClique-1; + for ( /* nothing */ ; cIndex >=0 ; cIndex--) { + const int length = cliqueSize[cIndex]; + int index1 = 0; + // find jPerm + for (/* nothing */; index1 < length; ++ index1) { + if (cliqueIndex[cIndex][index1] == jPerm) { + break; + } + } + jIndex = index1; + for (/* nothing */; index1 < length; ++ index1) { + if (cliqueIndex[cIndex][index1] == iPerm) { + break; + } + } + iIndex = index1; + + if (jIndex < length && iIndex < length) { + // found both iPerm & jPerm + break; + } + } + + if (cIndex < 0) { + rMessage("Ordering display"); display(); + rMessage("i = " << i << " : j = " << j); + rError("Code bug here."); + } + blockNumber = cIndex; + blockIndex = iIndex + jIndex*cliqueSize[cIndex]; +} + +void OrderingMatrix::extractCliques(CholmodMatrix& C) +{ + if (nDim == 0) { + rError("OrderingMatrix is not initialized"); + } + cholmod_factor* L = C.Lz; + // L is already set by analyze(); + // This function will initialize the structure of OrderingMatrix + nClique = L->nsuper; + // rMessage("nClique = " << nClique); + NewArray(cliqueSize, int, nClique); + NewArray(cliqueIndex, int*, nClique); + int* super = (int*) (L->super); + for (int s = 0; s < nClique; ++s) { + int start_column = super[s]; + int end_column = super[s+1]; + const int psi = ((int*)L->pi)[s]; + const int psiend = ((int*)L->pi)[s+1]; + const int nsrow = psiend-psi; + cliqueSize[s] = nsrow; + #if 0 + rMessage("clique["<s)[psi+index_i]; + cliqueIndex[s][index_i] = i; + } + } + + Perm = (int*) L->Perm; + NewArray(ReversePerm, int, L->n); + for (size_t index1 = 0; index1 < L->n; ++index1) { + ReversePerm[Perm[index1]] = index1; + } + + vector* tmpVector; + NewArray(tmpVector, vector, nDim); + for (int s = 0; s < nClique; ++s) { + const int length = cliqueSize[s]; + for (int j_index = 0; j_index < length; ++j_index) { + const int j = Perm[cliqueIndex[s][j_index]]; + // since dX~tilde is not symmetric, + // we have to add both lower and upper triangular information + for (int i_index = 0; i_index < length; ++i_index) { + OrderingMatrix::ISB* tmpISB; + NewArray(tmpISB, OrderingMatrix::ISB, 1); + const int i = Perm[cliqueIndex[s][i_index]]; + tmpISB[0].i = i; + tmpISB[0].s = s; + tmpISB[0].b = i_index + j_index*length; + tmpVector[j].push_back(tmpISB); + } + } + } + + NewArray(dXtNonzeros, int, nDim); + NewArray(dXtIndex, int*, nDim); + NewArray(dXtClique, int*, nDim); + NewArray(dXtBlock, int*, nDim); + for (int j=0; ji; + dXtClique[j][index] = tmpISB->s; + dXtBlock [j][index] = tmpISB->b; + DeleteArray(tmpISB); + } + } + DeleteArray(tmpVector); +} + +void OrderingMatrix::displayDxIndex(FILE* fpout, char* printFormat) +{ + if (dXtNonzeros == NULL) { + fprintf(fpout, "dXtNonzeros is not set yet\n"); + } + else { + for (int k=0; k ", dXtIndex[k][index1], k); + fprintf(fpout, "cl{%d}(%d)\n", dXtClique[k][index1], + dXtBlock[k][index1]); + } + } + } +} + +void OrderingMatrix::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + + if (nClique > 0) { + fprintf(fpout, "nClique = %d\n", nClique); + fprintf(fpout, "cliqueSize = "); + for (int s=0; s maxClique) { + maxClique = cliqueSize[s]; + } + } + fprintf(fpout, " sum = %d, ave = %.2f, max = %d\n", + sumClique, (double) sumClique / (double) nClique, maxClique); + +} + +bool OrderingMatrix::compareISB(OrderingMatrix::ISB* a, OrderingMatrix::ISB* b) +{ + if (a->i < b->i) { + return true; + } + if (a->i > b->i) { + return false; + } + if (a->s < b->s) { + return true; + } + if (a->s > b->s) { + return false; + } + if (a->b < b->b) { + return true; + } + if (a->b > b->b) { + return false; + } + return false; // a==b + +} + +OrderingSpace::OrderingSpace() +{ + initialize(); +} + +OrderingSpace::~OrderingSpace() +{ + finalize(); +} + +void OrderingSpace::initialize() +{ + SDP_nBlock = 0; + SDP_block = NULL; + // Memory assignment will be done by + // extractCliques() +} + +void OrderingSpace::initialize(int SDP_nBlock, int* SDP_blockStruct) +{ + this->SDP_nBlock = SDP_nBlock; + if (SDP_nBlock > 0 ) { + NewArray(SDP_block, OrderingMatrix, SDP_nBlock); + for (int l = 0; l < SDP_nBlock; ++l) { + SDP_block[l].initialize(SDP_blockStruct[l]); + } + } +} + +void OrderingSpace::finalize() +{ + if (SDP_nBlock > 0 ) { + for (int l = 0; l < SDP_nBlock; ++l) { + SDP_block[l].finalize(); + } + DeleteArray(SDP_block); + SDP_nBlock = 0; + } +} + +void OrderingSpace::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (SDP_nBlock > 0) { + for (int index1 = 0; index1 < SDP_nBlock; ++index1) { + fprintf(fpout, "Block = %d\n", index1); + SDP_block[index1].display(fpout, printFormat); + } + } +} + +void OrderingSpace::displayStatistics(FILE* fpout, CholmodSpace& cholmodSpace) +{ + if (fpout == NULL) { + return; + } + if (SDP_nBlock > 0) { + for (int index1 = 0; index1 < SDP_nBlock; ++index1) { + fprintf(fpout, "[SDP %d-th Block] : order = ", index1); + SDP_block[index1].displayStatistics(fpout, + cholmodSpace.SDP_block[index1]); + } + } +} + +void OrderingSpace::displayDxIndex(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (SDP_nBlock > 0) { + for (int index1 = 0; index1 < SDP_nBlock; ++index1) { + fprintf(fpout, "Block = %d\n", index1); + SDP_block[index1].displayDxIndex(fpout, printFormat); + } + } +} + +void OrderingSpace::extractCliques(CholmodSpace& C) +{ + for (int l=0; l < SDP_nBlock; ++l) { + SDP_block[l].extractCliques(C.SDP_block[l]); + } +} + + + +CholmodMatrix::CholmodMatrix() +{ + initialize(); +} + +CholmodMatrix::~CholmodMatrix() +{ + finalize(); +} + +void CholmodMatrix::initialize() +{ + nDim = 0; // nDim will be set by extractCliques + Z = NULL; + Lz = NULL; + Lx = NULL; + x_x = NULL; + x_z = NULL; + b_x = NULL; + b_z = NULL; + cholmod_start(&common); + common.supernodal = CHOLMOD_SUPERNODAL; + common.final_super = 1; + + common.nrelax[0] = 4; // default 4 + common.nrelax[1] = 16; // default 16 + common.nrelax[2] = 48; // default 48 + + NNZ_Z = 0; + NNZ_L = 0; + Z_blockNumber = NULL; + Z_blockIndex = NULL; +} + +void CholmodMatrix::finalize() +{ + nDim = 0; + if (Z != NULL) { + cholmod_free_sparse(&Z,&common); + Z = NULL; + } + if (Lz != NULL) { + cholmod_free_factor(&Lz,&common); + Lz = NULL; + } + if (Lx != NULL) { + cholmod_free_factor(&Lx,&common); + Lx = NULL; + } + if (x_x != NULL) { + cholmod_free_dense(&x_x,&common); + x_x = NULL; + } + if (x_z != NULL) { + cholmod_free_dense(&x_z,&common); + x_z = NULL; + } + if (b_x != NULL) { + cholmod_free_dense(&b_x,&common); + b_x = NULL; + } + if (b_z != NULL) { + cholmod_free_dense(&b_z,&common); + b_z = NULL; + } + if (dZ != NULL) { + cholmod_free_sparse(&dZ,&common); + dZ = NULL; + } + if (rD != NULL) { + cholmod_free_sparse(&rD,&common); + rD = NULL; + } + cholmod_finish(&common); + DeleteArray(Z_blockNumber); + DeleteArray(Z_blockIndex); +} + +void CholmodMatrix::display(FILE* fpout, char* printFormat) +{ + if (fpout == NULL) { + return; + } + if (Z == NULL) { + rMessage("Each matrix is not set yet."); + return; + } + fprintf(fpout, "CholmodMatrix::display =start=============\n"); + fprintf(fpout, "Z = \n"); + display_sparse(Z, fpout, printFormat); + fprintf(fpout, "dZ = \n"); + display_sparse(dZ, fpout, printFormat); + fprintf(fpout, "rD = \n"); + display_sparse(rD, fpout, printFormat); + fprintf(fpout, "Lz = \n"); + display_factor(Lz, fpout, printFormat); + fprintf(fpout, "Lx = \n"); + display_factor(Lx, fpout, printFormat); + fprintf(fpout, "clique_xMat = \n"); + clique_xMat.display(fpout, printFormat); + fprintf(fpout, "clique_choleskyX = \n"); + clique_choleskyX.display(fpout, printFormat); + fprintf(fpout, "clique_invCholeskyX = \n"); + clique_invCholeskyX.display(fpout, printFormat); + fprintf(fpout, "clique_dX = \n"); + clique_dX.display(fpout, printFormat); + + #if 0 + fprintf(fpout, "b_z = \n"); + display_dense(b_z, fpout, printFormat); + if (x_z == NULL) { + rMessage("x_z is not set yet."); + } + else { + fprintf(fpout, "x_z = \n"); + display_dense(x_z, fpout, printFormat); + } + fprintf(fpout, "b_x = \n"); + display_dense(b_x, fpout, printFormat); + if (x_x == NULL) { + rMessage("x_x is not set yet."); + } + else { + fprintf(fpout, "x_x = \n"); + display_dense(x_x, fpout, printFormat); + } + #endif + fprintf(fpout, "CholmodMatrix::display = end =============\n"); +} + +void CholmodMatrix::display_sparse(cholmod_sparse* A, + FILE* fpout, char* printFormat) +{ + fprintf(fpout, "NNZ = %d\n", A->nzmax); + const int ncol = (int) A->ncol; + for (int j=0; j < ncol; ++j) { + const int start_row = ((int*)A->p)[j]; + const int end_row = ((int*)A->p)[j+1]; + for (int i_index = start_row; i_index < end_row; ++i_index) { + const int i = (( int*)A->i)[i_index]; + const double value = ((double*)A->x)[i_index]; + fprintf(fpout, "%d,%d,",i,j); + fprintf(fpout, printFormat, value); + fprintf(fpout, "\n"); + } + } +} + +void CholmodMatrix::display_factor(cholmod_factor* L, + FILE* fpout, char* printFormat) +{ + const int nsuper = L->nsuper; + const int* super = (int*) L->super; + const int* Ls = (int*) L->s; + const int* Lpi = (int*) L->pi; + const int* Lpx = (int*) L->px; + const double* Lx = (double*) L->x; + const int xtype = L->xtype; + + fprintf(fpout, "noOfSupernode = %d\n", nsuper); + for (int s=0; snrow; + const int ncol = (int) X->ncol; + const double* x = (double*) X->x; + fprintf(fpout, "[\n"); + for (int i=0; ix))[start_row] = scalar; + } +} + +void CholmodMatrix::setXIdentity(double scalar) +{ + clique_xMat.setIdentity(scalar); +} + + +void CholmodMatrix::setB_Zzero() +{ + for (int index1=0;index1 < nDim; ++index1) { + ((double*)(b_z->x))[index1] = 0.0; + } +} + +void CholmodMatrix::setB_Xzero() +{ + for (int index1=0;index1 < nDim; ++index1) { + ((double*)(b_x->x))[index1] = 0.0; + } +} + +void CholmodMatrix::setDxZero() +{ + clique_dX.setZero(); +} + +void CholmodMatrix::initializeClique(OrderingMatrix& order) +{ + clique_dX.initialize(order.nClique, order.cliqueSize); + clique_xMat.initialize(order.nClique, order.cliqueSize); + clique_choleskyX.initialize(order.nClique, order.cliqueSize); + clique_invCholeskyX.initialize(order.nClique, order.cliqueSize); +} + +bool CholmodMatrix::getCholesky(OrderingMatrix& order) +{ + cholmod_factorize(Z, Lz, &common); + #if 0 + rMessage("Z before Cholesky = "); CholmodMatrix::display_sparse(Z); + rMessage("Lz after Cholesky = "); CholmodMatrix::display_factor(Lz); + #endif + bool total_judge = SDPA_SUCCESS; + for (int l = 0; ls; + int* Lpi = (int*) Lx->pi; + int* Lpx = (int*) Lx->px; + double* Lxx = (double*) Lx->x; + int* super = (int*) Lx->super; + int nsuper = (int) Lx->nsuper; + + for (int s=0; s target.nCol) { + rError("coding bug"); + } + const int start_row = Lpi[s]; + const int end_row = Lpi[s+1]; + const int nsrow = end_row - start_row; + int length = nsrow * nscol; + double* target_address = &Lxx[Lpx[s]]; + dcopy_fc(&length, target.de_ele, &IONE, target_address, &IONE); + } + #if 0 + rMessage("clique_xMat = "); clique_xMat.display(); + rMessage("clique_choleskyX = "); clique_choleskyX.display(); + rMessage("clique_invCholeskyX = "); clique_invCholeskyX.display(); + rMessage("Lx after Cholesky = "); CholmodMatrix::display_factor(Lx); + #endif + return SDPA_SUCCESS; +} + +CholmodSpace::CholmodSpace() +{ + initialize(); +} + +CholmodSpace::~CholmodSpace() +{ + finalize(); +} + +void CholmodSpace::initialize() +{ + LP_nBlock = 0; + LP_Z = NULL; + LP_invZ = NULL; + LP_dZ = NULL; + LP_X = NULL; + LP_invX = NULL; + LP_dX = NULL; + LP_rD = NULL; + SDP_nBlock = 0; +} + +void CholmodSpace::finalize() +{ + DeleteArray(LP_Z); + DeleteArray(LP_invZ); + DeleteArray(LP_dZ); + DeleteArray(LP_X); + DeleteArray(LP_invX); + DeleteArray(LP_dX); + DeleteArray(LP_rD); + if (SDP_nBlock > 0) { + for (int index = 0; indexLP_nBlock = LP_nBlock; + this->SDP_nBlock = SDP_nBlock; + NewArray(LP_Z, double, LP_nBlock); + NewArray(LP_invZ, double, LP_nBlock); + NewArray(LP_dZ, double, LP_nBlock); + NewArray(LP_X, double, LP_nBlock); + NewArray(LP_invX, double, LP_nBlock); + NewArray(LP_dX, double, LP_nBlock); + NewArray(LP_rD, double, LP_nBlock); + NewArray(SDP_block, CholmodMatrix, SDP_nBlock); + // nClique is NOT initialized now +} + +void CholmodSpace::makeAggregate(int m, int SDP_nBlock, int* SDP_blockStruct, + CompSpace& C, CompSpace* A) +{ + vector** tmpAggregate; + // tmpAggregate[l][j] contains row numbers (i) in vector + + NewArray(tmpAggregate, vector*, SDP_nBlock); + for (int l=0; l, SDP_blockStruct[l]); + // diagonal elements should be added anytime + for (int j=0; jSDP_sp_nBlock; ++l_index) { + const int l = targetSpace->SDP_sp_index[l_index]; + CompMatrix& target = targetSpace->SDP_sp_block[l_index]; + for (int j_index=0; j_index < target.nzColumn; ++j_index) { + const int j = target.column_index[j_index]; + // only lower triangular part + const int row_start = target.diag_index[j_index]; + const int row_end = target.column_start[j_index+1]; + if (row_start < 0) { + continue; + } + for (int i_index = row_start; i_index < row_end; ++i_index) { + tmpAggregate[l][j].push_back(target.row_index[i_index]); + } + } + } + } + + for (int l=0; l& vec = tmpAggregate[l][j]; + for (int i=0; i 0) { + for (int l = 0; l + +#define DATA_CAPSULE 1 + // DATA_CAPSULE 0 : Three Arrays (row,column,sp_ele) + // DATA_CAPSULE 1 : Capsuled data storage + +namespace sdpa { + +class CholmodMatrix; +class CholmodSpace; +class OrderingMatrix; +class OrderingSpace; + + +class Vector +{ +public: + int nDim; + double* ele; + + Vector(); + Vector(int nDim, double value = 0.0); + ~Vector(); + + void initialize(); + void initialize(int nDim, double value = 0.0); + void initialize(double value); + void finalize(); + + void setZero(); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void display(FILE* fpout,double scalar, char* printFormat = P_FORMAT); + bool copyFrom(Vector& other); +}; + +class BlockVector +{ +public: + int nBlock; + int* blockStruct; + + Vector* ele; + + BlockVector(); + BlockVector(BlockStruct& bs, double value = 0.0); + BlockVector(int nBlock, int* blockStruct, double value = 0.0); + ~BlockVector(); + + void initialize(BlockStruct& bs, double value = 0.0); + void initialize(int nBlock, int* blockStruct, double value = 0.0); + void initialize(double value); + void finalize(); + + void setZero(); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + bool copyFrom(BlockVector& other); +}; + +class SparseMatrix +{ +public: + int nRow, nCol; + + enum Type { SPARSE, DENSE}; + Type type; + + int NonZeroNumber; + // for memory + int NonZeroCount; + // currentry stored + int NonZeroEffect; + // use for calculation of F1,F2,F3 + + // for Dense + double* de_ele; + + // for Sparse ; 0:sparse 1:dense + enum dsType {DSarrays, DScapsule}; + dsType DataStruct; + + // for Sparse Data1 // dsArrays + int* row_index; + int* column_index; + double* sp_ele; + + // for Sparse Data2 // dsCapsule + typedef struct{ + int vRow; + int vCol; + double vEle; + } SparseElement __attribute__( (aligned (16))); + + SparseElement* DataS; + + SparseMatrix(); + SparseMatrix(int nRow,int nCol, Type type, int NonZeroNumber); + ~SparseMatrix(); + + #if DATA_CAPSULE + void initialize(int nRow,int nCol, Type type, int NonZeroNumber, + dsType DataStruct = DScapsule); + #else + void initialize(int nRow,int nCol, Type type, int NonZeroNumber, + dsType DataStruct = DSarrays); + #endif + void finalize(); + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + bool copyFrom(SparseMatrix& other); + + void changeToDense(bool forceChange = false); + void setZero(); + void setIdentity(double scalar = 1.0); + + bool sortSparseIndex(int&i, int& j); +}; + +class DenseMatrix +{ +public: + int nRow, nCol; + + double* de_ele; + + DenseMatrix(); + ~DenseMatrix(); + + void initialize(); + void initialize(int nRow,int nCol); + void finalize(); + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + bool copyFrom(DenseMatrix& other); + bool copyFrom(SparseMatrix& other); + + void setZero(); + void setIdentity(double scalar = 1.0); +}; + +class SparseLinearSpace +{ +public: + int SDP_sp_nBlock; + int SOCP_sp_nBlock; + int LP_sp_nBlock; + + int* SDP_sp_index; + int* SOCP_sp_index; + int* LP_sp_index; + + SparseMatrix* SDP_sp_block; + SparseMatrix* SOCP_sp_block; + double* LP_sp_block; + + SparseLinearSpace(); + SparseLinearSpace(int SDP_nBlock, int* SDP_blockStruct, + int* SDP_NonZeroNumber, + int SOCP_nBlock, int* SOCP_blockStruct, + int* SOCP_NonZeroNumber, + int LP_nBlock, bool* LP_NonZeroNumber); + SparseLinearSpace(int SDP_sp_nBlock, + int* SDP_sp_index, + int* SDP_sp_blockStruct, + int* SDP_sp_NonZeroNumber, + int SOCP_sp_nBlock, + int* SOCP_sp_index, + int* SOCP_sp_blockStruct, + int* SOCP_sp_NonZeroNumber, + int LP_sp_nBlock, + int* LP_sp_index); + ~SparseLinearSpace(); + + // dense form of block index + void initialize(int SDP_nBlock, int* SDP_blockStruct, + int* SDP_NonZeroNumber, + int SOCP_nBlock, int* SOCP_blockStruct, + int* SOCP_NonZeroNumber, + int LP_nBlock, bool* LP_NonZeroNumber); + // sparse form of block index 2008/02/27 kazuhide nakata + void initialize(int SDP_sp_nBlock, + int* SDP_sp_index, + int* SDP_sp_blockStruct, + int* SDP_sp_NonZeroNumber, + int SOCP_sp_nBlock, + int* SOCP_sp_index, + int* SOCP_sp_blockStruct, + int* SOCP_sp_NonZeroNumber, + int LP_sp_nBlock, + int* LP_sp_index); + void finalize(); + + void changeToDense(bool forceChange=false); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + bool copyFrom(SparseLinearSpace& other); + + void setElement_SDP(int block, int nCol, int nRow, double ele); + void setElement_SOCP(int block, int nCol, int nRow, double ele); + void setElement_LP(int block, double ele); + + void setZero(); + void setIdentity(double scalar = 1.0); + // no check + bool sortSparseIndex(int&l , int& i, int& j); +}; + +class DenseLinearSpace +{ + public: + int SDP_nBlock; + int LP_nBlock; + + DenseMatrix* SDP_block; + double* LP_block; + + DenseLinearSpace(); + DenseLinearSpace(BlockStruct& bs); + ~DenseLinearSpace(); + void initialize(BlockStruct& bs); + void finalize(); + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void displaySolution(BlockStruct& bs, FILE* fpout = stdout, + char* printFormat = P_FORMAT); + bool copyFrom(DenseLinearSpace& other); + void setElement_SDP(int block, int nCol, int nRow, double ele); + void setElement_SOCP(int block, int nCol, int nRow, double ele); + void setElement_LP(int block, double ele); + void setZero(); + void setIdentity(double scalar = 1.0); +}; + + // Input Matrix A_k for Compleition + // Column-Compressed structure +class CompMatrix +{ +public: + int nRow; + int nCol; + int nzColumn; // nunmber of non-zero columns + int effectiveNzColumn; // nunmber of non-zero LOWER columns + int* column_index; // index of non-zero columns [length:nzColumn] + int NNZ; // number of non-zero + int lowerNNZ; // number of non-zero in lower triangular matrix + int* column_start; // starting point of each non-zero columns + // [length:nzColumn+1] + // the last one should be NNZ + int* row_index; // row-index of each element [length:NNZ] + double* ele; // value of each element [length:NNZ] + int* diag_index; // diagonal point of each non-zero columns + // [length:nzColumn] + // if diagonal is empty, diag_index[j] = -1; + int* agg_index; // aggregate index [length: NNZ] + + // This element corresponds to X.ele[blockNumber].de_ele[blockIndex] + int* blockNumber; + int* blockIndex; + + int nzColumn_diag; // number of LOWER non-zero columns with diagonal elements + int* column_diag_index; + int nzColumn_nondiag; // number of LOWER non-zero columns WITHOUT diagonal elements + int* column_nondiag_index; + + + class inputIJV + { + public: + int i; + int j; + double v; + }; + vector* inputVector; + // inputVector is the vector + // After makeInternalStructure(), this vector will be released + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void initialize(); + CompMatrix(); + void finalize(); + ~CompMatrix(); + + void initializeInputVector(); + void setElement(int i, int j, double v); + static bool compareIJV(inputIJV* a, inputIJV* b); + void sortInputVector(); + void makeInternalStructure(); + void checkInputDataStructure(int& i, int& j, double& v1, double& v2); + + void assignAgg(CholmodMatrix& cholmodMatrix); + // Aggregate contains only lower triangular + + void assignBlockIndex(OrderingMatrix& order); +}; + + // diagonal block structure of CompMatrix +class CompSpace +{ +public: + + int LP_sp_nBlock; + int SDP_sp_nBlock; + int* LP_sp_index; + int* SDP_sp_index; + + double* LP_sp_block; + CompMatrix* SDP_sp_block; + + int NNZ; + int lowerNNZ; + + // LP_agg_index is not neccesarry, because LP_sp_index does the same thing + + CompSpace(); + ~CompSpace(); + void initialize(); + void initialize(int LP_sp_nBlock, int SDP_sp_nBlock); + void finalize(); + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + + void initializeInputVector(); + void setElement_LP(int i, double v); + void setElement_SDP(int l, int i, int j, double v); + + void sortInputVector(); + void makeInternalStructure(); + void checkInputDataStructure(int& l, int& i, int& j, double& v1, double& v2); + void assignAgg(CholmodSpace& cholModSpace); + void assignBlockIndex(OrderingSpace& order); +}; + +// CliqueMatrix should be diagonal block of fully-dense matrix +// LP block is handled separately by CliqueSpace +class CliqueMatrix +{ +public: + int nBlock; + int* blockStruct; + DenseMatrix* ele; + + CliqueMatrix(); + ~CliqueMatrix(); + void initialize(); + void initialize(int nBlock, int* blockStruct); + void finalize(); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void setZero(); + void setIdentity(double scalar = 1.0); +}; + // diagonal block structure of CliqueMatrix +class CliqueSpace +{ +public: + int LP_nBlock; + double* LP_block; + int SDP_nBlock; + CliqueMatrix* SDP_block; // each block is decomposed into multiple matrices + + CliqueSpace(); + ~CliqueSpace(); + void initialize(); + void initialize(BlockStruct& bs, OrderingSpace& order); + void finalize(); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void setZero(); + void setIdentity(double scalar = 1.0); +}; + +class OrderingMatrix +{ +public: + int nClique; + int* cliqueSize; //length nCliques + // arrays of nCliques, i-th array has cliqueSize[i] length + int** cliqueIndex; + + int nDim; + int* Perm; + int* ReversePerm; + + // dXt means dX~tilde + // This matrix is nonsymemetric and [dX~]_{*k} + // is usually computed. + // By copying nonzero elements of [dX~]_{*k} to a clique structure, + // its efficiency will be enhanced. + // Details:: + // The dXtildeIndex-th element of [dX~]_{*k} will be mapped to + // cliqueMatrix{dXtilde[k][dXtClique]}(dXtBlock); + // dXtBlock is the index of the corresponding block inside. + int* dXtNonzeros; // size of nDim + int** dXtIndex; // size of nDim*dXtNonzeros + int** dXtClique; // size of nDim*dXtNonzeros + int** dXtBlock; // size of nDim*dXtNonzeros + + // tmporary class for making dXtNonzers, etc. + class ISB { + public: + int i; + int s; + int b; // blockIndex + }; + + static bool compareISB(ISB* a, ISB* b); + + OrderingMatrix(); + ~OrderingMatrix(); + void initialize(); + void initialize(int nDim); + void finalize(); + + // A[i,j] * X[i,j] means A[i,j] * X.ele[blockNumber].ele[blockIndex] + void getIndex(int i, int j, int& blockNumber, int& blockIndex); + void extractCliques(CholmodMatrix& C); + void displayDxIndex(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void displayStatistics(FILE* fpout, CholmodMatrix& cholmodMatrix); + +}; + +class OrderingSpace +{ +public: + int SDP_nBlock; + OrderingMatrix* SDP_block; + OrderingSpace(); + ~OrderingSpace(); + void initialize(); + void initialize(int SDP_nBlock, int* SDP_blockStruct); + void finalize(); + void displayDxIndex(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void displayStatistics(FILE* fpout, CholmodSpace& cholmodSpace); + void extractCliques(CholmodSpace& C); + +}; + +class CholmodMatrix +{ +public: + int nDim; + cholmod_sparse* Z; + cholmod_factor* Lz; + cholmod_factor* Lx; + cholmod_sparse* dZ; + cholmod_sparse* rD; + CliqueMatrix clique_xMat; + CliqueMatrix clique_dX; + CliqueMatrix clique_choleskyX; + CliqueMatrix clique_invCholeskyX; + + cholmod_dense* x_x; // solution of cholmod_solve + cholmod_dense* x_z; // solution of cholmod_solve + cholmod_dense* b_x; // right-hand-side of cholmod_solve + cholmod_dense* b_z; // right-hand-side of cholmod_solve + + cholmod_common common; + int NNZ_Z; + int NNZ_L; + int* Z_blockNumber; + int* Z_blockIndex; + + CholmodMatrix(); + ~CholmodMatrix(); + void initialize(); + void finalize(); + + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + static void display_sparse(cholmod_sparse* A, FILE* fpout = stdout, + char* printFormat = P_FORMAT); + static void display_factor(cholmod_factor* L, FILE* fpout = stdout, + char* printFormat = P_FORMAT); + static void display_dense(cholmod_dense* X, FILE* fpout = stdout, + char* printFormat = P_FORMAT); + void analyze(); + void solveByZ(); // b should be set properly before solve. + void solveByX(); // b should be set properly before solve. + + void assignBlockIndex(OrderingMatrix& order); + + static void setZero_sparse(cholmod_sparse* A); + void setZzero(); + void setZIdentity(double scalar = 1.0); + void setXIdentity(double scalar = 1.0); + void setB_Zzero(); + void setB_Xzero(); + void setDxZero(); + void initializeClique(OrderingMatrix& order); + + bool getCholesky(OrderingMatrix& order); +}; + +class InputData; +// diagonal block structure of cholmod_sparse & cholmod_factor +// for Aggregate Matrix & Factorized Matrix +class CholmodSpace +{ +public: + + int LP_nBlock; + double* LP_Z; + double* LP_invZ; + double* LP_dZ; + double* LP_X; + double* LP_invX; + double* LP_dX; + int SDP_nBlock; + CholmodMatrix* SDP_block; + + Vector yVec; + Vector dyVec; + + Vector rp; // primal residual vector + double* LP_rD; // dual residual vector + + CholmodSpace(); + ~CholmodSpace(); + void initialize(); + void initialize(int LP_nBlock, int SDP_nBlock); + void finalize(); + + void makeAggregate(int m, int SDP_nBlock, int* SDP_blockStruct, + CompSpace& C, CompSpace* A); + void assignBlockIndex(OrderingSpace& order); + void setZzero(); + void setZIdentity(double scalar = 1.0); + void setXIdentity(double scalar = 1.0); + void display(FILE* fpout = stdout, char* printFormat = P_FORMAT); + void analyze(); + void initializeClique(int m, OrderingSpace& order); + + void getInnerProductAX(double& ret, + CompSpace& A, OrderingSpace& order); + void getInnerProductAdX(double& ret, + CompSpace& A, OrderingSpace& order); + void computeResiduals(InputData& inputData, OrderingSpace& order); + + bool getCholesky(OrderingSpace& order); + +}; + +} // end of namespace 'sdpa' + +#endif // __sdpa_struct_h__ diff --git a/external/sdpa/sdpa_tool.cpp b/external/sdpa/sdpa_tool.cpp new file mode 100644 index 0000000..2e5d7e2 --- /dev/null +++ b/external/sdpa/sdpa_tool.cpp @@ -0,0 +1,71 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*----------------------------------------- + sdpa_tool.cpp +-----------------------------------------*/ + +#include "sdpa_tool.h" +#include +#include + +#include +#ifndef CLK_TCK +#define CLK_TCK sysconf(_SC_CLK_TCK) +#endif + +namespace sdpa { + +// These are constant. +// Do Not Change . +int IZERO = 0; +int IONE = 1; +int IMONE = -1; +double DZERO = 0.0; +double DONE = 1.0; +double DMONE = -1.0; + +double Time::rGetUseTime() +{ + #if PROCESS_TIME + struct tms TIME; + times(&TIME); + return (double)TIME.tms_utime/(double)CLK_TCK; + #else + return 0.0; + #endif +} + +void Time::rSetTimeVal(struct timeval& targetVal) +{ + static struct timezone tz; + gettimeofday(&targetVal,&tz); +} + +double Time::rGetRealTime(const struct timeval& start, + const struct timeval& end) +{ + const long int second = end.tv_sec - start.tv_sec; + const long int usecond = end.tv_usec - start.tv_usec; + return ((double)second) + ((double)usecond)*(1.0e-6); +} + +} // end of namespace 'sdpa' + diff --git a/external/sdpa/sdpa_tool.h b/external/sdpa/sdpa_tool.h new file mode 100644 index 0000000..ef24fb9 --- /dev/null +++ b/external/sdpa/sdpa_tool.h @@ -0,0 +1,147 @@ +/* ------------------------------------------------------------- + +This file is a component of SDPA +Copyright (C) 2004-2013 SDPA Project + +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 + +------------------------------------------------------------- */ +/*-------------------------------------------------- + sdpa_tool.h +--------------------------------------------------*/ + +#ifndef __sdpa_tool_h__ +#define __sdpa_tool_h__ + +#include "sdpa_right.h" + +#include +#include +#include +#include +#include + + +namespace sdpa { + +// Note : only GNU has the macro __PRETTY_FUNCTION__ +#define USE_PRETTY_FUNCTION 0 +#if USE_PRETTY_FUNCTION +#define rMessage(message) \ +{ cout << message << " :: line " << __LINE__ \ + << " in " << __FILE__ \ + << " [ " << __PRETTY_FUNCTION__ << " ] " << endl; } +#elif 1 +#define rMessage(message) \ +{cout << message << " :: line " << __LINE__ \ + << " in " << __FILE__ << endl; } +#else +#define rMessage(message) ; +#endif + +#if USE_PRETTY_FUNCTION +#define rError(message) \ +{ cout << message << " :: line " << __LINE__ \ + << " in " << __FILE__ \ + << " [ " << __PRETTY_FUNCTION__ << " ] " << endl; \ +exit(false);} +#else +#define rError(message) \ +{cout << message << " :: line " << __LINE__ \ + << " in " << __FILE__ << endl; \ +exit(false);} +#endif + +#if 1 +#define NewArray(val,type,number) \ + {val = NULL; \ + try{ val = new type[number]; } \ + catch(bad_alloc){ \ + rMessage("Memory Exhausted (bad_alloc)"); abort(); } \ + catch(...){ \ + rMessage("Fatal Error (related memory allocation"); abort(); } \ + } +#else +#define NewArray(val,type,number) \ + {rMessage("New Invoked"); \ + val = NULL; val = new type[number]; \ + if (val==NULL) {rError("Over Memory");} \ + } +#endif + +#define DeleteArray(val) \ + { if (val!=NULL) { \ + delete[] val; \ + val = NULL; \ + } \ + } + +#define REVERSE_PRIMAL_DUAL 1 + + +// These are constant. Do NOT change +extern int IZERO ; // = 0; +extern int IONE ; // = 1; +extern int IMONE ; // = -1; +extern double DZERO; // = 0.0; +extern double DONE ; // = 1.0; +extern double DMONE; // = -1.0; + +class Time +{ +public: + static double rGetUseTime(); + static void rSetTimeVal(struct timeval & targetVal); + static double rGetRealTime(const struct timeval & start, + const struct timeval & end); +}; + +#define PROCESS_TIME 0 +#if PROCESS_TIME // count time with process time +#include +#define TimeStart(START__) \ + static double START__; START__ = Time::rGetUseTime() +#define TimeEnd(END__) \ + static double END__; END__ = Time::rGetUseTime() +#define TimeCal(START__,END__) (END__ - START__) +#else // count time with real time +#define TimeStart(START__) \ + static struct timeval START__; Time::rSetTimeVal(START__) +#define TimeEnd(END__) \ + static struct timeval END__; Time::rSetTimeVal(END__) +#define TimeCal(START__,END__) Time::rGetRealTime(START__,END__) +#endif + +#define sdpa_dset(dset_length,dset_value,dset_pointer,dset_step) \ +for (int dset_i=0,dset_index = 0; dset_i gSceneData; +StructuredBuffer gSceneData; + +[[vk::push_constant]] +ConstantBuffer gSceneDataIndex; + +PrimitiveSceneData getSceneData() +{ + return gSceneData[gSceneDataIndex]; +} \ No newline at end of file diff --git a/res/shaders/lib/StaticMeshVertexInput.slang b/res/shaders/lib/StaticMeshVertexInput.slang index f04a21a..11c7b90 100644 --- a/res/shaders/lib/StaticMeshVertexInput.slang +++ b/res/shaders/lib/StaticMeshVertexInput.slang @@ -131,9 +131,10 @@ struct VertexShaderInput float3 getWorldPosition() { - float4x4 localToWorld = gSceneData.localToWorld; + float4x4 localToWorld = getSceneData().localToWorld; float3 rotatedPosition = localToWorld[0].xyz * position.xxx + localToWorld[1].xyz * position.yyy + localToWorld[2].xyz * position.zzz; - return rotatedPosition + localToWorld[3].xyz; + return mul(getSceneData().localToWorld, position).xyz; + //rotatedPosition + float3(localToWorld[0].w, localToWorld[1].w, localToWorld[2].w); } VertexValueCache getVertexCache() @@ -152,9 +153,9 @@ struct VertexShaderInput cache.tangentToLocal[1] = tangentToLocal[1]; cache.tangentToLocal[2] = tangentToLocal[2]; - cache.tangentToWorld[0] = mul(gSceneData.localToWorld, float4(tangentToLocal[0], 0.0f)).xyz; - cache.tangentToWorld[1] = mul(gSceneData.localToWorld, float4(tangentToLocal[1], 0.0f)).xyz; - cache.tangentToWorld[2] = mul(gSceneData.localToWorld, float4(tangentToLocal[2], 0.0f)).xyz; + cache.tangentToWorld[0] = mul(getSceneData().localToWorld, float4(tangentToLocal[0], 0.0f)).xyz; + cache.tangentToWorld[1] = mul(getSceneData().localToWorld, float4(tangentToLocal[1], 0.0f)).xyz; + cache.tangentToWorld[2] = mul(getSceneData().localToWorld, float4(tangentToLocal[2], 0.0f)).xyz; return cache; } @@ -183,9 +184,9 @@ struct VertexShaderInput { ShaderAttributeInterpolation result = (ShaderAttributeInterpolation)0; float3x3 tangentToWorld = cache.getTangentToWorld(); - result.normal = mul(gSceneData.localToWorld, float4(normal, 0.0f)).xyz; - result.tangent = mul(gSceneData.localToWorld, float4(tangent, 0.0f)).xyz; - result.biTangent = mul(gSceneData.localToWorld, float4(biTangent, 0.0f)).xyz; + result.normal = mul(getSceneData().localToWorld, float4(normal, 0.0f)).xyz; + result.tangent = mul(getSceneData().localToWorld, float4(tangent, 0.0f)).xyz; + result.biTangent = mul(getSceneData().localToWorld, float4(biTangent, 0.0f)).xyz; result.color = color; result.worldPosition = vertexParams.worldPosition; result.viewPosition = vertexParams.viewPosition; @@ -215,8 +216,9 @@ struct PositionOnlyVertexShaderInput #endif // USE_INSTANCING float3 getWorldPosition() { - float4x4 localToWorld = gSceneData.localToWorld; + float4x4 localToWorld = getSceneData().localToWorld; float3 rotatedPosition = localToWorld[0].xyz * position.xxx + localToWorld[1].xyz * position.yyy + localToWorld[2].xyz * position.zzz; - return rotatedPosition + localToWorld[3].xyz; + return mul(getSceneData().localToWorld, position).xyz; + //rotatedPosition + float3(localToWorld[0].w, localToWorld[1].w, localToWorld[2].w); } }; diff --git a/src/Editor/Window/SceneView.cpp b/src/Editor/Window/SceneView.cpp index eaf6b02..317d879 100644 --- a/src/Editor/Window/SceneView.cpp +++ b/src/Editor/Window/SceneView.cpp @@ -20,7 +20,7 @@ SceneView::SceneView(Gfx::PGraphics graphics, PWindow owner, const ViewportCreat LightCullingPass(graphics), BasePass(graphics) )) - , cameraSystem(createInfo.dimensions, Math::Vector(0, 0, 10)) + , cameraSystem(createInfo.dimensions, Vector(0, 0, 10)) { AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Diffuse.png"); AssetRegistry::importFile("C:\\Users\\Dynamitos\\TestSeeleProject\\Assets\\Ayaka\\Avatar_Girl_Sword_Ayaka_Tex_Body_Lightmap.png"); diff --git a/src/Editor/Window/ViewportControl.cpp b/src/Editor/Window/ViewportControl.cpp index a64582c..0124544 100644 --- a/src/Editor/Window/ViewportControl.cpp +++ b/src/Editor/Window/ViewportControl.cpp @@ -3,7 +3,7 @@ using namespace Seele; -ViewportControl::ViewportControl(const Math::URect& viewportDimensions, Math::Vector initialPos) +ViewportControl::ViewportControl(const URect& viewportDimensions, Vector initialPos) : position(initialPos) , fieldOfView(glm::radians(70.f)) , aspectRatio(static_cast(viewportDimensions.size.x) / viewportDimensions.size.y) @@ -25,9 +25,9 @@ void ViewportControl::update(Component::Camera& camera, float deltaTime) { cameraMove *= 4; } - Math::Vector moveVector = Math::Vector(); - Math::Vector forward = glm::normalize(springArm); - Math::Vector side = glm::cross(Math::Vector(0, 1, 0), forward); + Vector moveVector = Vector(); + Vector forward = glm::normalize(springArm); + Vector side = glm::cross(Vector(0, 1, 0), forward); if(keys[KeyCode::KEY_W]) { moveVector += forward * cameraMove; @@ -64,11 +64,11 @@ void ViewportControl::update(Component::Camera& camera, float deltaTime) lastX = mouseX; lastY = mouseY; springArm = glm::normalize( - Math::Vector( + Vector( cos(yaw) * cos(pitch), sin(pitch), sin(yaw) * cos(pitch))); - camera.viewMatrix = glm::lookAt(position, position + springArm, Math::Vector(0, 1, 0)); + camera.viewMatrix = glm::lookAt(position, position + springArm, Vector(0, 1, 0)); camera.projectionMatrix = glm::perspective(fieldOfView, aspectRatio, 0.1f, 1000.0f); std::cout << yaw << " " << pitch << std::endl; } @@ -96,7 +96,7 @@ void ViewportControl::mouseButtonCallback(MouseButton button, InputAction action } } -void ViewportControl::viewportResize(Math::URect dimensions) +void ViewportControl::viewportResize(URect dimensions) { aspectRatio = static_cast(dimensions.size.x) / dimensions.size.y; } diff --git a/src/Editor/Window/ViewportControl.h b/src/Editor/Window/ViewportControl.h index 248dc33..98ef264 100644 --- a/src/Editor/Window/ViewportControl.h +++ b/src/Editor/Window/ViewportControl.h @@ -8,16 +8,16 @@ namespace Seele class ViewportControl { public: - ViewportControl(const Math::URect& viewportDimensions, Math::Vector initialPos /*TODO: configurable initial rotations*/); + ViewportControl(const URect& viewportDimensions, Vector initialPos /*TODO: configurable initial rotations*/); ~ViewportControl(); void update(Component::Camera& camera, float deltaTime); void keyCallback(KeyCode key, InputAction action); void mouseMoveCallback(double xPos, double yPos); void mouseButtonCallback(MouseButton button, InputAction action); - void viewportResize(Math::URect dimensions); + void viewportResize(URect dimensions); private: - Math::Vector position; - Math::Vector springArm; + Vector position; + Vector springArm; float fieldOfView; float aspectRatio; StaticArray(KeyCode::KEY_LAST)> keys; diff --git a/src/Engine/Actor/Actor.cpp b/src/Engine/Actor/Actor.cpp index 3b3d00a..9109046 100644 --- a/src/Engine/Actor/Actor.cpp +++ b/src/Engine/Actor/Actor.cpp @@ -6,7 +6,7 @@ using namespace Seele; Actor::Actor(PScene scene) : Entity(scene) { - scene->attachComponent(identifier); + attachComponent(); } Actor::~Actor() @@ -32,13 +32,9 @@ void Actor::removeChild(PActor child) children.remove(children.find(child), false); child->setParent(nullptr); } -const Component::Transform& Actor::getTransform() const + +Component::Transform& Actor::getTransform() { - return scene->accessComponent(identifier); + return accessComponent(); } -//Component::Transform& Actor::getTransform() -//{ -// return scene->accessComponent(identifier); -//} - diff --git a/src/Engine/Actor/Actor.h b/src/Engine/Actor/Actor.h index 47ef8c0..e13566a 100644 --- a/src/Engine/Actor/Actor.h +++ b/src/Engine/Actor/Actor.h @@ -18,8 +18,7 @@ public: void removeChild(PActor child); Array getChildren(); - // Returns a read-only copy of the actors transform - const Component::Transform& getTransform() const; + Component::Transform& getTransform(); protected: //Component::Transform& getTransform(); diff --git a/src/Engine/Actor/CameraActor.cpp b/src/Engine/Actor/CameraActor.cpp index 9dc2b94..1da543d 100644 --- a/src/Engine/Actor/CameraActor.cpp +++ b/src/Engine/Actor/CameraActor.cpp @@ -6,8 +6,8 @@ using namespace Seele; CameraActor::CameraActor(PScene scene) : Actor(scene) { - scene->attachComponent(identifier); - scene->accessComponent(identifier).setRelativeLocation(Math::Vector(10, 5, 14)); + attachComponent(); + attachComponent().setRelativeLocation(Vector(10, 5, 14)); } CameraActor::~CameraActor() @@ -16,10 +16,10 @@ CameraActor::~CameraActor() Component::Camera& CameraActor::getCameraComponent() { - return scene->accessComponent(identifier); + return accessComponent(); } const Component::Camera& CameraActor::getCameraComponent() const { - return scene->accessComponent(identifier); + return accessComponent(); } \ No newline at end of file diff --git a/src/Engine/Actor/Entity.cpp b/src/Engine/Actor/Entity.cpp index 9641d99..6282557 100644 --- a/src/Engine/Actor/Entity.cpp +++ b/src/Engine/Actor/Entity.cpp @@ -11,5 +11,5 @@ Entity::Entity(PScene scene) Entity::~Entity() { - + scene->destroyEntity(identifier); } \ No newline at end of file diff --git a/src/Engine/Actor/Entity.h b/src/Engine/Actor/Entity.h index 431bed9..25de08d 100644 --- a/src/Engine/Actor/Entity.h +++ b/src/Engine/Actor/Entity.h @@ -13,9 +13,19 @@ public: virtual ~Entity(); template - Component& attachComponent(Args... args) + Component& attachComponent(Args&&... args) { - return scene->attachComponent(identifier, args...); + return scene->attachComponent(identifier, std::forward(args)...); + } + template + Component& accessComponent() + { + return scene->accessComponent(identifier); + } + template + const Component& accessComponent() const + { + return scene->accessComponent(identifier); } protected: PScene scene; diff --git a/src/Engine/Asset/AssetRegistry.cpp b/src/Engine/Asset/AssetRegistry.cpp index c9c3a43..86da3c3 100644 --- a/src/Engine/Asset/AssetRegistry.cpp +++ b/src/Engine/Asset/AssetRegistry.cpp @@ -2,18 +2,20 @@ #include "MeshAsset.h" #include "FontAsset.h" #include "TextureAsset.h" +#include "MaterialAsset.h" #include "FontLoader.h" #include "TextureLoader.h" #include "MaterialLoader.h" #include "MeshLoader.h" -#include "Material/MaterialAsset.h" #include "Graphics/Mesh.h" #include "Graphics/Graphics.h" #include "Window/WindowManager.h" #include "MeshAsset.h" +#include #include using namespace Seele; +using json = nlohmann::json; AssetRegistry::~AssetRegistry() { @@ -25,6 +27,11 @@ void AssetRegistry::init(const std::string& rootFolder) } void AssetRegistry::importFile(const std::string &filePath) +{ + importFile(filePath, ""); +} + +void AssetRegistry::importFile(const std::string &filePath, const std::string& importPath) { std::filesystem::path fsPath = std::filesystem::path(filePath); std::string extension = fsPath.extension().string(); @@ -32,43 +39,78 @@ void AssetRegistry::importFile(const std::string &filePath) || extension.compare(".obj") == 0 || extension.compare(".blend") == 0) { - get().importMesh(fsPath); + get().importMesh(fsPath, importPath); } if (extension.compare(".png") == 0 || extension.compare(".jpg") == 0) { - get().importTexture(fsPath); + get().importTexture(fsPath, importPath); } if(extension.compare(".ttf") == 0) { - get().importFont(fsPath); + get().importFont(fsPath, importPath); } if (extension.compare(".asset") == 0) { - get().importMaterial(fsPath); + get().importMaterial(fsPath, importPath); } } PMeshAsset AssetRegistry::findMesh(const std::string &filePath) { - auto it = get().meshes.find(filePath); - assert(it != get().meshes.end()); + AssetFolder& folder = get().assetRoot; + std::string fileName = filePath; + size_t slashLoc = filePath.rfind("/"); + if(slashLoc != -1) + { + folder = get().getOrCreateFolder(filePath.substr(0, slashLoc)); + fileName = filePath.substr(slashLoc+1, filePath.size()); + } + auto it = folder.meshes.find(fileName); + assert(it != folder.meshes.end()); return it->second; } PTextureAsset AssetRegistry::findTexture(const std::string &filePath) { - return get().textures[filePath]; + std::string fileName = filePath; + size_t slashLoc = filePath.rfind("/"); + if(slashLoc != -1) + { + AssetFolder& folder = get().getOrCreateFolder(filePath.substr(0, slashLoc)); + fileName = filePath.substr(slashLoc+1, filePath.size()); + return folder.textures[fileName]; + } + else + { + return get().assetRoot.textures[fileName]; + } } -PFontAsset AssetRegistry::findFont(const std::string& name) +PFontAsset AssetRegistry::findFont(const std::string& filePath) { - return get().fonts[name]; + AssetFolder& folder = get().assetRoot; + std::string fileName = filePath; + size_t slashLoc = filePath.rfind("/"); + if(slashLoc != -1) + { + folder = get().getOrCreateFolder(filePath.substr(0, slashLoc)); + fileName = filePath.substr(slashLoc+1, filePath.size()); + } + return folder.fonts[fileName]; } PMaterialAsset AssetRegistry::findMaterial(const std::string &filePath) { - return get().materials[filePath]; + AssetFolder& folder = get().assetRoot; + std::string fileName = filePath; + size_t slashLoc = filePath.rfind("/"); + if(slashLoc != -1) + { + folder = get().getOrCreateFolder(filePath.substr(0, slashLoc)); + fileName = filePath.substr(slashLoc+1, filePath.size()); + } + return folder.materials[fileName]; } std::ofstream AssetRegistry::createWriteStream(const std::string& relativePath, std::ios_base::openmode openmode) @@ -106,56 +148,65 @@ std::string AssetRegistry::getRootFolder() return get().rootFolder.generic_string(); } -void AssetRegistry::importMesh(const std::filesystem::path &filePath) +void AssetRegistry::importMesh(const std::filesystem::path &filePath, const std::string& importPath) { - meshLoader->importAsset(filePath); + meshLoader->importAsset(filePath, importPath); } -void AssetRegistry::importTexture(const std::filesystem::path &filePath) +void AssetRegistry::importTexture(const std::filesystem::path &filePath, const std::string& importPath) { - textureLoader->importAsset(filePath); + textureLoader->importAsset(filePath, importPath); } -void AssetRegistry::importFont(const std::filesystem::path& filePath) +void AssetRegistry::importFont(const std::filesystem::path& filePath, const std::string& importPath) { - fontLoader->importAsset(filePath); + fontLoader->importAsset(filePath, importPath); } -void AssetRegistry::importMaterial(const std::filesystem::path &filePath) +void AssetRegistry::importMaterial(const std::filesystem::path &filePath, const std::string& importPath) { - materialLoader->importAsset(filePath); + materialLoader->importAsset(filePath, importPath); } -void AssetRegistry::registerMesh(PMeshAsset mesh) +void AssetRegistry::registerMesh(PMeshAsset mesh, const std::string& importPath) { - PMeshAsset existingMesh = meshes[mesh->getFileName()]; - if(existingMesh != nullptr) + AssetFolder& folder = getOrCreateFolder(importPath); + folder.meshes[mesh->getFileName()] = mesh; +} + +void AssetRegistry::registerTexture(PTextureAsset texture, const std::string& importPath) +{ + AssetFolder& folder = getOrCreateFolder(importPath); + folder.textures[texture->getFileName()] = texture; +} + +void AssetRegistry::registerFont(PFontAsset font, const std::string& importPath) +{ + AssetFolder& folder = getOrCreateFolder(importPath); + folder.fonts[font->getFileName()] = font; +} + +void AssetRegistry::registerMaterial(PMaterialAsset material, const std::string& importPath) +{ + AssetFolder& folder = getOrCreateFolder(importPath); + folder.materials[material->getFileName()] = material; +} + +AssetRegistry::AssetFolder& AssetRegistry::getOrCreateFolder(std::string fullPath) +{ + AssetFolder& result = assetRoot; + while(!fullPath.empty()) { - auto newMeshes = mesh->getMeshes(); - for(uint32 i = 0; i < newMeshes.size(); ++i) + size_t slashLoc = fullPath.find("/"); + if(slashLoc == -1) { - existingMesh->addMesh(newMeshes[i]); + return result.children[fullPath]; } + std::string folderName = fullPath.substr(0, slashLoc); + result = result.children[folderName]; + fullPath = fullPath.substr(slashLoc+1, fullPath.size()); } - else - { - meshes[mesh->getFileName()] = mesh; - } -} - -void AssetRegistry::registerTexture(PTextureAsset texture) -{ - textures[texture->getFileName()] = texture; -} - -void AssetRegistry::registerFont(PFontAsset font) -{ - fonts[font->getFileName()] = font; -} - -void AssetRegistry::registerMaterial(PMaterialAsset material) -{ - materials[material->getFileName()] = material; + return result; } std::ofstream AssetRegistry::internalCreateWriteStream(const std::string& relativePath, std::ios_base::openmode openmode) diff --git a/src/Engine/Asset/AssetRegistry.h b/src/Engine/Asset/AssetRegistry.h index 313a9f1..7055a10 100644 --- a/src/Engine/Asset/AssetRegistry.h +++ b/src/Engine/Asset/AssetRegistry.h @@ -1,7 +1,6 @@ #pragma once #include "MinimalEngine.h" #include "Asset.h" -#include "Material/MaterialAsset.h" #include #include @@ -25,6 +24,7 @@ public: static std::string getRootFolder(); static void importFile(const std::string& filePath); + static void importFile(const std::string& filePath, const std::string& importPath); static PMeshAsset findMesh(const std::string& filePath); static PTextureAsset findTexture(const std::string& filePath); @@ -34,30 +34,38 @@ public: static std::ofstream createWriteStream(const std::string& relativePath, std::ios_base::openmode openmode = std::ios::out); static std::ifstream createReadStream(const std::string& relativePath, std::ios_base::openmode openmode = std::ios::in); private: + struct AssetFolder + { + std::map children; + //Todo: Seele::Map doesn't really work with strings for some reason, so just use std::map for now + std::map textures; + std::map fonts; + std::map meshes; + std::map materials; + }; + static AssetRegistry& get(); AssetRegistry(); void init(const std::filesystem::path& rootFolder, Gfx::PGraphics graphics); - void importMesh(const std::filesystem::path& filePath); - void importTexture(const std::filesystem::path& filePath); - void importFont(const std::filesystem::path& filePath); - void importMaterial(const std::filesystem::path& filePath); + void importMesh(const std::filesystem::path& filePath, const std::string& importPath); + void importTexture(const std::filesystem::path& filePath, const std::string& importPath); + void importFont(const std::filesystem::path& filePath, const std::string& importPath); + void importMaterial(const std::filesystem::path& filePath, const std::string& importPath); - void registerMesh(PMeshAsset mesh); - void registerTexture(PTextureAsset texture); - void registerFont(PFontAsset font); - void registerMaterial(PMaterialAsset material); + void registerMesh(PMeshAsset mesh, const std::string& importPath); + void registerTexture(PTextureAsset texture, const std::string& importPath); + void registerFont(PFontAsset font, const std::string& importPath); + void registerMaterial(PMaterialAsset material, const std::string& importPath); + + AssetFolder& getOrCreateFolder(std::string foldername); std::ofstream internalCreateWriteStream(const std::string& relativePath, std::ios_base::openmode openmode = std::ios::out); std::ifstream internalCreateReadStream(const std::string& relaitvePath, std::ios_base::openmode openmode = std::ios::in); std::filesystem::path rootFolder; - //Todo: Seele::Map doesn't really work with strings for some reason, so just use std::map for now - std::map textures; - std::map fonts; - std::map meshes; - std::map materials; + AssetFolder assetRoot; UPTextureLoader textureLoader; UPFontLoader fontLoader; UPMeshLoader meshLoader; diff --git a/src/Engine/Asset/CMakeLists.txt b/src/Engine/Asset/CMakeLists.txt index 0f98654..3dfb127 100644 --- a/src/Engine/Asset/CMakeLists.txt +++ b/src/Engine/Asset/CMakeLists.txt @@ -8,6 +8,10 @@ target_sources(Engine FontAsset.cpp FontLoader.h FontLoader.cpp + MaterialAsset.h + MaterialAsset.cpp + MaterialInstanceAsset.h + MaterialInstanceAsset.cpp MaterialLoader.h MaterialLoader.cpp MeshAsset.h @@ -26,6 +30,8 @@ target_sources(Engine AssetRegistry.h FontAsset.h FontLoader.h + MaterialAsset.h + MaterialInstanceAsset.h MaterialLoader.h MeshAsset.h MeshLoader.h diff --git a/src/Engine/Asset/FontAsset.cpp b/src/Engine/Asset/FontAsset.cpp index f483be6..a17bdb2 100644 --- a/src/Engine/Asset/FontAsset.cpp +++ b/src/Engine/Asset/FontAsset.cpp @@ -52,8 +52,8 @@ void FontAsset::load() continue; } Glyph& glyph = glyphs[c]; - glyph.size = Math::IVector2(face->glyph->bitmap.width, face->glyph->bitmap.rows); - glyph.bearing = Math::IVector2(face->glyph->bitmap_left, face->glyph->bitmap_top); + glyph.size = IVector2(face->glyph->bitmap.width, face->glyph->bitmap.rows); + glyph.bearing = IVector2(face->glyph->bitmap_left, face->glyph->bitmap_top); glyph.advance = face->glyph->advance.x; TextureCreateInfo imageData; imageData.format = Gfx::SE_FORMAT_R8_UINT; diff --git a/src/Engine/Asset/FontAsset.h b/src/Engine/Asset/FontAsset.h index 600d274..7a50390 100644 --- a/src/Engine/Asset/FontAsset.h +++ b/src/Engine/Asset/FontAsset.h @@ -17,8 +17,8 @@ public: struct Glyph { Gfx::PTexture2D texture; - Math::IVector2 size; - Math::IVector2 bearing; + IVector2 size; + IVector2 bearing; uint32 advance; }; const std::map getGlyphData() const { return glyphs; } diff --git a/src/Engine/Asset/FontLoader.cpp b/src/Engine/Asset/FontLoader.cpp index 35744e2..14cde23 100644 --- a/src/Engine/Asset/FontLoader.cpp +++ b/src/Engine/Asset/FontLoader.cpp @@ -15,7 +15,7 @@ FontLoader::~FontLoader() { } -void FontLoader::importAsset(const std::filesystem::path& filePath) +void FontLoader::importAsset(const std::filesystem::path& filePath, const std::string& importPath) { std::filesystem::path assetPath = filePath.filename(); assetPath.replace_extension("asset"); @@ -23,12 +23,11 @@ void FontLoader::importAsset(const std::filesystem::path& filePath) std::error_code code; std::filesystem::copy_file(filePath, asset->getFullPath(), code); asset->setStatus(Asset::Status::Loading); - AssetRegistry::get().registerFont(asset); + AssetRegistry::get().registerFont(asset, importPath); import(filePath, asset); } void FontLoader::import(std::filesystem::path path, PFontAsset asset) { asset->load(); - AssetRegistry::get().registerFont(asset); } \ No newline at end of file diff --git a/src/Engine/Asset/FontLoader.h b/src/Engine/Asset/FontLoader.h index 390044f..8c20c3f 100644 --- a/src/Engine/Asset/FontLoader.h +++ b/src/Engine/Asset/FontLoader.h @@ -12,7 +12,7 @@ class FontLoader public: FontLoader(Gfx::PGraphics graphic); ~FontLoader(); - void importAsset(const std::filesystem::path& filePath); + void importAsset(const std::filesystem::path& filePath, const std::string& importPath); private: void import(std::filesystem::path path, PFontAsset asset); Gfx::PGraphics graphics; diff --git a/src/Engine/Asset/MaterialAsset.cpp b/src/Engine/Asset/MaterialAsset.cpp new file mode 100644 index 0000000..59cb3f5 --- /dev/null +++ b/src/Engine/Asset/MaterialAsset.cpp @@ -0,0 +1,41 @@ +#include "MaterialAsset.h" +#include "Material/Material.h" + +using namespace Seele; + +MaterialAsset::MaterialAsset() +{ +} + +MaterialAsset::MaterialAsset(const std::string& directory, const std::string& name) + : Asset(directory, name) +{ +} + +MaterialAsset::MaterialAsset(const std::filesystem::path& fullPath) + : Asset(fullPath) +{ +} + +MaterialAsset::~MaterialAsset() +{ +} + + +void MaterialAsset::save() +{ +} + +void MaterialAsset::load() +{ + +} + + +void MaterialAsset::beginFrame() +{ +} + +void MaterialAsset::endFrame() +{ +} diff --git a/src/Engine/Asset/MaterialAsset.h b/src/Engine/Asset/MaterialAsset.h new file mode 100644 index 0000000..faf6bf0 --- /dev/null +++ b/src/Engine/Asset/MaterialAsset.h @@ -0,0 +1,24 @@ +#pragma once +#include "Asset.h" + +namespace Seele +{ +DECLARE_REF(Material) +class MaterialAsset : public Asset +{ +public: + MaterialAsset(); + MaterialAsset(const std::string &directory, const std::string &name); + MaterialAsset(const std::filesystem::path &fullPath); + virtual ~MaterialAsset(); + virtual void beginFrame(); + virtual void endFrame(); + virtual void save() override; + virtual void load() override; + PMaterial getMaterial() const { return material; } +private: + PMaterial material; + friend class MaterialLoader; +}; +DEFINE_REF(MaterialAsset) +} // namespace Seele diff --git a/src/Engine/Asset/MaterialInstanceAsset.cpp b/src/Engine/Asset/MaterialInstanceAsset.cpp new file mode 100644 index 0000000..38682cf --- /dev/null +++ b/src/Engine/Asset/MaterialInstanceAsset.cpp @@ -0,0 +1,32 @@ +#include "MaterialInstanceAsset.h" +#include "Material/MaterialInstance.h" +#include "Material/Material.h" + +using namespace Seele; + +MaterialInstanceAsset::MaterialInstanceAsset() +{ +} + +MaterialInstanceAsset::MaterialInstanceAsset(const std::string& directory, const std::string& name) + : Asset(directory, name) +{ +} + +MaterialInstanceAsset::MaterialInstanceAsset(const std::filesystem::path& fullPath) + : Asset(fullPath) +{ +} + +MaterialInstanceAsset::~MaterialInstanceAsset() +{ +} + + +void MaterialInstanceAsset::save() +{ +} + +void MaterialInstanceAsset::load() +{ +} diff --git a/src/Engine/Asset/MaterialInstanceAsset.h b/src/Engine/Asset/MaterialInstanceAsset.h new file mode 100644 index 0000000..c5f84ed --- /dev/null +++ b/src/Engine/Asset/MaterialInstanceAsset.h @@ -0,0 +1,22 @@ +#pragma once +#include "Asset.h" +#include "Material/MaterialInstance.h" + +namespace Seele +{ +class MaterialInstanceAsset : public Asset +{ +public: + MaterialInstanceAsset(); + MaterialInstanceAsset(const std::string &directory, const std::string &name); + MaterialInstanceAsset(const std::filesystem::path &fullPath); + virtual ~MaterialInstanceAsset(); + virtual void beginFrame(); + virtual void endFrame(); + virtual void save() override; + virtual void load() override; +private: + PMaterialInstance material; +}; +DEFINE_REF(MaterialInstanceAsset) +} // namespace Seele diff --git a/src/Engine/Asset/MaterialLoader.cpp b/src/Engine/Asset/MaterialLoader.cpp index 32909f0..e679a61 100644 --- a/src/Engine/Asset/MaterialLoader.cpp +++ b/src/Engine/Asset/MaterialLoader.cpp @@ -1,37 +1,141 @@ #include "MaterialLoader.h" #include "Graphics/Graphics.h" -#include "Material/MaterialAsset.h" +#include "MaterialAsset.h" #include "AssetRegistry.h" +#include "Material/Material.h" +#include "Material/BRDF.h" +#include "Window/WindowManager.h" +#include "Material/ShaderExpression.h" +#include "TextureAsset.h" +#include using namespace Seele; +using json = nlohmann::json; MaterialLoader::MaterialLoader(Gfx::PGraphics graphics) : graphics(graphics) { - placeholderMaterial = new MaterialAsset(std::filesystem::absolute("./shaders/Placeholder.asset")); - placeholderMaterial->load(); - graphics->getShaderCompiler()->registerMaterial(placeholderMaterial); + importAsset(std::filesystem::absolute("./shaders/Placeholder.asset"), ""); } MaterialLoader::~MaterialLoader() { } -void MaterialLoader::importAsset(const std::filesystem::path& name) +void MaterialLoader::importAsset(const std::filesystem::path& name, const std::string& importPath) { std::filesystem::path assetPath = name.filename(); assetPath.replace_extension("asset"); PMaterialAsset asset = new MaterialAsset(assetPath.generic_string()); asset->setStatus(Asset::Status::Loading); - AssetRegistry::get().registerMaterial(asset); + AssetRegistry::get().registerMaterial(asset, importPath); import(name, asset); } -void MaterialLoader::import(std::filesystem::path, PMaterialAsset asset) +void MaterialLoader::import(std::filesystem::path name, PMaterialAsset asset) { - asset->load(); - graphics->getShaderCompiler()->registerMaterial(asset); - AssetRegistry::get().registerMaterial(asset); + auto stream = std::ifstream(name.c_str()); + json j; + stream >> j; + std::string materialName = j["name"].get() + "Material"; + Gfx::PDescriptorLayout layout = WindowManager::getGraphics()->createDescriptorLayout(materialName + "Layout"); + //Shader file needs to conform to the slang standard, which prohibits _ + materialName.erase(std::remove(materialName.begin(), materialName.end(), '_'), materialName.end()); + materialName.erase(std::remove(materialName.begin(), materialName.end(), '.'), materialName.end()); + std::ofstream codeStream("./shaders/generated/"+materialName+".slang"); + std::string profile = j["profile"].get(); + + codeStream << "import Material;" << std::endl; + codeStream << "import BRDF;" << std::endl; + codeStream << "import MaterialParameter;" << std::endl << std::endl; + + codeStream << "struct " << materialName << " : IMaterial {" << std::endl; + uint32 uniformBufferOffset = 0; + uint32 bindingCounter = 0; // Uniform buffers are always binding 0 + uint32 uniformBinding = -1; + Array parameters; + for(auto param : j["params"].items()) + { + std::string type = param.value()["type"].get(); + auto defaultValue = param.value().find("default"); + // TODO: ALIGNMENT RULES + if(type.compare("float") == 0) + { + PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0); + codeStream << "\tlayout(offset = " << uniformBufferOffset << ")"; + if(uniformBinding == -1) + { + layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + uniformBinding = bindingCounter++; + } + uniformBufferOffset += 4; + if(defaultValue != param.value().end()) + { + p->data = std::stof(defaultValue.value().get()); + } + parameters.add(p); + } + // TODO: ALIGNMENT RULES + else if(type.compare("float3") == 0) + { + PVectorParameter p = new VectorParameter(param.key(), uniformBufferOffset, 0); + codeStream << "\tlayout(offset = " << uniformBufferOffset << ")"; + if(uniformBinding == -1) + { + layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + uniformBinding = bindingCounter++; + } + uniformBufferOffset += 12; + if(defaultValue != param.value().end()) + { + p->data = parseVector(defaultValue.value().get().c_str()); + } + parameters.add(p); + } + else if(type.compare("Texture2D") == 0) + { + PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter); + layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + if(defaultValue != param.value().end()) + { + std::string defaultString = defaultValue.value().get(); + p->data = AssetRegistry::findTexture(defaultString); + } + if(p->data == nullptr) + { + p->data = AssetRegistry::findTexture(""); // this will return placeholder texture + } + parameters.add(p); + } + else if(type.compare("SamplerState") == 0) + { + PSamplerParameter p = new SamplerParameter(param.key(), 0, bindingCounter); + layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER); + p->data = WindowManager::getGraphics()->createSamplerState({}); + parameters.add(p); + } + else + { + std::cout << "Error unsupported parameter type" << std::endl; + } + codeStream << "\t" << type << " " << param.key() << ";\n"; + } + uint32 uniformDataSize = uniformBufferOffset; + + BRDF* brdf = BRDF::getBRDFByName(profile); + brdf->generateMaterialCode(codeStream, j["code"]); + codeStream << "};"; + codeStream.close(); + layout->create(); + asset->material = new Material( + std::move(parameters), + std::move(layout), + uniformDataSize, + uniformBinding, + materialName + ); + graphics->getShaderCompiler()->registerMaterial(asset->material); + asset->setStatus(Asset::Status::Ready); ////co_return; } diff --git a/src/Engine/Asset/MaterialLoader.h b/src/Engine/Asset/MaterialLoader.h index 1d452fd..1575535 100644 --- a/src/Engine/Asset/MaterialLoader.h +++ b/src/Engine/Asset/MaterialLoader.h @@ -12,7 +12,7 @@ class MaterialLoader public: MaterialLoader(Gfx::PGraphics graphic); ~MaterialLoader(); - void importAsset(const std::filesystem::path& name); + void importAsset(const std::filesystem::path& name, const std::string& importPath); PMaterialAsset getPlaceHolderMaterial(); private: void import(std::filesystem::path filePath, PMaterialAsset asset); diff --git a/src/Engine/Asset/MeshAsset.cpp b/src/Engine/Asset/MeshAsset.cpp index c9743b0..9d84973 100644 --- a/src/Engine/Asset/MeshAsset.cpp +++ b/src/Engine/Asset/MeshAsset.cpp @@ -1,6 +1,7 @@ #include "MeshAsset.h" #include "Graphics/Mesh.h" #include "Graphics/VertexShaderInput.h" +#include "Material/MaterialInterface.h" using namespace Seele; diff --git a/src/Engine/Asset/MeshAsset.h b/src/Engine/Asset/MeshAsset.h index 99cd912..5db9431 100644 --- a/src/Engine/Asset/MeshAsset.h +++ b/src/Engine/Asset/MeshAsset.h @@ -1,10 +1,11 @@ #pragma once #include "Asset.h" +#include "Component/Collider.h" namespace Seele { DECLARE_REF(Mesh) -DECLARE_REF(MaterialAsset) +DECLARE_REF(MaterialInterface) class MeshAsset : public Asset { public: @@ -17,8 +18,9 @@ public: void addMesh(PMesh mesh); const Array getMeshes(); //Workaround while no editor - Array referencedMaterials; + Array referencedMaterials; Array meshes; + Component::Collider physicsMesh; }; DEFINE_REF(MeshAsset) } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Asset/MeshLoader.cpp b/src/Engine/Asset/MeshLoader.cpp index 0861398..0efd4cd 100644 --- a/src/Engine/Asset/MeshLoader.cpp +++ b/src/Engine/Asset/MeshLoader.cpp @@ -5,6 +5,7 @@ #include "Graphics/Mesh.h" #include "Graphics/StaticMeshVertexInput.h" #include "AssetRegistry.h" +#include "MaterialAsset.h" #include #include #include @@ -26,17 +27,17 @@ MeshLoader::~MeshLoader() { } -void MeshLoader::importAsset(const std::filesystem::path &path) +void MeshLoader::importAsset(const std::filesystem::path &path, const std::string& importPath) { std::filesystem::path assetPath = path.filename(); assetPath.replace_extension("asset"); PMeshAsset asset = new MeshAsset(assetPath.generic_string()); asset->setStatus(Asset::Status::Loading); - AssetRegistry::get().registerMesh(asset); + AssetRegistry::get().registerMesh(asset, importPath); import(path, asset); } -void MeshLoader::loadMaterials(const aiScene* scene, Array& globalMaterials) +void MeshLoader::loadMaterials(const aiScene* scene, Array& globalMaterials) { using json = nlohmann::json; for(uint32 i = 0; i < scene->mNumMaterials; ++i) @@ -92,15 +93,13 @@ void MeshLoader::loadMaterials(const aiScene* scene, Array& glob outMatFile.close(); std::cout << "writing json to " << outMatFilename << std::endl; - PMaterialAsset result = new MaterialAsset(outMatFilename); - result->load(); - graphics->getShaderCompiler()->registerMaterial(result); - AssetRegistry::get().registerMaterial(result); - PMaterialAsset asset = AssetRegistry::findMaterial(result->getFileName()); - globalMaterials[i] = asset; + AssetRegistry::importFile(AssetRegistry::getRootFolder() + "/" + outMatFilename); + PMaterialAsset asset = AssetRegistry::findMaterial(matCode["name"].get()); + globalMaterials[i] = asset->getMaterial(); } } + void findMeshRoots(aiNode *node, List &meshNodes) { if (node->mNumMeshes > 0) @@ -115,61 +114,70 @@ void findMeshRoots(aiNode *node, List &meshNodes) } VertexStreamComponent createVertexStream(uint32 size, aiVector3D* sourceData, Gfx::PGraphics graphics) { - Array buffer(size); + Array buffer(size); for(uint32 i = 0; i < size; ++i) { - buffer[i] = Math::Vector(sourceData[i].x, sourceData[i].y, sourceData[i].z); - } + buffer[i] = Vector(sourceData[i].x, sourceData[i].y, sourceData[i].z); + } VertexBufferCreateInfo vbInfo; vbInfo.numVertices = size; - vbInfo.vertexSize = sizeof(Math::Vector); + vbInfo.vertexSize = sizeof(Vector); vbInfo.resourceData.data = (uint8 *)buffer.data(); vbInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER; - vbInfo.resourceData.size = sizeof(Math::Vector) * buffer.size(); + vbInfo.resourceData.size = sizeof(Vector) * buffer.size(); Gfx::PVertexBuffer vertexBuffer = graphics->createVertexBuffer(vbInfo); vertexBuffer->transferOwnership(Gfx::QueueType::GRAPHICS); return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32B32_SFLOAT); } VertexStreamComponent createVertexStream(uint32 size, aiVector2D* sourceData, Gfx::PGraphics graphics) { - Array buffer(size); + Array buffer(size); for(uint32 i = 0; i < size; ++i) { - buffer[i] = Math::Vector2(sourceData[i].x, sourceData[i].y); + buffer[i] = Vector2(sourceData[i].x, sourceData[i].y); } VertexBufferCreateInfo vbInfo; vbInfo.numVertices = size; - vbInfo.vertexSize = sizeof(Math::Vector2); + vbInfo.vertexSize = sizeof(Vector2); vbInfo.resourceData.data = (uint8 *)buffer.data(); vbInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER; - vbInfo.resourceData.size = sizeof(Math::Vector2) * buffer.size(); + vbInfo.resourceData.size = sizeof(Vector2) * buffer.size(); Gfx::PVertexBuffer vertexBuffer = graphics->createVertexBuffer(vbInfo); vertexBuffer->transferOwnership(Gfx::QueueType::GRAPHICS); return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32_SFLOAT); } VertexStreamComponent createVertexStream(uint32 size, aiColor4D* sourceData, Gfx::PGraphics graphics) { - Array buffer(size); + Array buffer(size); for(uint32 i = 0; i < size; ++i) { - buffer[i] = Math::Vector4(sourceData[i].r, sourceData[i].g, sourceData[i].b, sourceData[i].a); + buffer[i] = Vector4(sourceData[i].r, sourceData[i].g, sourceData[i].b, sourceData[i].a); } VertexBufferCreateInfo vbInfo; vbInfo.numVertices = size; - vbInfo.vertexSize = sizeof(Math::Vector4); + vbInfo.vertexSize = sizeof(Vector4); vbInfo.resourceData.data = (uint8 *)buffer.data(); vbInfo.resourceData.owner = Gfx::QueueType::DEDICATED_TRANSFER; - vbInfo.resourceData.size = sizeof(Math::Vector4) * buffer.size(); + vbInfo.resourceData.size = sizeof(Vector4) * buffer.size(); Gfx::PVertexBuffer vertexBuffer = graphics->createVertexBuffer(vbInfo); vertexBuffer->transferOwnership(Gfx::QueueType::GRAPHICS); - return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32_SFLOAT); + return VertexStreamComponent(vertexBuffer, 0, vbInfo.vertexSize, Gfx::SE_FORMAT_R32G32B32A32_SFLOAT); } -void MeshLoader::loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, const Array& materials) +void MeshLoader::loadGlobalMeshes(const aiScene* scene, const Array& materials, Array& globalMeshes, Component::Collider& collider) { for (uint32 meshIndex = 0; meshIndex < scene->mNumMeshes; ++meshIndex) { aiMesh *mesh = scene->mMeshes[meshIndex]; - PMaterialAsset material = materials[mesh->mMaterialIndex]; + collider.boundingbox.adjust(Vector(mesh->mAABB.mMin.x, mesh->mAABB.mMin.y, mesh->mAABB.mMin.z)); + collider.boundingbox.adjust(Vector(mesh->mAABB.mMax.x, mesh->mAABB.mMax.y, mesh->mAABB.mMax.z)); + + //! \todo duplicate from createVertexStream, clean up + Array vertices(mesh->mNumVertices); + for(uint32 i = 0; i < mesh->mNumVertices; ++i) + { + vertices[i] = Vector(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); + } + PStaticMeshVertexInput vertexShaderInput = new StaticMeshVertexInput(std::string(mesh->mName.C_Str())); StaticMeshDataType data; data.positionStream = createVertexStream(mesh->mNumVertices, mesh->mVertices, graphics); @@ -205,6 +213,9 @@ void MeshLoader::loadGlobalMeshes(const aiScene* scene, Array& globalMesh indices[faceIndex * 3 + 1] = mesh->mFaces[faceIndex].mIndices[1]; indices[faceIndex * 3 + 2] = mesh->mFaces[faceIndex].mIndices[2]; } + + collider.physicsMesh.addCollider(vertices, indices, Matrix4(1.0f)); + IndexBufferCreateInfo idxInfo; idxInfo.indexType = Gfx::SE_INDEX_TYPE_UINT32; idxInfo.resourceData.data = (uint8 *)indices.data(); @@ -259,22 +270,23 @@ void MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset) std::cout << "Starting to import "<setStatus(Asset::Status::Loading); Assimp::Importer importer; - importer.ReadFile(path.string().c_str(), + importer.ReadFile(path.string().c_str(), (uint32)( aiProcess_FlipUVs | aiProcess_Triangulate | aiProcess_SortByPType | + aiProcess_GenBoundingBoxes | aiProcess_GenSmoothNormals | aiProcess_GenUVCoords | - aiProcess_FindDegenerates); + aiProcess_FindDegenerates)); const aiScene *scene = importer.ApplyPostProcessing(aiProcess_CalcTangentSpace); - Array globalMaterials(scene->mNumMaterials); + Array globalMaterials(scene->mNumMaterials); loadTextures(scene, path.parent_path()); loadMaterials(scene, globalMaterials); Array globalMeshes(scene->mNumMeshes); - loadGlobalMeshes(scene, globalMeshes, globalMaterials); - + Component::Collider collider; + loadGlobalMeshes(scene, globalMaterials, globalMeshes, collider); List meshNodes; findMeshRoots(scene->mRootNode, meshNodes); @@ -286,6 +298,7 @@ void MeshLoader::import(std::filesystem::path path, PMeshAsset meshAsset) meshAsset->addMesh(globalMeshes[meshNode->mMeshes[i]]); } } + meshAsset->physicsMesh = std::move(collider); meshAsset->setStatus(Asset::Status::Ready); meshAsset->save(); std::cout << "Finished loading " << path << std::endl; diff --git a/src/Engine/Asset/MeshLoader.h b/src/Engine/Asset/MeshLoader.h index 7de51c8..726806f 100644 --- a/src/Engine/Asset/MeshLoader.h +++ b/src/Engine/Asset/MeshLoader.h @@ -1,6 +1,7 @@ #pragma once #include "MinimalEngine.h" #include "Containers/List.h" +#include "Component/Collider.h" #include struct aiScene; @@ -9,18 +10,18 @@ namespace Seele { DECLARE_REF(Mesh) DECLARE_REF(MeshAsset) -DECLARE_REF(MaterialAsset) +DECLARE_REF(Material) DECLARE_NAME_REF(Gfx, Graphics) class MeshLoader { public: MeshLoader(Gfx::PGraphics graphic); ~MeshLoader(); - void importAsset(const std::filesystem::path& filePath); + void importAsset(const std::filesystem::path& filePath, const std::string& importPath); private: - void loadMaterials(const aiScene* scene, Array& globalMaterials); + void loadMaterials(const aiScene* scene, Array& globalMaterials); void loadTextures(const aiScene* scene, const std::filesystem::path& meshPath); - void loadGlobalMeshes(const aiScene* scene, Array& globalMeshes, const Array& materials); + void loadGlobalMeshes(const aiScene* scene, const Array& materials, Array& globalMeshes, Component::Collider& collider); void convertAssimpARGB(unsigned char* dst, aiTexel* src, uint32 numPixels); void import(std::filesystem::path path, PMeshAsset meshAsset); diff --git a/src/Engine/Asset/TextureAsset.h b/src/Engine/Asset/TextureAsset.h index bd845da..6586a55 100644 --- a/src/Engine/Asset/TextureAsset.h +++ b/src/Engine/Asset/TextureAsset.h @@ -1,3 +1,4 @@ +#pragma once #include "Asset.h" namespace Seele diff --git a/src/Engine/Asset/TextureLoader.cpp b/src/Engine/Asset/TextureLoader.cpp index 08350d0..c51f51d 100644 --- a/src/Engine/Asset/TextureLoader.cpp +++ b/src/Engine/Asset/TextureLoader.cpp @@ -16,21 +16,21 @@ TextureLoader::TextureLoader(Gfx::PGraphics graphics) { placeholderAsset = new TextureAsset(std::filesystem::absolute("./textures/placeholder.ktx")); placeholderAsset->load(); - AssetRegistry::get().textures[""] = placeholderAsset; + AssetRegistry::get().assetRoot.textures[""] = placeholderAsset; } TextureLoader::~TextureLoader() { } -void TextureLoader::importAsset(const std::filesystem::path& path) +void TextureLoader::importAsset(const std::filesystem::path& path, const std::string& importPath) { std::filesystem::path assetPath = path.filename(); assetPath.replace_extension("asset"); PTextureAsset asset = new TextureAsset(assetPath.generic_string()); asset->setStatus(Asset::Status::Loading); asset->setTexture(placeholderAsset->getTexture()); - AssetRegistry::get().registerTexture(asset); + AssetRegistry::get().registerTexture(asset, importPath); import(path, asset); } diff --git a/src/Engine/Asset/TextureLoader.h b/src/Engine/Asset/TextureLoader.h index f527f3f..a61f16e 100644 --- a/src/Engine/Asset/TextureLoader.h +++ b/src/Engine/Asset/TextureLoader.h @@ -13,7 +13,7 @@ class TextureLoader public: TextureLoader(Gfx::PGraphics graphic); ~TextureLoader(); - void importAsset(const std::filesystem::path& filePath); + void importAsset(const std::filesystem::path& filePath, const std::string& importPath); PTextureAsset getPlaceholderTexture(); private: void import(std::filesystem::path path, PTextureAsset asset); diff --git a/src/Engine/Component/AABB.h b/src/Engine/Component/AABB.h index 2fdfcd2..7977ad7 100644 --- a/src/Engine/Component/AABB.h +++ b/src/Engine/Component/AABB.h @@ -2,16 +2,64 @@ #include "Math/Vector.h" #include "Math/Matrix.h" #include "Containers/Array.h" - +#include "Graphics/DebugVertex.h" namespace Seele { struct AABB { - Math::Vector min = Math::Vector(std::numeric_limits::max()); - Math::Vector max = Math::Vector(std::numeric_limits::min()); + Vector min = Vector(std::numeric_limits::max()); + Vector max = Vector(std::numeric_limits::lowest());// cause of reasons + void visualize(Array& vertices) const + { + StaticArray corners; + corners[0] = DebugVertex { .position = Vector(min.x, min.y, min.z), .color = Vector(0, 1, 0) }; + corners[1] = DebugVertex { .position = Vector(min.x, min.y, max.z), .color = Vector(0, 1, 0) }; + corners[2] = DebugVertex { .position = Vector(min.x, max.y, min.z), .color = Vector(0, 1, 0) }; + corners[3] = DebugVertex { .position = Vector(min.x, max.y, max.z), .color = Vector(0, 1, 0) }; + corners[4] = DebugVertex { .position = Vector(max.x, min.y, min.z), .color = Vector(0, 1, 0) }; + corners[5] = DebugVertex { .position = Vector(max.x, min.y, max.z), .color = Vector(0, 1, 0) }; + corners[6] = DebugVertex { .position = Vector(max.x, max.y, min.z), .color = Vector(0, 1, 0) }; + corners[7] = DebugVertex { .position = Vector(max.x, max.y, max.z), .color = Vector(0, 1, 0) }; + + vertices.add(corners[0]); + vertices.add(corners[1]); + + vertices.add(corners[1]); + vertices.add(corners[3]); + + vertices.add(corners[2]); + vertices.add(corners[3]); + + vertices.add(corners[0]); + vertices.add(corners[2]); + + vertices.add(corners[0]); + vertices.add(corners[4]); + + vertices.add(corners[1]); + vertices.add(corners[5]); + + vertices.add(corners[2]); + vertices.add(corners[6]); + + vertices.add(corners[3]); + vertices.add(corners[7]); + + vertices.add(corners[4]); + vertices.add(corners[5]); + + vertices.add(corners[5]); + vertices.add(corners[7]); + + vertices.add(corners[6]); + vertices.add(corners[7]); + + vertices.add(corners[4]); + vertices.add(corners[6]); + } float surfaceArea() const { - Math::Vector d = max - min; + Vector d = max - min; return 2.0f * (d.x * d.y + d.y * d.z + d.z * d.x); } bool intersects(const AABB& other) const @@ -52,31 +100,31 @@ struct AABB } return true; } - AABB getTransformedBox(const Math::Matrix4& matrix) const + AABB getTransformedBox(const Matrix4& matrix) const { - StaticArray corners; - corners[0] = Math::Vector(min.x, min.y, min.z); - corners[1] = Math::Vector(min.x, min.y, max.z); - corners[2] = Math::Vector(min.x, max.y, min.z); - corners[3] = Math::Vector(min.x, max.y, max.z); - corners[4] = Math::Vector(max.x, min.y, min.z); - corners[5] = Math::Vector(max.x, min.y, max.z); - corners[6] = Math::Vector(max.x, max.y, min.z); - corners[7] = Math::Vector(max.x, max.y, max.z); - Math::Vector tmin = Math::Vector(1, 1, 1) * std::numeric_limits::max(); - Math::Vector tmax = Math::Vector(1, 1, 1) * std::numeric_limits::min(); + StaticArray corners; + corners[0] = Vector(min.x, min.y, min.z); + corners[1] = Vector(min.x, min.y, max.z); + corners[2] = Vector(min.x, max.y, min.z); + corners[3] = Vector(min.x, max.y, max.z); + corners[4] = Vector(max.x, min.y, min.z); + corners[5] = Vector(max.x, min.y, max.z); + corners[6] = Vector(max.x, max.y, min.z); + corners[7] = Vector(max.x, max.y, max.z); + Vector tmin = Vector(1, 1, 1) * std::numeric_limits::max(); + Vector tmax = Vector(1, 1, 1) * std::numeric_limits::lowest(); for(int i = 0; i < 8; ++i) { - Math::Vector transformed = matrix * Math::Vector4(corners[i], 1.0f); - tmin = Math::Vector(std::min(tmin.x, transformed.x), std::min(tmin.y, transformed.y), std::min(tmin.z, transformed.z)); - tmax = Math::Vector(std::max(tmax.x, transformed.x), std::max(tmax.y, transformed.y), std::max(tmax.z, transformed.z)); + Vector transformed = matrix * Vector4(corners[i], 1.0f); + tmin = Vector(std::min(tmin.x, transformed.x), std::min(tmin.y, transformed.y), std::min(tmin.z, transformed.z)); + tmax = Vector(std::max(tmax.x, transformed.x), std::max(tmax.y, transformed.y), std::max(tmax.z, transformed.z)); } return AABB { .min = tmin, .max = tmax, }; } - void adjust(const Math::Vector vertex) + void adjust(const Vector vertex) { min.x = std::min(min.x, vertex.x); min.y = std::min(min.y, vertex.y); @@ -89,12 +137,12 @@ struct AABB AABB combine(const AABB& other) const { return AABB { - .min = Math::Vector( + .min = Vector( std::min(min.x, other.min.x), std::min(min.y, other.min.y), std::min(min.z, other.min.z) ), - .max = Math::Vector ( + .max = Vector ( std::max(max.x, other.max.x), std::max(max.y, other.max.y), std::max(max.z, other.max.z) diff --git a/src/Engine/Component/Camera.h b/src/Engine/Component/Camera.h index ef3bff2..4401298 100644 --- a/src/Engine/Component/Camera.h +++ b/src/Engine/Component/Camera.h @@ -15,14 +15,14 @@ struct Camera Camera(); ~Camera(); - Math::Matrix4 getViewMatrix() const + Matrix4 getViewMatrix() const { assert (!bNeedsViewBuild); return viewMatrix; } - Math::Vector getCameraPosition() const + Vector getCameraPosition() const { - return Math::Vector(viewMatrix[3]); + return Vector(viewMatrix[3]); } void setViewport(Gfx::PViewport viewport); void mouseMove(float deltaX, float deltaY); @@ -30,7 +30,7 @@ struct Camera void moveX(float amount); void moveY(float amount); void buildViewMatrix(); - Math::Matrix4 viewMatrix; + Matrix4 viewMatrix; //Transforms relative to actor float yaw; float pitch; diff --git a/src/Engine/Component/Collider.h b/src/Engine/Component/Collider.h index 86d392b..7f055b0 100644 --- a/src/Engine/Component/Collider.h +++ b/src/Engine/Component/Collider.h @@ -13,7 +13,7 @@ enum class ColliderType }; struct Collider { - ColliderType type; + ColliderType type = ColliderType::STATIC; AABB boundingbox; ShapeBase physicsMesh; Collider transform(const Transform& transform) const; diff --git a/src/Engine/Component/RigidBody.h b/src/Engine/Component/RigidBody.h index d31d0e7..11ab93c 100644 --- a/src/Engine/Component/RigidBody.h +++ b/src/Engine/Component/RigidBody.h @@ -8,10 +8,10 @@ namespace Component struct RigidBody { float mass = 1.0f; - Math::Vector force; - Math::Vector torque; - Math::Vector linearMomentum; - Math::Vector angularMomentum; + Vector force; + Vector torque; + Vector linearMomentum; + Vector angularMomentum; }; } // namespace Component } // namespace Seele diff --git a/src/Engine/Component/ShapeBase.cpp b/src/Engine/Component/ShapeBase.cpp index 40a86d7..62921eb 100644 --- a/src/Engine/Component/ShapeBase.cpp +++ b/src/Engine/Component/ShapeBase.cpp @@ -1,4 +1,5 @@ #include "ShapeBase.h" +#include "AABB.h" using namespace Seele; using namespace Seele::Component; @@ -20,13 +21,13 @@ struct ComputationState /* volume integrals */ float T0; - Math::Vector T1, T2, TP; + Vector T1, T2, TP; }; struct Face { - StaticArray vertices; - Math::Vector normal; + StaticArray vertices; + Vector normal; float w; }; @@ -126,7 +127,7 @@ void computeFaceIntegrals(Face& f, ComputationState& state) + w * (2 * (n[state.A] * state.Paa + n[state.B] * state.Pab) + w * state.Pa)); } -void computeVolumeIntegrals(const Array vertices, const Array& indices, ComputationState& state) +void computeVolumeIntegrals(const Array vertices, const Array& indices, ComputationState& state) { std::memset(&state, 0, sizeof(ComputationState)); for (size_t i = 0; i < indices.size(); i+=3) @@ -138,8 +139,8 @@ void computeVolumeIntegrals(const Array vertices, const Array vertices, const Array& vertices, const Array& indices, Math::Matrix3& bodyInertia, Math::Vector& centerOfMass, float& mass) +void computePhysicsParamsForMesh(Array& vertices, const Array& indices, Matrix3& bodyInertia, Vector& centerOfMass, float& mass) { ComputationState state; computeVolumeIntegrals(vertices, indices, state); float density = 1; mass = density * state.T0; - Math::Vector r = state.T1 / state.T0; + Vector r = state.T1 / state.T0; centerOfMass = r; bodyInertia[0][0] = density * (state.T2.y + state.T2.z); bodyInertia[1][1] = density * (state.T2.z + state.T2.x); @@ -194,7 +195,12 @@ void computePhysicsParamsForMesh(Array& vertices, const Array vertices, Array indices) +ShapeBase::ShapeBase() +{ + +} + +ShapeBase::ShapeBase(Array vertices, Array indices) : vertices(vertices) , indices(indices) { @@ -206,17 +212,17 @@ ShapeBase ShapeBase::transform(const Component::Transform& transform) const ShapeBase result = *this; for(auto& vert : result.vertices) { - vert = transform.toMatrix() * Math::Vector4(vert, 1.0f); + vert = transform.toMatrix() * Vector4(vert, 1.0f); } return result; } -void ShapeBase::addCollider(Array verts, Array inds, Math::Matrix4 matrix) +void ShapeBase::addCollider(Array verts, Array inds, Matrix4 matrix) { size_t indOffset = vertices.size(); for(auto vert : verts) { - vertices.add(Math::Vector(matrix * Math::Vector4(vert, 1.0f))); + vertices.add(Vector(matrix * Vector4(vert, 1.0f))); } for(auto ind : inds) { @@ -224,3 +230,39 @@ void ShapeBase::addCollider(Array verts, Array inds, Math: } computePhysicsParamsForMesh(vertices, indices, bodyInertia, centerOfMass, mass); } + +void ShapeBase::visualize() const +{ + for(uint32 i = 0; i < indices.size(); i+=3) + { + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+0]]), + .color = Vector(1, 0, 0), + }); + + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+1]]), + .color = Vector(1, 0, 0), + }); + + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+1]]), + .color = Vector(1, 0, 0), + }); + + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+2]]), + .color = Vector(1, 0, 0), + }); + + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+2]]), + .color = Vector(1, 0, 0), + }); + + gDebugVertices.add(DebugVertex{ + .position = Vector(vertices[indices[i+0]]), + .color = Vector(1, 0, 0), + }); + } +} diff --git a/src/Engine/Component/ShapeBase.h b/src/Engine/Component/ShapeBase.h index 2c1b006..a036c2a 100644 --- a/src/Engine/Component/ShapeBase.h +++ b/src/Engine/Component/ShapeBase.h @@ -1,6 +1,7 @@ #pragma once #include "Containers/Array.h" #include "Transform.h" +#include "Graphics/DebugVertex.h" namespace Seele { @@ -8,13 +9,15 @@ namespace Component { struct ShapeBase { - ShapeBase(Array vertices, Array indices); + ShapeBase(); + ShapeBase(Array vertices, Array indices); ShapeBase transform(const Component::Transform& transform) const; - void addCollider(Array vertices, Array indices, Math::Matrix4 matrix); - Math::Vector centerOfMass; + void addCollider(Array vertices, Array indices, Matrix4 matrix); + void visualize() const; + Vector centerOfMass; float mass; - Math::Matrix3 bodyInertia; - Array vertices; + Matrix3 bodyInertia; + Array vertices; Array indices; }; } // namespace Component diff --git a/src/Engine/Component/StaticMesh.h b/src/Engine/Component/StaticMesh.h index 2b72b5e..7a2be45 100644 --- a/src/Engine/Component/StaticMesh.h +++ b/src/Engine/Component/StaticMesh.h @@ -7,6 +7,8 @@ namespace Component { struct StaticMesh { + StaticMesh() {} + StaticMesh(PMeshAsset mesh) : mesh(mesh) {} PMeshAsset mesh; }; } // namespace Component diff --git a/src/Engine/Component/Transform.cpp b/src/Engine/Component/Transform.cpp index 792dd9e..82173f3 100644 --- a/src/Engine/Component/Transform.cpp +++ b/src/Engine/Component/Transform.cpp @@ -5,55 +5,55 @@ using namespace Seele::Component; DEFINE_COMPONENT(Transform) -void Transform::setPosition(Math::Vector pos) +void Transform::setPosition(Vector pos) { transform.setPosition(pos); dirty = true; } -void Transform::setRotation(Math::Quaternion quat) +void Transform::setRotation(Quaternion quat) { transform.setRotation(quat); dirty = true; } -void Transform::setScale(Math::Vector scale) +void Transform::setScale(Vector scale) { transform.setScale(scale); dirty = true; } -void Transform::setRelativeLocation(Math::Vector location) +void Transform::setRelativeLocation(Vector location) { transform = Math::Transform(location, transform.getRotation(), transform.getScale()); dirty = true; } -void Transform::setRelativeRotation(Math::Vector rotation) +void Transform::setRelativeRotation(Vector rotation) { - transform = Math::Transform(transform.getPosition(), Math::Quaternion(rotation), transform.getScale()); + transform = Math::Transform(transform.getPosition(), Quaternion(rotation), transform.getScale()); dirty = true; } -void Transform::setRelativeRotation(Math::Quaternion rotation) +void Transform::setRelativeRotation(Quaternion rotation) { transform = Math::Transform(transform.getPosition(), rotation, transform.getScale()); dirty = true; } -void Transform::setRelativeScale(Math::Vector scale) +void Transform::setRelativeScale(Vector scale) { transform = Math::Transform(transform.getPosition(), transform.getRotation(), scale); dirty = true; } -void Transform::addRelativeLocation(Math::Vector translation) +void Transform::addRelativeLocation(Vector translation) { transform = Math::Transform(transform.getPosition() + translation, transform.getRotation(), transform.getScale()); dirty = true; } -void Transform::addRelativeRotation(Math::Vector rotation) +void Transform::addRelativeRotation(Vector rotation) { - transform = Math::Transform(transform.getPosition(), transform.getRotation() * Math::Quaternion(rotation), transform.getScale()); + transform = Math::Transform(transform.getPosition(), transform.getRotation() * Quaternion(rotation), transform.getScale()); dirty = true; } -void Transform::addRelativeRotation(Math::Quaternion rotation) +void Transform::addRelativeRotation(Quaternion rotation) { transform = Math::Transform(transform.getPosition(), transform.getRotation() * rotation, transform.getScale()); dirty = true; diff --git a/src/Engine/Component/Transform.h b/src/Engine/Component/Transform.h index bec4f5f..6809a34 100644 --- a/src/Engine/Component/Transform.h +++ b/src/Engine/Component/Transform.h @@ -8,31 +8,31 @@ namespace Component { struct Transform { - Math::Vector getPosition() const { return transform.getPosition(); } - Math::Quaternion getRotation() const { return transform.getRotation(); } - Math::Vector getScale() const { return transform.getScale(); } + Vector getPosition() const { return transform.getPosition(); } + Quaternion getRotation() const { return transform.getRotation(); } + Vector getScale() const { return transform.getScale(); } - Math::Vector getForward() const { return transform.getForward(); } - Math::Vector getUp() const { return transform.getUp(); } - Math::Vector getRight() const { return transform.getRight(); } + Vector getForward() const { return transform.getForward(); } + Vector getUp() const { return transform.getUp(); } + Vector getRight() const { return transform.getRight(); } - Math::Matrix4 toMatrix() const { return transform.toMatrix(); } + Matrix4 toMatrix() const { return transform.toMatrix(); } bool isDirty() const { return dirty; } void clean() { dirty = false; } - void setPosition(Math::Vector pos); - void setRotation(Math::Quaternion quat); - void setScale(Math::Vector scale); + void setPosition(Vector pos); + void setRotation(Quaternion quat); + void setScale(Vector scale); - void setRelativeLocation(Math::Vector location); - void setRelativeRotation(Math::Quaternion rotation); - void setRelativeRotation(Math::Vector rotation); - void setRelativeScale(Math::Vector scale); + void setRelativeLocation(Vector location); + void setRelativeRotation(Quaternion rotation); + void setRelativeRotation(Vector rotation); + void setRelativeScale(Vector scale); - void addRelativeLocation(Math::Vector translation); - void addRelativeRotation(Math::Quaternion rotation); - void addRelativeRotation(Math::Vector rotation); + void addRelativeLocation(Vector translation); + void addRelativeRotation(Quaternion rotation); + void addRelativeRotation(Vector rotation); private: bool dirty = true; Math::Transform transform; diff --git a/src/Engine/Containers/Array.h b/src/Engine/Containers/Array.h index 5cb1756..e479e1c 100644 --- a/src/Engine/Containers/Array.h +++ b/src/Engine/Containers/Array.h @@ -156,7 +156,8 @@ public: assert(_data != nullptr); std::uninitialized_copy(init.begin(), init.end(), begin()); } - Array(const Array &other) + + constexpr Array(const Array &other) : arraySize(other.arraySize) , allocated(other.allocated) , allocator(std::allocator_traits::select_on_container_copy_construction(other.allocator)) @@ -165,7 +166,16 @@ public: assert(_data != nullptr); std::uninitialized_copy(other.begin(), other.end(), begin()); } - Array(Array &&other) noexcept + constexpr Array(const Array& other, const Allocator& alloc) + : arraySize(other.arraySize) + , allocated(other.allocated) + , allocator(alloc) + { + _data = allocateArray(other.allocated); + assert(_data != nullptr); + std::uninitialized_copy(other.begin(), other.end(), begin()); + } + constexpr Array(Array &&other) noexcept : arraySize(std::move(other.arraySize)) , allocated(std::move(other.allocated)) , allocator(std::move(other.allocator)) @@ -175,10 +185,26 @@ public: other.allocated = 0; other.arraySize = 0; } + constexpr Array(Array &&other, const Allocator& alloc) noexcept + : arraySize(std::move(other.arraySize)) + , allocated(std::move(other.allocated)) + , allocator(alloc) + { + _data = allocateArray(other.allocated); + std::uninitialized_move(other.begin(), other.end(), begin()); + other.deallocateArray(other._data, other.allocated); + other._data = nullptr; + other.allocated = 0; + other.arraySize = 0; + } Array &operator=(const Array &other) { if (this != &other) { + if (other.arraySize > allocated) + { + clear(); + } if constexpr (std::allocator_traits::propagate_on_container_copy_assignment::value ) { if (!std::allocator_traits::is_always_equal::value @@ -188,10 +214,6 @@ public: } allocator = other.allocator; } - if (other.arraySize > allocated) - { - clear(); - } if(_data == nullptr) { _data = allocateArray(other.allocated); @@ -207,14 +229,14 @@ public: { if (this != &other) { - if constexpr (std::allocator_traits::propagate_on_container_move_assignment::value) - { - allocator = std::move(other.allocator); - } if (_data != nullptr) { clear(); } + if constexpr (std::allocator_traits::propagate_on_container_move_assignment::value) + { + allocator = std::move(other.allocator); + } allocated = std::move(other.allocated); arraySize = std::move(other.arraySize); _data = other._data; @@ -395,7 +417,7 @@ public: } constexpr void resize(size_type newSize) { - resizeInternal(newSize, std::move(T())); + resizeInternal(newSize, T()); } constexpr void resize(size_type newSize, const value_type& value) { @@ -532,7 +554,7 @@ private: return _data[arraySize - 1]; } template - void resizeInternal(size_type newSize, Type&& value) noexcept + void resizeInternal(size_type newSize, const Type& value) noexcept { if (newSize <= allocated) { @@ -550,7 +572,7 @@ private: // Or construct the new elements by default for(size_type i = arraySize; i < newSize; ++i) { - std::allocator_traits::construct(allocator, &_data[i], std::move(value)); + std::allocator_traits::construct(allocator, &_data[i], value); } } arraySize = newSize; @@ -568,7 +590,7 @@ private: // As well as default initialize the others for(size_type i = arraySize; i < newSize; ++i) { - std::allocator_traits::construct(allocator, &newData[i], std::move(value)); + std::allocator_traits::construct(allocator, &newData[i], value); } deallocateArray(_data, allocated); arraySize = newSize; diff --git a/src/Engine/Containers/List.h b/src/Engine/Containers/List.h index 3b1a3e7..567636c 100644 --- a/src/Engine/Containers/List.h +++ b/src/Engine/Containers/List.h @@ -124,10 +124,46 @@ public: , beginIt(Iterator(root)) , endIt(Iterator(tail)) , _size(0) - , allocator(NodeAllocator()) + , allocator(Allocator()) { } + explicit List(const Allocator& alloc) + : root(nullptr) + , tail(nullptr) + , beginIt(Iterator(root)) + , endIt(Iterator(tail)) + , _size(0) + , allocator(alloc) + { + } + List(size_type count, const T& value = T(), const Allocator& alloc = Allocator()) + : List(alloc) + { + for(size_type i = 0; i < count; ++i) + { + add(value); + } + } + List(size_type count, const Allocator& alloc = Allocator()) + : List(alloc) + { + for(size_type i = 0; i < count; ++i) + { + add(T()); + } + } List(const List& other) + : List(std::allocator_traits::select_on_container_copy_construction(other.allocator)) + { + //TODO: improve + for(const auto& it : other) + { + add(it); + } + } + + List(const List& other, const Allocator& alloc) + : List(alloc) { //TODO: improve for(const auto& it : other) @@ -141,8 +177,19 @@ public: , beginIt(std::move(other.beginIt)) , endIt(std::move(other.endIt)) , _size(std::move(other._size)) + , allocator(std::move(other.allocator)) { - other._size = 0; + other.clear(); + } + List(List&& other, const Allocator& alloc) + : root(std::move(other.root)) + , tail(std::move(other.tail)) + , beginIt(std::move(other.beginIt)) + , endIt(std::move(other.endIt)) + , _size(std::move(other._size)) + , allocator(allocator) + { + other.clear(); } ~List() { @@ -153,6 +200,15 @@ public: if(this != &other) { clear(); + if constexpr (std::allocator_traits::propagate_on_container_copy_assignment::value ) + { + if (!std::allocator_traits::is_always_equal::value + && allocator != other.allocator) + { + clear(); + } + allocator = other.allocator; + } for(const auto& it : other) { add(it); @@ -166,6 +222,10 @@ public: if(this != &other) { clear(); + if constexpr (std::allocator_traits::propagate_on_container_move_assignment::value) + { + allocator = std::move(other.allocator); + } root = other.root; tail = other.tail; beginIt = other.beginIt; @@ -214,7 +274,7 @@ public: } // takes all elements from other and move-inserts them into // this, clearing other in the process - void moveElements(List& other) + void moveElements(List&& other) { tail->prev->next = other.root; other.root->prev = tail->prev; diff --git a/src/Engine/EngineTypes.h b/src/Engine/EngineTypes.h index 18e72fe..54037f4 100644 --- a/src/Engine/EngineTypes.h +++ b/src/Engine/EngineTypes.h @@ -1,7 +1,5 @@ #include -namespace Seele -{ typedef uint64_t uint64; typedef uint32_t uint32; typedef uint16_t uint16; @@ -11,4 +9,3 @@ typedef int64_t int64; typedef int32_t int32; typedef int16_t int16; typedef int8_t int8; -} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Graphics/CMakeLists.txt b/src/Engine/Graphics/CMakeLists.txt index a52dbbc..4c7c7a3 100644 --- a/src/Engine/Graphics/CMakeLists.txt +++ b/src/Engine/Graphics/CMakeLists.txt @@ -1,5 +1,6 @@ target_sources(Engine PRIVATE + DebugVertex.h GraphicsResources.h GraphicsResources.cpp GraphicsInitializer.h @@ -23,6 +24,7 @@ target_sources(Engine target_sources(Engine PUBLIC FILE_SET HEADERS FILES + DebugVertex.h GraphicsResources.h GraphicsInitializer.h GraphicsEnums.h diff --git a/src/Engine/Graphics/DebugVertex.h b/src/Engine/Graphics/DebugVertex.h new file mode 100644 index 0000000..565c3cd --- /dev/null +++ b/src/Engine/Graphics/DebugVertex.h @@ -0,0 +1,13 @@ +#pragma once +#include "Math/Vector.h" +#include "Containers/Array.h" + +namespace Seele +{ +struct DebugVertex +{ + Vector position; + Vector color; +}; +extern Array gDebugVertices; +} // namespace Seele diff --git a/src/Engine/Graphics/Graphics.cpp b/src/Engine/Graphics/Graphics.cpp index 5e59c6e..9b55e72 100644 --- a/src/Engine/Graphics/Graphics.cpp +++ b/src/Engine/Graphics/Graphics.cpp @@ -18,10 +18,10 @@ PVertexBuffer Graphics::getNullVertexBuffer() { VertexBufferCreateInfo createInfo; createInfo.numVertices = 1; - createInfo.vertexSize = sizeof(Math::Vector4); - Math::Vector4 data = Math::Vector4(1, 1, 1, 1); + createInfo.vertexSize = sizeof(Vector4); + Vector4 data = Vector4(1, 1, 1, 1); createInfo.resourceData.data = reinterpret_cast(&data); - createInfo.resourceData.size = sizeof(Math::Vector4); + createInfo.resourceData.size = sizeof(Vector4); nullVertexBuffer = createVertexBuffer(createInfo); } return nullVertexBuffer; diff --git a/src/Engine/Graphics/GraphicsInitializer.h b/src/Engine/Graphics/GraphicsInitializer.h index 8b33c91..037a7e0 100644 --- a/src/Engine/Graphics/GraphicsInitializer.h +++ b/src/Engine/Graphics/GraphicsInitializer.h @@ -42,7 +42,7 @@ struct WindowCreateInfo }; struct ViewportCreateInfo { - Math::URect dimensions; + URect dimensions; float fieldOfView = 1.222f; // 70 deg }; // doesnt own the data, only proxy it diff --git a/src/Engine/Graphics/GraphicsResources.cpp b/src/Engine/Graphics/GraphicsResources.cpp index e30d18e..7854c6c 100644 --- a/src/Engine/Graphics/GraphicsResources.cpp +++ b/src/Engine/Graphics/GraphicsResources.cpp @@ -2,7 +2,7 @@ #include "Graphics.h" #include "RenderPass/DepthPrepass.h" #include "RenderPass/BasePass.h" -#include "Material/MaterialAsset.h" +#include "Material/Material.h" using namespace Seele; using namespace Seele::Gfx; @@ -54,7 +54,7 @@ const ShaderCollection* ShaderMap::findShaders(PermutationId&& id) const ShaderCollection& ShaderMap::createShaders( PGraphics graphics, RenderPassType renderPass, - PMaterialAsset material, + PMaterial material, VertexInputType* vertexInput, bool /*bPositionOnly*/) { @@ -195,10 +195,11 @@ bool UniformBuffer::updateContents(const BulkResourceData& resourceData) return true; } -StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, const BulkResourceData& resourceData) +StructuredBuffer::StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, uint32 numElements, const BulkResourceData& resourceData) : Buffer(mapping, resourceData.owner) , contents(resourceData.size) , stride(stride) + , numElements(numElements) { if(resourceData.data != nullptr) { @@ -515,7 +516,7 @@ Viewport::~Viewport() { } -Math::Matrix4 Viewport::getProjectionMatrix() const +Matrix4 Viewport::getProjectionMatrix() const { if(fieldOfView > 0.0f) { diff --git a/src/Engine/Graphics/GraphicsResources.h b/src/Engine/Graphics/GraphicsResources.h index b6224fb..6f339fd 100644 --- a/src/Engine/Graphics/GraphicsResources.h +++ b/src/Engine/Graphics/GraphicsResources.h @@ -17,7 +17,7 @@ struct VertexInputStream; struct VertexStreamComponent; class VertexInputType; struct MeshBatchElement; -DECLARE_REF(MaterialAsset) +DECLARE_REF(Material) namespace Gfx { DECLARE_REF(Graphics) @@ -97,11 +97,11 @@ struct PermutationId { uint32 hash; PermutationId() + : hash(0) {} PermutationId(ShaderPermutation permutation) - { - hash = CRC::Calculate(&permutation, sizeof(ShaderPermutation), CRC::CRC_32()); - } + : hash(CRC::Calculate(&permutation, sizeof(ShaderPermutation), CRC::CRC_32())) + {} friend inline bool operator==(const PermutationId& lhs, const PermutationId& rhs) { return lhs.hash == rhs.hash; @@ -138,7 +138,7 @@ public: ShaderCollection& createShaders( PGraphics graphics, RenderPassType passName, - PMaterialAsset material, + PMaterial material, VertexInputType* vertexInput, bool bPositionOnly); private: @@ -409,7 +409,7 @@ DEFINE_REF(IndexBuffer) class StructuredBuffer : public Buffer { public: - StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, const BulkResourceData& bulkResourceData); + StructuredBuffer(QueueFamilyMapping mapping, uint32 stride, uint32 numElements, const BulkResourceData& bulkResourceData); virtual ~StructuredBuffer(); virtual bool updateContents(const BulkResourceData& resourceData); bool isDataEquals(StructuredBuffer* other) @@ -428,6 +428,10 @@ public: } return true; } + constexpr uint32 getNumElements() const + { + return numElements; + } constexpr uint32 getStride() const { return stride; @@ -439,6 +443,7 @@ protected: SeAccessFlags dstAccess, SePipelineStageFlags dstStage) = 0; Array contents; + uint32 numElements; uint32 stride; }; DEFINE_REF(StructuredBuffer) @@ -655,7 +660,7 @@ public: constexpr uint32 getSizeY() const {return sizeY;} constexpr uint32 getOffsetX() const {return offsetX;} constexpr uint32 getOffsetY() const {return offsetY;} - Math::Matrix4 getProjectionMatrix() const; + Matrix4 getProjectionMatrix() const; protected: uint32 sizeX; uint32 sizeY; diff --git a/src/Engine/Graphics/Mesh.cpp b/src/Engine/Graphics/Mesh.cpp index a1d663b..c0e1835 100644 --- a/src/Engine/Graphics/Mesh.cpp +++ b/src/Engine/Graphics/Mesh.cpp @@ -4,8 +4,8 @@ using namespace Seele; Mesh::Mesh(PVertexShaderInput vertexInput, Gfx::PIndexBuffer indexBuffer) - : indexBuffer(indexBuffer) - , vertexInput(vertexInput) + : vertexInput(vertexInput) + , indexBuffer(indexBuffer) { } diff --git a/src/Engine/Graphics/Mesh.h b/src/Engine/Graphics/Mesh.h index 00d70ba..9fc4da8 100644 --- a/src/Engine/Graphics/Mesh.h +++ b/src/Engine/Graphics/Mesh.h @@ -1,10 +1,11 @@ #pragma once #include "GraphicsResources.h" -#include "Material/MaterialAsset.h" +#include "Material/MaterialInterface.h" namespace Seele { -DECLARE_REF(MaterialAsset) +DECLARE_REF(VertexShaderInput) +DECLARE_NAME_REF(Gfx, IndexBuffer) class Mesh { public: @@ -13,7 +14,7 @@ public: Gfx::PIndexBuffer indexBuffer; PVertexShaderInput vertexInput; - PMaterialAsset referencedMaterial; + PMaterialInterface referencedMaterial; private: }; DEFINE_REF(Mesh) diff --git a/src/Engine/Graphics/MeshBatch.cpp b/src/Engine/Graphics/MeshBatch.cpp index ce1458d..d628c12 100644 --- a/src/Engine/Graphics/MeshBatch.cpp +++ b/src/Engine/Graphics/MeshBatch.cpp @@ -1,13 +1,12 @@ #include "MeshBatch.h" #include "GraphicsResources.h" #include "VertexShaderInput.h" -#include "Material/MaterialAsset.h" +#include "Material/MaterialInterface.h" using namespace Seele; MeshBatchElement::MeshBatchElement() - : uniformBuffer(nullptr) - , indexBuffer(nullptr) + : indexBuffer(nullptr) , firstIndex(0) , numPrimitives(0) , numInstances(1) diff --git a/src/Engine/Graphics/MeshBatch.h b/src/Engine/Graphics/MeshBatch.h index 9024bfa..14705b1 100644 --- a/src/Engine/Graphics/MeshBatch.h +++ b/src/Engine/Graphics/MeshBatch.h @@ -4,22 +4,16 @@ namespace Seele { DECLARE_REF(VertexShaderInput) -DECLARE_REF(MaterialAsset) +DECLARE_REF(MaterialInterface) DECLARE_NAME_REF(Gfx, VertexBuffer) DECLARE_NAME_REF(Gfx, IndexBuffer) DECLARE_NAME_REF(Gfx, UniformBuffer) struct MeshBatchElement { public: - Gfx::PUniformBuffer uniformBuffer; Gfx::PIndexBuffer indexBuffer; - - union - { - uint32* instanceRuns; - }; - + uint32 sceneDataIndex; uint32 firstIndex; uint32 numPrimitives; @@ -45,27 +39,7 @@ struct MeshBatch PVertexShaderInput vertexInput; - PMaterialAsset material; - - inline int32 getNumPrimitives() const - { - int32 count = 0; - for(uint32 index = 0; index < elements.size(); ++index) - { - if(elements[index].isInstanced && elements[index].instanceRuns) - { - for(uint32 run = 0; run < elements[index].numInstances; ++run) - { - count += elements[index].numPrimitives * (elements[index].instanceRuns[run * 2 + 1] - elements[index].instanceRuns[run * 2] - 1); - } - } - else - { - count += elements[index].numPrimitives * elements[index].numInstances; - } - } - return count; - } + PMaterialInterface material; MeshBatch(); MeshBatch(const MeshBatch& other) = default; diff --git a/src/Engine/Graphics/RenderPass/BasePass.cpp b/src/Engine/Graphics/RenderPass/BasePass.cpp index 6033a83..68efdad 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.cpp +++ b/src/Engine/Graphics/RenderPass/BasePass.cpp @@ -5,7 +5,7 @@ #include "Actor/CameraActor.h" #include "Math/Vector.h" #include "RenderGraph.h" -#include "Material/MaterialAsset.h" +#include "Material/MaterialInstance.h" using namespace Seele; @@ -29,7 +29,7 @@ void BasePassMeshProcessor::processMeshBatch( Array descriptorSets, int32 /*staticMeshId*/) { - PMaterialAsset material = batch.material; + PMaterialInterface material = batch.material; //const Gfx::MaterialShadingModel shadingModel = material->getShadingModel(); const PVertexShaderInput vertexInput = batch.vertexInput; @@ -47,12 +47,7 @@ void BasePassMeshProcessor::processMeshBatch( descriptorSets[BasePass::INDEX_MATERIAL] = materialSet; for(uint32 i = 0; i < batch.elements.size(); ++i) { - Gfx::PDescriptorSet descriptorSet = primitiveLayout->allocateDescriptorSet(); - descriptorSet->updateBuffer(0, batch.elements[i].uniformBuffer); - descriptorSet->writeChanges(); - descriptorSets[BasePass::INDEX_SCENE_DATA] = descriptorSet; buildMeshDrawCommand(batch, -// primitiveComponent, renderPass, pipelineLayout, renderCommand, @@ -104,9 +99,14 @@ BasePass::BasePass(Gfx::PGraphics graphics) descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet(); primitiveLayout = graphics->createDescriptorLayout("PrimitiveLayout"); - primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER); primitiveLayout->create(); basePassLayout->addDescriptorLayout(INDEX_SCENE_DATA, primitiveLayout); + basePassLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = (Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT), + .offset = 0, + .size = sizeof(uint32), + }); } BasePass::~BasePass() @@ -121,13 +121,17 @@ void BasePass::beginFrame(const Component::Camera& cam) viewParams.viewMatrix = cam.getViewMatrix(); viewParams.projectionMatrix = viewport->getProjectionMatrix(); - viewParams.cameraPosition = Math::Vector4(cam.getCameraPosition(), 0); - viewParams.screenDimensions = Math::Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); + viewParams.cameraPosition = Vector4(cam.getCameraPosition(), 0); + viewParams.screenDimensions = Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); uniformUpdate.size = sizeof(ViewParameter); uniformUpdate.data = (uint8*)&viewParams; viewParamBuffer->updateContents(uniformUpdate); viewLayout->reset(); lightLayout->reset(); + + descriptorSets[INDEX_SCENE_DATA] = primitiveLayout->allocateDescriptorSet(); + descriptorSets[INDEX_SCENE_DATA]->updateBuffer(0, passData.sceneDataBuffer); + descriptorSets[INDEX_SCENE_DATA]->writeChanges(); descriptorSets[INDEX_LIGHT_ENV] = lightLayout->allocateDescriptorSet(); descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet(); descriptorSets[INDEX_VIEW_PARAMS]->updateBuffer(0, viewParamBuffer); @@ -152,6 +156,7 @@ void BasePass::render() descriptorSets[INDEX_LIGHT_ENV]->updateBuffer(4, oLightIndexList); descriptorSets[INDEX_LIGHT_ENV]->updateTexture(5, oLightGrid); descriptorSets[INDEX_LIGHT_ENV]->writeChanges(); + graphics->beginRenderPass(renderPass); for (auto &&meshBatch : passData.staticDrawList) { diff --git a/src/Engine/Graphics/RenderPass/BasePass.h b/src/Engine/Graphics/RenderPass/BasePass.h index 2efb8a3..e8c42dd 100644 --- a/src/Engine/Graphics/RenderPass/BasePass.h +++ b/src/Engine/Graphics/RenderPass/BasePass.h @@ -29,6 +29,7 @@ DECLARE_REF(CameraActor) struct BasePassData { Array staticDrawList; + Gfx::PStructuredBuffer sceneDataBuffer; }; class BasePass : public RenderPass { diff --git a/src/Engine/Graphics/RenderPass/CMakeLists.txt b/src/Engine/Graphics/RenderPass/CMakeLists.txt index ee97bc7..70cea3d 100644 --- a/src/Engine/Graphics/RenderPass/CMakeLists.txt +++ b/src/Engine/Graphics/RenderPass/CMakeLists.txt @@ -2,6 +2,8 @@ target_sources(Engine PRIVATE BasePass.h BasePass.cpp + DebugPass.h + DebugPass.cpp DepthPrepass.h DepthPrepass.cpp LightCullingPass.h @@ -21,6 +23,7 @@ target_sources(Engine PUBLIC FILE_SET HEADERS FILES BasePass.h + DebugPass.h DepthPrepass.h LightCullingPass.h MeshProcessor.h diff --git a/src/Engine/Graphics/RenderPass/DebugPass.cpp b/src/Engine/Graphics/RenderPass/DebugPass.cpp new file mode 100644 index 0000000..d148daa --- /dev/null +++ b/src/Engine/Graphics/RenderPass/DebugPass.cpp @@ -0,0 +1,132 @@ +#include "DebugPass.h" +#include "Graphics/Graphics.h" + +using namespace Seele; + +Array Seele::gDebugVertices; + +DebugPass::DebugPass(Gfx::PGraphics graphics) + : RenderPass(graphics) +{ + +} +DebugPass::~DebugPass() +{ + +} + +void DebugPass::beginFrame(const Component::Camera& cam) +{ + BulkResourceData uniformUpdate; + + viewParams.viewMatrix = cam.getViewMatrix(); + viewParams.projectionMatrix = viewport->getProjectionMatrix(); + viewParams.cameraPosition = Vector4(cam.getCameraPosition(), 0); + viewParams.screenDimensions = Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); + uniformUpdate.size = sizeof(ViewParameter); + uniformUpdate.data = (uint8*)&viewParams; + viewParamsBuffer->updateContents(uniformUpdate); + descriptorLayout->reset(); + descriptorSet = descriptorLayout->allocateDescriptorSet(); + descriptorSet->updateBuffer(0, viewParamsBuffer); + descriptorSet->writeChanges(); + + VertexBufferCreateInfo vertexBufferInfo = { + .resourceData = { + .size = sizeof(DebugVertex) * passData.vertices.size(), + .data = (uint8*)passData.vertices.data(), + }, + .vertexSize = sizeof(DebugVertex), + .numVertices = (uint32)passData.vertices.size(), + }; + debugVertices = graphics->createVertexBuffer(vertexBufferInfo); + +} + +void DebugPass::render() +{ + graphics->beginRenderPass(renderPass); + Gfx::PRenderCommand renderCommand = graphics->createRenderCommand("DebugRender"); + renderCommand->setViewport(viewport); + renderCommand->bindPipeline(pipeline); + renderCommand->bindDescriptor(descriptorSet); + renderCommand->bindVertexBuffer({VertexInputStream(0, 0, debugVertices)}); + renderCommand->draw((uint32)passData.vertices.size(), 1, 0, 0); + graphics->executeCommands(Array{renderCommand}); + graphics->endRenderPass(); +} + +void DebugPass::endFrame() +{ + +} + +void DebugPass::publishOutputs() +{ + UniformBufferCreateInfo viewCreateInfo = { + .resourceData = BulkResourceData { + .size = sizeof(ViewParameter), + .data = nullptr, + }, + .bDynamic = true + }; + viewParamsBuffer = graphics->createUniformBuffer(viewCreateInfo); + + descriptorLayout = graphics->createDescriptorLayout("DebugDescLayout"); + descriptorLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + descriptorLayout->create(); + + pipelineLayout = graphics->createPipelineLayout(); + pipelineLayout->addDescriptorLayout(0, descriptorLayout); + pipelineLayout->create(); +} + +void DebugPass::createRenderPass() +{ + Gfx::PRenderTargetAttachment baseColorAttachment = resources->requestRenderTarget("BASEPASS_COLOR"); + baseColorAttachment->loadOp = Gfx::SE_ATTACHMENT_LOAD_OP_LOAD; + Gfx::PRenderTargetAttachment depthAttachment = resources->requestRenderTarget("DEPTHPREPASS_DEPTH"); + depthAttachment->loadOp = Gfx::SE_ATTACHMENT_LOAD_OP_LOAD; + Gfx::PRenderTargetLayout layout = new Gfx::RenderTargetLayout(baseColorAttachment, depthAttachment); + renderPass = graphics->createRenderPass(layout, viewport); + + ShaderCreateInfo createInfo; + createInfo.name = "DebugVertex"; + createInfo.mainModule = "Debug"; + createInfo.entryPoint = "vertexMain"; + createInfo.defines["INDEX_VIEW_PARAMS"] = "0"; + Gfx::PVertexShader vertexShader = graphics->createVertexShader(createInfo); + + createInfo.name = "DebugFragment"; + + createInfo.entryPoint = "fragmentMain"; + Gfx::PFragmentShader fragmentShader = graphics->createFragmentShader(createInfo); + + Gfx::PVertexDeclaration vertexDecl = graphics->createVertexDeclaration({ + Gfx::VertexElement { + .streamIndex = 0, + .offset = offsetof(DebugVertex, position), + .vertexFormat = Gfx::SE_FORMAT_R32G32B32_SFLOAT, + .attributeIndex = 0, + .stride = sizeof(DebugVertex), + }, + Gfx::VertexElement { + .streamIndex = 0, + .offset = offsetof(DebugVertex, color), + .vertexFormat = Gfx::SE_FORMAT_R32G32B32_SFLOAT, + .attributeIndex = 1, + .stride = sizeof(DebugVertex), + } + }); + + GraphicsPipelineCreateInfo gfxInfo; + gfxInfo.vertexDeclaration = vertexDecl; + gfxInfo.vertexShader = vertexShader; + gfxInfo.fragmentShader = fragmentShader; + gfxInfo.rasterizationState.polygonMode = Gfx::SE_POLYGON_MODE_LINE; + gfxInfo.rasterizationState.lineWidth = 5.f; + gfxInfo.topology = Gfx::SE_PRIMITIVE_TOPOLOGY_LINE_LIST; + gfxInfo.pipelineLayout = pipelineLayout; + gfxInfo.renderPass = renderPass; + pipeline = graphics->createGraphicsPipeline(gfxInfo); +} diff --git a/src/Engine/Graphics/RenderPass/DebugPass.h b/src/Engine/Graphics/RenderPass/DebugPass.h new file mode 100644 index 0000000..bf7ef5e --- /dev/null +++ b/src/Engine/Graphics/RenderPass/DebugPass.h @@ -0,0 +1,35 @@ +#pragma once +#include "RenderPass.h" +#include "Graphics/GraphicsResources.h" +#include "Scene/Scene.h" +#include "Graphics/DebugVertex.h" + +namespace Seele +{ +DECLARE_REF(CameraActor) +DECLARE_REF(Scene) +DECLARE_REF(Viewport) +struct DebugPassData +{ + Array vertices; +}; +class DebugPass : public RenderPass +{ +public: + DebugPass(Gfx::PGraphics graphics); + virtual ~DebugPass(); + virtual void beginFrame(const Component::Camera& cam) override; + virtual void render() override; + virtual void endFrame() override; + virtual void publishOutputs() override; + virtual void createRenderPass() override; +private: + Gfx::PVertexBuffer debugVertices; + Gfx::PUniformBuffer viewParamsBuffer; + Gfx::PDescriptorLayout descriptorLayout; + Gfx::PDescriptorSet descriptorSet; + Gfx::PPipelineLayout pipelineLayout; + Gfx::PGraphicsPipeline pipeline; +}; +DEFINE_REF(DebugPass) +} // namespace Seele diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp index 759ecab..1d214f6 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.cpp +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.cpp @@ -5,7 +5,7 @@ #include "Actor/CameraActor.h" #include "Math/Vector.h" #include "RenderGraph.h" -#include "Material/MaterialAsset.h" +#include "Material/MaterialInterface.h" using namespace Seele; @@ -28,7 +28,7 @@ void DepthPrepassMeshProcessor::processMeshBatch( int32 /*staticMeshId*/) { //std::cout << "Depth void started" << std::endl; - PMaterialAsset material = batch.material; + PMaterialInterface material = batch.material; //const Gfx::MaterialShadingModel shadingModel = material->getShadingModel(); const PVertexShaderInput vertexInput = batch.vertexInput; @@ -44,11 +44,7 @@ void DepthPrepassMeshProcessor::processMeshBatch( Gfx::PDescriptorSet materialSet = material->createDescriptorSet(); descriptorSets[DepthPrepass::INDEX_MATERIAL] = materialSet; for(uint32 i = 0; i < batch.elements.size(); ++i) - { - Gfx::PDescriptorSet descriptorSet = primitiveLayout->allocateDescriptorSet(); - descriptorSet->updateBuffer(0, batch.elements[i].uniformBuffer); - descriptorSet->writeChanges(); - descriptorSets[DepthPrepass::INDEX_SCENE_DATA] = descriptorSet; + { buildMeshDrawCommand(batch, // primitiveComponent, renderPass, @@ -87,9 +83,14 @@ DepthPrepass::DepthPrepass(Gfx::PGraphics graphics) depthPrepassLayout->addDescriptorLayout(INDEX_VIEW_PARAMS, viewLayout); primitiveLayout = graphics->createDescriptorLayout("PrimitiveLayout"); - primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + primitiveLayout->addDescriptorBinding(0, Gfx::SE_DESCRIPTOR_TYPE_STORAGE_BUFFER); primitiveLayout->create(); depthPrepassLayout->addDescriptorLayout(INDEX_SCENE_DATA, primitiveLayout); + depthPrepassLayout->addPushConstants(Gfx::SePushConstantRange{ + .stageFlags = (Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT), + .offset = 0, + .size = sizeof(uint32), + }); } DepthPrepass::~DepthPrepass() @@ -104,12 +105,15 @@ void DepthPrepass::beginFrame(const Component::Camera& cam) viewParams.viewMatrix = cam.getViewMatrix(); viewParams.projectionMatrix = viewport->getProjectionMatrix(); - viewParams.cameraPosition = Math::Vector4(cam.getCameraPosition(), 0); - viewParams.screenDimensions = Math::Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); + viewParams.cameraPosition = Vector4(cam.getCameraPosition(), 0); + viewParams.screenDimensions = Vector2(static_cast(viewport->getSizeX()), static_cast(viewport->getSizeY())); uniformUpdate.size = sizeof(ViewParameter); uniformUpdate.data = (uint8*)&viewParams; viewParamBuffer->updateContents(uniformUpdate); viewLayout->reset(); + descriptorSets[INDEX_SCENE_DATA] = primitiveLayout->allocateDescriptorSet(); + descriptorSets[INDEX_SCENE_DATA]->updateBuffer(0, passData.sceneDataBuffer); + descriptorSets[INDEX_SCENE_DATA]->writeChanges(); descriptorSets[INDEX_VIEW_PARAMS] = viewLayout->allocateDescriptorSet(); descriptorSets[INDEX_VIEW_PARAMS]->updateBuffer(0, viewParamBuffer); descriptorSets[INDEX_VIEW_PARAMS]->writeChanges(); diff --git a/src/Engine/Graphics/RenderPass/DepthPrepass.h b/src/Engine/Graphics/RenderPass/DepthPrepass.h index d597a69..0fc97c5 100644 --- a/src/Engine/Graphics/RenderPass/DepthPrepass.h +++ b/src/Engine/Graphics/RenderPass/DepthPrepass.h @@ -26,6 +26,7 @@ DEFINE_REF(DepthPrepassMeshProcessor) struct DepthPrepassData { Array staticDrawList; + Gfx::PStructuredBuffer sceneDataBuffer; }; class DepthPrepass : public RenderPass { diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp index 9f9de52..20cd06b 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.cpp +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.cpp @@ -25,8 +25,8 @@ void LightCullingPass::beginFrame(const Component::Camera& cam) BulkResourceData uniformUpdate; viewParams.viewMatrix = cam.getViewMatrix(); viewParams.projectionMatrix = viewport->getProjectionMatrix(); - viewParams.cameraPosition = Math::Vector4(cam.getCameraPosition(), 0); - viewParams.screenDimensions = Math::Vector2(static_cast(viewportWidth), static_cast(viewportHeight)); + viewParams.cameraPosition = Vector4(cam.getCameraPosition(), 0); + viewParams.screenDimensions = Vector2(static_cast(viewportWidth), static_cast(viewportHeight)); uniformUpdate.size = sizeof(ViewParameter); uniformUpdate.data = (uint8*)&viewParams; viewParamsBuffer->updateContents(uniformUpdate); @@ -261,9 +261,9 @@ void LightCullingPass::setupFrustums() glm::uvec3 numThreadGroups = glm::ceil(glm::vec3(numThreads.x / (float)BLOCK_SIZE, numThreads.y / (float)BLOCK_SIZE, 1)); viewParams = { - .viewMatrix = Math::Matrix4(), - .projectionMatrix = Math::Matrix4(), - .cameraPosition = Math::Vector4(), + .viewMatrix = Matrix4(), + .projectionMatrix = Matrix4(), + .cameraPosition = Vector4(), .screenDimensions = glm::vec2(viewportWidth, viewportHeight), }; dispatchParams.numThreads = numThreads; diff --git a/src/Engine/Graphics/RenderPass/LightCullingPass.h b/src/Engine/Graphics/RenderPass/LightCullingPass.h index 03801ab..c011c0d 100644 --- a/src/Engine/Graphics/RenderPass/LightCullingPass.h +++ b/src/Engine/Graphics/RenderPass/LightCullingPass.h @@ -36,7 +36,7 @@ private: } dispatchParams; struct Plane { - Math::Vector n; + Vector n; float d; }; struct Frustum diff --git a/src/Engine/Graphics/RenderPass/MeshProcessor.cpp b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp index 910de4d..ad5f24e 100644 --- a/src/Engine/Graphics/RenderPass/MeshProcessor.cpp +++ b/src/Engine/Graphics/RenderPass/MeshProcessor.cpp @@ -56,10 +56,18 @@ void MeshProcessor::buildMeshDrawCommand( drawCommand->bindPipeline(pipeline); drawCommand->bindVertexBuffer(vertexStreams); drawCommand->bindDescriptor(descriptors); - for(auto element : meshBatch.elements) + for(const auto& element : meshBatch.elements) { - drawCommand->bindIndexBuffer(element.indexBuffer); - drawCommand->draw(element); + drawCommand->pushConstants(pipelineLayout, Gfx::SE_SHADER_STAGE_VERTEX_BIT | Gfx::SE_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(uint32), &element.sceneDataIndex); + if(element.indexBuffer != nullptr) + { + drawCommand->bindIndexBuffer(element.indexBuffer); + drawCommand->draw(element); + } + else + { + drawCommand->draw(vertexStreams[0].vertexBuffer->getNumVertices(), 1, 0, 0); + } } } diff --git a/src/Engine/Graphics/RenderPass/RenderPass.h b/src/Engine/Graphics/RenderPass/RenderPass.h index 811e568..c820051 100644 --- a/src/Engine/Graphics/RenderPass/RenderPass.h +++ b/src/Engine/Graphics/RenderPass/RenderPass.h @@ -35,11 +35,11 @@ public: protected: struct ViewParameter { - Math::Matrix4 viewMatrix; - Math::Matrix4 projectionMatrix; - Math::Vector4 cameraPosition; - Math::Vector2 screenDimensions; - Math::Vector2 pad0; + Matrix4 viewMatrix; + Matrix4 projectionMatrix; + Vector4 cameraPosition; + Vector2 screenDimensions; + Vector2 pad0; } viewParams; PRenderGraphResources resources; RenderPassDataType passData; diff --git a/src/Engine/Graphics/RenderPass/TextPass.cpp b/src/Engine/Graphics/RenderPass/TextPass.cpp index 9514ed4..ff59698 100644 --- a/src/Engine/Graphics/RenderPass/TextPass.cpp +++ b/src/Engine/Graphics/RenderPass/TextPass.cpp @@ -27,8 +27,8 @@ void TextPass::beginFrame(const Component::Camera&) for(uint32 c : render.text) { const GlyphData& glyph = fd.glyphDataSet[fd.characterToGlyphIndex[c]]; - Math::Vector2 bearing = glyph.bearing; - Math::Vector2 size = glyph.size; + Vector2 bearing = glyph.bearing; + Vector2 size = glyph.size; float xpos = x + bearing.x * render.scale; float ypos = y - (size.y - bearing.y) * render.scale; @@ -36,8 +36,8 @@ void TextPass::beginFrame(const Component::Camera&) float h = size.y * render.scale; instanceData.add(GlyphInstanceData{ - .position = Math::Vector2(xpos, ypos), - .widthHeight = Math::Vector2(w, h), + .position = Vector2(xpos, ypos), + .widthHeight = Vector2(w, h), .glyphIndex = fd.characterToGlyphIndex[c], }); x += (glyph.advance >> 6) * render.scale; @@ -61,7 +61,7 @@ void TextPass::beginFrame(const Component::Camera&) } auto proj = viewport->getProjectionMatrix(); BulkResourceData projectionUpdate = { - .size = sizeof(Math::Matrix4), + .size = sizeof(Matrix4), .data = (uint8*)&proj, }; projectionBuffer->updateContents(projectionUpdate); @@ -157,7 +157,7 @@ void TextPass::createRenderPass() projectionBuffer = graphics->createUniformBuffer({ .resourceData = { - .size = sizeof(Math::Matrix4), + .size = sizeof(Matrix4), .data = nullptr, }, .bDynamic = true, diff --git a/src/Engine/Graphics/RenderPass/TextPass.h b/src/Engine/Graphics/RenderPass/TextPass.h index 1bdf590..fd8a829 100644 --- a/src/Engine/Graphics/RenderPass/TextPass.h +++ b/src/Engine/Graphics/RenderPass/TextPass.h @@ -13,8 +13,8 @@ struct TextRender { std::string text; PFontAsset font; - Math::Vector4 textColor; - Math::Vector2 position; + Vector4 textColor; + Vector2 position; float scale; }; struct TextPassData @@ -35,19 +35,19 @@ public: private: struct GlyphData { - Math::Vector2 bearing; - Math::Vector2 size; + Vector2 bearing; + Vector2 size; uint32 advance; }; struct GlyphInstanceData { - Math::Vector2 position; - Math::Vector2 widthHeight; + Vector2 position; + Vector2 widthHeight; uint32 glyphIndex; }; struct TextData { - Math::Vector4 textColor; + Vector4 textColor; float scale; }; struct FontData diff --git a/src/Engine/Graphics/RenderPass/UIPass.cpp b/src/Engine/Graphics/RenderPass/UIPass.cpp index 7e0d9a0..18ae0ac 100644 --- a/src/Engine/Graphics/RenderPass/UIPass.cpp +++ b/src/Engine/Graphics/RenderPass/UIPass.cpp @@ -144,10 +144,10 @@ void UIPass::createRenderPass() descriptorLayout->addDescriptorBinding(3, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 256, Gfx::SE_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT | Gfx::SE_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT); descriptorLayout->create(); - Math::Matrix4 projectionMatrix = glm::ortho(0, 1, 1, 0); + Matrix4 projectionMatrix = glm::ortho(0, 1, 1, 0); UniformBufferCreateInfo info = { .resourceData = { - .size = sizeof(Math::Matrix4), + .size = sizeof(Matrix4), .data = (uint8*)&projectionMatrix, }, .bDynamic = false, diff --git a/src/Engine/Graphics/ShaderCompiler.cpp b/src/Engine/Graphics/ShaderCompiler.cpp index 99000bb..008bba6 100644 --- a/src/Engine/Graphics/ShaderCompiler.cpp +++ b/src/Engine/Graphics/ShaderCompiler.cpp @@ -1,5 +1,4 @@ #include "ShaderCompiler.h" -#include "Material/MaterialAsset.h" #include "VertexShaderInput.h" #include "Graphics.h" @@ -17,7 +16,7 @@ ShaderCompiler::~ShaderCompiler() } -void ShaderCompiler::registerMaterial(PMaterialAsset material) +void ShaderCompiler::registerMaterial(PMaterial material) { for(auto& type : VertexInputType::getTypeList()) { diff --git a/src/Engine/Graphics/ShaderCompiler.h b/src/Engine/Graphics/ShaderCompiler.h index 8216c61..02ada7c 100644 --- a/src/Engine/Graphics/ShaderCompiler.h +++ b/src/Engine/Graphics/ShaderCompiler.h @@ -1,4 +1,5 @@ #pragma once +#include "Material/Material.h" #include "GraphicsResources.h" namespace Seele @@ -11,9 +12,9 @@ class ShaderCompiler public: ShaderCompiler(PGraphics graphics); ~ShaderCompiler(); - void registerMaterial(PMaterialAsset material); + void registerMaterial(PMaterial material); private: - Array pendingCompiles; + Array pendingCompiles; PGraphics graphics; }; DEFINE_REF(ShaderCompiler) diff --git a/src/Engine/Graphics/VertexShaderInput.cpp b/src/Engine/Graphics/VertexShaderInput.cpp index f2cc2c3..27bc739 100644 --- a/src/Engine/Graphics/VertexShaderInput.cpp +++ b/src/Engine/Graphics/VertexShaderInput.cpp @@ -6,16 +6,16 @@ using namespace Seele; -List VertexInputType::globalTypeList; List& VertexInputType::getTypeList() { + static List globalTypeList; return globalTypeList; } VertexInputType* VertexInputType::getVertexInputByName(const std::string& name) { - for(auto type : globalTypeList) + for(auto type : getTypeList()) { if(name.compare(type->getName()) == 0) { @@ -30,12 +30,12 @@ VertexInputType::VertexInputType(const char* name, : name(name) , shaderFilename(shaderFilename) { - globalTypeList.add(this); + getTypeList().add(this); } VertexInputType::~VertexInputType() { - globalTypeList.remove(globalTypeList.find(this)); + getTypeList().remove(getTypeList().find(this)); } const char* VertexInputType::getName() diff --git a/src/Engine/Graphics/VertexShaderInput.h b/src/Engine/Graphics/VertexShaderInput.h index cee2345..1d3eb4c 100644 --- a/src/Engine/Graphics/VertexShaderInput.h +++ b/src/Engine/Graphics/VertexShaderInput.h @@ -95,8 +95,6 @@ public: private: const char* name; const char* shaderFilename; - - static List globalTypeList; }; #define DECLARE_VERTEX_INPUT_TYPE(inputClass) \ diff --git a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp index 8903e44..1f638f7 100644 --- a/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanAllocator.cpp @@ -95,7 +95,7 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice VkDeviceSize allocatedOffset = it.first; PSubAllocation freeAllocation = it.second; assert(allocatedOffset == freeAllocation->allocatedOffset); - VkDeviceSize alignedOffset = Math::align(allocatedOffset, alignment); + VkDeviceSize alignedOffset = align(allocatedOffset, alignment); VkDeviceSize alignmentAdjustment = alignedOffset - allocatedOffset; VkDeviceSize size = alignmentAdjustment + requestedSize; if (freeAllocation->size == size) @@ -113,8 +113,8 @@ PSubAllocation Allocation::getSuballocation(VkDeviceSize requestedSize, VkDevice freeAllocation->alignedOffset += size; PSubAllocation subAlloc = new SubAllocation(this, allocatedOffset, size, alignedOffset, size); activeAllocations[allocatedOffset] = subAlloc.getHandle(); - freeRanges[freeAllocation->allocatedOffset] = freeAllocation; freeRanges.erase(allocatedOffset); + freeRanges[freeAllocation->allocatedOffset] = freeAllocation; bytesUsed += size; return subAlloc; } diff --git a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp index 18bc9c6..de2dbcf 100644 --- a/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp +++ b/src/Engine/Graphics/Vulkan/VulkanBuffer.cpp @@ -363,7 +363,7 @@ VkAccessFlags UniformBuffer::getDestAccessMask() } StructuredBuffer::StructuredBuffer(PGraphics graphics, const StructuredBufferCreateInfo &resourceData) - : Gfx::StructuredBuffer(graphics->getFamilyMapping(), resourceData.stride, resourceData.resourceData) + : Gfx::StructuredBuffer(graphics->getFamilyMapping(), resourceData.stride, resourceData.resourceData.size / resourceData.stride, resourceData.resourceData) , Vulkan::ShaderBuffer(graphics, resourceData.resourceData.size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, currentOwner, resourceData.bDynamic) { if (resourceData.resourceData.data != nullptr) @@ -380,6 +380,7 @@ StructuredBuffer::~StructuredBuffer() bool StructuredBuffer::updateContents(const BulkResourceData &resourceData) { + assert(resourceData.size <= getSize()); Gfx::StructuredBuffer::updateContents(resourceData); //We always want to update, as the contents could be different on the GPU void* data = lock(); diff --git a/src/Engine/Material/CMakeLists.txt b/src/Engine/Material/CMakeLists.txt index 7a9e3e9..6f41849 100644 --- a/src/Engine/Material/CMakeLists.txt +++ b/src/Engine/Material/CMakeLists.txt @@ -2,8 +2,12 @@ target_sources(Engine PRIVATE BRDF.h BRDF.cpp - MaterialAsset.h - MaterialAsset.cpp + Material.h + Material.cpp + MaterialInstance.h + MaterialInstance.cpp + MaterialInterface.h + MaterialInterface.cpp ShaderExpression.h ShaderExpression.cpp) @@ -11,6 +15,8 @@ target_sources(Engine PUBLIC FILE_SET HEADERS FILES BRDF.h - MaterialAsset.h + Material.h + MaterialInstance.h + MaterialInterface.h ShaderExpression.h) diff --git a/src/Engine/Material/Material.cpp b/src/Engine/Material/Material.cpp new file mode 100644 index 0000000..43b7ddf --- /dev/null +++ b/src/Engine/Material/Material.cpp @@ -0,0 +1,60 @@ +#include "Material.h" +#include "Window/WindowManager.h" +#include "MaterialInstance.h" + +using namespace Seele; + +Gfx::ShaderMap Material::shaderMap; +std::mutex Material::shaderMapLock; + +Material::Material(Array parameter, Gfx::PDescriptorLayout layout, uint32 uniformDataSize, uint32 uniformBinding, std::string materialName) + : MaterialInterface(parameter, uniformDataSize, uniformBinding) + , layout(layout) + , materialName(materialName) +{ +} + +Material::~Material() +{ +} + +Gfx::PDescriptorSet Material::createDescriptorSet() +{ + Gfx::PDescriptorSet descriptorSet = layout->allocateDescriptorSet(); + BulkResourceData uniformUpdate = { + .size = uniformDataSize, + .data = (uint8*)uniformData.data(), + }; + for(auto param : parameters) + { + param->updateDescriptorSet(descriptorSet, uniformData.data()); + } + if(uniformUpdate.size != 0) + { + uniformBuffer->updateContents(uniformUpdate); + descriptorSet->updateBuffer(uniformBinding, uniformBuffer); + } + descriptorSet->writeChanges(); + return descriptorSet; +} + +PMaterialInstance Material::instantiate() +{ + return new MaterialInstance(this); +} + +const Gfx::ShaderCollection* Material::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const +{ + Gfx::ShaderPermutation permutation; + permutation.passType = renderPass; + std::string vertexInputName = vertexInput->getName(); + std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName)); + std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName)); + return shaderMap.findShaders(Gfx::PermutationId(permutation)); +} + +Gfx::ShaderCollection& Material::createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput) +{ + std::scoped_lock l(shaderMapLock); + return shaderMap.createShaders(graphics, renderPass, this, vertexInput, false); +} diff --git a/src/Engine/Material/Material.h b/src/Engine/Material/Material.h new file mode 100644 index 0000000..fe53b30 --- /dev/null +++ b/src/Engine/Material/Material.h @@ -0,0 +1,32 @@ +#pragma once +#include "MaterialInterface.h" + +namespace Seele +{ +DECLARE_REF(MaterialInstance) +class Material : public MaterialInterface +{ +public: + Material(Array parameter, Gfx::PDescriptorLayout layout, uint32 uniformDataSize, uint32 uniformBinding, std::string materialName); + virtual ~Material(); + virtual Gfx::PDescriptorSet createDescriptorSet(); + virtual Gfx::PDescriptorLayout getDescriptorLayout() const { return layout; } + virtual const std::string& getName() { return materialName; } + + PMaterialInstance instantiate(); + + virtual const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const; + virtual Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput); +private: + static Gfx::ShaderMap shaderMap; + static std::mutex shaderMapLock; + + Gfx::PDescriptorLayout layout; + std::string materialName; + // With draw-indirect, we batch vertex data into big vertex buffers + // Gfx::PVertexDataManager vertexData; + + friend class MaterialInstance; +}; +DEFINE_REF(Material) +} // namespace Seele diff --git a/src/Engine/Material/MaterialAsset.cpp b/src/Engine/Material/MaterialAsset.cpp deleted file mode 100644 index 9bbd725..0000000 --- a/src/Engine/Material/MaterialAsset.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "MaterialAsset.h" -#include "Window/WindowManager.h" -#include "Asset/AssetRegistry.h" -#include "Asset/TextureAsset.h" -#include "BRDF.h" -#include -#include -#include - -using namespace Seele; - -Seele::Gfx::ShaderMap MaterialAsset::shaderMap; -std::mutex MaterialAsset::shaderMapLock; - -using json = nlohmann::json; - -using namespace Seele; - -MaterialAsset::MaterialAsset() -{ -} - -MaterialAsset::MaterialAsset(const std::string& directory, const std::string& name) - : Asset(directory, name) -{ -} - -MaterialAsset::MaterialAsset(const std::filesystem::path& fullPath) - : Asset(fullPath) -{ -} - -MaterialAsset::~MaterialAsset() -{ -} - - -void MaterialAsset::save() -{ - assert(false && "TODO"); -} - -void MaterialAsset::load() -{ - setStatus(Status::Loading); - auto stream = getReadStream(); - json j; - stream >> j; - materialName = j["name"].get() + "Material"; - layout = WindowManager::getGraphics()->createDescriptorLayout(materialName + "Layout"); - //Shader file needs to conform to the slang standard, which prohibits _ - materialName.erase(std::remove(materialName.begin(), materialName.end(), '_'), materialName.end()); - materialName.erase(std::remove(materialName.begin(), materialName.end(), '.'), materialName.end()); - std::ofstream codeStream("./shaders/generated/"+materialName+".slang"); - std::string profile = j["profile"].get(); - - codeStream << "import Material;" << std::endl; - codeStream << "import BRDF;" << std::endl; - codeStream << "import MaterialParameter;" << std::endl << std::endl; - - codeStream << "struct " << materialName << " : IMaterial {" << std::endl; - uint32 uniformBufferOffset = 0; - uint32 bindingCounter = 0; // Uniform buffers are always binding 0 - uniformBinding = -1; - for(auto param : j["params"].items()) - { - std::string type = param.value()["type"].get(); - auto defaultValue = param.value().find("default"); - if(type.compare("float") == 0) - { - PFloatParameter p = new FloatParameter(param.key(), uniformBufferOffset, 0); - codeStream << "\tlayout(offset = " << uniformBufferOffset << ")"; - if(uniformBinding == -1) - { - layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - uniformBinding = bindingCounter++; - } - uniformBufferOffset += 4; - if(defaultValue != param.value().end()) - { - p->data = std::stof(defaultValue.value().get()); - } - parameters.add(p); - } - else if(type.compare("float3") == 0) - { - PVectorParameter p = new VectorParameter(param.key(), uniformBufferOffset, 0); - codeStream << "\tlayout(offset = " << uniformBufferOffset << ")"; - if(uniformBinding == -1) - { - layout->addDescriptorBinding(bindingCounter, Gfx::SE_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - uniformBinding = bindingCounter++; - } - uniformBufferOffset += 12; - if(defaultValue != param.value().end()) - { - p->data = Math::parseVector(defaultValue.value().get().c_str()); - } - parameters.add(p); - } - else if(type.compare("Texture2D") == 0) - { - PTextureParameter p = new TextureParameter(param.key(), 0, bindingCounter); - layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLED_IMAGE); - if(defaultValue != param.value().end()) - { - std::string defaultString = defaultValue.value().get(); - p->data = AssetRegistry::findTexture(defaultString); - } - if(p->data == nullptr) - { - p->data = AssetRegistry::findTexture(""); // this will return placeholder texture - } - parameters.add(p); - } - else if(type.compare("SamplerState") == 0) - { - PSamplerParameter p = new SamplerParameter(param.key(), 0, bindingCounter); - layout->addDescriptorBinding(bindingCounter++, Gfx::SE_DESCRIPTOR_TYPE_SAMPLER); - p->data = WindowManager::getGraphics()->createSamplerState({}); - parameters.add(p); - } - else - { - std::cout << "Error unsupported parameter type" << std::endl; - } - codeStream << "\t" << type << " " << param.key() << ";\n"; - } - uniformDataSize = uniformBufferOffset; - if(uniformDataSize != 0) - { - uniformData = new uint8[uniformDataSize]; - UniformBufferCreateInfo uniformInitializer; - uniformInitializer.resourceData.data = uniformData; - uniformInitializer.resourceData.size = uniformDataSize; - uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(uniformInitializer); - } - BRDF* brdf = BRDF::getBRDFByName(profile); - brdf->generateMaterialCode(codeStream, j["code"]); - codeStream << "};"; - codeStream.close(); - layout->create(); - setStatus(Status::Ready); -} - - -void MaterialAsset::beginFrame() -{ -} - -void MaterialAsset::endFrame() -{ -} - -Gfx::PDescriptorSet MaterialAsset::createDescriptorSet() -{ - Gfx::PDescriptorSet descriptorSet = layout->allocateDescriptorSet(); - BulkResourceData uniformUpdate; - uniformUpdate.size = uniformDataSize; - uniformUpdate.data = uniformData; - for(auto param : parameters) - { - param->updateDescriptorSet(descriptorSet, uniformData); - } - if(uniformUpdate.size != 0) - { - uniformBuffer->updateContents(uniformUpdate); - descriptorSet->updateBuffer(uniformBinding, uniformBuffer); - } - descriptorSet->writeChanges(); - return descriptorSet; -} - - -const Gfx::ShaderCollection* MaterialAsset::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const -{ - Gfx::ShaderPermutation permutation; - permutation.passType = renderPass; - std::string vertexInputName = vertexInput->getName(); - std::memcpy(permutation.materialName, materialName.c_str(), sizeof(permutation.materialName)); - std::memcpy(permutation.vertexInputName, vertexInputName.c_str(), sizeof(permutation.vertexInputName)); - return shaderMap.findShaders(Gfx::PermutationId(permutation)); -} - -Gfx::ShaderCollection& MaterialAsset::createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput) -{ - std::scoped_lock l(shaderMapLock); - return shaderMap.createShaders(graphics, renderPass, this, vertexInput, false); -} diff --git a/src/Engine/Material/MaterialAsset.h b/src/Engine/Material/MaterialAsset.h deleted file mode 100644 index 1f7ca19..0000000 --- a/src/Engine/Material/MaterialAsset.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once -#include "Asset/Asset.h" -#include "Graphics/GraphicsResources.h" -#include "ShaderExpression.h" - -namespace Seele -{ -DECLARE_REF(VertexShaderInput) -class MaterialAsset : public Asset -{ -public: - MaterialAsset(); - MaterialAsset(const std::string &directory, const std::string &name); - MaterialAsset(const std::filesystem::path &fullPath); - ~MaterialAsset(); - virtual void beginFrame(); - virtual void endFrame(); - virtual void save() override; - virtual void load() override; - Gfx::SeBlendOp getBlendMode() const {return Gfx::SE_BLEND_OP_END_RANGE;} - Gfx::MaterialShadingModel getShadingModel() const {return Gfx::MaterialShadingModel::DefaultLit;} - - Gfx::PDescriptorSet createDescriptorSet(); - - Gfx::PDescriptorLayout getDescriptorLayout() const { return layout; } - // The name of the generated material shader, opposed to the name of the .asset file - const std::string& getName() {return materialName;} - - const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const; - Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput); -private: - static Gfx::ShaderMap shaderMap; - static std::mutex shaderMapLock; - - //For now its simply the collection of parameters, since there is no point for expressions - Array parameters; - Gfx::PDescriptorLayout layout; - Gfx::PUniformBuffer uniformBuffer; - uint32 uniformDataSize; - uint8* uniformData; - int32 uniformBinding; - std::string materialName; - // With draw-indirect, we batch vertex data into big vertex buffers - // Gfx::PVertexDataManager vertexData; -}; -DEFINE_REF(MaterialAsset) -} // namespace Seele diff --git a/src/Engine/Material/MaterialInstance.cpp b/src/Engine/Material/MaterialInstance.cpp new file mode 100644 index 0000000..be9c6ca --- /dev/null +++ b/src/Engine/Material/MaterialInstance.cpp @@ -0,0 +1,55 @@ +#include "MaterialInstance.h" +#include "Material.h" +#include "Graphics/Graphics.h" + +using namespace Seele; + +MaterialInstance::MaterialInstance(PMaterial baseMaterial) + : MaterialInterface(baseMaterial->parameters, baseMaterial->uniformDataSize, baseMaterial->uniformBinding) + , baseMaterial(baseMaterial) +{ +} + +MaterialInstance::~MaterialInstance() +{ + +} + +Gfx::PDescriptorSet MaterialInstance::createDescriptorSet() +{ + Gfx::PDescriptorSet descriptorSet = baseMaterial->layout->allocateDescriptorSet(); + BulkResourceData uniformUpdate; + uniformUpdate.size = uniformDataSize; + uniformUpdate.data = (uint8*)uniformData.data(); + for(auto param : parameters) + { + param->updateDescriptorSet(descriptorSet, uniformData.data()); + } + if(uniformUpdate.size != 0) + { + uniformBuffer->updateContents(uniformUpdate); + descriptorSet->updateBuffer(uniformBinding, uniformBuffer); + } + descriptorSet->writeChanges(); + return descriptorSet; +} + +Gfx::PDescriptorLayout MaterialInstance::getDescriptorLayout() const +{ + return baseMaterial->getDescriptorLayout(); +} + +const std::string& MaterialInstance::getName() +{ + return baseMaterial->getName(); +} + +const Gfx::ShaderCollection* Seele::MaterialInstance::getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const +{ + return baseMaterial->getShaders(renderPass, vertexInput); +} + +Gfx::ShaderCollection& Seele::MaterialInstance::createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput) +{ + return baseMaterial->createShaders(graphics, renderPass, vertexInput); +} diff --git a/src/Engine/Material/MaterialInstance.h b/src/Engine/Material/MaterialInstance.h new file mode 100644 index 0000000..9f42aea --- /dev/null +++ b/src/Engine/Material/MaterialInstance.h @@ -0,0 +1,24 @@ +#pragma once +#include "MaterialInterface.h" + +namespace Seele +{ +DECLARE_REF(Material) +class MaterialInstance : public MaterialInterface +{ +public: + MaterialInstance(PMaterial baseMaterial); + virtual ~MaterialInstance(); + virtual Gfx::PDescriptorSet createDescriptorSet(); + virtual Gfx::PDescriptorLayout getDescriptorLayout() const; + + // The name of the generated material shader, opposed to the name of the .asset file + virtual const std::string& getName(); + virtual const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const; + virtual Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput); + +private: + PMaterial baseMaterial; +}; +DEFINE_REF(MaterialInstance) +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/MaterialInterface.cpp b/src/Engine/Material/MaterialInterface.cpp new file mode 100644 index 0000000..f83cb11 --- /dev/null +++ b/src/Engine/Material/MaterialInterface.cpp @@ -0,0 +1,39 @@ +#include "MaterialInterface.h" +#include "Window/WindowManager.h" +#include "Graphics/Graphics.h" + +using namespace Seele; + +MaterialInterface::MaterialInterface(Array parameter, uint32 uniformDataSize, uint32 uniformBinding) + : parameters(parameter) + , uniformDataSize(uniformDataSize) + , uniformBinding(uniformBinding) +{ + if(uniformDataSize != 0) + { + uniformData.resize(uniformDataSize); + UniformBufferCreateInfo uniformInitializer = { + .resourceData = { + .size = uniformDataSize, + .data = nullptr, + } + }; + uniformBuffer = WindowManager::getGraphics()->createUniformBuffer(uniformInitializer); + } +} + +MaterialInterface::~MaterialInterface() +{ +} + +PShaderParameter MaterialInterface::getParameter(const std::string& name) +{ + for (auto param : parameters) + { + if(param->name.compare(name) == 0) + { + return param; + } + } + return nullptr; +} \ No newline at end of file diff --git a/src/Engine/Material/MaterialInterface.h b/src/Engine/Material/MaterialInterface.h new file mode 100644 index 0000000..b9cee5f --- /dev/null +++ b/src/Engine/Material/MaterialInterface.h @@ -0,0 +1,31 @@ +#pragma once +#include "ShaderExpression.h" +#include "Graphics/GraphicsResources.h" + +namespace Seele +{ +DECLARE_NAME_REF(Gfx, DescriptorLayout) +DECLARE_NAME_REF(Gfx, UniformBuffer) +class MaterialInterface +{ +public: + MaterialInterface(Array parameter, uint32 uniformDataSize, uint32 uniformBinding); + virtual ~MaterialInterface(); + PShaderParameter getParameter(const std::string& name); + virtual Gfx::PDescriptorSet createDescriptorSet() = 0; + virtual Gfx::PDescriptorLayout getDescriptorLayout() const = 0; + + // The name of the generated material shader, opposed to the name of the .asset file + virtual const std::string& getName() = 0; + virtual const Gfx::ShaderCollection* getShaders(Gfx::RenderPassType renderPass, VertexInputType* vertexInput) const = 0; + virtual Gfx::ShaderCollection& createShaders(Gfx::PGraphics graphics, Gfx::RenderPassType renderPass, VertexInputType* vertexInput) = 0; +protected: + //For now its simply the collection of parameters, since there is no point for expressions + Array parameters; + Gfx::PUniformBuffer uniformBuffer; + uint32 uniformDataSize; + Array uniformData; + int32 uniformBinding; +}; +DEFINE_REF(MaterialInterface) +} // namespace Seele \ No newline at end of file diff --git a/src/Engine/Material/ShaderExpression.cpp b/src/Engine/Material/ShaderExpression.cpp index 8eb7aa5..435eced 100644 --- a/src/Engine/Material/ShaderExpression.cpp +++ b/src/Engine/Material/ShaderExpression.cpp @@ -40,7 +40,7 @@ VectorParameter::~VectorParameter() void VectorParameter::updateDescriptorSet(Gfx::PDescriptorSet, uint8* dst) { - std::memcpy(dst + byteOffset, &data, sizeof(Math::Vector)); + std::memcpy(dst + byteOffset, &data, sizeof(Vector)); } TextureParameter::TextureParameter(std::string name, uint32 byteOffset, uint32 binding) diff --git a/src/Engine/Material/ShaderExpression.h b/src/Engine/Material/ShaderExpression.h index c9fc972..3a5fdb2 100644 --- a/src/Engine/Material/ShaderExpression.h +++ b/src/Engine/Material/ShaderExpression.h @@ -36,7 +36,7 @@ struct FloatParameter : public ShaderParameter DEFINE_REF(FloatParameter) struct VectorParameter : public ShaderParameter { - Math::Vector data; + Vector data; VectorParameter(std::string name, uint32 byteOffset, uint32 binding); virtual ~VectorParameter(); virtual void updateDescriptorSet(Gfx::PDescriptorSet descriptorSet, uint8* dst) override; diff --git a/src/Engine/Math/Math.h b/src/Engine/Math/Math.h index 34743b3..9a18713 100644 --- a/src/Engine/Math/Math.h +++ b/src/Engine/Math/Math.h @@ -5,8 +5,6 @@ namespace Seele { -namespace Math -{ struct Rect { Rect() @@ -60,5 +58,4 @@ inline constexpr T align(const T ptr, int64_t alignment) { return (T)(((uint64_t)ptr + alignment - 1) & ~(alignment - 1)); } -} // namespace Math } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Math/Matrix.h b/src/Engine/Math/Matrix.h index 837e2ad..b1f68bb 100644 --- a/src/Engine/Math/Matrix.h +++ b/src/Engine/Math/Matrix.h @@ -5,10 +5,7 @@ #include namespace Seele { -namespace Math -{ typedef glm::mat2 Matrix2; typedef glm::mat3 Matrix3; typedef glm::mat4 Matrix4; -} // namespace Math } // namespace Seele \ No newline at end of file diff --git a/src/Engine/Math/Transform.cpp b/src/Engine/Math/Transform.cpp index 0bb68c4..4c5a51c 100644 --- a/src/Engine/Math/Transform.cpp +++ b/src/Engine/Math/Transform.cpp @@ -145,17 +145,17 @@ Vector Transform::getScale() const return Vector(scale); } -void Transform::setPosition(Math::Vector pos) +void Transform::setPosition(Vector pos) { position = Vector4(pos, 0); } -void Transform::setRotation(Math::Quaternion quat) +void Transform::setRotation(Quaternion quat) { rotation = quat; } -void Transform::setScale(Math::Vector s) +void Transform::setScale(Vector s) { scale = Vector4(s, 0); } diff --git a/src/Engine/Math/Transform.h b/src/Engine/Math/Transform.h index 7fab4fe..6252e97 100644 --- a/src/Engine/Math/Transform.h +++ b/src/Engine/Math/Transform.h @@ -26,9 +26,9 @@ public: Quaternion getRotation() const; Vector getScale() const; - void setPosition(Math::Vector pos); - void setRotation(Math::Quaternion quat); - void setScale(Math::Vector scale); + void setPosition(Vector pos); + void setRotation(Quaternion quat); + void setScale(Vector scale); Vector getForward() const; Vector getRight() const; diff --git a/src/Engine/Math/Vector.cpp b/src/Engine/Math/Vector.cpp index dc89855..c6c12f5 100644 --- a/src/Engine/Math/Vector.cpp +++ b/src/Engine/Math/Vector.cpp @@ -1,7 +1,30 @@ #include "Vector.h" #include +#include +#include -using namespace Seele::Math; +using namespace Seele; + +void to_json(nlohmann::json& j, const Vector& vec) +{ + j = nlohmann::json{std::format("({}, {}, {})", vec.x, vec.y, vec.z)}; +} + +void from_json(const nlohmann::json& j, Vector& vec) +{ + std::string str; + j.get_to(str); + auto newEnd = std::remove(str.begin(), str.end(), ' '); + str.erase(newEnd); + std::stringstream stream(str); + std::string temp; + std::getline(stream, temp, ','); + vec.x = std::stof(temp); + std::getline(stream, temp, ','); + vec.y = std::stof(temp); + std::getline(stream, temp, ','); + vec.z = std::stof(temp); +} std::ostream& operator<<(std::ostream& stream, const Vector2& vector) { @@ -19,7 +42,7 @@ std::ostream& operator<<(std::ostream& stream, const Vector4& vector) return stream; } -Vector Seele::Math::parseVector(const char* str) +Vector Seele::parseVector(const char* str) { //regex pattern consisting of 'float3(xComp, yComp, zComp)', more also matches for invalid floats, but that will throw later std::regex pattern("float3\\(\\s*([0-9.]+f?)\\s*,\\s*([0-9.]+f?)\\s*,\\s*([0-9.]+f?)\\s*\\)"); diff --git a/src/Engine/Math/Vector.h b/src/Engine/Math/Vector.h index f0f0af5..6f0de18 100644 --- a/src/Engine/Math/Vector.h +++ b/src/Engine/Math/Vector.h @@ -7,10 +7,9 @@ #include #pragma warning(pop) +#include namespace Seele { -namespace Math -{ typedef glm::vec2 Vector2; typedef glm::vec3 Vector; typedef glm::vec4 Vector4; @@ -96,10 +95,10 @@ static inline Vector toRotator(const Quaternion &other) } return rotatorFromQuat; } -} // namespace Math +void to_json(nlohmann::json& j, const Vector& vec); +void from_json(nlohmann::json& j, Vector& vec); } // namespace Seele - -std::ostream& operator<<(std::ostream& stream, const Seele::Math::Vector2& vector); -std::ostream& operator<<(std::ostream& stream, const Seele::Math::Vector& vector); -std::ostream& operator<<(std::ostream& stream, const Seele::Math::Vector4& vector); \ No newline at end of file +std::ostream& operator<<(std::ostream& stream, const Seele::Vector2& vector); +std::ostream& operator<<(std::ostream& stream, const Seele::Vector& vector); +std::ostream& operator<<(std::ostream& stream, const Seele::Vector4& vector); \ No newline at end of file diff --git a/src/Engine/Physics/BVH.cpp b/src/Engine/Physics/BVH.cpp index c3a252c..5cc65ef 100644 --- a/src/Engine/Physics/BVH.cpp +++ b/src/Engine/Physics/BVH.cpp @@ -7,6 +7,10 @@ void BVH::findOverlaps(Array>& overlaps) overlaps.clear(); for(const auto& node : dynamicNodes) { + if(!node.isLeaf) + { + continue; + } traverseStaticTree(node.box, node.owner, staticRoot, overlaps); traverseDynamicTree(node.box, node.owner, dynamicRoot, overlaps); } @@ -14,39 +18,48 @@ void BVH::findOverlaps(Array>& overlaps) void BVH::updateDynamicCollider(entt::entity entity, AABB aabb) { - for(auto& aabbcenter : dynamicCollider) + + for(auto& node : dynamicNodes) { - if(aabbcenter.id == entity) + if(node.owner == entity) { - if(!aabbcenter.bb.contains(aabb)) + if(!node.box.contains(aabb)) { // moved out of extended bounds reinsertCollider(entity, aabb); + } return; } } // new collider addDynamicCollider(entity, aabb); + +} + +void BVH::colliderCallback(entt::registry& registry, entt::entity entity) +{ + Component::Collider& collider = registry.get(entity); + Component::Transform& transform = registry.get(entity); + if(collider.type == Component::ColliderType::STATIC) + { + addStaticCollider(entity, collider.boundingbox.getTransformedBox(transform.toMatrix())); + } +} + +void BVH::visualize() +{ + for(const auto& node : staticNodes) + { + node.box.visualize(gDebugVertices); + } + for(const auto& node : dynamicNodes) + { + node.box.visualize(gDebugVertices); + } } void BVH::traverseStaticTree(const AABB& aabb, entt::entity source, int32 nodeIndex, Array>& overlaps) -{ - const Node& node = staticNodes[nodeIndex]; - if(!aabb.intersects(node.box)) - { - return; - } - if(node.isLeaf) - { - overlaps.add(Pair(source, node.owner)); - return; - } - traverseStaticTree(aabb, source, node.left, overlaps); - traverseStaticTree(aabb, source, node.right, overlaps); -} - -void BVH::traverseDynamicTree(const AABB& aabb, entt::entity source, int32 nodeIndex, Array>& overlaps) { const Node& node = staticNodes[nodeIndex]; if(!aabb.intersects(node.box)) @@ -62,7 +75,36 @@ void BVH::traverseDynamicTree(const AABB& aabb, entt::entity source, int32 nodeI traverseStaticTree(aabb, source, node.right, overlaps); } +void BVH::traverseDynamicTree(const AABB& aabb, entt::entity source, int32 nodeIndex, Array>& overlaps) +{ + if(nodeIndex == -1) + { + return; + } + const Node& node = dynamicNodes[nodeIndex]; + if(!aabb.intersects(node.box)) + { + return; + } + if(node.isLeaf && node.owner != source) + { + overlaps.add(Pair(source, node.owner)); + return; + } + traverseDynamicTree(aabb, source, node.left, overlaps); + traverseDynamicTree(aabb, source, node.right, overlaps); +} + void BVH::reinsertCollider(entt::entity entity, AABB aabb) +{ + + removeCollider(entity); + + addDynamicCollider(entity, aabb); + +} + +void BVH::removeCollider(entt::entity entity) { int32 nodeIndex = -1; for (int32 i = 0; i < dynamicNodes.size(); i++) @@ -75,11 +117,21 @@ void BVH::reinsertCollider(entt::entity entity, AABB aabb) } if(nodeIndex == -1) { + return; } int32 parentIndex = dynamicNodes[nodeIndex].parentIndex; + if(parentIndex == -1) + { + // its the root node + dynamicRoot = -1; + freeNode(nodeIndex); + + return; + } const Node& parent = dynamicNodes[parentIndex]; int32 siblingIndex; + if(parent.left == nodeIndex) { siblingIndex = parent.right; @@ -88,21 +140,34 @@ void BVH::reinsertCollider(entt::entity entity, AABB aabb) { siblingIndex = parent.left; } + // the node to remove and their sibling share a parent // now that the node is removed, the parent is also useless - // so the grandparent should point32 to the sibling directly instead of the parent - Node& grandParent = dynamicNodes[parent.parentIndex]; - if(grandParent.left == parentIndex) + // so the grandparent should point to the sibling directly instead of the parent + if(parent.parentIndex != -1) { - grandParent.left = siblingIndex; + Node& grandParent = dynamicNodes[parent.parentIndex]; + if(grandParent.left == parentIndex) + { + grandParent.left = siblingIndex; + } + else + { + grandParent.right = siblingIndex; + } + dynamicNodes[siblingIndex].parentIndex = parent.parentIndex; } else { - grandParent.right = siblingIndex; + // if the shared parent was the root, we need a new root, which is the remaining sibling + dynamicRoot = siblingIndex; + dynamicNodes[siblingIndex].parentIndex = -1; } - freeNode(parentIndex); + freeNode(nodeIndex); - addDynamicCollider(entity, aabb); + + freeNode(parentIndex); + } void BVH::addDynamicCollider(entt::entity entity, AABB aabb) @@ -113,18 +178,15 @@ void BVH::addDynamicCollider(entt::entity entity, AABB aabb) .min = center + (aabb.min - center) * 1.1f, .max = center + (aabb.max - center) * 1.1f, }; - dynamicCollider.add(AABBCenter { - .bb = aabb, - .center = center, - .id = entity - }); int32 leafIndex = allocateNode(); Node newNode = Node { .box = aabb, .isLeaf = true, + .isValid = true, .owner = entity, }; dynamicNodes[leafIndex] = newNode; + if (dynamicRoot == -1) { @@ -135,6 +197,7 @@ void BVH::addDynamicCollider(entt::entity entity, AABB aabb) int32 bestSibling; float bestCost = std::numeric_limits::max(); findSibling(newNode, dynamicRoot, bestCost, bestSibling); + int32 oldParent = dynamicNodes[bestSibling].parentIndex; int32 newParent = allocateNode(); @@ -142,7 +205,9 @@ void BVH::addDynamicCollider(entt::entity entity, AABB aabb) .box = aabb.combine(dynamicNodes[bestSibling].box), .parentIndex = oldParent, .isLeaf = false, + .isValid = true, }; + if(oldParent != -1) { @@ -158,6 +223,7 @@ void BVH::addDynamicCollider(entt::entity entity, AABB aabb) dynamicNodes[newParent].right = leafIndex; dynamicNodes[bestSibling].parentIndex = newParent; dynamicNodes[leafIndex].parentIndex = newParent; + } else { @@ -166,6 +232,7 @@ void BVH::addDynamicCollider(entt::entity entity, AABB aabb) dynamicNodes[bestSibling].parentIndex = newParent; dynamicNodes[leafIndex].parentIndex = newParent; dynamicRoot = newParent; + } int32 index = dynamicNodes[leafIndex].parentIndex; while(index != -1) @@ -186,6 +253,7 @@ void BVH::addStaticCollider(entt::entity entity, AABB boundingBox) .id = entity, }); staticNodes.clear(); + staticRoot = splitNode(staticCollider); } void BVH::findSibling(Node newNode, int32 nodeIndex, float& bestCost, int32& result) @@ -218,6 +286,7 @@ float BVH::siblingCost(Node newNode, int32 siblingIndex) { AABB parentBox = dynamicNodes[parentIndex].box; cost += parentBox.combine(newBox).surfaceArea() - parentBox.surfaceArea(); + parentIndex = dynamicNodes[parentIndex].parentIndex; } return cost; } @@ -240,6 +309,7 @@ int32 BVH::splitNode(Array aabbs) { int32 leafIndex = static_cast(staticNodes.size()); Node& leaf = staticNodes.add(); + leaf.isLeaf = true; leaf.box = aabbs[0].bb; leaf.left = -1; leaf.right = -1; @@ -296,5 +366,25 @@ int32 BVH::allocateNode() void BVH::freeNode(int32 nodeIndex) { dynamicNodes[nodeIndex].isValid = false; + dynamicNodes[nodeIndex].parentIndex = -1; +} + +void BVH::validateBVH() const +{ + if(dynamicRoot != -1) + { + assert(dynamicNodes[dynamicRoot].parentIndex == -1); + } + for(int32 i = 0; i < dynamicNodes.size(); ++i) + { + int32 nodeIdx = i; + size_t counter = dynamicNodes.size(); + if(!dynamicNodes[nodeIdx].isValid) + continue; + while(dynamicNodes[nodeIdx].parentIndex != -1) + { + nodeIdx = dynamicNodes[nodeIdx].parentIndex; + assert(counter-- > 0 && dynamicNodes[nodeIdx].isValid); + } + } } - \ No newline at end of file diff --git a/src/Engine/Physics/BVH.h b/src/Engine/Physics/BVH.h index 965fbde..d703add 100644 --- a/src/Engine/Physics/BVH.h +++ b/src/Engine/Physics/BVH.h @@ -12,11 +12,13 @@ class BVH public: void findOverlaps(Array>& overlaps); void updateDynamicCollider(entt::entity entity, AABB aabb); + void colliderCallback(entt::registry& registry, entt::entity entity); + void visualize(); private: struct AABBCenter { AABB bb; - Math::Vector center; + Vector center; entt::entity id; }; struct Node @@ -41,9 +43,9 @@ private: int32 splitNode(Array aabbs); int32 allocateNode(); void freeNode(int32 nodeIndex); + void validateBVH() const; Array dynamicNodes; Array staticNodes; - Array dynamicCollider; Array staticCollider; int32 staticRoot = -1; int32 dynamicRoot = -1; diff --git a/src/Engine/Physics/CollisionSystem.cpp b/src/Engine/Physics/CollisionSystem.cpp index 9851b9b..91f8f0f 100644 --- a/src/Engine/Physics/CollisionSystem.cpp +++ b/src/Engine/Physics/CollisionSystem.cpp @@ -3,9 +3,10 @@ using namespace Seele; using namespace Seele::Component; -CollisionSystem::CollisionSystem() +CollisionSystem::CollisionSystem(entt::registry& registry) + : registry(registry) { - + registry.on_construct().connect<&BVH::colliderCallback>(bvh); } CollisionSystem::~CollisionSystem() @@ -13,22 +14,24 @@ CollisionSystem::~CollisionSystem() } -void CollisionSystem::detectCollisions(const entt::registry& registry, Array& collisions) +void CollisionSystem::detectCollisions(Array& collisions) { collisions.clear(); auto view = registry.view(); for(auto && [entity, collider, transform] : view.each()) { - if(collider.type == ColliderType::DYNAMIC && transform.isDirty()) + if(collider.type == ColliderType::DYNAMIC) { bvh.updateDynamicCollider(entity, collider.boundingbox.getTransformedBox(transform.toMatrix())); } + collider.physicsMesh.transform(transform).visualize(); } + bvh.visualize(); Array> overlaps; bvh.findOverlaps(overlaps); for(auto pair : overlaps) { - if(checkCollision(registry, pair)) + if(checkCollision(pair)) { collisions.add(Collision { .a = pair.key, @@ -38,7 +41,7 @@ void CollisionSystem::detectCollisions(const entt::registry& registry, Array pair) +bool CollisionSystem::checkCollision(Pair pair) { const auto&[collider1, transform1] = registry.get(pair.key); const auto&[collider2, transform2] = registry.get(pair.value); @@ -64,7 +67,6 @@ void CollisionSystem::updateWitness(Witness& result, const glm::vec3& point, con result.p = point; } - bool CollisionSystem::createWitness(Witness& result, const ShapeBase& source, const ShapeBase& other) { for (size_t i = 0; i < source.indices.size(); i += 3) diff --git a/src/Engine/Physics/CollisionSystem.h b/src/Engine/Physics/CollisionSystem.h index 8533981..6974ef5 100644 --- a/src/Engine/Physics/CollisionSystem.h +++ b/src/Engine/Physics/CollisionSystem.h @@ -15,14 +15,14 @@ struct Collision class CollisionSystem { public: - CollisionSystem(); + CollisionSystem(entt::registry& registry); virtual ~CollisionSystem(); - void detectCollisions(const entt::registry& registry, Array& collisions); + void detectCollisions(Array& collisions); private: struct Witness { - Math::Vector p; - Math::Vector n; + Vector p; + Vector n; // for finding p uint32_t point1Index; // and the face where the plane lies on @@ -33,11 +33,12 @@ private: entt::entity other; }; BVH bvh; + entt::registry& registry; Map, Witness> cachedWitness; - bool checkCollision(const entt::registry& registry, Pair pair); + bool checkCollision(Pair pair); - void updateWitness(Witness& witness, const Math::Vector& point, const Math::Vector& v1, const Math::Vector& v2); + void updateWitness(Witness& witness, const Vector& point, const Vector& v1, const Vector& v2); // returns true if a collision was found bool createWitness(Witness& witness, const Component::ShapeBase& source, const Component::ShapeBase& other); diff --git a/src/Engine/Physics/PhysicsSystem.cpp b/src/Engine/Physics/PhysicsSystem.cpp index c16330e..54715ff 100644 --- a/src/Engine/Physics/PhysicsSystem.cpp +++ b/src/Engine/Physics/PhysicsSystem.cpp @@ -1,10 +1,13 @@ #include "PhysicsSystem.h" #include +#include using namespace Seele; using namespace Seele::Component; -PhysicsSystem::PhysicsSystem() +PhysicsSystem::PhysicsSystem(entt::registry& registry) + : registry(registry) + , collisionSystem(registry) { } @@ -14,24 +17,25 @@ PhysicsSystem::~PhysicsSystem() } -void PhysicsSystem::update(entt::registry& registry, float deltaTime) +void PhysicsSystem::update(float deltaTime) { Array initialBodies; - readRigidBodies(initialBodies, registry); + readRigidBodies(initialBodies); + std::cout << "Updating " << initialBodies.size() << " bodies" << std::endl; Array bodies = integratePhysics(initialBodies, 0, deltaTime); - writeRigidBodies(bodies, registry); + writeRigidBodies(bodies); Array collisions; - collisionSystem.detectCollisions(registry, collisions); + collisionSystem.detectCollisions(collisions); if(!collisions.empty()) { constexpr size_t numSteps = 2; for (float t = 0; t < deltaTime; t += deltaTime / numSteps) { - rewindCollisions(initialBodies, registry, t, t + (deltaTime / numSteps), 10); - readRigidBodies(initialBodies, registry); + rewindCollisions(initialBodies, t, t + (deltaTime / numSteps), 10); + readRigidBodies(initialBodies); } } } @@ -99,7 +103,7 @@ void PhysicsSystem::deserializeArray(Array& bodies, const Array& x) } } -void PhysicsSystem::readRigidBodies(Array& bodies, entt::registry& registry) const +void PhysicsSystem::readRigidBodies(Array& bodies) const { auto view = registry.view(); bodies.clear(); @@ -118,7 +122,7 @@ void PhysicsSystem::readRigidBodies(Array& bodies, entt::registry& registr }); } -void PhysicsSystem::writeRigidBodies(const Array& bodies, entt::registry& registry) const +void PhysicsSystem::writeRigidBodies(const Array& bodies) const { for(auto& body : bodies) { @@ -135,7 +139,7 @@ void PhysicsSystem::writeRigidBodies(const Array& bodies, entt::registry& } } -PhysicsSystem::Body PhysicsSystem::readRigidBody(entt::entity entity, entt::registry& registry) const +PhysicsSystem::Body PhysicsSystem::readRigidBody(entt::entity entity) const { Body rigidBody; if(registry.all_of(entity)) @@ -153,7 +157,7 @@ PhysicsSystem::Body PhysicsSystem::readRigidBody(entt::entity entity, entt::regi } -void PhysicsSystem::writeRigidBody(const Body& body, entt::registry& registry) const +void PhysicsSystem::writeRigidBody(const Body& body) const { if(registry.all_of(body.id)) { @@ -193,7 +197,7 @@ Array PhysicsSystem::integratePhysics(const Array& bo *xdot++ = result[i].v.z; // R(t)' = omega(t)*R(t) - Math::Quaternion qdot = 0.5f * (Math::Quaternion(0, result[i].omega) * result[i].q); + Quaternion qdot = 0.5f * (Quaternion(0, result[i].omega) * result[i].q); *xdot++ = qdot.w; *xdot++ = qdot.x; *xdot++ = qdot.y; @@ -218,7 +222,7 @@ Array PhysicsSystem::integratePhysics(const Array& bo -void PhysicsSystem::rewindCollisions(const Array& t0Bodies, entt::registry& registry, const float t0, const float t1, size_t remainingRecursionDepth) +void PhysicsSystem::rewindCollisions(const Array& t0Bodies, const float t0, const float t1, size_t remainingRecursionDepth) { if(remainingRecursionDepth == 0) { @@ -227,8 +231,8 @@ void PhysicsSystem::rewindCollisions(const Array& t0Bodies, entt::registry // there are collisions happening between t0 and t1 // we integrate until tc and see if they have already occured then Array collisions; - writeRigidBodies(integratePhysics(t0Bodies, t0, t1), registry); - collisionSystem.detectCollisions(registry, collisions); + writeRigidBodies(integratePhysics(t0Bodies, t0, t1)); + collisionSystem.detectCollisions(collisions); //std::cout << "detected " << collisions.size() << " at " << tc << std::endl; // now we check if there has been a contact at tc @@ -239,16 +243,17 @@ void PhysicsSystem::rewindCollisions(const Array& t0Bodies, entt::registry const auto&[collider1, transform1] = registry.get(collision.a); const auto&[collider2, transform2] = registry.get(collision.b); calculateContacts(collision.a, collider1.physicsMesh.transform(transform1), collision.b, collider2.physicsMesh.transform(transform2), contacts); + calculateContacts(collision.b, collider2.physicsMesh.transform(transform2), collision.a, collider1.physicsMesh.transform(transform1), contacts); } // we then apply forces in order to counteract interpenetration Array restingContacts; for(const auto& contact : contacts) { - Body a = readRigidBody(contact.a, registry); - Body b = readRigidBody(contact.b, registry); - Math::Vector paDot = a.ptVelocity(contact.p); - Math::Vector pbDot = b.ptVelocity(contact.p); + Body a = readRigidBody(contact.a); + Body b = readRigidBody(contact.b); + Vector paDot = a.ptVelocity(contact.p); + Vector pbDot = b.ptVelocity(contact.p); float vrel = glm::dot(contact.n, paDot - pbDot); if(vrel > 0.001f) { @@ -262,10 +267,10 @@ void PhysicsSystem::rewindCollisions(const Array& t0Bodies, entt::registry resolvePenetratingContact(contact, a, b); a.updateMatrix(); b.updateMatrix(); - writeRigidBody(a, registry); - writeRigidBody(b, registry); + writeRigidBody(a); + writeRigidBody(b); } - resolveRestingContacts(restingContacts, registry); + resolveRestingContacts(restingContacts); } void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, entt::entity id2, const ShapeBase& shape2, Array& contacts) const @@ -273,25 +278,33 @@ void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, for(size_t i = 0; i < shape1.indices.size(); i += 3) { // face - vertex contacts - const Math::Vector point1 = shape1.vertices[shape1.indices[i + 0]]; - const Math::Vector point2 = shape1.vertices[shape1.indices[i + 1]]; - const Math::Vector point3 = shape1.vertices[shape1.indices[i + 2]]; - const Math::Vector v1 = point2 - point1; - const Math::Vector v2 = point3 - point1; - const Math::Vector faceNormal = glm::normalize(glm::cross(v1, v2)); - auto area = [](Math::Vector ab, Math::Vector ac){ + const Vector point1 = shape1.vertices[shape1.indices[i + 0]]; + const Vector point2 = shape1.vertices[shape1.indices[i + 1]]; + const Vector point3 = shape1.vertices[shape1.indices[i + 2]]; + const Vector v1 = point2 - point1; + const Vector v2 = point3 - point1; + const Vector faceNormal = glm::normalize(glm::cross(v1, v2)); + Seele::gDebugVertices.add(DebugVertex{ + .position = (point1 + point2 + point3) / 3.f, + .color = Vector(1, 0, 0) + }); + Seele::gDebugVertices.add(DebugVertex{ + .position = faceNormal + (point1 + point2 + point3) / 3.f, + .color = Vector(1, 0, 0) + }); + auto area = [](Vector ab, Vector ac){ return glm::length(glm::cross(ab, ac)) / 2.0f; }; float faceArea = area(v1, v2); for(size_t j = 0; j < shape2.vertices.size(); j++) { - Math::Vector worldPos = shape2.vertices[j]; + Vector worldPos = shape2.vertices[j]; float dot = glm::dot(faceNormal, worldPos - point1); - if(dot < 0.2f) + if(std::abs(dot) < 0.2f) { - Math::Vector pa = point1 - worldPos; - Math::Vector pb = point2 - worldPos; - Math::Vector pc = point3 - worldPos; + Vector pa = point1 - worldPos; + Vector pb = point2 - worldPos; + Vector pc = point3 - worldPos; float a1 = area(pa, pb); float a2 = area(pb, pc); float a3 = area(pc, pa); @@ -311,16 +324,16 @@ void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, contacts.add(c); } } - + //std::cout << minTemp << std::endl; // edge - edge contacts - auto lineLineContact = [=, &contacts](Math::Vector p1, Math::Vector p2, Math::Vector p3, Math::Vector p4) + auto lineLineContact = [=, &contacts](Vector p1, Vector p2, Vector p3, Vector p4) { //L1 = p1 + t * p2 - p1; //L2 = p3 + u * p4 - p3; - Math::Vector a = p1; - Math::Vector c = p3; - Math::Vector ab = p2 - p1; - Math::Vector cd = p4 - p3; + Vector a = p1; + Vector c = p3; + Vector ab = p2 - p1; + Vector cd = p4 - p3; float tx_den = cd.z * ab.y - cd.y * ab.z; float tx = (c.y * ab.z - a.y * ab.z - c.z * ab.y + a.z * ab.y) / tx_den; float ty_den = cd.z * ab.x - cd.z * ab.z; @@ -333,10 +346,10 @@ void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, && tx >= 0.f && tx <= 1.f) { - Math::Vector p = p1 + tx * (p2 - p1); - Math::Vector ea = p2 - p1; - Math::Vector eb = p4 - p3; - Math::Vector n = glm::normalize(glm::cross(eb, ea)); + Vector p = p1 + tx * (p2 - p1); + Vector ea = p2 - p1; + Vector eb = p4 - p3; + Vector n = glm::normalize(glm::cross(eb, ea)); Contact contact = { .a = id1, .b = id2, @@ -350,9 +363,9 @@ void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, }; for(size_t j = 0; j < shape2.indices.size(); j+=3) { - const Math::Vector point4 = shape2.vertices[shape2.indices[j + 0]]; - const Math::Vector point5 = shape2.vertices[shape2.indices[j + 1]]; - const Math::Vector point6 = shape2.vertices[shape2.indices[j + 2]]; + const Vector point4 = shape2.vertices[shape2.indices[j + 0]]; + const Vector point5 = shape2.vertices[shape2.indices[j + 1]]; + const Vector point6 = shape2.vertices[shape2.indices[j + 2]]; lineLineContact(point1, point2, point4, point5); lineLineContact(point1, point2, point5, point6); @@ -369,54 +382,46 @@ void PhysicsSystem::calculateContacts(entt::entity id1, const ShapeBase& shape1, } } -void PhysicsSystem::resolveRestingContacts(const Array& contacts, entt::registry& registry) const +void PhysicsSystem::resolveRestingContacts(const Array& contacts) const { - Array> amat(contacts.size(), Array(contacts.size())); + Array> amat(contacts.size()); + for(size_t i = 0; i < contacts.size(); ++i) + { + amat[i] = Array(contacts.size()); + } Array bvec(contacts.size()); - computeAMatrix(contacts, amat, registry); - computeBVector(contacts, bvec, registry); + computeAMatrix(contacts, amat); + computeBVector(contacts, bvec); + + Array fvec(bvec); + solveQP(amat, bvec, fvec); - /*CGAL::Quadratic_program qp(CGAL::SMALLER, true, 0, false, 0); - for(size_t x = 0; x < contacts.size(); ++x) - { - for(size_t y = 0; y < contacts.size(); ++y) - { - qp.set_a(x, y, amat[x][y]); - } - } for(size_t y = 0; y < contacts.size(); ++y) { - qp.set_b(y, bvec[y]); - } - CGAL::Quadratic_program_solution s = CGAL::solve_quadratic_program(qp, CGAL::MP_Float()); - assert(s.solves_quadratic_program(qp)); - - auto solutionBegin = s.variable_values_begin(); - for(size_t y = 0; y < contacts.size(); ++y) - { - float f = CGAL::to_double(*solutionBegin++); - Math::Vector n = contacts[y].n; - RigidBody a = readRigidBody(contacts[y].a, registry); - RigidBody b = readRigidBody(contacts[y].b, registry); + std::cout << "resting contact force: " << fvec[y] << std::endl; + float f = fvec[y]; + Vector n = contacts[y].n; + Body a = readRigidBody(contacts[y].a); + Body b = readRigidBody(contacts[y].b); a.force += f * n; a.torque += (contacts[y].p - a.x + a.centerOfMass) * (f * n); b.force -= f * n; b.torque -= (contacts[y].p - b.x + b.centerOfMass) * (f * n); - writeRigidBody(a, registry); - writeRigidBody(b, registry); - }*/ + writeRigidBody(a); + writeRigidBody(b); + } } void PhysicsSystem::resolvePenetratingContact(const Contact& contact, Body& a, Body& b) const { - Math::Vector paDot = a.ptVelocity(contact.p); - Math::Vector pbDot = b.ptVelocity(contact.p); + Vector paDot = a.ptVelocity(contact.p); + Vector pbDot = b.ptVelocity(contact.p); float vrel = glm::dot(contact.n, paDot - pbDot); - Math::Vector n = contact.n; - Math::Vector ra = contact.p - a.x + a.centerOfMass; - Math::Vector rb = contact.p - b.x + b.centerOfMass; + Vector n = contact.n; + Vector ra = contact.p - a.x + a.centerOfMass; + Vector rb = contact.p - b.x + b.centerOfMass; float numerator = -(1 + 0.5f) * vrel; float term1 = a.inverseMass; @@ -425,7 +430,7 @@ void PhysicsSystem::resolvePenetratingContact(const Contact& contact, Body& a, B float term4 = glm::dot(n, glm::cross(b.iInv * glm::cross(rb, n), rb)); float j = numerator / (term1 + term2 + term3 + term4); - Math::Vector force = j * n; + Vector force = j * n; a.P += force; b.P -= force; @@ -439,7 +444,7 @@ void PhysicsSystem::resolvePenetratingContact(const Contact& contact, Body& a, B b.omega = b.iInv * b.L; } -Math::Vector PhysicsSystem::computeNdot(const Contact& c, const Body& a, const Body& b) const +Vector PhysicsSystem::computeNdot(const Contact& c, const Body& a, const Body& b) const { if(c.vf) { @@ -447,10 +452,10 @@ Math::Vector PhysicsSystem::computeNdot(const Contact& c, const Body& a, const B } else { - Math::Vector eadot = glm::cross(a.omega, c.ea); - Math::Vector ebdot = glm::cross(b.omega, c.eb); - Math::Vector n1 = glm::cross(c.ea, c.eb); - Math::Vector z = glm::cross(eadot, c.eb) + glm::cross(c.ea, ebdot); + Vector eadot = glm::cross(a.omega, c.ea); + Vector ebdot = glm::cross(b.omega, c.eb); + Vector n1 = glm::cross(c.ea, c.eb); + Vector z = glm::cross(eadot, c.eb) + glm::cross(c.ea, ebdot); float l = glm::length(n1); n1 = glm::normalize(n1); @@ -458,23 +463,23 @@ Math::Vector PhysicsSystem::computeNdot(const Contact& c, const Body& a, const B } } -float PhysicsSystem::computeAij(const Contact& ci, const Contact& cj, entt::registry& registry) const +float PhysicsSystem::computeAij(const Contact& ci, const Contact& cj) const { if((ci.a != cj.a) && (ci.b != cj.b) && (ci.a != cj.b) && (ci.b != cj.a)) return 0.0f; - Body a = readRigidBody(ci.a, registry); - Body b = readRigidBody(ci.b, registry); - Math::Vector ni = ci.n; - Math::Vector nj = cj.n; - Math::Vector pi = ci.p; - Math::Vector pj = cj.p; - Math::Vector ra = pi - a.x + a.centerOfMass; - Math::Vector rb = pi - b.x + b.centerOfMass; + Body a = readRigidBody(ci.a); + Body b = readRigidBody(ci.b); + Vector ni = ci.n; + Vector nj = cj.n; + Vector pi = ci.p; + Vector pj = cj.p; + Vector ra = pi - a.x + a.centerOfMass; + Vector rb = pi - b.x + b.centerOfMass; - Math::Vector forceOnA = Math::Vector(0); - Math::Vector torqueOnA = Math::Vector(0); + Vector forceOnA = Vector(0); + Vector torqueOnA = Vector(0); if(cj.a == ci.a) { forceOnA = nj; @@ -485,8 +490,8 @@ float PhysicsSystem::computeAij(const Contact& ci, const Contact& cj, entt::regi forceOnA = -nj; torqueOnA = glm::cross((pj - a.x + a.centerOfMass), nj); } - Math::Vector forceOnB = Math::Vector(0); - Math::Vector torqueOnB = Math::Vector(0); + Vector forceOnB = Vector(0); + Vector torqueOnB = Vector(0); if(cj.a == ci.b) { forceOnB = nj; @@ -498,52 +503,83 @@ float PhysicsSystem::computeAij(const Contact& ci, const Contact& cj, entt::regi torqueOnB = glm::cross((pj - b.x + b.centerOfMass), nj); } - Math::Vector aLinear = forceOnA * a.inverseMass; - Math::Vector aAngular = glm::cross((a.iInv * torqueOnA), ra); + Vector aLinear = forceOnA * a.inverseMass; + Vector aAngular = glm::cross((a.iInv * torqueOnA), ra); - Math::Vector bLinear = forceOnB * b.inverseMass; - Math::Vector bAngular = glm::cross((b.iInv * torqueOnB), rb); + Vector bLinear = forceOnB * b.inverseMass; + Vector bAngular = glm::cross((b.iInv * torqueOnB), rb); return glm::dot(ni, ((aLinear + aAngular) - (bLinear + bAngular))); } -void PhysicsSystem::computeAMatrix(const Array& contacts, Array>& amat, entt::registry& registry) const +void PhysicsSystem::computeAMatrix(const Array& contacts, Array>& amat) const { for(size_t x = 0; x < contacts.size(); ++x) { for(size_t y = 0; y < contacts.size(); ++y) { - amat[x][y] = computeAij(contacts[x], contacts[y], registry); + amat[x][y] = computeAij(contacts[x], contacts[y]); } } } -void PhysicsSystem::computeBVector(const Array& contacts, Array& bvec, entt::registry& registry) const +void PhysicsSystem::computeBVector(const Array& contacts, Array& bvec) const { for(size_t y = 0; y < contacts.size(); ++y) { Contact c = contacts[y]; - Body a = readRigidBody(c.a, registry); - Body b = readRigidBody(c.b, registry); - Math::Vector n = c.n; - Math::Vector ra = c.p - a.x + a.centerOfMass; - Math::Vector rb = c.p - b.x + b.centerOfMass; + Body a = readRigidBody(c.a); + Body b = readRigidBody(c.b); + Vector n = c.n; + Vector ra = c.p - a.x + a.centerOfMass; + Vector rb = c.p - b.x + b.centerOfMass; - Math::Vector fExtA = a.force; - Math::Vector fExtB = b.force; - Math::Vector tExtA = a.torque; - Math::Vector tExtB = b.torque; + Vector fExtA = a.force; + Vector fExtB = b.force; + Vector tExtA = a.torque; + Vector tExtB = b.torque; - Math::Vector aExtPart = fExtA * a.inverseMass + glm::cross(a.iInv * tExtA, ra); - Math::Vector bExtPart = fExtB * b.inverseMass + glm::cross(b.iInv * tExtB, rb); + Vector aExtPart = fExtA * a.inverseMass + glm::cross(a.iInv * tExtA, ra); + Vector bExtPart = fExtB * b.inverseMass + glm::cross(b.iInv * tExtB, rb); - Math::Vector aVelPart = glm::cross(a.omega, glm::cross(a.omega, ra)) + glm::cross(a.iInv * glm::cross(a.L, a.omega), ra); - Math::Vector bVelPart = glm::cross(b.omega, glm::cross(b.omega, rb)) + glm::cross(b.iInv * glm::cross(b.L, b.omega), rb); + Vector aVelPart = glm::cross(a.omega, glm::cross(a.omega, ra)) + glm::cross(a.iInv * glm::cross(a.L, a.omega), ra); + Vector bVelPart = glm::cross(b.omega, glm::cross(b.omega, rb)) + glm::cross(b.iInv * glm::cross(b.L, b.omega), rb); float k1 = glm::dot(n, (aExtPart + aVelPart) - (bExtPart + bVelPart)); - Math::Vector ndot = computeNdot(c, a, b); + Vector ndot = computeNdot(c, a, b); float k2 = 2.0f * glm::dot(ndot, (a.ptVelocity(c.p) - b.ptVelocity(c.p))); bvec[y] = k1 + k2; } -} \ No newline at end of file +} + +void PhysicsSystem::solveQP(const Array>& CI, const Array& ci0, Array& sol) const +{ + static std::mt19937_64 generator; + static std::uniform_real_distribution dist(0.01f, 0.1f); + sol.resize(CI.size()); + bool solved = false; + while(!solved) + { + for(size_t i = 0; i < sol.size(); ++i) + { + sol[i] = dist(generator); + } + solved = true; + for(size_t i = 0; i < sol.size(); ++i) + { + float res = 0; + for(size_t j = 0; j < sol.size(); ++j) + { + res += CI[i][j] * sol[j] + ci0[i]; + } + if(res < 0) + { + solved = false; + std::cout << "failed to solve QP" << std::endl; + continue; + } + } + return; + } +} diff --git a/src/Engine/Physics/PhysicsSystem.h b/src/Engine/Physics/PhysicsSystem.h index 0b64115..c39566b 100644 --- a/src/Engine/Physics/PhysicsSystem.h +++ b/src/Engine/Physics/PhysicsSystem.h @@ -11,35 +11,35 @@ namespace Seele class PhysicsSystem { public: - PhysicsSystem(); + PhysicsSystem(entt::registry& registry); ~PhysicsSystem(); - void update(entt::registry& registry, float deltaTime); + void update(float deltaTime); private: struct Body { entt::entity id; float inverseMass; - Math::Vector centerOfMass; - Math::Matrix3 iBody, iBodyInv; - Math::Vector scale; + Vector centerOfMass; + Matrix3 iBody, iBodyInv; + Vector scale; - Math::Vector x; - Math::Quaternion q; - Math::Vector P; - Math::Vector L; + Vector x; + Quaternion q; + Vector P; + Vector L; - Math::Matrix3 iInv; - Math::Matrix3 R; - Math::Vector v; - Math::Vector omega; - Math::Vector force; - Math::Vector torque; - Math::Matrix4 matrix; - Math::Vector ptVelocity(Math::Vector p) const {return v + glm::cross(omega, p - x + centerOfMass);} + Matrix3 iInv; + Matrix3 R; + Vector v; + Vector omega; + Vector force; + Vector torque; + Matrix4 matrix; + Vector ptVelocity(Vector p) const {return v + glm::cross(omega, p - x + centerOfMass);} void updateMatrix() { - Math::Matrix4 scaleMatrix = glm::scale(Math::Matrix4(1), scale); - Math::Matrix4 rotationMatrix = glm::mat4_cast(q); - Math::Matrix4 translationMatrix = glm::translate(Math::Matrix4(1), x); + Matrix4 scaleMatrix = glm::scale(Matrix4(1), scale); + Matrix4 rotationMatrix = glm::mat4_cast(q); + Matrix4 translationMatrix = glm::translate(Matrix4(1), x); matrix = translationMatrix * rotationMatrix * scaleMatrix; } Body() @@ -57,8 +57,8 @@ private: , L(physics.angularMomentum) , iInv(glm::mat3()) , R(glm::mat3()) - , v(Math::Vector()) - , omega(Math::Vector()) + , v(Vector()) + , omega(Vector()) , force(physics.force) , torque(physics.torque) { @@ -76,14 +76,14 @@ private: , scale(transform.getScale()) , x(transform.getPosition()) , q(transform.getRotation()) - , P(Math::Vector(0)) - , L(Math::Vector(0)) + , P(Vector(0)) + , L(Vector(0)) , iInv(glm::mat3()) , R(glm::mat3()) - , v(Math::Vector()) - , omega(Math::Vector()) - , force(Math::Vector(0)) - , torque(Math::Vector(0)) + , v(Vector()) + , omega(Vector()) + , force(Vector(0)) + , torque(Vector(0)) { R = glm::mat3_cast(glm::normalize(q)); iInv = R * iBodyInv * glm::transpose(R); @@ -99,9 +99,10 @@ private: glm::vec3 eb; bool vf; }; - static constexpr size_t FLOATS_PER_RB = sizeof(Body) / sizeof(float); - + static constexpr size_t FLOATS_PER_RB = 13; + entt::registry& registry; CollisionSystem collisionSystem; + bool pause = false; void serializeRB(const Body& rb, float* y) const; @@ -111,30 +112,32 @@ private: void deserializeArray(Array& bodies, const Array& x) const; - void readRigidBodies(Array& bodies, entt::registry& registry) const; + void readRigidBodies(Array& bodies) const; - void writeRigidBodies(const Array& bodies, entt::registry& registry) const; + void writeRigidBodies(const Array& bodies) const; - Body readRigidBody(entt::entity entity, entt::registry& regsitry) const; + Body readRigidBody(entt::entity entity) const; - void writeRigidBody(const Body& body, entt::registry& registry) const; + void writeRigidBody(const Body& body) const; Array integratePhysics(const Array& bodies, const float t0, const float tdelta) const; - void rewindCollisions(const Array& t0Bodies, entt::registry& registry, const float t0, const float t1, size_t remainingDepth); + void rewindCollisions(const Array& t0Bodies, const float t0, const float t1, size_t remainingDepth); void calculateContacts(entt::entity id1, const Component::ShapeBase& shape1, entt::entity id2, const Component::ShapeBase& shape2, Array& contacts) const; - void resolveRestingContacts(const Array& contacts, entt::registry& registry) const; + void resolveRestingContacts(const Array& contacts) const; void resolvePenetratingContact(const Contact& c, Body& a, Body& b) const; - Math::Vector computeNdot(const Contact& c, const Body& a, const Body& b) const; + Vector computeNdot(const Contact& c, const Body& a, const Body& b) const; - float computeAij(const Contact& ci, const Contact& cj, entt::registry& registry) const; + float computeAij(const Contact& ci, const Contact& cj) const; - void computeAMatrix(const Array& contacts, Array>& amat, entt::registry& registry) const; + void computeAMatrix(const Array& contacts, Array>& amat) const; - void computeBVector(const Array& contacts, Array& avec, entt::registry& registry) const; + void computeBVector(const Array& contacts, Array& avec) const; + + void solveQP(const Array>& A, const Array& b, Array& f) const; }; } // namespace Seele diff --git a/src/Engine/Scene/Scene.cpp b/src/Engine/Scene/Scene.cpp index a78b5a1..5b28018 100644 --- a/src/Engine/Scene/Scene.cpp +++ b/src/Engine/Scene/Scene.cpp @@ -1,5 +1,4 @@ #include "Scene.h" -#include "Material/MaterialAsset.h" #include "Graphics/Graphics.h" #include "Graphics/Mesh.h" #include "Component/StaticMesh.h" @@ -14,6 +13,7 @@ inline float frand() Scene::Scene(Gfx::PGraphics graphics) : graphics(graphics) + , physics(registry) { } @@ -21,69 +21,24 @@ Scene::~Scene() { } -void Scene::start() +void Scene::update(float deltaTime) { - //for(auto actor : rootActors) - //{ - // actor->launchStart(); - //} -} - -static int64 lastUpdate; -static uint64 numUpdates; - -void Scene::beginUpdate(double) -{ - //std::cout << "Scene::beginUpdate" << std::endl; - auto startTime = std::chrono::high_resolution_clock::now(); - // TODO - auto endTime = std::chrono::high_resolution_clock::now(); - int64 delta = std::chrono::duration_cast(endTime - startTime).count(); - lastUpdate += delta; - numUpdates++; - if(lastUpdate > 1000000) - { - lastUpdate -= 1000000; - std::cout << numUpdates << " updates per second" << std::endl; - numUpdates = 0; - } -} - -void Scene::commitUpdate() -{ - //std::cout << "Scene::commitUpdate" << std::endl; - //for(auto actor : rootActors) - //{ - // actor->launchUpdate(); - //} - //std::cout << "Scene::commitUpdate finished waiting" << std::endl; + physics.update(deltaTime); } Array Scene::getStaticMeshes() { Array result; auto view = registry.view(); - struct PrimitiveSceneData - { - Math::Matrix4 localToWorld; - Math::Matrix4 worldToLocal; - Math::Vector4 actorLocation; - }; + uint32 sceneDataIndex = 0; + sceneData.clear(); for(auto&& [entity, mesh, transform] : view.each()) { - PrimitiveSceneData sceneData = { + sceneData.add(PrimitiveSceneData { .localToWorld = transform.toMatrix(), .worldToLocal = glm::inverse(transform.toMatrix()), - .actorLocation = Math::Vector4(transform.getPosition(), 1.0f) - }; - UniformBufferCreateInfo info = { - .resourceData = { - .size = sizeof(PrimitiveSceneData), - .data = (uint8_t*)&sceneData, - } - }; - Gfx::PUniformBuffer transformBuf = graphics->createUniformBuffer(info); - // TODO + .actorLocation = Vector4(transform.getPosition(), 1.0f) + }); for(auto& m : mesh.mesh->meshes) { auto& batch = result.add(); @@ -99,23 +54,37 @@ Array Scene::getStaticMeshes() batchElement.firstIndex = 0; batchElement.indexBuffer = m->indexBuffer; batchElement.indirectArgsBuffer = nullptr; - batchElement.instanceRuns = nullptr; batchElement.isInstanced = false; batchElement.numInstances = 1; - batchElement.uniformBuffer = transformBuf; - batchElement.numPrimitives = static_cast(m->indexBuffer->getNumIndices() / 3); //TODO: hardcoded + batchElement.sceneDataIndex = sceneDataIndex; batch.elements.add(batchElement); } + sceneDataIndex++; } + if(sceneDataBuffer == nullptr || sceneDataBuffer->getNumElements() != sceneData.size()) + { + StructuredBufferCreateInfo createInfo = StructuredBufferCreateInfo { + .resourceData = { + .size = sceneData.size() * sizeof(PrimitiveSceneData), + .data = nullptr, + }, + .stride = (uint32)sceneData.size(), + }; + sceneDataBuffer = graphics->createStructuredBuffer(createInfo); + } + sceneDataBuffer->updateContents(BulkResourceData { + .size = sceneData.size() * sizeof(PrimitiveSceneData), + .data = (uint8*)sceneData.data(), + }); return result; } LightEnv Scene::getLightBuffer() const { LightEnv result; - result.directionalLights[0].color = Math::Vector4(0.4, 0.3, 0.5, 1.0); - result.directionalLights[0].direction = Math::Vector4(0.5, 0.5, 0, 0); - result.directionalLights[0].intensity = Math::Vector4(1.0, 0.9, 0.7, 0.5);\ + result.directionalLights[0].color = Vector4(0.4, 0.3, 0.5, 1.0); + result.directionalLights[0].direction = Vector4(0.5, 0.5, 0, 0); + result.directionalLights[0].intensity = Vector4(1.0, 0.9, 0.7, 0.5);\ result.numDirectionalLights = 1; result.numPointLights = 0; return result; diff --git a/src/Engine/Scene/Scene.h b/src/Engine/Scene/Scene.h index 2358bb9..f714476 100644 --- a/src/Engine/Scene/Scene.h +++ b/src/Engine/Scene/Scene.h @@ -3,6 +3,7 @@ #include "MinimalEngine.h" #include "Graphics/GraphicsResources.h" #include "Graphics/MeshBatch.h" +#include "Physics/PhysicsSystem.h" namespace Seele { @@ -11,16 +12,16 @@ DECLARE_REF(Entity) struct DirectionalLight { - Math::Vector4 color; - Math::Vector4 direction; - Math::Vector4 intensity; + Vector4 color; + Vector4 direction; + Vector4 intensity; }; struct PointLight { - Math::Vector4 positionWS; + Vector4 positionWS; //Vector4 positionVS; - Math::Vector4 colorRange; + Vector4 colorRange; }; #define MAX_DIRECTIONAL_LIGHTS 4 @@ -38,17 +39,19 @@ class Scene public: Scene(Gfx::PGraphics graphics); ~Scene(); - void start(); - void beginUpdate(double deltaTime); - void commitUpdate(); + void update(float deltaTime); entt::entity createEntity() { return registry.create(); } - template - Component& attachComponent(entt::entity entity, Args... args) + void destroyEntity(entt::entity identifier) { - return registry.emplace(entity, args...); + registry.destroy(identifier); + } + template + Component& attachComponent(entt::entity entity, Args&&... args) + { + return registry.emplace(entity, std::forward(args)...); } template Component& accessComponent(entt::entity entity) @@ -62,9 +65,19 @@ public: } Array getStaticMeshes(); LightEnv getLightBuffer() const; + Gfx::PStructuredBuffer getSceneDataBuffer() const { return sceneDataBuffer; } entt::registry registry; private: + struct PrimitiveSceneData + { + Matrix4 localToWorld; + Matrix4 worldToLocal; + Vector4 actorLocation; + }; + Array sceneData; + Gfx::PStructuredBuffer sceneDataBuffer; + PhysicsSystem physics; Gfx::PGraphics graphics; }; DEFINE_REF(Scene) diff --git a/src/Engine/UI/Elements/Element.cpp b/src/Engine/UI/Elements/Element.cpp index 1291341..b0a9cb7 100644 --- a/src/Engine/UI/Elements/Element.cpp +++ b/src/Engine/UI/Elements/Element.cpp @@ -59,12 +59,12 @@ bool Element::isEnabled() const return enabled; } -Math::Rect& Element::getBoundingBox() +Rect& Element::getBoundingBox() { return boundingBox; } -const Math::Rect Element::getBoundingBox() const +const Rect Element::getBoundingBox() const { return boundingBox; } \ No newline at end of file diff --git a/src/Engine/UI/Elements/Element.h b/src/Engine/UI/Elements/Element.h index c071e26..b803b73 100644 --- a/src/Engine/UI/Elements/Element.h +++ b/src/Engine/UI/Elements/Element.h @@ -23,13 +23,13 @@ public: bool isEnabled() const; // maybe not the healthiest inteface // non-const version - Math::Rect& getBoundingBox(); + Rect& getBoundingBox(); // The bounding box describes the relative size of any Element // relative to the total view, meaning a bounding box of (0,0), (1,1) // would take up the entire view - const Math::Rect getBoundingBox() const; + const Rect getBoundingBox() const; protected: - Math::Rect boundingBox; + Rect boundingBox; bool dirty; bool enabled; diff --git a/src/Engine/UI/HorizontalLayout.cpp b/src/Engine/UI/HorizontalLayout.cpp index d191e8d..3363ffa 100644 --- a/src/Engine/UI/HorizontalLayout.cpp +++ b/src/Engine/UI/HorizontalLayout.cpp @@ -18,14 +18,14 @@ HorizontalLayout::~HorizontalLayout() void HorizontalLayout::apply() { Array children = element->getChildren(); - const Math::Rect parent = element->getBoundingBox(); + const Rect parent = element->getBoundingBox(); float xOffset = parent.offset.x; float yOffset = parent.offset.y; float xSize = parent.size.x / children.size(); float ySize = parent.size.y; for(uint32 index = 0; index < children.size(); ++index) { - Math::Rect& child = children[index]->getBoundingBox(); + Rect& child = children[index]->getBoundingBox(); child.offset.x = xOffset + (index * xSize); child.offset.y = yOffset; child.size.x = xSize; diff --git a/src/Engine/UI/RenderHierarchy.h b/src/Engine/UI/RenderHierarchy.h index 3a1944b..dbccd2b 100644 --- a/src/Engine/UI/RenderHierarchy.h +++ b/src/Engine/UI/RenderHierarchy.h @@ -9,9 +9,9 @@ namespace UI { struct RenderElementStyle { - Math::Vector position = Math::Vector(0, 0, 0); + Vector position = Vector(0, 0, 0); uint32 backgroundImageIndex = UINT32_MAX; - Math::Vector backgroundColor = Math::Vector(1, 1, 1); + Vector backgroundColor = Vector(1, 1, 1); float opacity = 1.0f; //Vector4 borderBottomColor = Vector4(1, 1, 1, 1); //Vector4 borderLeftColor = Vector4(1, 1, 1, 1); @@ -21,7 +21,7 @@ struct RenderElementStyle //float borderBottomRightRadius = 0; //float borderTopLeftRadius = 0; //float borderTopRightRadius = 0; - Math::Vector2 dimensions = Math::Vector2(1, 1); + Vector2 dimensions = Vector2(1, 1); }; class RenderElement { diff --git a/src/Engine/UI/System.cpp b/src/Engine/UI/System.cpp index a12c4ff..8e2b56e 100644 --- a/src/Engine/UI/System.cpp +++ b/src/Engine/UI/System.cpp @@ -31,9 +31,9 @@ UIPassData System::getUIPassData() { UIPassData uiPassData; RenderElementStyle& style = uiPassData.renderElements.add(); - style.position = Math::Vector(0, 0, -0.1); - style.dimensions = Math::Vector2(0.4, 0.4); - style.backgroundColor = Math::Vector(0.2, 0.3, 0.1); + style.position = Vector(0, 0, -0.1); + style.dimensions = Vector2(0.4, 0.4); + style.backgroundColor = Vector(0.2, 0.3, 0.1); style.backgroundImageIndex = 0; uiPassData.usedTextures.add(AssetRegistry::findTexture("")->getTexture()); return uiPassData; @@ -46,9 +46,9 @@ TextPassData System::getTextPassData() render.font = AssetRegistry::findFont("Calibri"); render.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis magna ex. Morbi ullamcorper fringilla risus eget vehicula. Praesent vel quam vel ante molestie gravida vitae ac enim. Donec vitae eleifend orci. Phasellus at sodales lorem, ac eleifend turpis. Vivamus vitae condimentum lacus, a bibendum neque. Ut et est ut felis varius vehicula. Etiam lorem magna, dapibus vitae felis in, vulputate suscipit neque. Aenean facilisis ac risus et scelerisque. Ut tincidunt eros quis posuere iaculis. Curabitur justo lacus, molestie id varius vel, sodales efficitur diam. Integer orci velit, condimentum sit amet turpis sit amet, congue blandit nisl. Donec pretium ligula id mauris pretium commodo. Mauris quis lectus mi. In blandit, dolor non accumsan venenatis, ipsum erat congue neque, quis elementum orci nunc vel justo. "; //render.text = "Seele Engine"; - render.position = Math::Vector2(0.f, 300.f); + render.position = Vector2(0.f, 300.f); render.scale = 0.1f; - render.textColor = Math::Vector4(1, 0, 0, 1); + render.textColor = Vector4(1, 0, 0, 1); return textPassData; } diff --git a/src/Engine/UI/VerticalLayout.cpp b/src/Engine/UI/VerticalLayout.cpp index 8e8356c..76de71d 100644 --- a/src/Engine/UI/VerticalLayout.cpp +++ b/src/Engine/UI/VerticalLayout.cpp @@ -18,14 +18,14 @@ VerticalLayout::~VerticalLayout() void VerticalLayout::apply() { Array children = element->getChildren(); - const Math::Rect parent = element->getBoundingBox(); + const Rect parent = element->getBoundingBox(); float xOffset = parent.offset.x; float yOffset = parent.offset.y; float xSize = parent.size.x; float ySize = parent.size.y / children.size(); for(uint32 index = 0; index < children.size(); ++index) { - Math::Rect& child = children[index]->getBoundingBox(); + Rect& child = children[index]->getBoundingBox(); child.offset.x = xOffset; child.offset.y = yOffset + (index * ySize); child.size.x = xSize; diff --git a/src/Engine/Window/View.cpp b/src/Engine/Window/View.cpp index d34f91c..eea5c6b 100644 --- a/src/Engine/Window/View.cpp +++ b/src/Engine/Window/View.cpp @@ -16,7 +16,7 @@ View::~View() { } -void View::applyArea(Math::URect) +void View::applyArea(URect) { } diff --git a/src/Engine/Window/View.h b/src/Engine/Window/View.h index 46fca21..0cb94e9 100644 --- a/src/Engine/Window/View.h +++ b/src/Engine/Window/View.h @@ -21,7 +21,7 @@ public: // prepare render is also locked, so reading from shared memory is also safe virtual void prepareRender() = 0; virtual void render() = 0; - void applyArea(Math::URect area); + void applyArea(URect area); void setFocused(); const std::string& getName();