Skip to content

Tensor class #32

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

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
cmake --build build --parallel
- name: Test
run: |
build/bin/run_tests
build/test/run_test
env:
CTEST_OUTPUT_ON_FAILURE: 1
- name: Generate lcov Coverage Data
Expand Down
19 changes: 13 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 11)

project(cpp_template)

include(cmake/configure.cmake)
set(ProjectName "itlab")
project(${ProjectName})

include_directories(include)

enable_testing()

add_subdirectory(3rdparty)
add_subdirectory(app)
add_subdirectory(include)

add_subdirectory(3rdparty/googletest)
add_subdirectory(src)
add_subdirectory(test)

# REPORT
message( STATUS "")
message( STATUS "General configuration for ${PROJECT_NAME}")
message( STATUS "======================================")
message( STATUS "")
message( STATUS " Configuration: ${CMAKE_BUILD_TYPE}")
message( STATUS "")
Empty file removed include/CMakeLists.txt
Empty file.
43 changes: 43 additions & 0 deletions include/graph/graph.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef GRAPH_H
#define GRAPH_H

#include <list>
#include <unordered_map>
#include <vector>

class Vertex {
private:
int id_;
std::list<int> neighbors_;

public:
Vertex(int id_);
void addNeighbor(int neighbor);
void removeNeighbor(int neighbor);
void print() const;
int getId() const;
const std::list<int>& getNeighbors() const;
};

class Graph {
private:
std::unordered_map<int, Vertex*> vertices_;

public:
Graph();
void addVertex(int id_);
void getVertex() const;
void addEdge(int u, int v);
void removeEdge(int u, int v);
void removeVertex(int id_);
int vertexCount() const;
int edgeCount() const;
bool empty() const;
void printGraph() const;
bool bfs_helper(int start, int vert, bool flag, std::vector<int>* v_ord);
bool hasPath(int u, int v);
std::vector<int> BFS(int start);
~Graph();
};

#endif
35 changes: 35 additions & 0 deletions include/tensor/tensor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef TENSOR_H
#define TENSOR_H

#include <cstddef>
#include <cstdint>
#include <vector>

struct Shape {
std::vector<size_t> dimensions;
size_t total_elements;

Shape(std::vector<size_t> dims);

size_t get_rank() const;
};

enum Layout : std::uint8_t { kNchw, kNhwc, kNd };

template <typename T>
class Tensor {
public:
Shape shape;
Layout layout;
std::vector<T> data;

Tensor(const Shape &sh, Layout l = Layout::kNd);
Tensor(std::vector<size_t> dims, Layout l = Layout::kNd);

size_t get_linear_index(const std::vector<size_t> &indices) const;

T &at(const std::vector<size_t> &indices);
const T &at(const std::vector<size_t> &indices) const;
};

#endif
7 changes: 7 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
file(GLOB_RECURSE HEADER_FILES "${CMAKE_SOURCE_DIR}/include/*.h")
file(GLOB_RECURSE SOURCE_FILES "${CMAKE_SOURCE_DIR}/src/*.cpp")

add_library(${ProjectName} STATIC ${SOURCE_FILES} ${HEADER_FILES})
target_sources(${ProjectName} PRIVATE ${HEADER_FILES})

target_include_directories(${ProjectName} PUBLIC ${CMAKE_SOURCE_DIR}/src)
141 changes: 141 additions & 0 deletions src/graph/graph.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "./graph/graph.h"

#include <iostream>
#include <list>
#include <queue>
#include <unordered_map>
#include <vector>

Vertex::Vertex(int id_) : id_(id_) {}

void Vertex::addNeighbor(int neighbor) {
if (neighbor != id_) {
neighbors_.push_back(neighbor);
}
}

void Vertex::removeNeighbor(int neighbor) { neighbors_.remove(neighbor); }

void Vertex::print() const {
std::cout << id_ << ": ";
for (const int& neighbor : neighbors_) {
std::cout << neighbor << " ";
}
std::cout << '\n';
}

int Vertex::getId() const { return id_; }

const std::list<int>& Vertex::getNeighbors() const { return neighbors_; }

Graph::Graph() = default;

void Graph::addVertex(int id_) {
if (vertices_.find(id_) == vertices_.end()) {
vertices_[id_] = new Vertex(id_);
}
}

void Graph::getVertex() const {
if (!this->empty()) {
for (const auto& vertice : vertices_) {
std::cout << vertice.first << " ";
}
std::cout << '\n';
}
}

void Graph::addEdge(int u, int v) {
if (vertices_.find(u) == vertices_.end()) {
addVertex(u);
}
if (vertices_.find(v) == vertices_.end()) {
addVertex(v);
}
vertices_[u]->addNeighbor(v);
}

void Graph::removeEdge(int u, int v) {
if (vertices_.find(u) != vertices_.end()) {
vertices_[u]->removeNeighbor(v);
}
}

void Graph::removeVertex(int id_) {
for (auto& pair : vertices_) {
pair.second->removeNeighbor(id_);
}
auto it = vertices_.find(id_);
if (it != vertices_.end()) {
delete it->second;
vertices_.erase(it);
}
}

int Graph::vertexCount() const { return static_cast<int>(vertices_.size()); }

int Graph::edgeCount() const {
int count = 0;
for (const auto& vertice : vertices_) {
count += (vertice.second->getNeighbors()).size();
}
return count;
}

bool Graph::empty() const { return vertices_.empty(); }

void Graph::printGraph() const {
for (const auto& pair : vertices_) {
pair.second->print();
}
}

bool Graph::bfs_helper(int start, int vert, bool flag,
std::vector<int>* v_ord) {
std::unordered_map<int, bool> visited;
std::queue<int> queue;
queue.push(start);
visited[start] = true;

while (!queue.empty()) {
int current = queue.front();
queue.pop();

if (flag && current == vert) {
return true;
}
if (v_ord != nullptr) {
v_ord->push_back(current);
}

if (vertices_.find(current) != vertices_.end()) {
for (const int& neighbor : vertices_[current]->getNeighbors()) {
if (!visited[neighbor]) {
visited[neighbor] = true;
queue.push(neighbor);
}
}
}
}
return false;
}

bool Graph::hasPath(int u, int v) {
if (vertices_.find(u) == vertices_.end() ||
vertices_.find(v) == vertices_.end()) {
return false;
}
return bfs_helper(u, v, true, nullptr);
}

std::vector<int> Graph::BFS(int start) {
std::vector<int> v_ord;
bfs_helper(start, -1, false, &v_ord);
return v_ord;
}

Graph::~Graph() {
for (auto& pair : vertices_) {
delete pair.second;
}
}
84 changes: 84 additions & 0 deletions src/tensor/tensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "./tensor/tensor.h"

#include <algorithm>
#include <cstddef>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <utility>
#include <vector>

Shape::Shape(std::vector<size_t> dims) : dimensions(std::move(dims)) {
total_elements = std::accumulate(dimensions.begin(), dimensions.end(),
static_cast<size_t>(1),
[](size_t a, size_t b) { return a * b; });
}

size_t Shape::get_rank() const { return dimensions.size(); }

template <typename T>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, move template implementation to the header, otherwise it will not work for other data types specified by the user

Tensor<T>::Tensor(const Shape &sh, Layout l)
: shape(sh), layout(l), data(sh.total_elements) {
if (sh.get_rank() == 4 && l == Layout::kNd) {
std::cerr << "4D Tensor created with kNd layout." << '\n';
}
}

template <typename T>
Tensor<T>::Tensor(std::vector<size_t> dims, Layout l)
: Tensor(Shape(std::move(dims)), l) {}

template <typename T>
size_t Tensor<T>::get_linear_index(const std::vector<size_t> &indices) const {
if (indices.size() != shape.get_rank()) {
throw std::runtime_error("Incorrect number of indices provided.");
}
for (size_t i = 0; i < indices.size(); ++i) {
if (indices[i] >= shape.dimensions[i]) {
throw std::out_of_range("Index out of range for dimension");
}
}

size_t linear_index = 0;
size_t stride = 1;

if (shape.get_rank() == 4) {
if (layout == Layout::kNchw) {
linear_index = indices[0] * (shape.dimensions[1] * shape.dimensions[2] *
shape.dimensions[3]) +
indices[1] * (shape.dimensions[2] * shape.dimensions[3]) +
indices[2] * shape.dimensions[3] + indices[3];
} else if (layout == Layout::kNhwc) {
linear_index = indices[0] * (shape.dimensions[1] * shape.dimensions[2] *
shape.dimensions[3]) +
indices[1] * (shape.dimensions[2] * shape.dimensions[3]) +
indices[2] * shape.dimensions[3] + indices[3];
} else {
linear_index = indices[0] * (shape.dimensions[1] * shape.dimensions[2] *
shape.dimensions[3]) +
indices[1] * (shape.dimensions[2] * shape.dimensions[3]) +
indices[2] * shape.dimensions[3] + indices[3];
}
} else {
std::vector<size_t> reversed_dims = shape.dimensions;
std::reverse(reversed_dims.begin(), reversed_dims.end());
for (int i = static_cast<int>(reversed_dims.size()) - 1; i >= 0; --i) {
linear_index += indices[i] * stride;
stride *= reversed_dims[i];
}
}

return linear_index;
}

template <typename T>
T &Tensor<T>::at(const std::vector<size_t> &indices) {
return data[get_linear_index(indices)];
}

template <typename T>
const T &Tensor<T>::at(const std::vector<size_t> &indices) const {
return data[get_linear_index(indices)];
}

template class Tensor<double>;
15 changes: 10 additions & 5 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
file(GLOB_RECURSE TEST_SRC_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)

add_executable(run_tests ${TEST_SRC_FILES})
target_link_libraries(run_tests PUBLIC
gtest_main
)
file(GLOB_RECURSE TEST_FILES ./*.cpp)

set(TestsName "run_test")

add_executable(${TestsName} ${TEST_FILES})

target_link_libraries(${TestsName} PRIVATE ${ProjectName} gtest)

enable_testing()
add_test(NAME ${TestsName} COMMAND ${TestsName})
Loading
Loading