diff --git a/Makefile b/Makefile index a6934fe8b9df79ef4c6dda217660c9280ecc9ebc..149798d4ba1f9dc1034f029667b9336c452689d6 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ all: kissinference kissinference_test kissinference: - dotnet msbuild kissinference.csproj -t:Build + dotnet msbuild kissinferencesharp.csproj -t:Build kissinference_test: kissinference dotnet msbuild kissinference_test.csproj -t:Build clean: - dotnet msbuild kissinference.csproj -t:Clean + dotnet msbuild kissinferencesharp.csproj -t:Clean dotnet msbuild kissinference_test.csproj -t:Clean rm -r doc/html doc/latex || true @@ -16,7 +16,7 @@ doc: doxygen doc/libkissinference.doxygen restore: - dotnet restore kissinference.sln + dotnet restore kissinferencesharp.sln dotnet restore kissinference_test.csproj run: diff --git a/doc/libkissinference.doxygen b/doc/libkissinference.doxygen index faf9a6de8b21dc89d75d0c05d161220fdbbe2ba6..0049a94fd362e4f19fa9a17130aac3f91d27cd37 100644 --- a/doc/libkissinference.doxygen +++ b/doc/libkissinference.doxygen @@ -1,4 +1,4 @@ -# Doxyfile 1.9.3 +# Doxyfile 1.10.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = doc -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,14 +109,14 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English @@ -331,6 +359,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -442,7 +481,7 @@ TYPEDEF_HIDES_STRUCT = YES LOOKUP_CACHE_SIZE = 0 -# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use # during processing. When set to 0 doxygen will based this on the number of # cores available in the system. You can set it explicitly to a value larger # than 0 to get more control over the balance between CPU load and processing @@ -455,6 +494,14 @@ LOOKUP_CACHE_SIZE = 0 NUM_PROC_THREADS = 1 +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = NO + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -536,7 +583,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -567,14 +615,15 @@ INTERNAL_DOCS = NO # filesystem is case sensitive (i.e. it supports files in the same directory # whose names only differ in casing), the option must be set to YES to properly # deal with such files in case they appear in the input. For filesystems that -# are not case sensitive the option should be be set to NO to properly deal with +# are not case sensitive the option should be set to NO to properly deal with # output files written for symbols that only differ in casing, such as for two # classes, one named CLASS and the other named Class, and to also support # references to files without having to specify the exact matching casing. On # Windows (including Cygwin) and MacOS, users should typically set this option # to NO, whereas on Linux or other Unix flavors it should typically be set to # YES. -# The default value is: system dependent. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -826,11 +875,26 @@ WARN_IF_INCOMPLETE_DOC = YES WARN_NO_PARAMDOC = YES +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS # then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but # at the end of the doxygen process doxygen will return with a non-zero status. -# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = NO @@ -841,10 +905,21 @@ WARN_AS_ERROR = NO # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). In case the file specified cannot be opened for writing the @@ -864,17 +939,34 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = kissinference.cs doc/mainpage.txt +INPUT = src/network.cs \ + src/spectra.cs \ + src/capi.cs \ + src/utils.cs \ + src/versionfixed.cs \ + src/inferenceexception.cs \ + doc/mainpage.txt # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: # https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -886,12 +978,12 @@ INPUT_ENCODING = UTF-8 # Note the list of default checked file patterns might differ from the list of # default file extension mappings. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, -# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C -# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -931,9 +1023,6 @@ EXCLUDE_PATTERNS = # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # ANamespace::AClass, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = @@ -978,6 +1067,11 @@ IMAGE_PATH = doc/ # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -1019,6 +1113,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -1033,7 +1136,8 @@ USE_MDFILE_AS_MAINPAGE = SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1105,6 +1209,46 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = NO + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = + #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1116,10 +1260,11 @@ VERBATIM_HEADERS = YES ALPHABETICAL_INDEX = NO -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1198,7 +1343,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = doc/style.css @@ -1213,6 +1363,19 @@ HTML_EXTRA_STYLESHEET = doc/style.css HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see @@ -1243,15 +1406,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = NO - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1271,6 +1425,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1401,6 +1582,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1576,17 +1767,6 @@ HTML_FORMULA_FORMAT = png FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1900,9 +2080,16 @@ PDF_HYPERLINKS = NO USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if <return> is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1923,14 +2110,6 @@ LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -2096,13 +2275,39 @@ DOCBOOK_OUTPUT = docbook #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2177,7 +2382,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2244,15 +2450,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2266,16 +2472,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2284,7 +2483,7 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO # The default value is: NO. @@ -2301,37 +2500,55 @@ HAVE_DOT = YES DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see <a href=https://graphviz.org/doc/info/attrs.html>Node, +# Edge and Graph Attributes specification</a> You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. <a +# href=https://graphviz.org/doc/info/arrows.html>Complete documentation about +# arrows shapes.</a> +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' <a +# href=https://www.graphviz.org/doc/info/shapes.html>Shapes specification</a> +# The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a -# graph for each documented class showing the direct and indirect inheritance -# relations. In case HAVE_DOT is set as well dot will be used to draw the graph, -# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set -# to TEXT the direct and indirect inheritance relations will be shown as texts / -# links. -# Possible values are: NO, YES, TEXT and GRAPH. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. CLASS_GRAPH = TEXT @@ -2339,14 +2556,21 @@ CLASS_GRAPH = TEXT # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2388,8 +2612,8 @@ DOT_UML_DETAILS = NO # The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters # to display on a single line. If the actual line length exceeds this threshold -# significantly it will wrapped across multiple lines. Some heuristics are apply -# to avoid ugly line breaks. +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. # Minimum value: 0, maximum value: 1000, default value: 17. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2406,7 +2630,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2415,7 +2641,10 @@ INCLUDE_GRAPH = NO # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2455,7 +2684,10 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2471,7 +2703,7 @@ DIR_GRAPH_MAX_DEPTH = 1 # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). @@ -2508,11 +2740,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2562,18 +2795,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2601,3 +2822,19 @@ GENERATE_LEGEND = NO # The default value is: YES. DOT_CLEANUP = NO + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# <outfile_format> -o <outputfile> <inputfile>. The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = diff --git a/doc/mainpage.txt b/doc/mainpage.txt index 55abec9d8967c0abb56017ffe12a4a45d1fe99e4..80a66fa5a47e52d15e33833dc0be1d7a26d1dfde 100644 --- a/doc/mainpage.txt +++ b/doc/mainpage.txt @@ -1,12 +1,12 @@ /*! \mainpage libkissinferencesharp manual -_libkissinferencesharp_ is a c# libary containing bindings to the c libary libkissinference that allows client applicaitons to use KISS neural networks for varous tasks. +_libkissinferencesharp_ is a C# libary containing bindings to the C libary libkissinference that allows client applicaitons to use KISS neural networks for varous tasks. -A full description of the api can be found here: \ref API +The best place to start, and probubly the only classes most users of this libary will need can be found here: \ref Kiss.Network and \ref Kiss.Spectra ## Building -the main development platform of _libkissinferencesharp_ is explicitly cross-platform and has minimal dependancies. It is tested to work in Linux and Microsoft Windows 10. +The main development platform of _libkissinferencesharp_ is explicitly cross-platform and has minimal dependancies. It is tested to work in Linux and Microsoft Windows 10. ### Requirements - [git](https://git-scm.com/) is required to get the source diff --git a/kissinference.cs b/kissinference.cs deleted file mode 100644 index 7cf6066abaadae024827a29fcf5a8317388c00f8..0000000000000000000000000000000000000000 --- a/kissinference.cs +++ /dev/null @@ -1,611 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Collections.Generic; -using System.Threading; - -namespace Kiss -{ - -/// <summary> -/// Struct <c>VersionFixed</c> reprisents the version of kissinference -/// </summary> -[StructLayout (LayoutKind.Sequential)] -public struct VersionFixed -{ - public int Major; - public int Minor; - public int Patch; - - /// <summary> - /// This Method returns the version of the currently loaded kissinference instance. - /// </summary> - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_get_version", CallingConvention=CallingConvention.StdCall)] - public static extern VersionFixed GetVersion(); -} - - -/// <summary> -/// This Exception is thrown when an error occures during infference, usualy due to oom. -/// </summary> -public class InferenceException : Exception -{ - public InferenceException(){} - public InferenceException(string message): base(message){} - public InferenceException(string message, Exception inner): base(message, inner){} -} - - -/// <summary> -/// This is the main class of kissinference, it allows you to load and use Kiss neural neturoks -/// </summary> -public class Network: System.IDisposable -{ - public delegate void ResultDlg(float[] result, Network network); - - private struct Flight - { - public ResultDlg Callback; - public AutoResetEvent Signal; - } - - private CNetwork net; - private bool disposed = false; - private Dictionary<IntPtr, Flight> inflight = new Dictionary<IntPtr, Flight>(); - private IntPtr flightcounter = (IntPtr)0; - - private void CResultCb(IntPtr result, ref CNetwork network, IntPtr data) - { - var managedResult = new float[(int)net.outputSize]; - Marshal.Copy(result, managedResult, 0, (int)net.outputSize); - Capi.free(result); - var flight = inflight[data]; - inflight.Remove(data); - flight.Callback(managedResult, this); - flight.Signal.Set(); - } - - /// <summary> - /// Constructs a new Network object by loading a network off disk - /// </summary> - /// <param name="path"> - /// the path to the onnx network file to load - /// </param> - /// <param name="verbose"> - /// if true is set here some extra debug information will be printed by the runtime - /// </param> - /// <exception cref="System.IO.FileLoadException"> - /// Thrown when the network file could not be loaded - /// </exception> - public Network(string path, bool verbose = false) - { - byte ret = Capi.kiss_load_network_prealloc(ref net, path, CResultCb, Convert.ToByte(verbose)); - Console.WriteLine("ret: {0:D}", ret); - if(ret == 0) - throw new System.IO.FileLoadException(getError()); - } - - /// <summary> - /// This method runs an inference pass on the given spectra asynchronously - /// </summary> - /// <param name="spectra"> - /// the spectra to run inference on, must be of InputSize length - /// </param> - /// <param name="callback"> - /// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool - /// </param> - /// <exception cref="ArgumentException"> - /// Thrown when the input is of an incorrect size for the network - /// </exception> - /// <exception cref="InferenceException"> - /// Thrown when the inference engine encounteres an internal error - /// </exception> - /// <returns> - /// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed. - /// </returns> - public AutoResetEvent Run(Spectra spectra, ResultDlg callback) - { - if(spectra.Real.Length*2 != (int)net.inputSize) - throw new ArgumentException("Spectra is the wrong size for network, use resample() first"); - var flight = new Flight(); - flight.Callback = callback; - flight.Signal = new AutoResetEvent(false); - inflight.Add(flightcounter, flight); - byte ret = Capi.kiss_async_run_inference_complex(ref net, spectra.Real, spectra.Imaginary, flightcounter); - if(ret == 0) - throw new InferenceException(getError()); - - flightcounter += 1; - return flight.Signal; - } - - /// <summary> - /// This method runs an inference pass on the given spectra asynchronously - /// </summary> - /// <param name="data"> - /// and array of floats containing the data inference on, must be of InputSize length - /// </param> - /// <param name="callback"> - /// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool - /// </param> - /// <exception cref="ArgumentException"> - /// Thrown when the input is of an incorrect size for the network - /// </exception> - /// <exception cref="InferenceException"> - /// Thrown when the inference engine encounteres an internal error - /// </exception> - /// <returns> - /// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed. - /// </returns> - public AutoResetEvent Run(float[] data, ResultDlg callback) - { - if(data.Length != (int)net.inputSize) - throw new ArgumentException("Data is the wrong size for network"); - var flight = new Flight(); - flight.Callback = callback; - flight.Signal = new AutoResetEvent(false); - inflight.Add(flightcounter, flight); - byte ret = Capi.kiss_async_run_inference(ref net, data, flightcounter); - if(ret == 0) - throw new InferenceException(getError()); - flightcounter += 1; - return flight.Signal; - } - - /// <summary> - /// This method returns an error string for the last error to have occured in the libkissiniference. - /// Usually this method is not usefull as all errors reported by this interface are forwared via exceptions, - /// It is provided to ease implementations that also call the C api directly. - /// </summary> - /// <returns> - /// A string describeing the last reported error. - /// </returns> - private string getError() - { -#if (NET6_0_OR_GREATER) - return Marshal.PtrToStringUTF8(Capi.kiss_get_strerror(ref net)); -#else - return Capi.UTF8StringFromPointer(Capi.kiss_get_strerror(ref net)); -#endif - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if(!disposed) - { - disposed = true; - Capi.kiss_free_network_prealloc(ref net); - } - } - - ~Network() - { - Dispose(false); - } - - /// <summary> - /// This Property holds the number of input values the loaded network expects. - /// For networks with a convolutional input this may be -1 designateing "Any" - /// </summary> - public int InputSize - { - get{return (int)net.inputSize;} - } - - /// <summary> - /// This Property holds the number of output values the loaded network expects. - /// </summary> - public int OutputSize - { - get{return (int)net.outputSize;} - } - - /// <summary> - /// This Property holds a string describeing the purpose the network was trained on. - /// </summary> - public string Purpose - { - get{return Marshal.PtrToStringAnsi(net.purpose);} - } - - /// <summary> - /// This Property holds a string describeing the type of input the network expects. - /// </summary> - public string InputLabel - { - get{return Marshal.PtrToStringAnsi(net.inputLabel);} - } - - /// <summary> - /// This Property is true if the network expects a complex valued input - /// </summary> - public bool ComplexInput - { - get{return Convert.ToBoolean(net.complexInput);} - } - - /// <summary> - /// This Property is an array of OutputSize with strings nameing what every output corrisponds to - /// </summary> - public string[] OutputLabels - { - get{return Capi.IntPtrToUtf8Array(net.outputLabels);} - } -} - -/// <summary> -/// This Class holds an impedance spectra and provides various transformations that are required to get the values into a form expected by kiss networks -/// </summary> -public class Spectra -{ - /// <summary> - /// The real part of the spectra - /// </summary> - public float[] Real; - - /// <summary> - /// The imaginary part of the spectra - /// </summary> - public float[] Imaginary; - - /// <summary> - /// The frequencys of the datapoints of the spectra - /// </summary> - public float[] Omega; - - /// <summary> - /// This constructor constructs a spectra from a series of arrays - /// </summary> - /// <param name="Real"> - /// The real part of the spectra - /// </param> - /// <param name="Imaginary"> - /// The imaginary part of the spectra, its length must be the same as Real - /// </param> - /// <param name="Omega"> - /// The frequency values in rad/s of eatch datapoint, its lenght must be the same as Real - /// </param> - public Spectra(float[] Real, float[] Imaginary, float[] Omega) - { - if(Real.Length != Imaginary.Length || Real.Length != Omega.Length) - throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size"); - this.Real = Real; - this.Imaginary = Imaginary; - this.Omega = Omega; - } - - /// <summary> - /// This constructor constructs a spectra from a series of arrays - /// </summary> - /// <param name="Real"> - /// The real part of the spectra - /// </param> - /// <param name="Imaginary"> - /// The imaginary part of the spectra, its length must be the same as Real - /// </param> - /// <param name="Omega"> - /// The frequency values in rad/s of eatch datapoint, its lenght must be the same as Real - /// </param> - public Spectra(double[] Real, double[] Imaginary, double[] Omega) - { - if(Real.Length != Imaginary.Length || Real.Length != Omega.Length) - throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size"); - this.Real = DoubleToFloat(Real); - this.Imaginary = DoubleToFloat(Imaginary); - this.Omega = DoubleToFloat(Omega); - } - - /// <summary> - /// This method normalizes the data into the range [0, 1] - /// </summary> - public void Normalize() - { - Capi.kiss_normalize_spectra(Real, Imaginary, (UIntPtr)Real.Length); - } - - /// <summary> - /// This method resamples the spectra to the size given in newSize. - /// Upsampling is achived via linear interpolation, downsampling is achived via the nearest-neighbor method. - /// </summary> - /// <param name="newSize"> - /// The size to resample the spectra to - /// </param> - public void Resample(int newSize) - { - var ret_ptr_real = new IntPtr(); - var ret_ptr_imag = new IntPtr(); - Capi.kiss_resample_spectra(Real, Imaginary, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)newSize); - - Real = new float[newSize]; - Imaginary = new float[newSize]; - Marshal.Copy(ret_ptr_real, Real, 0, newSize); - Marshal.Copy(ret_ptr_imag, Imaginary, 0, newSize); - - Capi.free(ret_ptr_real); - Capi.free(ret_ptr_imag); - } - - /// <summary> - /// Approximate the element wise absolute gradient at the given point of the sepctra in the place given - /// </summary> - /// <param name="index"> - /// The index at which to aproxmiate the gradiant - /// </param> - /// <return> - /// The element wise absolute of the gradiant as a tuple of floats - /// </return> - public Tuple<float, float> Absgrad(int index) - { - var resultArray = new float[2]; - IntPtr ptr = Capi.kiss_absgrad(Real, Imaginary, Omega, (UIntPtr)Real.Length, (UIntPtr)index); - Marshal.Copy(ptr, resultArray, 0, 2); - Capi.free(ptr); - return new Tuple<float, float>(resultArray[0], resultArray[1]); - } - - /// <summary> - /// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training. - /// - /// In almost all cases this function should be called before a sepctra is given to a kiss network. - /// </summary> - /// <param name="outputSize"> - /// the length the spectra should have after filtering - /// </param> - /// <return> - /// True if sucessfull, false otherwise - /// </return> - public bool Filter(int outputSize) - { - var ret_ptr_real = new IntPtr(); - var ret_ptr_imag = new IntPtr(); - byte ret = Capi.kiss_filter_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)outputSize); - - if(ret == 1) - { - Real = new float[(int)outputSize]; - Imaginary = new float[(int)outputSize]; - Marshal.Copy(ret_ptr_real, Real, 0, (int)outputSize); - Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)outputSize); - Capi.free(ret_ptr_real); - Capi.free(ret_ptr_imag); - } - - return Convert.ToBoolean(ret); - } - - /// <summary> - /// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training. - /// - /// In almost all cases this function should be called before a sepctra is given to a kiss network. - /// </summary> - /// <param name="outputSize"> - /// the length the spectra should have after filtering - /// </param> - /// <return> - /// True if sucessfull, false otherwise - /// </return> - public bool Reduce(float threshFactor, bool useSecondDeriv) - { - var ret_ptr_real = new IntPtr(); - var ret_ptr_imag = new IntPtr(); - var lengthPtr = new UIntPtr(); - byte ret = Capi.kiss_reduce_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, threshFactor, Convert.ToByte(useSecondDeriv), ref ret_ptr_real, ref ret_ptr_imag, ref lengthPtr); - - if(ret == 1) - { - Real = new float[(int)lengthPtr]; - Imaginary = new float[(int)lengthPtr]; - Marshal.Copy(ret_ptr_real, Real, 0, (int)lengthPtr); - Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)lengthPtr); - Capi.free(ret_ptr_real); - Capi.free(ret_ptr_imag); - } - - return Convert.ToBoolean(ret); - } - - /// <summary> - /// Converts an array of doubles to an array of floats. - /// </summary> - /// <param name="input"> - /// The input array. - /// </param> - /// <return> - /// An array with the same values as the input truncated to floats. - /// </return> - private static float[] DoubleToFloat(double[] input) - { - var res = new float[input.Length]; - for(int i = 0; i < input.Length; ++i) - res[i] = (float)input[i]; - return res; - } - -} - -/// <summary> -/// This class is a collection of static methods usefull for use with kissinference. -/// </summary> -public class Utils -{ - /// <summary> - /// Converts an array containing a linear or log range. - /// </summary> - /// <param name="start"> - /// The startig value of the range. - /// </param> - /// <param name="end"> - /// The ending value of the range. - /// </param> - /// <param name="size"> - /// The number of elements in the range. - /// </param> - /// <param name="log"> - /// If this is set to true the elements in the range are spaced in log10 fashion, otherwise linear spaceing is used. - /// </param> - /// <return> - /// An array containing the requested range - /// </return> - public static float[] CreateRange(float start, float end, int size, bool log) - { - IntPtr ptr = Capi.kiss_create_range(start, end, (UIntPtr)size, Convert.ToByte(log)); - var ret = new float[size]; - Marshal.Copy(ptr, ret, 0, size); - Capi.free(ptr); - return ret; - } - - /// <summary> - /// Approximates the the derivative of an array at the given index. - /// </summary> - /// <param name="data"> - /// The array, or y values, to approximate the derivative on - /// </param> - /// <param name="omegas"> - /// The omega, or x values to approximate the derivative on - /// </param> - /// <param name="index"> - /// The index at which to aproxmiate the gradiant at. - /// </param> - /// <return> - /// The aproxmiate derivative. - /// </return> - public static float Grad(float[] data, float[] omegas, int index) - { - if(data.Length != omegas.Length) - throw new ArgumentException("the data and omegas must be the same length"); - return Capi.kiss_grad(data, omegas, (UIntPtr)data.Length, (UIntPtr)index); - } - - /// <summary> - /// Calculates the median of the values given - /// </summary> - /// <param name="input"> - /// The input array. - /// </param> - /// <return> - /// The median value - /// </return> - public static float Median(float[] data) - { - return Capi.kiss_median(data, (UIntPtr)data.Length); - } -} - -/// <summary> -/// This struct is a raw repisenstion of the C struct used in libkissiniference, ususally users of these bindings will not need to directly use this. -/// </summary> -[StructLayout (LayoutKind.Sequential)] -public struct CNetwork -{ - private IntPtr _private; - public UIntPtr inputSize; - public UIntPtr outputSize; - public IntPtr purpose; - public IntPtr inputLabel; - public IntPtr outputLabels; - public byte complexInput; - public byte ready; - public byte softmax; - private IntPtr _resultCb; -} - -internal class Capi -{ - public delegate void resultDlg(IntPtr result, ref CNetwork network, IntPtr data); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_free", CallingConvention=CallingConvention.StdCall)] - public static extern void free(IntPtr ptr); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern IntPtr kiss_create_range(float start, float end, UIntPtr length, byte log); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern void kiss_resample_spectra(float[] in_re, float[] in_im, UIntPtr input_length, ref IntPtr ret_ptr_real, ref IntPtr ret_ptr_imag, UIntPtr output_length); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern void kiss_normalize_spectra(float[] in_re, float[] in_im, UIntPtr input_length); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern IntPtr kiss_absgrad(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, UIntPtr index); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern float kiss_grad(float[] data, float[] omegas, UIntPtr input_length, UIntPtr index); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern float kiss_median(float[] data, UIntPtr input_length); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern byte kiss_reduce_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, float thresh_factor, - byte use_second_deriv, ref IntPtr out_re, ref IntPtr out_im, ref UIntPtr output_length); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - - public static extern byte kiss_filter_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, - ref IntPtr out_re, ref IntPtr out_im, UIntPtr output_length); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern byte kiss_load_network_prealloc(ref CNetwork net, string path, resultDlg callback, byte verbose); - - [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern void puts(string path); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern void kiss_free_network_prealloc(ref CNetwork net); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern byte kiss_async_run_inference(ref CNetwork net, [Out] float[] inputs, IntPtr data); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern byte kiss_async_run_inference_complex(ref CNetwork net, [Out] float[] real, [Out] float[] imag, IntPtr data); - - [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] - public static extern IntPtr kiss_get_strerror(ref CNetwork net); - - - public static unsafe string[] IntPtrToUtf8Array(IntPtr array) - { - IntPtr* ptr = (IntPtr*)array.ToPointer(); - int size = 0; - while(ptr[size] != IntPtr.Zero) - ++size; - string[] OutputStrArray = new string[size]; - -#if (NET6_0_OR_GREATER) - for(int i = 0; i < size; i++) - OutputStrArray[i] = Marshal.PtrToStringUTF8(ptr[i]); -#else - for(int i = 0; i < size; i++) - OutputStrArray[i] = UTF8StringFromPointer(ptr[i]); -#endif - - return OutputStrArray; - } - -#if (NETSTANDARD2_0_OR_GREATER) - public static string UTF8StringFromPointer(IntPtr ptr) - { - var bytes = new List<byte>(128); - var idx = 0; - while (true) - { - var b = Marshal.ReadByte(ptr, idx); - if (b == 0) - { - break; - } - - bytes.Add(b); - } - - return System.Text.Encoding.UTF8.GetString(bytes.ToArray()); - } -#endif -} - -} diff --git a/kissinference.csproj b/kissinference.csproj deleted file mode 100644 index cfe9bad193903c0c378a465e056ac2ff34413ee3..0000000000000000000000000000000000000000 --- a/kissinference.csproj +++ /dev/null @@ -1,13 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> -<PropertyGroup> - <AssemblyName>kissinference</AssemblyName> - <OutputPath>bin\</OutputPath> - <OutputType>library</OutputType> - <AllowUnsafeBlocks>true</AllowUnsafeBlocks> - <TargetFrameworks>netstandard2.0;net6;net7;net8</TargetFrameworks> - <EnableDefaultCompileItems>false</EnableDefaultCompileItems> -</PropertyGroup> -<ItemGroup> - <Compile Include="kissinference.cs" /> -</ItemGroup> -</Project> diff --git a/kissinference_test.csproj b/kissinference_test.csproj index 0b18f8a538982e219a3eb894896ee896b7db5082..ec10ed5b93f78fe7dda3be6b70842efe15e46be9 100644 --- a/kissinference_test.csproj +++ b/kissinference_test.csproj @@ -9,9 +9,9 @@ </PropertyGroup> <ItemGroup> - <Reference Include="kissinference"> - <HintPath>bin\$(TargetFramework)\kissinference.dll</HintPath> + <Reference Include="kissinferencesharp"> + <HintPath>bin\$(TargetFramework)\kissinferencesharp.dll</HintPath> </Reference> - <Compile Include="program.cs" /> + <Compile Include="src/test.cs" /> </ItemGroup> </Project> diff --git a/kissinferencesharp.csproj b/kissinferencesharp.csproj new file mode 100644 index 0000000000000000000000000000000000000000..88cf2a4b5a175bd53325af71dbc8077b8ad7cf0d --- /dev/null +++ b/kissinferencesharp.csproj @@ -0,0 +1,22 @@ +<Project Sdk="Microsoft.NET.Sdk"> +<PropertyGroup> + <AssemblyName>kissinferencesharp</AssemblyName> + <OutputPath>bin\</OutputPath> + <OutputType>library</OutputType> + <TargetFrameworks>netstandard2.0;net6;net7;net8</TargetFrameworks> + <EnableDefaultCompileItems>false</EnableDefaultCompileItems> + <VersionPrefix>1.0.0</VersionPrefix> + <Title>KISS Inference</Title> + <Authors>Carl Philipp Klemm</Authors> + <Company>rhd instruments GmbH and Co. KG</Company> + <Description>A .NET interface for model inference from impedance spectra.</Description> +</PropertyGroup> +<ItemGroup> + <Compile Include="src/capi.cs" /> + <Compile Include="src/network.cs"/> + <Compile Include="src/inferenceexception.cs" /> + <Compile Include="src/utils.cs" /> + <Compile Include="src/spectra.cs" /> + <Compile Include="src/versionfixed.cs" /> +</ItemGroup> +</Project> diff --git a/kissinference.sln b/kissinferencesharp.sln similarity index 92% rename from kissinference.sln rename to kissinferencesharp.sln index cd5c5b3cf4ac3f46d1c510436e765947a61a4c7d..a48e6214a262c17550dd36331f9ccc98ea7015d3 100644 --- a/kissinference.sln +++ b/kissinferencesharp.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.9.34728.123 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "kissinference", "kissinference.csproj", "{B5C86025-19DE-4DCC-BE8A-63C85EEBC870}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "kissinferencesharp", "kissinferencesharp.csproj", "{B5C86025-19DE-4DCC-BE8A-63C85EEBC870}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/capi.cs b/src/capi.cs new file mode 100644 index 0000000000000000000000000000000000000000..18871c07d7e68e2cc1da70d1832e61ac972a6ede --- /dev/null +++ b/src/capi.cs @@ -0,0 +1,116 @@ +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; + +namespace Kiss +{ + +/// <summary> +/// This struct is a raw repisenstion of the C struct used in libkissiniference. Ususally users of these bindings will not need to directly use this. +/// </summary> +[StructLayout (LayoutKind.Sequential)] +public struct CNetwork +{ + private IntPtr _private; + public UIntPtr inputSize; + public UIntPtr outputSize; + public IntPtr purpose; + public IntPtr inputLabel; + public IntPtr outputLabels; + public byte complexInput; + public byte ready; + public byte softmax; + private IntPtr _resultCb; +} + +internal class Capi +{ + public delegate void resultDlg(IntPtr result, ref CNetwork network, IntPtr data); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_free", CallingConvention=CallingConvention.StdCall)] + public static extern void free(IntPtr ptr); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern IntPtr kiss_create_range(float start, float end, UIntPtr length, byte log); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern void kiss_resample_spectra(float[] in_re, float[] in_im, UIntPtr input_length, ref IntPtr ret_ptr_real, ref IntPtr ret_ptr_imag, UIntPtr output_length); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern void kiss_normalize_spectra(float[] in_re, float[] in_im, UIntPtr input_length); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern IntPtr kiss_absgrad(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, UIntPtr index); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern float kiss_grad(float[] data, float[] omegas, UIntPtr input_length, UIntPtr index); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern float kiss_median(float[] data, UIntPtr input_length); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern byte kiss_reduce_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, float thresh_factor, + byte use_second_deriv, ref IntPtr out_re, ref IntPtr out_im, ref UIntPtr output_length); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + + public static extern byte kiss_filter_spectra(float[] in_re, float[] in_im, float[] omegas, UIntPtr input_length, + ref IntPtr out_re, ref IntPtr out_im, UIntPtr output_length); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern byte kiss_load_network_prealloc(ref CNetwork net, string path, resultDlg callback, byte verbose); + + [DllImport("libc", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern void puts(string path); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern void kiss_free_network_prealloc(ref CNetwork net); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern byte kiss_async_run_inference(ref CNetwork net, [Out] float[] inputs, IntPtr data); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern byte kiss_async_run_inference_complex(ref CNetwork net, [Out] float[] real, [Out] float[] imag, IntPtr data); + + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention=CallingConvention.StdCall)] + public static extern IntPtr kiss_get_strerror(ref CNetwork net); + + public static string[] IntPtrToUtf8Array(IntPtr array) + { + var pointers = new List<IntPtr>(); + var size = Marshal.SizeOf<IntPtr>(); + var idx = 0; + while (true) + { + var ptr = Marshal.ReadIntPtr(array, idx * size); + if (ptr == IntPtr.Zero) + break; + pointers.Add(ptr); + idx++; + } + + var res = new List<string>(); + foreach (var p in pointers) + res.Add(UTF8StringFromPointer(p)); + + return res.ToArray(); + } + + public static string UTF8StringFromPointer(IntPtr ptr) + { + var bytes = new List<byte>(128); + var idx = 0; + while (true) + { + var b = Marshal.ReadByte(ptr, idx); + if (b == 0) + break; + + bytes.Add(b); + } + + return System.Text.Encoding.UTF8.GetString(bytes.ToArray()); + } +} + +} diff --git a/src/inferenceexception.cs b/src/inferenceexception.cs new file mode 100644 index 0000000000000000000000000000000000000000..dc95710f6acce64d327de85b6486cafdd58a26ef --- /dev/null +++ b/src/inferenceexception.cs @@ -0,0 +1,16 @@ +using System; + +namespace Kiss +{ + +/// <summary> +/// This exception is thrown when an error occures during inference, usually due to running out of memory. +/// </summary> +public class InferenceException : Exception +{ + public InferenceException(){} + public InferenceException(string message): base(message){} + public InferenceException(string message, Exception inner): base(message, inner){} +} + +} diff --git a/src/network.cs b/src/network.cs new file mode 100644 index 0000000000000000000000000000000000000000..746f8b4846c171b064ed749aa1a32482eb584f1b --- /dev/null +++ b/src/network.cs @@ -0,0 +1,212 @@ +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using System.Threading; + +namespace Kiss +{ + +/// <summary> +/// This is the main class of kissinference, it allows you to load and use Kiss neural neturoks +/// </summary> +public class Network: System.IDisposable +{ + public delegate void ResultDlg(float[] result, Network network); + + private struct Flight + { + public ResultDlg Callback; + public AutoResetEvent Signal; + } + + private CNetwork net; + private bool disposed = false; + private Dictionary<IntPtr, Flight> inflight = new Dictionary<IntPtr, Flight>(); + private IntPtr flightcounter = (IntPtr)0; + + private void CResultCb(IntPtr result, ref CNetwork network, IntPtr data) + { + var managedResult = new float[(int)net.outputSize]; + Marshal.Copy(result, managedResult, 0, (int)net.outputSize); + Capi.free(result); + var flight = inflight[data]; + inflight.Remove(data); + flight.Callback(managedResult, this); + flight.Signal.Set(); + } + + /// <summary> + /// Constructs a new Network object by loading a network off disk + /// </summary> + /// <param name="path"> + /// the path to the onnx network file to load + /// </param> + /// <param name="verbose"> + /// if true is set here some extra debug information will be printed by the runtime + /// </param> + /// <exception cref="System.IO.FileLoadException"> + /// Thrown when the network file could not be loaded + /// </exception> + public Network(string path, bool verbose = false) + { + byte ret = Capi.kiss_load_network_prealloc(ref net, path, CResultCb, Convert.ToByte(verbose)); + Console.WriteLine("ret: {0:D}", ret); + if(ret == 0) + throw new System.IO.FileLoadException(getError()); + } + + /// <summary> + /// This method runs an inference pass on the given spectra asynchronously + /// </summary> + /// <param name="spectra"> + /// the spectra to run inference on, must be of InputSize length + /// </param> + /// <param name="callback"> + /// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool + /// </param> + /// <exception cref="ArgumentException"> + /// Thrown when the input is of an incorrect size for the network + /// </exception> + /// <exception cref="InferenceException"> + /// Thrown when the inference engine encounteres an internal error + /// </exception> + /// <returns> + /// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed. + /// </returns> + public AutoResetEvent Run(Spectra spectra, ResultDlg callback) + { + if(spectra.Real.Length*2 != (int)net.inputSize) + throw new ArgumentException("Spectra is the wrong size for network, use resample() first"); + var flight = new Flight(); + flight.Callback = callback; + flight.Signal = new AutoResetEvent(false); + inflight.Add(flightcounter, flight); + byte ret = Capi.kiss_async_run_inference_complex(ref net, spectra.Real, spectra.Imaginary, flightcounter); + if(ret == 0) + throw new InferenceException(getError()); + + flightcounter += 1; + return flight.Signal; + } + + /// <summary> + /// This method runs an inference pass on the given spectra asynchronously + /// </summary> + /// <param name="data"> + /// and array of floats containing the data inference on, must be of InputSize length + /// </param> + /// <param name="callback"> + /// a delegate that will be called when inference completes, this callback will be called from a native thread in libkissiniferences thread pool + /// </param> + /// <exception cref="ArgumentException"> + /// Thrown when the input is of an incorrect size for the network + /// </exception> + /// <exception cref="InferenceException"> + /// Thrown when the inference engine encounteres an internal error + /// </exception> + /// <returns> + /// The AutoResetEvent returned can be waited on to ensure that the inference is finished and the callback has been executed. + /// </returns> + public AutoResetEvent Run(float[] data, ResultDlg callback) + { + if(data.Length != (int)net.inputSize) + throw new ArgumentException("Data is the wrong size for network"); + var flight = new Flight(); + flight.Callback = callback; + flight.Signal = new AutoResetEvent(false); + inflight.Add(flightcounter, flight); + byte ret = Capi.kiss_async_run_inference(ref net, data, flightcounter); + if(ret == 0) + throw new InferenceException(getError()); + flightcounter += 1; + return flight.Signal; + } + + /// <summary> + /// This method returns an error string for the last error to have occured in the libkissiniference. + /// Usually this method is not usefull as all errors reported by this interface are forwared via exceptions, + /// It is provided to ease implementations that also call the C api directly. + /// </summary> + /// <returns> + /// A string describeing the last reported error. + /// </returns> + private string getError() + { +#if (NET6_0_OR_GREATER) + return Marshal.PtrToStringUTF8(Capi.kiss_get_strerror(ref net)); +#else + return Capi.UTF8StringFromPointer(Capi.kiss_get_strerror(ref net)); +#endif + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if(!disposed) + { + disposed = true; + Capi.kiss_free_network_prealloc(ref net); + } + } + + ~Network() + { + Dispose(false); + } + + /// <summary> + /// This Property holds the number of input values the loaded network expects. + /// For networks with a convolutional input this may be -1 designateing "Any" + /// </summary> + public int InputSize + { + get{return (int)net.inputSize;} + } + + /// <summary> + /// This Property holds the number of output values the loaded network expects. + /// </summary> + public int OutputSize + { + get{return (int)net.outputSize;} + } + + /// <summary> + /// This Property holds a string describeing the purpose the network was trained on. + /// </summary> + public string Purpose + { + get{return Marshal.PtrToStringAnsi(net.purpose);} + } + + /// <summary> + /// This Property holds a string describeing the type of input the network expects. + /// </summary> + public string InputLabel + { + get{return Marshal.PtrToStringAnsi(net.inputLabel);} + } + + /// <summary> + /// This Property is true if the network expects a complex valued input + /// </summary> + public bool ComplexInput + { + get{return Convert.ToBoolean(net.complexInput);} + } + + /// <summary> + /// This Property is an array of OutputSize with strings nameing what every output corrisponds to + /// </summary> + public string[] OutputLabels + { + get{return Capi.IntPtrToUtf8Array(net.outputLabels);} + } +} + +} diff --git a/src/spectra.cs b/src/spectra.cs new file mode 100644 index 0000000000000000000000000000000000000000..cde143beaecc9bc525ba2bd54629f2ac23a3155c --- /dev/null +++ b/src/spectra.cs @@ -0,0 +1,197 @@ +using System; +using System.Runtime.InteropServices; + +namespace Kiss +{ + +/// <summary> +/// This Class holds an impedance spectra and provides various transformations that are required to get the values into a form expected by kiss networks +/// </summary> +public class Spectra +{ + /// <summary> + /// The real part of the spectra + /// </summary> + public float[] Real; + + /// <summary> + /// The imaginary part of the spectra + /// </summary> + public float[] Imaginary; + + /// <summary> + /// The frequencys of the datapoints of the spectra + /// </summary> + public float[] Omega; + + /// <summary> + /// This constructor constructs a spectra from a series of arrays + /// </summary> + /// <param name="Real"> + /// The real part of the spectra + /// </param> + /// <param name="Imaginary"> + /// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/> + /// </param> + /// <param name="Omega"> + /// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/> + /// </param> + public Spectra(float[] Real, float[] Imaginary, float[] Omega) + { + if(Real.Length != Imaginary.Length || Real.Length != Omega.Length) + throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size"); + this.Real = Real; + this.Imaginary = Imaginary; + this.Omega = Omega; + } + + /// <summary> + /// This constructor constructs a spectra from a series of arrays + /// </summary> + /// <param name="Real"> + /// The real part of the spectra + /// </param> + /// <param name="Imaginary"> + /// The imaginary part of the spectra, its length must be the same as <paramref name="Real"/> + /// </param> + /// <param name="Omega"> + /// The frequency values in rad/s of eatch datapoint, its lenght must be the same as <paramref name="Real"/> + /// </param> + public Spectra(double[] Real, double[] Imaginary, double[] Omega) + { + if(Real.Length != Imaginary.Length || Real.Length != Omega.Length) + throw new ArgumentException("the real, imaginary and omega parts of the spectra have to be of the same size"); + this.Real = DoubleToFloat(Real); + this.Imaginary = DoubleToFloat(Imaginary); + this.Omega = DoubleToFloat(Omega); + } + + /// <summary> + /// This method normalizes the data into the range [0, 1] + /// </summary> + public void Normalize() + { + Capi.kiss_normalize_spectra(Real, Imaginary, (UIntPtr)Real.Length); + } + + /// <summary> + /// This method resamples the spectra to the size given in newSize. + /// Upsampling is achived via linear interpolation, downsampling is achived via the nearest-neighbor method. + /// </summary> + /// <param name="newSize"> + /// The size to resample the spectra to + /// </param> + public void Resample(int newSize) + { + var ret_ptr_real = new IntPtr(); + var ret_ptr_imag = new IntPtr(); + Capi.kiss_resample_spectra(Real, Imaginary, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)newSize); + + Real = new float[newSize]; + Imaginary = new float[newSize]; + Marshal.Copy(ret_ptr_real, Real, 0, newSize); + Marshal.Copy(ret_ptr_imag, Imaginary, 0, newSize); + + Capi.free(ret_ptr_real); + Capi.free(ret_ptr_imag); + } + + /// <summary> + /// Approximate the element wise absolute gradient at the given point of the sepctra in the place given + /// </summary> + /// <param name="index"> + /// The index at which to aproxmiate the gradiant + /// </param> + /// <returns> + /// The element wise absolute of the gradiant as a tuple of floats + /// </returns> + public Tuple<float, float> Absgrad(int index) + { + var resultArray = new float[2]; + IntPtr ptr = Capi.kiss_absgrad(Real, Imaginary, Omega, (UIntPtr)Real.Length, (UIntPtr)index); + Marshal.Copy(ptr, resultArray, 0, 2); + Capi.free(ptr); + return new Tuple<float, float>(resultArray[0], resultArray[1]); + } + + /// <summary> + /// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training. + /// + /// In almost all cases this function should be called before a sepctra is given to a kiss network. + /// </summary> + /// <param name="outputSize"> + /// the length the spectra should have after filtering + /// </param> + /// <returns> + /// True if sucessfull, false otherwise + /// </returns> + public bool Filter(int outputSize) + { + var ret_ptr_real = new IntPtr(); + var ret_ptr_imag = new IntPtr(); + byte ret = Capi.kiss_filter_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, ref ret_ptr_real, ref ret_ptr_imag, (UIntPtr)outputSize); + + if(ret == 1) + { + Real = new float[(int)outputSize]; + Imaginary = new float[(int)outputSize]; + Marshal.Copy(ret_ptr_real, Real, 0, (int)outputSize); + Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)outputSize); + Capi.free(ret_ptr_real); + Capi.free(ret_ptr_imag); + } + + return Convert.ToBoolean(ret); + } + + /// <summary> + /// Applies the same series of filteres used by kiss networks (applied by TorchKissAnn) during training. + /// + /// In almost all cases this function should be called before a sepctra is given to a kiss network. + /// </summary> + /// <param name="outputSize"> + /// the length the spectra should have after filtering + /// </param> + /// <returns> + /// True if sucessfull, false otherwise + /// </returns> + public bool Reduce(float threshFactor, bool useSecondDeriv) + { + var ret_ptr_real = new IntPtr(); + var ret_ptr_imag = new IntPtr(); + var lengthPtr = new UIntPtr(); + byte ret = Capi.kiss_reduce_spectra(Real, Imaginary, Omega, (UIntPtr)Real.Length, threshFactor, Convert.ToByte(useSecondDeriv), ref ret_ptr_real, ref ret_ptr_imag, ref lengthPtr); + + if(ret == 1) + { + Real = new float[(int)lengthPtr]; + Imaginary = new float[(int)lengthPtr]; + Marshal.Copy(ret_ptr_real, Real, 0, (int)lengthPtr); + Marshal.Copy(ret_ptr_imag, Imaginary, 0, (int)lengthPtr); + Capi.free(ret_ptr_real); + Capi.free(ret_ptr_imag); + } + + return Convert.ToBoolean(ret); + } + + /// <summary> + /// Converts an array of doubles to an array of floats. + /// </summary> + /// <param name="input"> + /// The input array. + /// </param> + /// <returns> + /// An array with the same values as the input truncated to floats. + /// </returns> + private static float[] DoubleToFloat(double[] input) + { + var res = new float[input.Length]; + for(int i = 0; i < input.Length; ++i) + res[i] = (float)input[i]; + return res; + } + +} + +} diff --git a/program.cs b/src/test.cs similarity index 100% rename from program.cs rename to src/test.cs diff --git a/src/utils.cs b/src/utils.cs new file mode 100644 index 0000000000000000000000000000000000000000..f37931346fbbdda8d7f66e915689c9bba1505615 --- /dev/null +++ b/src/utils.cs @@ -0,0 +1,76 @@ +using System; +using System.Runtime.InteropServices; + +namespace Kiss +{ + +/// <summary> +/// This class is a collection of static methods usefull for use with kissinference. +/// </summary> +public class Utils +{ + /// <summary> + /// Converts an array containing a linear or log range. + /// </summary> + /// <param name="start"> + /// The startig value of the range. + /// </param> + /// <param name="end"> + /// The ending value of the range. + /// </param> + /// <param name="size"> + /// The number of elements in the range. + /// </param> + /// <param name="log"> + /// If this is set to true the elements in the range are spaced in log10 fashion, otherwise linear spaceing is used. + /// </param> + /// <returns> + /// An array containing the requested range + /// </returns> + public static float[] CreateRange(float start, float end, int size, bool log) + { + IntPtr ptr = Capi.kiss_create_range(start, end, (UIntPtr)size, Convert.ToByte(log)); + var ret = new float[size]; + Marshal.Copy(ptr, ret, 0, size); + Capi.free(ptr); + return ret; + } + + /// <summary> + /// Approximates the the derivative of an array at the given index. + /// </summary> + /// <param name="data"> + /// The array, or y values, to approximate the derivative on + /// </param> + /// <param name="omegas"> + /// The omega, or x values to approximate the derivative on + /// </param> + /// <param name="index"> + /// The index at which to aproxmiate the gradiant at. + /// </param> + /// <returns> + /// The aproxmiate derivative. + /// </returns> + public static float Grad(float[] data, float[] omegas, int index) + { + if(data.Length != omegas.Length) + throw new ArgumentException("the data and omegas must be the same length"); + return Capi.kiss_grad(data, omegas, (UIntPtr)data.Length, (UIntPtr)index); + } + + /// <summary> + /// Calculates the median of the values given + /// </summary> + /// <param name="input"> + /// The input array. + /// </param> + /// <returns> + /// The median value + /// </returns> + public static float Median(float[] data) + { + return Capi.kiss_median(data, (UIntPtr)data.Length); + } +} + +} diff --git a/src/versionfixed.cs b/src/versionfixed.cs new file mode 100644 index 0000000000000000000000000000000000000000..f2c175dac9fb8f97ca046318be9e165026ae0c45 --- /dev/null +++ b/src/versionfixed.cs @@ -0,0 +1,23 @@ +using System.Runtime.InteropServices; + +namespace Kiss +{ + +/// <summary> +/// Struct <c>VersionFixed</c> reprisents the version of kissinference +/// </summary> +[StructLayout (LayoutKind.Sequential)] +public struct VersionFixed +{ + public int Major; + public int Minor; + public int Patch; + + /// <summary> + /// This Method returns the version of the currently loaded kissinference instance. + /// </summary> + [DllImport("kissinference", CharSet = CharSet.Ansi, SetLastError = true, EntryPoint = "kiss_get_version", CallingConvention=CallingConvention.StdCall)] + public static extern VersionFixed GetVersion(); +} + +}