Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added CMake and C89 support #51

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
*.o
*.log
*.tmp

.idea
cmake-build-*
build*
*_export.h
63 changes: 63 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
cmake_minimum_required(VERSION 3.19)

# set the project name and version
project(genann VERSION 0.0.1 LANGUAGES "C")
string(TOLOWER "${PROJECT_NAME}" PROJECT_LOWER_NAME)

set(CMAKE_C_STANDARD 90)
set(CMAKE_VERBOSE_MAKEFILE ON)

add_library("${PROJECT_LOWER_NAME}_compiler_flags" INTERFACE)
target_compile_features("${PROJECT_LOWER_NAME}_compiler_flags" INTERFACE "c_std_90")

# add compiler warning flags just when building this project via
# the BUILD_INTERFACE genex
set(gcc_like "$<COMPILE_LANG_AND_ID:C,CXX,ARMClang,AppleClang,Clang,GNU>")
set(msvc "$<COMPILE_LANG_AND_ID:C,CXX,MSVC>")
target_compile_options(
"${PROJECT_LOWER_NAME}_compiler_flags"
INTERFACE
"$<${gcc_like}:$<BUILD_INTERFACE:-Wshadow;-Wformat=2;-Wall;-Wunused-macros;-pedantic;-march=native>>"
# "-Wgnu-zero-variadic-macro-arguments"
"$<${msvc}:$<BUILD_INTERFACE:-W3;-WX;-Zi;-permissive->>"
)

# control where the static and shared libraries are built so that on windows
# we don't need to tinker with the path to run the executable
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")

option(BUILD_SHARED_LIBS "Build using shared libraries" OFF)

if(APPLE)
set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
elseif(UNIX)
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
endif()

configure_file(
"${PROJECT_NAME}Config.h.in"
"config/${PROJECT_NAME}Config.h"
)

set(original_deps "genann" "example" "test")
foreach (_lib ${original_deps})
add_subdirectory("${_lib}")
message(STATUS "Built ${_lib}")
endforeach ()

#set_target_properties(
# "${PROJECT_NAME}"
# PROPERTIES
# LINKER_LANGUAGE
# C
#)

## add the binary tree to the search path for include files
## so that we will find "${PROJECT_NAME}Config.h"
target_include_directories(
"${PROJECT_NAME}"
PUBLIC
"${PROJECT_BINARY_DIR}/config"
)
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ functions and little extra.

## Features

- **C99 with no dependencies**.
- **C89 with no dependencies**.
- Contained in a single source code and header file.
- Simple.
- Fast and thread-safe.
- Easily extendible.
- Easily extendable.
- Implements backpropagation training.
- *Compatible with alternative training methods* (classic optimization, genetic algorithms, etc)
- Includes examples and test suite.
Expand Down
48 changes: 48 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
get_filename_component(LIBRARY_NAME "${CMAKE_CURRENT_SOURCE_DIR}" NAME)
string(REPLACE " " "_" LIBRARY_NAME "${LIBRARY_NAME}")

file(
COPY "iris.data" "iris.names" "xor.ann"
DESTINATION "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/example"
)

foreach(example RANGE 1 4)
set(EXEC_NAME "example${example}")

set(Source_Files "../${EXEC_NAME}.c")
source_group("Source Files" FILES "${Source_Files}")

set(TARGET_NAME "${PROJECT_NAME}_${EXEC_NAME}")
add_executable("${TARGET_NAME}" "${Source_Files}")

target_include_directories(
"${TARGET_NAME}"
INTERFACE
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
"$<INSTALL_INTERFACE:include>"
)

target_link_libraries(
"${TARGET_NAME}"
INTERFACE
"${PROJECT_LOWER_NAME}_compiler_flags"
)
target_link_libraries("${TARGET_NAME}" PRIVATE "genann")

set_target_properties(
"${TARGET_NAME}"
PROPERTIES
LINKER_LANGUAGE
C
)

# install rules
set(installable_libs "${TARGET_NAME}" "${PROJECT_LOWER_NAME}_compiler_flags")
if (TARGET "${DEPENDANT_LIBRARY}")
list(APPEND installable_libs "${DEPENDANT_LIBRARY}")
endif ()
install(TARGETS ${installable_libs}
DESTINATION "bin/"
EXPORT "${TARGET_NAME}Targets")

endforeach ()
46 changes: 26 additions & 20 deletions example1.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,42 @@

int main(int argc, char *argv[])
{
genann *ann;
printf("GENANN example 1.\n");
printf("Train a small ANN to the XOR function using backpropagation.\n");

/* This will make the neural network initialize differently each run. */
/* If you don't get a good result, try again for a different result. */
srand(time(0));

/* Input and expected out data for the XOR function. */
const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
const double output[4] = {0, 1, 1, 0};
int i;
{
/* Input and expected out data for the XOR function. */
const double input[4][2] = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
const double output[4] = {0, 1, 1, 0};
int i;

/* New network with 2 inputs,
* 1 hidden layer of 2 neurons,
* and 1 output. */
genann *ann = genann_init(2, 1, 2, 1);
/* New network with 2 inputs,
* 1 hidden layer of 2 neurons,
* and 1 output. */
ann = genann_init(2, 1, 2, 1);

/* Train on the four labeled data points many times. */
for (i = 0; i < 500; ++i) {
genann_train(ann, input[0], output + 0, 3);
genann_train(ann, input[1], output + 1, 3);
genann_train(ann, input[2], output + 2, 3);
genann_train(ann, input[3], output + 3, 3);
}
/* Train on the four labeled data points many times. */
for (i = 0; i < 500; ++i) {
genann_train(ann, input[0], output + 0, 3);
genann_train(ann, input[1], output + 1, 3);
genann_train(ann, input[2], output + 2, 3);
genann_train(ann, input[3], output + 3, 3);
}

/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
}

genann_free(ann);
return 0;
Expand Down
93 changes: 50 additions & 43 deletions example2.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,72 @@

int main(int argc, char *argv[])
{
genann *ann;
printf("GENANN example 2.\n");
printf("Train a small ANN to the XOR function using random search.\n");

srand(time(0));

/* Input and expected out data for the XOR function. */
const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};
const double output[4] = {0, 1, 1, 0};
int i;
{
const double input[4][2] = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};
const double output[4] = {0, 1, 1, 0};
int i;

/* New network with 2 inputs,
* 1 hidden layer of 2 neurons,
* and 1 output. */
genann *ann = genann_init(2, 1, 2, 1);
double err;
double last_err = 1000;
int count = 0;

double err;
double last_err = 1000;
int count = 0;
/* New network with 2 inputs,
* 1 hidden layer of 2 neurons,
* and 1 output. */
ann = genann_init(2, 1, 2, 1);

do {
++count;
if (count % 1000 == 0) {
/* We're stuck, start over. */
genann_randomize(ann);
last_err = 1000;
}
do {
genann *save;
++count;
if (count % 1000 == 0) {
/* We're stuck, start over. */
genann_randomize(ann);
last_err = 1000;
}

genann *save = genann_copy(ann);
save = genann_copy(ann);

/* Take a random guess at the ANN weights. */
for (i = 0; i < ann->total_weights; ++i) {
ann->weight[i] += ((double)rand())/RAND_MAX-0.5;
}
/* Take a random guess at the ANN weights. */
for (i = 0; i < ann->total_weights; ++i) {
ann->weight[i] += ((double) rand()) / RAND_MAX - 0.5;
}

/* See how we did. */
err = 0;
err += pow(*genann_run(ann, input[0]) - output[0], 2.0);
err += pow(*genann_run(ann, input[1]) - output[1], 2.0);
err += pow(*genann_run(ann, input[2]) - output[2], 2.0);
err += pow(*genann_run(ann, input[3]) - output[3], 2.0);
/* See how we did. */
err = 0;
err += pow(*genann_run(ann, input[0]) - output[0], 2.0);
err += pow(*genann_run(ann, input[1]) - output[1], 2.0);
err += pow(*genann_run(ann, input[2]) - output[2], 2.0);
err += pow(*genann_run(ann, input[3]) - output[3], 2.0);

/* Keep these weights if they're an improvement. */
if (err < last_err) {
genann_free(save);
last_err = err;
} else {
genann_free(ann);
ann = save;
}
/* Keep these weights if they're an improvement. */
if (err < last_err) {
genann_free(save);
last_err = err;
} else {
genann_free(ann);
ann = save;
}

} while (err > 0.01);
} while (err > 0.01);

printf("Finished in %d loops.\n", count);
printf("Finished in %d loops.\n", count);

/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
}

genann_free(ann);
return 0;
Expand Down
36 changes: 22 additions & 14 deletions example3.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,41 @@ const char *save_name = "example/xor.ann";

int main(int argc, char *argv[])
{
genann *ann;

printf("GENANN example 3.\n");
printf("Load a saved ANN to solve the XOR function.\n");

{
FILE *saved = fopen(save_name, "r");
if (!saved) {
printf("Couldn't open file: %s\n", save_name);
exit(1);
}

FILE *saved = fopen(save_name, "r");
if (!saved) {
printf("Couldn't open file: %s\n", save_name);
exit(1);
ann = genann_read(saved);
fclose(saved);
}

genann *ann = genann_read(saved);
fclose(saved);

if (!ann) {
printf("Error loading ANN from file: %s.", save_name);
exit(1);
}


/* Input data for the XOR function. */
const double input[4][2] = {{0, 0}, {0, 1}, {1, 0}, {1, 1}};

/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
{
const double input[4][2] = {{0, 0},
{0, 1},
{1, 0},
{1, 1}};

/* Run the network and see what it predicts. */
printf("Output for [%1.f, %1.f] is %1.f.\n", input[0][0], input[0][1], *genann_run(ann, input[0]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[1][0], input[1][1], *genann_run(ann, input[1]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[2][0], input[2][1], *genann_run(ann, input[2]));
printf("Output for [%1.f, %1.f] is %1.f.\n", input[3][0], input[3][1], *genann_run(ann, input[3]));
}

genann_free(ann);
return 0;
Expand Down
Loading