Quellcode durchsuchen

Added basic C idea

Randy Paredis vor 4 Jahren
Ursprung
Commit
42e22cef61

+ 40 - 12
src/CBD/converters/CBD2C/__init__.py

@@ -2,7 +2,11 @@
 A module that allows the creation of a C file, in which the block's computations are inlined.
 """
 from CBD.scheduling import TopologicalScheduler
+from CBD.solver import GaussianJordanLinearSolver
 from CBD.depGraph import DepGraph, createDepGraph
+from CBD.converters.latexify import CBD2Latex
+
+from jinja2 import Template
 
 class CBD2C:
 	def __init__(self, model, itcnt):
@@ -18,6 +22,16 @@ class CBD2C:
 		depGraph = createDepGraph(self.model, curIt)
 		return self.scheduler.schedule(depGraph, curIt, 0.0)
 
+	def generate(self, fname):
+		with open("template.c", 'r') as file:
+			template = Template(file.read(), trim_blocks=True, lstrip_blocks=True)
+		contents = template.render(itcnt = self.itcnt,
+		                           blocks = self.get_blocks(),
+		                           components0 = self.get_order(0),
+		                           components = self.get_order(1) )
+		with open(fname, 'w') as file:
+			file.write(contents)
+
 if __name__ == '__main__':
 	from CBD.Core import CBD
 	from CBD.lib.std import *
@@ -27,19 +41,33 @@ if __name__ == '__main__':
 			self.addBlock(AdderBlock("A"))
 			self.addBlock(ProductBlock("B"))
 			self.addBlock(ConstantBlock("C", 3.0))
-			self.addBlock(ConstantBlock("D", -4.0))
-			self.addBlock(ConstantBlock("E", -8.0))
+			self.addBlock(ConstantBlock("D", 6.0))
 			self.addConnection("C", "A")
-			self.addConnection("D", "A")
+			self.addConnection("B", "A")
 			self.addConnection("A", "B")
-			self.addConnection("E", "B")
+			self.addConnection("D", "B")
 			self.addConnection("B", "x")
 
-
-	gen = CBD2C(Test("bla"), 3000)
-	block = gen.get_blocks()
-	for comp in gen.get_order(0):
-		print("COMPONENT")
-		print(comp[0])
-
-	# TODO: Generate header file with all #defines
+	test = Test("test")
+	ltx = CBD2Latex(test, render_latex=False, escape_nonlatex=False, path_sep='_', ignore_path=False)
+	ltx.simplify_links()
+	print(ltx.equations)
+	gen = CBD2C(test, 3000)
+	gen.generate("example.c")
+	for block in gen.get_blocks():
+		try:
+			print(block.getBlockConnectedToInput("IN1"))
+		except: pass
+	# sol = GaussianJordanLinearSolver(None)
+	# # block = gen.get_blocks()
+	# for comp in gen.get_order(0):
+	# 	print("--------------")
+	# 	if len(comp) == 1:
+	# 		print(comp[0])
+	# 		comp[0].compute(0)
+	# 	else:
+	# 		m1, m2 = sol.constructInput(comp, 0)
+	# 		print(m1)
+	# 		print(m2)
+	#
+	# # TODO: Generate header file with all #defines

BIN
src/CBD/converters/CBD2C/a.out


+ 55 - 0
src/CBD/converters/CBD2C/example.c

@@ -0,0 +1,55 @@
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include "lsolve.h"
+
+#define M 5    /* No of Blocks */
+#define N 3000    /* No of Iterations */
+
+/* BLOCK VARIABLE NAMES */
+#define test_A RESULT[0]
+#define test_B RESULT[1]
+#define test_C RESULT[2]
+#define test_D RESULT[3]
+#define test_x RESULT[4]
+
+double RESULT[M][N];
+
+/* EQUATIONS */
+void _eq_init(const double delta) {
+    test_C = ??;
+    test_D = ??;
+
+    /* Algebraic Loop */
+    double _C2[2][3] = {{ -1.0, 6.0, 0.0}, {1.0, -1.0, -3.0 }};
+    agloop(&_C2, 2, &bla_B[0], &bla_A[0]);
+
+    test_x = ??;
+}
+
+void _eq_iter(const unsigned int i, const double time, const double delta) {
+    bla_C[i] = 3.0;
+    bla_D[i] = 6.0;
+
+    /* Algebraic Loop */
+    double _C3[2][3] = {{ -1.0, 6.0, 0.0}, {1.0, -1.0, -3.0 }};
+    agloop(&_C3, 2, &bla_B[i], &bla_A[i]);
+
+    bla_x[i] = bla_B[i];
+}
+
+/* SIMULATOR */
+int main(int argc, char *args[]) {
+    double delta = 0.1;
+    double time = 0.0;
+
+    _eq_init(delta);
+    for(int i = 1; i < N; ++i) {
+        time += delta;
+        _eq_iter(i, time, delta);
+    }
+
+    printf("\tTIME = %12.4f s\n", time);
+    printf("\tX    = %12.4f\n", bla_x[N - 1]);
+}

+ 21 - 15
src/CBD/converters/CBD2C/generated.c

@@ -1,7 +1,10 @@
-#include "math.h"
-#include "stdio.h"
-#include "time.h"
-#define M 6        /* No of Blocks */
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include "lsolve.h"
+
+#define M 5        /* No of Blocks */
 #define N 300      /* No of Iterations */
 
 /* BLOCK VARIABLE NAMES */
@@ -9,27 +12,30 @@
 #define bla_B RESULT[1]
 #define bla_C RESULT[2]
 #define bla_D RESULT[3]
-#define bla_E RESULT[4]
-#define bla_x RESULT[5]
+#define bla_x RESULT[4]
 
 double RESULT[M][N];
 
 /* EQUATIONS */
 void _eq_init(const double delta) {
     bla_C[0] = 3.0;
-    bla_D[0] = -4.0;
-    bla_A[0] = bla_C[0] + bla_D[0];
-    bla_E[0] = -8.0;
-    bla_B[0] = bla_A[0] * bla_E[0];
+    bla_D[0] = 6.0;
+
+    /* Algebraic Loop */
+    double _C3[2][3] = {{-1.0, 6.0, 0.0}, {1.0, -1.0, -3.0}};
+    agloop(&_C3, 2, &bla_B[0], &bla_A[0]);
+
     bla_x[0] = bla_B[0];
 }
 
 void _eq_iter(const unsigned int i, const double time, const double delta) {
     bla_C[i] = 3.0;
-    bla_D[i] = -4.0;
-    bla_A[i] = bla_C[i] + bla_D[i];
-    bla_E[i] = -8.0;
-    bla_B[i] = bla_A[i] * bla_E[i];
+    bla_D[i] = 6.0;
+
+    /* Algebraic Loop */
+    double _C3[2][3] = {{-1.0, 6.0, 0.0}, {1.0, -1.0, -3.0}};
+    agloop(&_C3, 2, &bla_B[i], &bla_A[i]);
+
     bla_x[i] = bla_B[i];
 }
 
@@ -45,5 +51,5 @@ int main(int argc, char *args[]) {
     }
 
     printf("\tTIME = %12.4f s\n", time);
-    printf("\tX = %12.4f\n", bla_x[N - 1]);
+    printf("\tX    = %12.4f\n", bla_x[N - 1]);
 }

+ 79 - 16
src/CBD/converters/CBD2C/lsolve.c

@@ -1,18 +1,20 @@
-#include "math.h"
-#include "stdio.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include "lsolve.h"
 
-double getelm(double* matrix, const unsigned i, const unsigned j, const unsigned m) {
+double getelm(double* matrix, const unsigned int i, const unsigned int j, const unsigned int m) {
     const unsigned n = m + 1;
     return *((matrix + i * n) + j);
 }
 
-void setelm(double* matrix, const unsigned i, const unsigned j, const unsigned m, double val) {
+void setelm(double* matrix, const unsigned i, const unsigned int j, const unsigned int m, double val) {
     const unsigned n = m + 1;
     *((matrix + i * n) + j) = val;
 }
 
 unsigned int argmax_abs(const unsigned int low, const unsigned int high, const unsigned int column, double* A) {
-    unsigned int i_max = -1;
+    unsigned int i_max = 0;
     double max_value = -1.0;  // computes the abs argmax, so always larger than -1
     for(unsigned int i = low; i < high; ++i) {
         double a = fabs(getelm(A, i, column, high));
@@ -25,6 +27,7 @@ unsigned int argmax_abs(const unsigned int low, const unsigned int high, const u
 }
 
 void swrows(double* matrix, const unsigned int r1, const unsigned int r2, const unsigned int cols) {
+    if(r1 == r2) { return; }
     double tmp;
     for(unsigned int i = 0; i < cols; ++i) {
         tmp = getelm(matrix, r2, i, cols - 1);
@@ -33,14 +36,14 @@ void swrows(double* matrix, const unsigned int r1, const unsigned int r2, const
     }
 }
 
-void lsolve(const unsigned int size, double* matrix) {
+void lsolve(double* matrix, const unsigned int size) {
     const double eps = 1e-4;
     const unsigned int m = size;        // rows
     const unsigned int n = size + 1;    // columns
-    unsigned int h = 0;  // pivot row
-    unsigned int k = 0;  // pivot column
+    unsigned int h = 0;                 // pivot row
+    unsigned int k = 0;                 // pivot column
 
-    while(h <= m && k <= n) {
+    while(h < m && k < n) {
         unsigned int i_max = argmax_abs(h, m, k, matrix);
         double elm = getelm(matrix, i_max, k, m);
         if(fabs(elm) <= eps) {
@@ -59,20 +62,80 @@ void lsolve(const unsigned int size, double* matrix) {
                     setelm(matrix, i, j, m, getelm(matrix, i, j, m) - getelm(matrix, h, j, m) * f);
                 }
             }
+            swrows(matrix, h, i_max, n);
+
+//            printf("MAT %d, %d\n", i_max, k);
+//            for(unsigned int i = 0; i < m; ++i) {
+//                for(unsigned int j = 0; j < n; ++j) {
+//                    printf("\t%7f", getelm(matrix, i, j, m));
+//                }
+//                printf("\n");
+//            }
+
             h += 1;
             k += 1;
         }
     }
 }
 
-int main(int argc, char *args[]) {
-    double A[3][4] = {{1, 3, 1, 9}, {1, 1, -1, 1}, {3, 11, 5, 35}};
-    lsolve(3, &A);
+double det(double* matrix, const unsigned int size) {
+    unsigned int height = size - 1;
 
-    for(unsigned int i = 0; i < 3; ++i) {
-        for(unsigned int j = 0; j < 4; ++j) {
-            printf("\t%7f", A[i][j]);
+    if(size == 2) {
+        double a00 = getelm(matrix, 0, 0, height);
+        double a01 = getelm(matrix, 0, 1, height);
+        double a10 = getelm(matrix, 1, 0, height);
+        double a11 = getelm(matrix, 1, 1, height);
+        return (a00 * a11) - (a01 * a10);
+    }
+
+    double total = 0.0;
+    for(unsigned int fc = 0; fc < size; ++fc) {
+        double As[height][height];
+        for(unsigned int r = 0; r < height; ++r) {
+            for(unsigned int c = 0; c < fc; ++c) {
+                As[r][c] = getelm(matrix, r + 1, c, height);
+            }
+            for(unsigned int c = fc; c < height; ++c) {
+                As[r][c] = getelm(matrix, r + 1, c + 1, height);
+            }
         }
-        printf("\n");
+        double sign = -1.0;
+        if(fc % 2 == 1) {
+            sign = 1.0;
+        }
+        double sub_det = det(&As, height);
+        total += sign * getelm(matrix, 0, fc, height) * sub_det;
     }
+    return total;
 }
+
+void agloop(double* A, const unsigned int size, ...) {
+    double D = det(A, size);
+    if(fabs(D) < 1e-5) {
+        printf("ERROR: SINGULAR MATRIX!\n");
+        exit(1);
+    }
+    lsolve(A, size);
+
+    // Read the arguments
+    va_list list;
+    va_start(list, size);
+    for(unsigned int j = 0; j < size; ++j) {
+        *va_arg(list, double*) = getelm(A, j, size, size);
+    }
+    va_end(list);
+}
+
+//int main(int argc, char *args[]) {
+//    double A[2][3] = {{-1.0, 6.0, 0.0}, {1.0, -1.0, -3.0}};
+//    lsolve(&A, 2);
+//
+////    printf("END\n");
+////    for(unsigned int i = 0; i < 2; ++i) {
+////        for(unsigned int j = 0; j < 3; ++j) {
+////            printf("\t%7f", A[i][j]);
+////        }
+////        printf("\n");
+////    }
+//}

+ 76 - 0
src/CBD/converters/CBD2C/lsolve.h

@@ -0,0 +1,76 @@
+#ifndef LSOLVE
+#define LSOLVE
+
+/**
+ *  Obtains an element from a 2D array matrix, using pointers.
+ *  This is mainly a helper function.
+ *
+ *  @param  matrix  An address to an (NxN+1) matrix, which is
+ *                  to be constructed as a 2D array.
+ *  @param  i       The row index of the element to obtain.
+ *  @param  j       The column index of the element to obtain.
+ *  @param  m       The amount of rows for the input matrix.
+ **/
+double getelm(double* matrix, const unsigned int i, const unsigned int j, const unsigned int m);
+
+/**
+ *  Sets an element in a 2D array matrix, using pointers.
+ *  This is mainly a helper function.
+ *
+ *  @param  matrix  An address to an (NxN+1) matrix, which is
+ *                  to be constructed as a 2D array.
+ *  @param  i       The row index of the element to set.
+ *  @param  j       The column index of the element to set.
+ *  @param  m       The amount of rows for the input matrix.
+ *  @param  val     The new value for the element.
+ **/
+void setelm(double* matrix, const unsigned int i, const unsigned int j, const unsigned int m, double val);
+
+/**
+ *  Computes the row index that yields the highest absolute value.
+ *  This is mainly a helper function.
+ *
+ *  @param  low     The minimal row index to return.
+ *  @param  high    The maximal row index to return.
+ *  @param  A       An address to an (NxN+1) matrix, which is
+ *                  to be constructed as a 2D array.
+ **/
+unsigned int argmax_abs(const unsigned int low, const unsigned int high, const unsigned int column, double* A);
+
+/**
+ *  Solves a system of equations linearly, by using matrices
+ *  and Gauss-Jordan Elimination. Only works for N equations
+ *  and N unknowns.
+ *
+ *  @param  matrix  An address to an (NxN+1) matrix, which is
+ *                  to be constructed as a 2D array.
+ *  @param  size    The amount of rows for the input matrix N.
+ **/
+void lsolve(double* matrix, const unsigned int size);
+
+/**
+ *  Computes the determinant of the matrix.
+ *
+ *  @param  matrix  An address to an (NxN) matrix, which is
+ *                  to be constructed as a 2D array.
+ *  @param  size    The amount of rows for the input matrix N.
+ **/
+double det(double* matrix, const unsigned int size);
+
+/**
+ *  Helper function to linearly solve algebraic loops.
+ *  This first checks if the block matrix is not singular,
+ *  after which it solves the equations w.r.t. Gauss-Jordan.
+ *  Finally, the resulting matrix is automatically stored in
+ *  the corresponding variables.
+ *
+ *  @param  A       An address to an (NxN+1) matrix, which is
+ *                  to be constructed as a 2D array.
+ *  @param  size    The amount of rows for the input matrix N.
+ *  @param  ...     An undefined amount of arguments that refer
+ *                  to the variables in which the data must be
+ *                  stored in the end.
+ **/
+void agloop(double* A, const unsigned int size, ...);
+
+#endif

+ 56 - 0
src/CBD/converters/CBD2C/template.c

@@ -0,0 +1,56 @@
+#include <math.h>
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include "lsolve.h"
+
+#define M {{ blocks|length }}    /* No of Blocks */
+#define N {{ itcnt }}    /* No of Iterations */
+
+/* BLOCK VARIABLE NAMES */
+{% for block in blocks %}
+#define {{ block.getPath('_') }} RESULT[{{ loop.index0 }}]
+{% endfor %}
+
+double RESULT[M][N];
+
+/* EQUATIONS */
+void _eq_init(const double delta) {
+    {% for comp in components0 %}
+        {% if comp|length == 1 %}
+    {{ comp[0].getPath('_') }} = ??;
+        {% else %}
+
+    /* Algebraic Loop */
+    double _C{{ loop.index0 }}[{{comp|length}}][{{comp|length + 1}}] = {{ '{{' }} -1.0, 6.0, 0.0}, {1.0, -1.0, -3.0 {{ '}}' }};
+    agloop(&_C{{ loop.index0 }}, {{comp|length}}, &bla_B[0], &bla_A[0]);
+
+        {% endif %}
+    {% endfor %}
+}
+
+void _eq_iter(const unsigned int i, const double time, const double delta) {
+    bla_C[i] = 3.0;
+    bla_D[i] = 6.0;
+
+    /* Algebraic Loop */
+    double _C3[2][3] = {{ '{{' }} -1.0, 6.0, 0.0}, {1.0, -1.0, -3.0 {{ '}}' }};
+    agloop(&_C3, 2, &bla_B[i], &bla_A[i]);
+
+    bla_x[i] = bla_B[i];
+}
+
+/* SIMULATOR */
+int main(int argc, char *args[]) {
+    double delta = 0.1;
+    double time = 0.0;
+
+    _eq_init(delta);
+    for(int i = 1; i < N; ++i) {
+        time += delta;
+        _eq_iter(i, time, delta);
+    }
+
+    printf("\tTIME = %12.4f s\n", time);
+    printf("\tX    = %12.4f\n", bla_x[N - 1]);
+}

+ 8 - 6
src/CBD/converters/latexify.py

@@ -43,6 +43,7 @@ class CBD2Latex:
 								where :code:`operationType` identifies the operation to remap
 								and :code:`callable` a function that takes the name/symbol and
 								the arguments as input and produces a string representation.
+		path_sep (str):         The separator to use for the paths. Defaults to :code:`"."`.
 		merge_sums (bool):      Whether or not multiple additions of the same sub-equation should
 								be merged into a product. Defaults to :code:`True`.
 		merge_prods (bool):     Whether or not multiple products of the same sub-equation should
@@ -62,6 +63,7 @@ class CBD2Latex:
 			"delta_t": "",
 			"replace_par": True,
 			"type_formats": {},
+			"path_sep": '.',
 
 			# Fnc settings
 			"merge_sums": True,
@@ -74,7 +76,7 @@ class CBD2Latex:
 				self.config[k] = kwargs[k]
 
 		self.equations = {}
-		self.outputs = [self._rename(self.model.getPath() + "." + x) for x in self.model.getSignals().keys()]
+		self.outputs = [self._rename(self.model.getPath(self.config['path_sep']) + self.config['path_sep'] + x) for x in self.model.getSignals().keys()]
 		self._collect_equations()
 		self._step = 0
 
@@ -85,7 +87,7 @@ class CBD2Latex:
 			name (str):     The name to convert.
 		"""
 		if self.config["ignore_path"]:
-			mname = self.model.getPath() + "."
+			mname = self.model.getPath(self.config['path_sep']) + self.config['path_sep']
 			if name.startswith(mname):
 				name = name[len(mname):]
 		if self.config["escape_nonlatex"]:
@@ -110,7 +112,7 @@ class CBD2Latex:
 					continue
 			if isinstance(func, str):
 				func = lambda b, p, f=func: (p("OUT1"), Fnc(f, [self._rename(p("%s") % x) for x in block.getInputPortNames()]))
-			res = func(block, lambda x: self._rename(block.getPath() + "." + x))
+			res = func(block, lambda x: self._rename(block.getPath(self.config['path_sep']) + self.config['path_sep'] + x))
 			if isinstance(res, tuple):
 				f = res[1]
 				if isinstance(f, Fnc):
@@ -126,12 +128,12 @@ class CBD2Latex:
 		# Add all connections
 		for block in self.model.getBlocks():
 			tp = block.getBlockType()
-			path = block.getPath()
+			path = block.getPath(self.config['path_sep'])
 			for k, v in block.getLinksIn().items():
 				if tp == "OutputPortBlock":
-					self.equations[self._rename(path)] = [self._rename(v.block.getPath() + "." + v.output_port)]
+					self.equations[self._rename(path)] = [self._rename(v.block.getPath(self.config['path_sep']) + self.config['path_sep'] + v.output_port)]
 				else:
-					self.equations[self._rename(path + "." + k)] = self._rename(v.block.getPath() + "." + v.output_port)
+					self.equations[self._rename(path + self.config['path_sep'] + k)] = self._rename(v.block.getPath(self.config['path_sep']) + self.config['path_sep'] + v.output_port)
 
 	def render(self, rl=True):
 		"""

+ 11 - 0
src/CBD/solver.py

@@ -264,6 +264,17 @@ class Matrix:
 		inner = absolute % self.__max_list_size
 		self.data[outer][inner] = value
 
+	def __str__(self):
+		res = ""
+		for row in range(self.rows):
+			if len(res) > 0:
+				res += "\n"
+			res += "["
+			for col in range(self.cols):
+				res += "\t%8.4f" % self[row, col]
+			res += "\t]"
+		return res
+
 
 try:
 	import sympy