Skip to content

Commit 5c452eb

Browse files
committedMar 3, 2025
create first innitial working package code.
1 parent f49a46e commit 5c452eb

10 files changed

+862
-0
lines changed
 

‎.clang-format

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
---
2+
Language: Cpp
3+
BasedOnStyle: Google
4+
AccessModifierOffset: -1
5+
AlignAfterOpenBracket: Align
6+
AlignArrayOfStructures: None
7+
AlignConsecutiveAssignments:
8+
Enabled: false
9+
AcrossEmptyLines: false
10+
AcrossComments: false
11+
AlignCompound: false
12+
AlignFunctionPointers: false
13+
PadOperators: true
14+
AlignConsecutiveBitFields:
15+
Enabled: false
16+
AcrossEmptyLines: false
17+
AcrossComments: false
18+
AlignCompound: false
19+
AlignFunctionPointers: false
20+
PadOperators: false
21+
AlignConsecutiveDeclarations:
22+
Enabled: false
23+
AcrossEmptyLines: false
24+
AcrossComments: false
25+
AlignCompound: false
26+
AlignFunctionPointers: false
27+
PadOperators: false
28+
AlignConsecutiveMacros:
29+
Enabled: false
30+
AcrossEmptyLines: false
31+
AcrossComments: false
32+
AlignCompound: false
33+
AlignFunctionPointers: false
34+
PadOperators: false
35+
AlignConsecutiveShortCaseStatements:
36+
Enabled: false
37+
AcrossEmptyLines: false
38+
AcrossComments: false
39+
AlignCaseColons: false
40+
AlignEscapedNewlines: Left
41+
AlignOperands: Align
42+
AlignTrailingComments:
43+
Kind: Always
44+
OverEmptyLines: 0
45+
AllowAllArgumentsOnNextLine: true
46+
AllowAllParametersOfDeclarationOnNextLine: true
47+
AllowBreakBeforeNoexceptSpecifier: Never
48+
AllowShortBlocksOnASingleLine: Never
49+
AllowShortCaseLabelsOnASingleLine: false
50+
AllowShortCompoundRequirementOnASingleLine: true
51+
AllowShortEnumsOnASingleLine: true
52+
AllowShortFunctionsOnASingleLine: All
53+
AllowShortIfStatementsOnASingleLine: WithoutElse
54+
AllowShortLambdasOnASingleLine: All
55+
AllowShortLoopsOnASingleLine: true
56+
AlwaysBreakAfterDefinitionReturnType: None
57+
AlwaysBreakAfterReturnType: None
58+
AlwaysBreakBeforeMultilineStrings: true
59+
AlwaysBreakTemplateDeclarations: Yes
60+
AttributeMacros:
61+
- __capability
62+
BinPackArguments: true
63+
BinPackParameters: true
64+
BitFieldColonSpacing: Both
65+
BraceWrapping:
66+
AfterCaseLabel: false
67+
AfterClass: false
68+
AfterControlStatement: Always # Changed from Never to Always for better block clarity
69+
AfterEnum: false
70+
AfterExternBlock: false
71+
AfterFunction: false
72+
AfterNamespace: false
73+
AfterObjCDeclaration: false
74+
AfterStruct: false
75+
AfterUnion: false
76+
BeforeCatch: true # Changed from false to true to align with Python's block structure
77+
BeforeElse: true # Changed from false to true for consistency
78+
BeforeLambdaBody: false
79+
BeforeWhile: false
80+
IndentBraces: false
81+
SplitEmptyFunction: true
82+
SplitEmptyRecord: true
83+
SplitEmptyNamespace: true
84+
BreakAdjacentStringLiterals: true
85+
BreakAfterAttributes: Leave
86+
BreakAfterJavaFieldAnnotations: false
87+
BreakArrays: true
88+
BreakBeforeBinaryOperators: None
89+
BreakBeforeConceptDeclarations: Always
90+
BreakBeforeBraces: Attach
91+
BreakBeforeInlineASMColon: OnlyMultiline
92+
BreakBeforeTernaryOperators: true
93+
BreakConstructorInitializers: BeforeColon
94+
BreakInheritanceList: BeforeColon
95+
BreakStringLiterals: true
96+
ColumnLimit: 100 # Increased from 80 to 100 for better readability
97+
CommentPragmas: '^ IWYU pragma:'
98+
CompactNamespaces: false
99+
ConstructorInitializerIndentWidth: 4
100+
ContinuationIndentWidth: 4
101+
Cpp11BracedListStyle: true
102+
DerivePointerAlignment: true
103+
DisableFormat: false
104+
EmptyLineAfterAccessModifier: Never
105+
EmptyLineBeforeAccessModifier: LogicalBlock
106+
ExperimentalAutoDetectBinPacking: false
107+
FixNamespaceComments: true
108+
ForEachMacros:
109+
- foreach
110+
- Q_FOREACH
111+
- BOOST_FOREACH
112+
IfMacros:
113+
- KJ_IF_MAYBE
114+
IncludeBlocks: Regroup
115+
IncludeCategories:
116+
- Regex: '^<ext/.*\.h>'
117+
Priority: 2
118+
SortPriority: 0
119+
CaseSensitive: false
120+
- Regex: '^<.*\.h>'
121+
Priority: 1
122+
SortPriority: 0
123+
CaseSensitive: false
124+
- Regex: '^<.*'
125+
Priority: 2
126+
SortPriority: 0
127+
CaseSensitive: false
128+
- Regex: '.*'
129+
Priority: 3
130+
SortPriority: 0
131+
CaseSensitive: false
132+
IncludeIsMainRegex: '([-_](test|unittest))?$'
133+
IncludeIsMainSourceRegex: ''
134+
IndentAccessModifiers: false
135+
IndentCaseBlocks: false
136+
IndentCaseLabels: true
137+
IndentExternBlock: AfterExternBlock
138+
IndentGotoLabels: true
139+
IndentPPDirectives: BeforeHash
140+
IndentRequiresClause: true
141+
IndentWidth: 4 # Changed from 2 to 4 for better readability
142+
IndentWrappedFunctionNames: false
143+
InsertBraces: false
144+
InsertNewlineAtEOF: false
145+
InsertTrailingCommas: None
146+
IntegerLiteralSeparator:
147+
Binary: 0
148+
BinaryMinDigits: 0
149+
Decimal: 0
150+
DecimalMinDigits: 0
151+
Hex: 0
152+
HexMinDigits: 0
153+
JavaScriptQuotes: Leave
154+
JavaScriptWrapImports: true
155+
KeepEmptyLinesAtTheStartOfBlocks: false
156+
KeepEmptyLinesAtEOF: false
157+
LambdaBodyIndentation: Signature
158+
LineEnding: DeriveLF
159+
MacroBlockBegin: ''
160+
MacroBlockEnd: ''
161+
MaxEmptyLinesToKeep: 1
162+
NamespaceIndentation: None
163+
ObjCBinPackProtocolList: Never
164+
ObjCBlockIndentWidth: 2
165+
ObjCBreakBeforeNestedBlockParam: true
166+
ObjCSpaceAfterProperty: false
167+
ObjCSpaceBeforeProtocolList: true
168+
PackConstructorInitializers: NextLine
169+
PenaltyBreakAssignment: 2
170+
PenaltyBreakBeforeFirstCallParameter: 1
171+
PenaltyBreakComment: 300
172+
PenaltyBreakFirstLessLess: 120
173+
PenaltyBreakOpenParenthesis: 0
174+
PenaltyBreakScopeResolution: 500
175+
PenaltyBreakString: 1000
176+
PenaltyBreakTemplateDeclaration: 10
177+
PenaltyExcessCharacter: 1000000
178+
PenaltyIndentedWhitespace: 0
179+
PenaltyReturnTypeOnItsOwnLine: 200
180+
PointerAlignment: Left
181+
PPIndentWidth: -1
182+
QualifierAlignment: Leave
183+
RawStringFormats:
184+
- Language: Cpp
185+
Delimiters:
186+
- cc
187+
- CC
188+
- cpp
189+
- Cpp
190+
- CPP
191+
- 'c++'
192+
- 'C++'
193+
CanonicalDelimiter: ''
194+
BasedOnStyle: Google
195+
- Language: TextProto
196+
Delimiters:
197+
- pb
198+
- PB
199+
- proto
200+
- PROTO
201+
EnclosingFunctions:
202+
- EqualsProto
203+
- EquivToProto
204+
- PARSE_PARTIAL_TEXT_PROTO
205+
- PARSE_TEST_PROTO
206+
- PARSE_TEXT_PROTO
207+
- ParseTextOrDie
208+
- ParseTextProtoOrDie
209+
- ParseTestProto
210+
- ParsePartialTestProto
211+
CanonicalDelimiter: pb
212+
BasedOnStyle: Google
213+
ReferenceAlignment: Pointer
214+
ReflowComments: true
215+
RemoveBracesLLVM: false
216+
RemoveParentheses: Leave
217+
RemoveSemicolon: false
218+
RequiresClausePosition: OwnLine
219+
RequiresExpressionIndentation: OuterScope
220+
SeparateDefinitionBlocks: Leave
221+
ShortNamespaceLines: 1
222+
SkipMacroDefinitionBody: false
223+
SortIncludes: CaseSensitive
224+
SortJavaStaticImport: Before
225+
SortUsingDeclarations: LexicographicNumeric
226+
SpaceAfterCStyleCast: false
227+
SpaceAfterLogicalNot: false
228+
SpaceAfterTemplateKeyword: true
229+
SpaceAroundPointerQualifiers: Default
230+
SpaceBeforeAssignmentOperators: true
231+
SpaceBeforeCaseColon: false
232+
SpaceBeforeCpp11BracedList: false
233+
SpaceBeforeCtorInitializerColon: true
234+
SpaceBeforeInheritanceColon: true
235+
SpaceBeforeJsonColon: false
236+
SpaceBeforeParensOptions:
237+
AfterControlStatements: true
238+
AfterForeachMacros: true
239+
AfterFunctionDefinitionName: false
240+
AfterFunctionDeclarationName: false
241+
AfterIfMacros: true
242+
AfterOverloadedOperator: false
243+
AfterPlacementOperator: true
244+
AfterRequiresInClause: false
245+
AfterRequiresInExpression: false
246+
BeforeNonEmptyParentheses: false
247+
SpaceBeforeRangeBasedForLoopColon: true
248+
SpaceBeforeSquareBrackets: false
249+
SpaceInEmptyBlock: false
250+
SpacesBeforeTrailingComments: 2
251+
SpacesInAngles: Never
252+
SpacesInContainerLiterals: true
253+
SpacesInLineCommentPrefix:
254+
Minimum: 1
255+
Maximum: -1
256+
SpacesInParens: Never
257+
SpacesInParensOptions:
258+
InCStyleCasts: false
259+
InConditionalStatements: false
260+
InEmptyParentheses: false
261+
Other: false
262+
SpacesInSquareBrackets: false
263+
Standard: Auto
264+
StatementAttributeLikeMacros:
265+
- Q_EMIT
266+
StatementMacros:
267+
- Q_UNUSED
268+
- QT_REQUIRE_VERSION
269+
TabWidth: 8
270+
UseTab: Never
271+
VerilogBreakBetweenInstancePorts: true
272+
WhitespaceSensitiveMacros:
273+
- BOOST_PP_STRINGIZE
274+
- CF_SWIFT_NAME
275+
- NS_SWIFT_NAME
276+
- PP_STRINGIZE
277+
- STRINGIZE
278+
...

‎.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,9 @@ cython_debug/
169169

170170
# PyPI configuration file
171171
.pypirc
172+
173+
# ### Neat3P
174+
175+
_skbuild
176+
libs/nanobind
177+
libs/flatbuffers

‎CMakeLists.txt

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
cmake_minimum_required(VERSION 3.15)
2+
3+
project(neat3p LANGUAGES CXX)
4+
5+
# ------------------------------------------------------------------------------
6+
# Basic Setup
7+
# ------------------------------------------------------------------------------
8+
list(APPEND CMAKE_PREFIX_PATH "~/anaconda3/envs/neat3p")
9+
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/src")
10+
11+
# If you need a specific compiler:
12+
set(CMAKE_CXX_COMPILER /usr/bin/g++-12)
13+
14+
project(Neat3pProject LANGUAGES CXX)
15+
set(CMAKE_CXX_STANDARD 20)
16+
17+
18+
# ------------------------------------------------------------------------------
19+
# nanobind Setup
20+
# ------------------------------------------------------------------------------
21+
# Point to nanobind submodule directory
22+
set(NANOBIND_DIR "${CMAKE_SOURCE_DIR}/libs/nanobind")
23+
include_directories(${NANOBIND_DIR}/include)
24+
add_subdirectory(${NANOBIND_DIR})
25+
26+
# Determine the nanobind CMake include path and register it
27+
# execute_process(
28+
# COMMAND "${Python_EXECUTABLE}" -m nanobind --cmake_dir
29+
# OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE NB_DIR)
30+
31+
# message(STATUS "NanoBind Cmake directory: " ${NB_DIR})
32+
# list(APPEND CMAKE_PREFIX_PATH "${NB_DIR}")
33+
34+
# ------------------------------------------------------------------------------
35+
# Build Options & Flags
36+
# ------------------------------------------------------------------------------
37+
# Example optimization flags
38+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -march=native -flto -ffast-math")
39+
40+
# Colored diagnostics in GCC/Clang
41+
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
42+
add_compile_options(-fdiagnostics-color=always)
43+
endif()
44+
45+
# Example definition (remove if not needed)
46+
add_compile_definitions(ENTT_ENTITY_TYPE=int)
47+
48+
# Hide internal symbols by default
49+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always -fvisibility=hidden")
50+
51+
# ------------------------------------------------------------------------------
52+
# Required Packages
53+
# ------------------------------------------------------------------------------
54+
find_package(Python3 COMPONENTS Interpreter Development REQUIRED)
55+
set(nanobind_DIR "${CMAKE_SOURCE_DIR}/libs/nanobind/cmake")
56+
find_package(nanobind CONFIG REQUIRED)
57+
58+
find_package(msgpack REQUIRED)
59+
find_package(spdlog REQUIRED)
60+
61+
# find_package(nanobind CONFIG REQUIRED)
62+
63+
find_package(
64+
REQUIRED COMPONENTS Interpreter Development.Module
65+
OPTIONAL_COMPONENTS Development.SABIModule)
66+
67+
# ------------------------------------------------------------------------------
68+
# FlatBuffers Setup
69+
# ------------------------------------------------------------------------------
70+
set(FLATBUFFERS_SRC_DIR "${CMAKE_SOURCE_DIR}/libs/flatbuffers")
71+
add_subdirectory(
72+
${FLATBUFFERS_SRC_DIR}
73+
${CMAKE_CURRENT_BINARY_DIR}/flatbuffers-build
74+
EXCLUDE_FROM_ALL
75+
)
76+
77+
# ------------------------------------------------------------------------------
78+
# Include Directories
79+
# ------------------------------------------------------------------------------
80+
include_directories(
81+
${Python3_INCLUDE_DIRS}
82+
${Python3_NumPy_INCLUDE_DIRS}
83+
${CMAKE_SOURCE_DIR}/src
84+
${NANOBIND_DIR}/include
85+
${MSGPACK_INCLUDE_DIRS}
86+
${CMAKE_SOURCE_DIR}/libs
87+
)
88+
89+
# ------------------------------------------------------------------------------
90+
# FlatBuffers Schema Compilation
91+
# ------------------------------------------------------------------------------
92+
find_program(FLATC_COMPILER flatc REQUIRED)
93+
if(NOT FLATC_COMPILER)
94+
message(FATAL_ERROR "flatc compiler not found. Please ensure it is installed and in your PATH.")
95+
endif()
96+
97+
# Example schema list. Adjust or remove if not needed.
98+
set(FLATBUFFERS_SCHEMAS
99+
${CMAKE_SOURCE_DIR}/schemas/Gene.fbs
100+
)
101+
102+
set(FLATBUFFERS_GENERATED_CPP_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated)
103+
file(MAKE_DIRECTORY ${FLATBUFFERS_GENERATED_CPP_DIR})
104+
105+
set(FLATBUFFERS_GENERATED_CPP_HEADERS)
106+
107+
foreach(schema ${FLATBUFFERS_SCHEMAS})
108+
get_filename_component(schema_name ${schema} NAME_WE)
109+
add_custom_command(
110+
OUTPUT ${FLATBUFFERS_GENERATED_CPP_DIR}/${schema_name}.h
111+
COMMAND ${FLATC_COMPILER} --cpp --gen-mutable -o ${FLATBUFFERS_GENERATED_CPP_DIR} ${schema}
112+
DEPENDS ${schema}
113+
COMMENT "Compiling FlatBuffers schema ${schema} to C++"
114+
)
115+
list(APPEND FLATBUFFERS_GENERATED_CPP_HEADERS ${FLATBUFFERS_GENERATED_CPP_DIR}/${schema_name}.h)
116+
endforeach()
117+
118+
add_custom_target(GenerateFlatBuffers ALL DEPENDS ${FLATBUFFERS_GENERATED_CPP_HEADERS})
119+
include_directories(${FLATBUFFERS_GENERATED_CPP_DIR})
120+
121+
# ------------------------------------------------------------------------------
122+
# Source Files
123+
# ------------------------------------------------------------------------------
124+
# Collect all .cpp files in neat3p/, excluding the ones you don’t want.
125+
file(GLOB SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp")
126+
list(REMOVE_ITEM SOURCES "${CMAKE_SOURCE_DIR}/src/neat3p.cpp")
127+
# list(REMOVE_ITEM SOURCES "${CMAKE_SOURCE_DIR}/neat3p/my_module.cpp")
128+
129+
# ------------------------------------------------------------------------------
130+
# Build the Python Module (nanobind)
131+
# ------------------------------------------------------------------------------
132+
nanobind_add_module(
133+
_neat3p
134+
MODULE
135+
${SOURCES}
136+
src/neat3p.cpp
137+
)
138+
139+
target_link_libraries(_neat3p PRIVATE
140+
${MSGPACK_LIBRARIES}
141+
${Python3_LIBRARIES}
142+
flatbuffers
143+
spdlog::spdlog
144+
)
145+
146+
# Ensure schema generation runs before building the module
147+
add_dependencies(_neat3p GenerateFlatBuffers)
148+
149+
# Install directive for scikit-build
150+
install(TARGETS _neat3p LIBRARY DESTINATION neat3p)
151+
152+
# ------------------------------------------------------------------------------
153+
# Final Message
154+
# ------------------------------------------------------------------------------
155+
message(STATUS "Build Configuration for '_neat3p' Complete")

‎Makefile

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Include environment variables from .env if it exists
2+
ifneq ("$(wildcard .env)","")
3+
include .env
4+
export
5+
endif
6+
7+
# Default value for PREFIX_PATH if not set in .env (Right now it must be set in the .env)
8+
PREFIX_PATH ?= /default/path/to/your/env
9+
10+
clean-build-run:
11+
rm -rf build && mkdir build && \
12+
cmake -S . -B ./build -DCMAKE_PREFIX_PATH="$(PREFIX_PATH)" && \
13+
cd build && make && \
14+
cd .. && \
15+
cp build/lib/libmy_module.so my_module.so && \
16+
python test.py
17+
18+
build-test:
19+
rm -rf build && \
20+
mkdir build && \
21+
cd build && \
22+
cmake -DCMAKE_CXX_FLAGS="-fdiagnostics-color=always" -DBUILD_WORLD_TEST=OFF -G Ninja -DCMAKE_PREFIX_PATH="$(PREFIX_PATH)" .. && \
23+
stdbuf -oL ninja && \
24+
cd .. && \
25+
pytest tests
26+
27+
device-info:
28+
nvidia-smi
29+
30+
.PHONY: clang-format
31+
clang-format:
32+
@echo "Formatting C++ files with clang-format..."
33+
find ./src -type f -regex '.*\.\(cpp\|hpp\|h\|cxx\|cc\)' | \
34+
xargs clang-format -i
35+
36+
.PHONY: style
37+
style: clang-format
38+
@echo "All formatting complete."
39+
40+
.PHONY: generate-stubs
41+
generate-stubs:
42+
@echo "Generating stubs for neat3p..."
43+
PYTHONPATH=build python -m nanobind.stubgen -m site-packages.neat3p -M py.typed -o neat3p.pyi
44+
45+
.PHONY: build-and-install
46+
build-and-install: build-test generate-stubs install-package conda-install
47+
@echo "Build, stubs generated, and module installed."

‎pyproject.toml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[build-system]
2+
requires = [
3+
"scikit-build-core",
4+
"nanobind>=1.3.2"
5+
]
6+
7+
build-backend = "scikit_build_core.build"
8+
9+
10+
[project]
11+
name = "neat3p"
12+
version = "0.0.1"
13+
authors = [
14+
{ name = "Arthur R. Moreno", email = "morenorarthur@gmail.com" },
15+
]
16+
description = "Neat Python, Amplified by C++ Boost"
17+
readme = "README.md"
18+
requires-python = ">=3.12"
19+
classifiers = [
20+
"Development Status :: 3 - Alpha",
21+
"Intended Audience :: Science/Research",
22+
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
23+
"Operating System :: OS Independent",
24+
"Programming Language :: Python",
25+
"Programming Language :: Python :: 3.12",
26+
"Topic :: Scientific/Engineering",
27+
"Topic :: Utilities",
28+
]
29+
30+
[project.urls]
31+
"Homepage" = "https://github.com/arthurmoreno/neat3p"
32+
33+
[tool.scikit-build]
34+
cmake.verbose = true
35+
# cmake.build-type = "Debug"
36+
37+
build-dir = "build/{wheel_tag}"
38+
39+
# Build stable ABI wheels for CPython 3.12+
40+
wheel.py-api = "cp312"

‎schemas/Gene.fbs

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Neat3P;
2+
3+
4+
table Gene {
5+
key:int;
6+
gene_data: [ubyte];
7+
}

‎src/genes.cpp

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#include "genes.hpp"
2+
3+
// ---------------------------------------------------------------------------
4+
// DefaultNodeGene Implementation
5+
// ---------------------------------------------------------------------------
6+
DefaultNodeGene::DefaultNodeGene(int key)
7+
: key(key), bias(0.0f), response(1.0f), activation(""), aggregation("") {}
8+
9+
DefaultNodeGene::~DefaultNodeGene() = default;
10+
11+
std::string DefaultNodeGene::to_string() const {
12+
std::ostringstream oss;
13+
oss << "DefaultNodeGene(key=" << key << ", bias=" << bias << ", response=" << response
14+
<< ", activation=" << activation << ", aggregation=" << aggregation << ")";
15+
return oss.str();
16+
}
17+
18+
DefaultNodeGene* DefaultNodeGene::copy() const {
19+
DefaultNodeGene* new_gene = new DefaultNodeGene(key);
20+
new_gene->bias = bias;
21+
new_gene->response = response;
22+
new_gene->activation = activation;
23+
new_gene->aggregation = aggregation;
24+
return new_gene;
25+
}
26+
27+
double DefaultNodeGene::distance(const DefaultNodeGene& other, const GenomeConfig& config) const {
28+
double d = std::abs(bias - other.bias) + std::abs(response - other.response);
29+
if (activation != other.activation) d += 1.0;
30+
if (aggregation != other.aggregation) d += 1.0;
31+
return d * config.compatibility_weight_coefficient;
32+
}
33+
34+
DefaultNodeGene* DefaultNodeGene::crossover(const DefaultNodeGene& other) const {
35+
DefaultNodeGene* new_gene = new DefaultNodeGene(key);
36+
std::random_device rd;
37+
std::mt19937 gen(rd());
38+
std::uniform_real_distribution<> dis(0, 1);
39+
new_gene->bias = (dis(gen) > 0.5) ? bias : other.bias;
40+
new_gene->response = (dis(gen) > 0.5) ? response : other.response;
41+
new_gene->activation = (dis(gen) > 0.5) ? activation : other.activation;
42+
new_gene->aggregation = (dis(gen) > 0.5) ? aggregation : other.aggregation;
43+
return new_gene;
44+
}
45+
46+
BaseGene* DefaultNodeGene::crossover(const BaseGene& other) const {
47+
// Downcast to DefaultNodeGene. Caller must ensure same type.
48+
const DefaultNodeGene& otherNode = dynamic_cast<const DefaultNodeGene&>(other);
49+
return static_cast<BaseGene*>(crossover(otherNode));
50+
}
51+
52+
// The init_attributes method sets default values for the node gene.
53+
// In a full implementation, these might be based on a configuration object.
54+
void DefaultNodeGene::init_attributes() {
55+
bias = 0.0f; // Default bias.
56+
response = 1.0f; // Default response.
57+
activation = ""; // Default activation function (empty string).
58+
aggregation = ""; // Default aggregation function (empty string).
59+
}
60+
61+
62+
void DefaultNodeGene::mutate() {
63+
// Implement mutation logic, even if empty for now.
64+
}
65+
66+
// ---------------------------------------------------------------------------
67+
// DefaultConnectionGene Implementation
68+
// ---------------------------------------------------------------------------
69+
DefaultConnectionGene::DefaultConnectionGene(const std::pair<int, int>& key)
70+
: key(key), weight(0.0f), enabled(true) {}
71+
72+
73+
std::string DefaultConnectionGene::to_string() const {
74+
std::ostringstream oss;
75+
oss << "DefaultConnectionGene(key=(" << key.first << ", " << key.second << ")"
76+
<< ", weight=" << weight << ", enabled=" << (enabled ? "true" : "false") << ")";
77+
return oss.str();
78+
}
79+
80+
DefaultConnectionGene* DefaultConnectionGene::copy() const {
81+
DefaultConnectionGene* new_gene = new DefaultConnectionGene(key);
82+
new_gene->weight = weight;
83+
new_gene->enabled = enabled;
84+
return new_gene;
85+
}
86+
87+
double DefaultConnectionGene::distance(const DefaultConnectionGene& other,
88+
const GenomeConfig& config) const {
89+
double d = std::abs(weight - other.weight);
90+
if (enabled != other.enabled) d += 1.0;
91+
return d * config.compatibility_weight_coefficient;
92+
}
93+
94+
DefaultConnectionGene* DefaultConnectionGene::crossover(const DefaultConnectionGene& other) const {
95+
DefaultConnectionGene* child = new DefaultConnectionGene(key);
96+
std::random_device rd;
97+
std::mt19937 gen(rd());
98+
std::uniform_real_distribution<> dis(0, 1);
99+
child->weight = (dis(gen) > 0.5) ? weight : other.weight;
100+
child->enabled = enabled && other.enabled;
101+
return child;
102+
}
103+
104+
BaseGene* DefaultConnectionGene::crossover(const BaseGene& other) const {
105+
// Downcast to DefaultConnectionGene. Caller must ensure same type.
106+
const DefaultConnectionGene& otherConn = dynamic_cast<const DefaultConnectionGene&>(other);
107+
return static_cast<BaseGene*>(crossover(otherConn));
108+
}
109+
110+
// The init_attributes method sets default values for the connection gene.
111+
// In a full implementation, these values might come from a configuration.
112+
void DefaultConnectionGene::init_attributes() {
113+
weight = 0.0f; // Default weight.
114+
enabled = true; // Default to enabled.
115+
}

‎src/genes.hpp

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#ifndef GENES_HPP
2+
#define GENES_HPP
3+
4+
#include <cmath>
5+
#include <random>
6+
#include <sstream>
7+
#include <string>
8+
#include <utility>
9+
10+
// A simple configuration structure for gene distance calculations.
11+
struct GenomeConfig {
12+
double compatibility_weight_coefficient;
13+
};
14+
15+
16+
// ---------------------------------------------------------------------------
17+
// BaseGene: Abstract base class for gene types.
18+
// ---------------------------------------------------------------------------
19+
class BaseGene {
20+
public:
21+
// The base class no longer forces all children to have an int key.
22+
BaseGene() = default;
23+
virtual ~BaseGene() = default;
24+
25+
virtual std::string to_string() const = 0;
26+
virtual BaseGene* copy() const = 0;
27+
virtual BaseGene* crossover(const BaseGene& other) const = 0;
28+
virtual void init_attributes() = 0;
29+
virtual void mutate() = 0;
30+
};
31+
32+
// ---------------------------------------------------------------------------
33+
// DefaultNodeGene: Represents a node gene with attributes similar to bias,
34+
// response, activation, and aggregation.
35+
// ---------------------------------------------------------------------------
36+
class DefaultNodeGene : public BaseGene {
37+
public:
38+
int key;
39+
float bias;
40+
float response;
41+
std::string activation;
42+
std::string aggregation;
43+
44+
// Constructor; initializes key and sets default attribute values.
45+
DefaultNodeGene(int key);
46+
virtual ~DefaultNodeGene();
47+
48+
// Return a string representation.
49+
virtual std::string to_string() const override;
50+
51+
// Deep copy.
52+
virtual DefaultNodeGene* copy() const override;
53+
54+
// Compute the distance between this node gene and another using config.
55+
double distance(const DefaultNodeGene& other, const GenomeConfig& config) const;
56+
57+
// Crossover: randomly inherit attributes from this gene or the other.
58+
DefaultNodeGene* crossover(const DefaultNodeGene& other) const;
59+
60+
// BaseGene override for crossover.
61+
virtual BaseGene* crossover(const BaseGene& other) const override;
62+
63+
// Initialize attributes to default values.
64+
virtual void init_attributes() override;
65+
66+
void mutate() override;
67+
};
68+
69+
// ---------------------------------------------------------------------------
70+
// DefaultConnectionGene: Represents a connection gene with a weight and an
71+
// enabled flag.
72+
// ---------------------------------------------------------------------------
73+
class DefaultConnectionGene : public BaseGene {
74+
public:
75+
std::pair<int, int> key; // (input, output)
76+
float weight;
77+
bool enabled;
78+
79+
// Constructor; initializes key and sets default weight and enabled.
80+
DefaultConnectionGene(const std::pair<int, int>& key);
81+
82+
// Return a string representation.
83+
virtual std::string to_string() const override;
84+
85+
// Deep copy.
86+
virtual DefaultConnectionGene* copy() const override;
87+
88+
// Compute the distance between this connection gene and another using config.
89+
double distance(const DefaultConnectionGene& other, const GenomeConfig& config) const;
90+
91+
// Crossover: create a new connection gene inheriting attributes.
92+
DefaultConnectionGene* crossover(const DefaultConnectionGene& other) const;
93+
94+
// BaseGene override for crossover.
95+
virtual BaseGene* crossover(const BaseGene& other) const override;
96+
97+
// Initialize attributes to default values.
98+
virtual void init_attributes() override;
99+
100+
void mutate() override {};
101+
};
102+
103+
#endif // GENES_HPP

‎src/neat3p.cpp

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
// #include <SDL2/SDL.h>
2+
// #include <SDL2/SDL_image.h>
3+
// #include <imgui/backends/imgui_impl_sdl2.h>
4+
// #include <imgui/backends/imgui_impl_sdlrenderer2.h>
5+
#define ENTT_ENTITY_TYPE int
6+
7+
#include <nanobind/nanobind.h>
8+
#include <nanobind/operators.h>
9+
#include <nanobind/stl/bind_map.h>
10+
#include <nanobind/stl/bind_vector.h>
11+
#include <nanobind/stl/string.h>
12+
#include <nanobind/stl/unique_ptr.h>
13+
#include <nanobind/stl/variant.h>
14+
#include <spdlog/spdlog.h>
15+
16+
#include <cstdint>
17+
18+
#include "genes.hpp"
19+
20+
// Create a shortcut for nanobind
21+
namespace nb = nanobind;
22+
23+
NB_MODULE(_neat3p, m) {
24+
25+
// nb::class_<GenomeParams>(m, "GenomeParams")
26+
// .def(nb::init<>())
27+
// .def_rw("num_inputs", &GenomeParams::num_inputs)
28+
// .def_rw("num_outputs", &GenomeParams::num_outputs)
29+
// .def_rw("num_hidden", &GenomeParams::num_hidden)
30+
// .def_rw("feed_forward", &GenomeParams::feed_forward)
31+
// .def_rw("compatibility_disjoint_coefficient",
32+
// &GenomeParams::compatibility_disjoint_coefficient)
33+
// .def_rw("compatibility_weight_coefficient",
34+
// &GenomeParams::compatibility_weight_coefficient)
35+
// .def_rw("conn_add_prob", &GenomeParams::conn_add_prob)
36+
// .def_rw("conn_delete_prob", &GenomeParams::conn_delete_prob)
37+
// .def_rw("node_add_prob", &GenomeParams::node_add_prob)
38+
// .def_rw("node_delete_prob", &GenomeParams::node_delete_prob)
39+
// .def_rw("single_structural_mutation",
40+
// &GenomeParams::single_structural_mutation)
41+
// .def_rw("structural_mutation_surer",
42+
// &GenomeParams::structural_mutation_surer)
43+
// .def_rw("initial_connection",
44+
// &GenomeParams::initial_connection);
45+
46+
// nb::class_<DefaultGenomeConfig>(m, "DefaultGenomeConfig")
47+
// .def(nb::init<const GenomeParams &>())
48+
// .def_rw("num_inputs", &DefaultGenomeConfig::num_inputs)
49+
// .def_rw("num_outputs", &DefaultGenomeConfig::num_outputs)
50+
// .def_rw("num_hidden", &DefaultGenomeConfig::num_hidden)
51+
// .def_rw("feed_forward", &DefaultGenomeConfig::feed_forward)
52+
// .def_rw("compatibility_disjoint_coefficient",
53+
// &DefaultGenomeConfig::compatibility_disjoint_coefficient)
54+
// .def_rw("compatibility_weight_coefficient",
55+
// &DefaultGenomeConfig::compatibility_weight_coefficient)
56+
// .def_rw("conn_add_prob",
57+
// &DefaultGenomeConfig::conn_add_prob)
58+
// .def_rw("conn_delete_prob",
59+
// &DefaultGenomeConfig::conn_delete_prob)
60+
// .def_rw("node_add_prob",
61+
// &DefaultGenomeConfig::node_add_prob)
62+
// .def_rw("node_delete_prob",
63+
// &DefaultGenomeConfig::node_delete_prob)
64+
// .def_rw("single_structural_mutation",
65+
// &DefaultGenomeConfig::single_structural_mutation)
66+
// .def_rw("structural_mutation_surer",
67+
// &DefaultGenomeConfig::structural_mutation_surer)
68+
// .def_rw("initial_connection",
69+
// &DefaultGenomeConfig::initial_connection)
70+
// .def_rw("connection_fraction",
71+
// &DefaultGenomeConfig::connection_fraction)
72+
// .def_rw("input_keys",
73+
// &DefaultGenomeConfig::input_keys)
74+
// .def_rw("output_keys",
75+
// &DefaultGenomeConfig::output_keys)
76+
// .def("get_new_node_key",
77+
// &DefaultGenomeConfig::get_new_node_key);
78+
79+
80+
nb::class_<GenomeConfig>(m, "GenomeConfig")
81+
.def(nb::init<>()) // Default constructor
82+
.def_rw("compatibility_weight_coefficient", &GenomeConfig::compatibility_weight_coefficient);
83+
84+
nb::class_<DefaultNodeGene>(m, "DefaultNodeGene")
85+
.def(nb::init<int>(), "Initialize with an integer key")
86+
.def_rw("key", &DefaultNodeGene::key)
87+
.def("copy", &DefaultNodeGene::copy)
88+
.def("distance", &DefaultNodeGene::distance);
89+
// .def("mutate", &DefaultNodeGene::mutate);
90+
91+
// nb::class_<DefaultConnectionGene>(m, "DefaultConnectionGene")
92+
// .def(nb::init<>())
93+
// .def_rw("weight", &DefaultConnectionGene::weight)
94+
// .def_rw("enabled", &DefaultConnectionGene::enabled)
95+
// .def("copy", &DefaultConnectionGene::copy)
96+
// .def("distance", &DefaultConnectionGene::distance);
97+
// // .def("mutate", &DefaultConnectionGene::mutate)
98+
// // .def("crossover", &DefaultConnectionGene::crossover);
99+
100+
// nb::class_<DefaultGenome>(m, "DefaultGenome")
101+
// .def(nb::init<>())
102+
// .def_rw("key", &DefaultGenome::key)
103+
// .def_rw("fitness", &DefaultGenome::fitness)
104+
// .def_rw("nodes", &DefaultGenome::nodes)
105+
// .def_rw("connections", &DefaultGenome::connections)
106+
// .def("configure_new", &DefaultGenome::configure_new)
107+
// .def("mutate_add_node", &DefaultGenome::mutate_add_node);
108+
109+
// m.def("get_pruned_copy", &get_pruned_copy, "Get a pruned copy of the genome");
110+
}

‎src/neat3p/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from ._neat3p import GenomeConfig, DefaultNodeGene

0 commit comments

Comments
 (0)
Please sign in to comment.