1 #include "BlackBoxRuntime.hpp"
8 random_double_logUniform()
14 uint16_t asIntegers
[4];
16 uint32_t asIntegers
[2];
30 X
.asIntegers
[0] = rand() | ((spareRand
& 0x1) << 15);
31 X
.asIntegers
[1] = rand() | ((spareRand
& 0x2) << 14);
32 X
.asIntegers
[2] = rand() | ((spareRand
& 0x4) << 13);
33 X
.asIntegers
[3] = rand() | ((spareRand
& 0x8) << 12);
35 X
.asIntegers
[0] = rand() | ((spareRand
& 0x1) << 31);
36 X
.asIntegers
[1] = rand() | ((spareRand
& 0x2) << 30);
39 while (!isfinite(X
.asDouble
));
45 : public MixedModelBase
48 MixedModelVM(const char* filename
)
49 : mFile(NULL
), mData(NULL
), mCode(NULL
), mInitBlackBoxes(NULL
),
50 mInitConstants(NULL
), mRun(NULL
), mTrain(NULL
), mFileEnd(NULL
),
51 mInputVariableCount(0), mOutputVariableCount(0), mConstantCount(0),
52 mOtherVariableCount(0), mTempInputCount(0), mTempOutputCount(0),
53 mBlackBoxCount(0), mnSetJumps(10), mVMFlags(0), mReady(false),
56 memset(mSetJumps
, 0xFF, sizeof(mSetJumps
));
57 mStack
= new uint32_t[1000];
58 mStackEnd
= mStack
+ 1000 - 1;
61 fd
= open(filename
, O_RDONLY
);
64 perror("Load black/white model VM file");
69 if (fstat(fd
, &sb
) < 0)
71 perror("Stat black/white model VM file");
76 if (!S_ISREG(sb
.st_mode
))
78 fprintf(stderr
, "Black/white model VM file isn't a regular file.\n");
83 mFileSize
= sb
.st_size
;
84 mFile
= (uint8_t*)mmap(0, sb
.st_size
, PROT_READ
| PROT_WRITE
, MAP_PRIVATE
, fd
, 0);
87 perror("mmap black/white model VM file");
94 // Check the header is right...
98 fprintf(stderr
, "Black/white model VM file < 8 bytes!\n");
102 if (memcmp(mFile
, "\xB1\xAB\x0C\x00", 4))
105 fprintf(stderr
, "Black/white model has wrong signature.\n");
109 mHeaderEnd
= *reinterpret_cast<uint32_t*>(mFile
+ 4);
111 if (mHeaderEnd
>= mFileSize
)
114 fprintf(stderr
, "Black/white file truncated in header.\n");
118 mFileEnd
= mFile
+ mFileSize
;
120 mCode
= mFile
+ mHeaderEnd
;
122 uint8_t * ptr
= mFile
+ 8;
123 while (ptr
+ 8 < mCode
)
125 uint32_t slen
= *reinterpret_cast<uint32_t*>(ptr
);
127 if (slen
+ ptr
+ 4 < ptr
|| slen
+ ptr
+ 4 > mCode
)
130 fprintf(stderr
, "Black/white header has invalid string length.\n");
134 char* str
= reinterpret_cast<char*>(ptr
);
138 uint32_t offset
= *reinterpret_cast<uint32_t*>(ptr
);
141 if (slen
== 18 && !strncmp(str
, "inputVariableCount", 18))
143 mInputVariableCount
= offset
;
147 if (slen
== 19 && !strncmp(str
, "outputVariableCount", 19))
149 mOutputVariableCount
= offset
;
153 if (slen
== 13 && !strncmp(str
, "constantCount", 13))
155 mConstantCount
= offset
;
159 if (slen
== 18 && !strncmp(str
, "otherVariableCount", 18))
161 mOtherVariableCount
= offset
;
165 if (slen
== 14 && !strncmp(str
, "tempInputCount", 14))
167 mTempInputCount
= offset
;
171 if (slen
== 15 && !strncmp(str
, "tempOutputCount", 15))
173 mTempOutputCount
= offset
;
177 if (slen
== 13 && !strncmp(str
, "blackBoxCount", 13))
179 mBlackBoxCount
= offset
;
183 if (mCode
+ offset
< mCode
|| mCode
+ offset
>= mFileEnd
)
186 fprintf(stderr
, "Black/white header has invalid function offset.\n");
189 if (slen
== 4 && !strncmp(str
, "data", 4))
190 mData
= mCode
+ offset
;
191 else if (slen
== 14 && !strncmp(str
, "initBlackBoxes", 14))
192 mInitBlackBoxes
= mCode
+ offset
;
193 else if (slen
== 13 && !strncmp(str
, "initConstants", 13))
194 mInitConstants
= mCode
+ offset
;
195 else if (slen
== 3 && !strncmp(str
, "run", 3))
196 mRun
= mCode
+ offset
;
197 else if (slen
== 5 && !strncmp(str
, "train", 5))
198 mTrain
= mCode
+ offset
;
204 INPUTS
= reinterpret_cast<double*>(mData
);
205 OUTPUTS
= INPUTS
+ mInputVariableCount
;
206 CONSTANTS
= OUTPUTS
+ mOutputVariableCount
;
207 VARIABLES
= CONSTANTS
+ mConstantCount
;
208 TMPINPUTS
= VARIABLES
+ mOtherVariableCount
;
209 TMPOUTPUTS
= TMPINPUTS
+ mTempInputCount
;
220 countInputVariables() const
222 return mInputVariableCount
;
226 countOutputVariables() const
228 return mOutputVariableCount
;
232 countConstants() const
234 return mConstantCount
;
238 countOtherVariables() const
240 return mOtherVariableCount
;
244 countTempInputs() const
246 return mTempInputCount
;
250 countTempOutputs() const
252 return mTempOutputCount
;
256 countBlackBoxes() const
258 return mBlackBoxCount
;
264 if (mInitConstants
!= NULL
)
265 execute(mInitConstants
);
271 if (mInitBlackBoxes
!= NULL
)
272 execute(mInitBlackBoxes
);
276 train(double * aINPUTS
, double * aOUTPUTS
)
278 memcpy(INPUTS
, aINPUTS
, mInputVariableCount
* sizeof(double));
279 memcpy(OUTPUTS
, aOUTPUTS
, mOutputVariableCount
* sizeof(double));
286 run(double * aINPUTS
, double * aOUTPUTS
)
288 memcpy(INPUTS
, aINPUTS
, mInputVariableCount
* sizeof(double));
293 memcpy(aOUTPUTS
, OUTPUTS
, mOutputVariableCount
* sizeof(double));
298 uint8_t * mFile
, * mData
, * mCode
, * mInitBlackBoxes
, * mInitConstants
,
299 * mRun
, * mTrain
, * mFileEnd
, * mEIP
, * mSetJumps
[10];
300 uint32_t * mStack
, * mStackEnd
, * mESP
;
302 uint32_t mInputVariableCount
, mOutputVariableCount
, mConstantCount
,
303 mOtherVariableCount
, mTempInputCount
, mTempOutputCount
, mBlackBoxCount
,
305 #define VMFLAG_HALT 1
308 #define VM_HAD_HALT (mVMFlags & VMFLAG_HALT)
309 #define VM_HAD_GPE (mVMFlags & VMFLAG_GPE)
313 typedef void (MixedModelVM::* OpcodeFunction
)();
314 static OpcodeFunction opCodes
[256];
319 munmap(mFile
, mFileSize
);
323 void execute(uint8_t* aEIP
);
325 void gpe(const char* aWhy
)
327 printf("VM General Protection Error: %s\n", aWhy
);
328 mVMFlags
|= VMFLAG_HALT
| VMFLAG_GPE
;
339 gpe("Attempt to pop from an empty stack.");
345 if (mESP
- 1 > mStack
)
348 return *reinterpret_cast<double*>(mESP
);
351 gpe("Attempt to pop double from an empty stack.");
355 void push(uint32_t aVal
)
357 if (mESP
== mStackEnd
- 1)
358 gpe("Stack overflow.");
362 void pushDouble(double aVal
)
364 if (mESP
>= mStackEnd
- 2)
366 gpe("Stack overflow.");
369 uint32_t* aRep
= reinterpret_cast<uint32_t*>(&aVal
);
376 gpe("Invalid opcode invoked.");
379 uint32_t getCodeLong()
381 if (mEIP
+ 3 >= mData
)
383 gpe("Instruction pointer outside code range.");
386 uint32_t ret
= *reinterpret_cast<uint32_t*>(mEIP
);
399 pushDouble(acos(popDouble()));
404 pushDouble(acosh(popDouble()));
409 uint32_t i
= 0, l
= pop();
411 if (popDouble() == 0.0)
414 for (i
++; i
< l
; i
++)
423 pushDouble(asin(popDouble()));
428 pushDouble(asinh(popDouble()));
433 pushDouble(atan(popDouble()));
438 pushDouble(atanh(popDouble()));
443 pushDouble(ceil(popDouble()));
448 pushDouble(cos(popDouble()));
453 pushDouble(cosh(popDouble()));
458 double d
= popDouble(), n
= popDouble();
464 uint32_t i
= 0, l
= pop();
470 double val
= popDouble();
472 for (i
--; i
< l
; i
++)
473 if (popDouble() != val
)
486 pushDouble(exp(popDouble()));
491 pushDouble(fabs(popDouble()));
496 double f
= popDouble();
508 pushDouble(floor(popDouble()));
511 double gcd_pair(double a
, double b
)
513 uint32_t ai
= (uint32_t)fabs(a
), bi
= (uint32_t)fabs(b
);
514 unsigned int shift
= 0;
519 #define EVEN(x) ((x&1)==0)
520 while (EVEN(ai
) && EVEN(bi
))
539 return (bi
<< shift
);
542 double lcm_pair(double a
, double b
)
544 return (a
* b
) / gcd_pair(a
, b
);
549 uint32_t i
= 0, l
= pop(), j
= 0;
557 double * storage1
, * storage2
, * t
, ret
;
558 storage1
= new double[l
];
559 if (storage1
== NULL
)
561 gpe("Not enough memory to compute operation result.");
564 storage2
= new double[l
>> 1];
565 if (storage2
== NULL
)
568 gpe("Not enough memory to compute operation result.");
572 for (; i
< l
- 1; i
+= 2)
573 storage1
[j
++] = gcd_pair(popDouble(), popDouble());
576 storage1
[j
++] = popDouble();
583 for (i
= 0; i
< j
- 1; i
+= 2)
584 storage2
[j
++] = gcd_pair(storage1
[i
], storage1
[i
+ 1]);
586 storage2
[j
++] = storage1
[i
];
602 uint32_t i
= 0, l
= pop();
608 double val
= popDouble(), t
;
610 // Remember, the order is reversed due to the stack.
611 for (i
--; i
< l
; i
++)
612 if ((t
= popDouble()) > val
)
627 uint32_t i
= 0, l
= pop();
633 double val
= popDouble(), t
;
635 // Remember, the order is reversed due to the stack.
636 for (i
--; i
< l
; i
++)
637 if ((t
= popDouble()) >= val
)
652 gpe("Sorry, definite integrals not implemented.");
657 uint32_t i
= 0, l
= pop(), j
= 0;
665 double * storage1
, * storage2
, * t
, ret
;
666 storage1
= new double[l
];
667 if (storage1
== NULL
)
669 gpe("Not enough memory to compute operation result.");
672 storage2
= new double[l
>> 1];
673 if (storage2
== NULL
)
676 gpe("Not enough memory to compute operation result.");
680 for (; i
< l
- 1; i
+= 2)
681 storage1
[j
++] = lcm_pair(popDouble(), popDouble());
684 storage1
[j
++] = popDouble();
691 for (i
= 0; i
< j
- 1; i
+= 2)
692 storage2
[j
++] = lcm_pair(storage1
[i
], storage1
[i
+ 1]);
694 storage2
[j
++] = storage1
[i
];
710 uint32_t i
= 0, l
= pop();
716 double val
= popDouble(), t
;
718 // Remember, the order is reversed due to the stack.
719 for (i
--; i
< l
; i
++)
720 if ((t
= popDouble()) > val
)
735 pushDouble(log(popDouble()));
740 uint32_t i
= 0, l
= pop();
746 double val
= popDouble(), t
;
748 // Remember, the order is reversed due to the stack.
749 for (i
--; i
< l
; i
++)
750 if ((t
= popDouble()) <= val
)
765 uint32_t i
= 0, l
= pop();
768 pushDouble(strtod("NAN", NULL
));
772 double best
= popDouble(), t
;
773 for (l
--; i
< l
; i
++)
784 uint32_t i
= 0, l
= pop();
787 pushDouble(strtod("NAN", NULL
));
791 double best
= popDouble(), t
;
792 for (l
--; i
< l
; i
++)
803 pushDouble(-(popDouble() - popDouble()));
808 double d
= popDouble(), n
= popDouble();
809 if (!isfinite(n
) || !isfinite(d
))
811 pushDouble(strtod("NAN", NULL
));
818 pushDouble(strtod("NAN", NULL
));
827 pushDouble((popDouble() == popDouble()) ? 0.0 : 1.0);
832 pushDouble((popDouble() == 0.0) ? 1.0 : 0.0);
837 uint32_t i
= 0, l
= pop();
839 if (popDouble() != 0.0)
842 for (i
++; i
< l
; i
++)
851 uint32_t i
= 0, l
= pop();
860 double e
= popDouble(), v
= popDouble();
861 pushDouble(pow(v
, e
));
866 double d
= popDouble(), n
= popDouble();
867 if (!isfinite(n
) || !isfinite(d
))
869 pushDouble(strtod("NAN", NULL
));
876 pushDouble(strtod("NAN", NULL
));
885 // Return with no stack means halt...
888 mVMFlags
|= VMFLAG_HALT
;
892 mEIP
= mCode
+ pop();
893 if (mEIP
< mCode
|| mEIP
>= mData
)
894 gpe("Return into non-code address.");
901 gpe("Return1 without stack operand.");
905 double retVal
= popDouble();
907 // Return with no stack means halt...
910 mVMFlags
|= VMFLAG_HALT
;
915 mEIP
= mCode
+ pop();
916 if (mEIP
< mCode
|| mEIP
>= mData
)
917 gpe("Return into non-code address.");
924 pushDouble(sin(popDouble()));
929 pushDouble(sinh(popDouble()));
934 pushDouble(tan(popDouble()));
939 pushDouble(tanh(popDouble()));
944 uint32_t i
= 0, l
= pop();
953 pushDouble(-popDouble());
958 uint32_t i
= 0, l
= pop();
961 if (popDouble() != 0.0)
963 pushDouble(val
? 1.0 : 0.0);
968 pushDouble(runConverged() ? 1.0 : 0.0);
973 bool doJump
= (popDouble() != 0.0);
974 uint32_t jmpTo
= pop();
979 if (jmpTo
> sizeof(mnSetJumps
))
981 gpe("jmpif for invalid setjmp ID.");
984 if (mSetJumps
[jmpTo
] == (uint8_t*)0xFFFFFFFF)
986 gpe("jmpif to ID not previously setjmpd.");
990 mEIP
= mSetJumps
[jmpTo
];
993 void opResetConvergence()
995 resetConvergenceCounter();
1000 convergenceSavePoint();
1005 uint32_t bbn
= pop();
1006 if (bbn
>= mBlackBoxCount
)
1008 gpe("calltrain: reference to black box which doesn't exist.");
1011 if (blackBoxes
[bbn
] == NULL
)
1013 gpe("calltrain: reference to black box which hasn't been initialised.");
1017 blackBoxes
[bbn
]->train(TMPINPUTS
, TMPOUTPUTS
);
1022 uint32_t bbn
= pop();
1023 if (bbn
>= mBlackBoxCount
)
1025 printf("Attempted to access black box 0x%x but only %u\n",
1026 bbn
, mBlackBoxCount
);
1027 gpe("callrun: reference to black box which doesn't exist.");
1030 if (blackBoxes
[bbn
] == NULL
)
1032 gpe("callrun: reference to black box which hasn't been initialised.");
1036 blackBoxes
[bbn
]->run(TMPINPUTS
, TMPOUTPUTS
);
1041 uint32_t bbn
= pop();
1042 if (bbn
>= mBlackBoxCount
)
1044 gpe("createbb: reference to black box which doesn't exist.");
1047 if (blackBoxes
[bbn
] != NULL
)
1049 gpe("createbb: attempt to create the same black box twice.");
1053 uint32_t bbOutCount
= pop(), bbInCount
= pop(), bbStringAddr
= pop();
1055 if (bbInCount
> mTempInputCount
)
1057 gpe("Black box input count exceeds specified maximal input count.");
1061 if (bbOutCount
> mTempOutputCount
)
1063 gpe("Black box output count exceeds specified maximal output count.");
1067 if (bbStringAddr
>= (mFileEnd
- mData
) ||
1068 (bbStringAddr
+ 3) >= (mFileEnd
- mData
))
1070 gpe("String constant address out of data range.");
1073 uint32_t len
= *reinterpret_cast<uint32_t*>(mData
+ bbStringAddr
);
1075 if (bbStringAddr
+ 4 + len
> (mFileEnd
- mData
))
1077 gpe("String length puts end of string out of data region.");
1081 std::wstring
URI(reinterpret_cast<wchar_t*>(bbStringAddr
+ 4 + mData
),
1082 len
/ sizeof(wchar_t));
1086 createBlackBox(bbn
, URI
.c_str(), bbInCount
, bbOutCount
);
1090 gpe("createBlackBox instruction failed.");
1094 void opGetAvgInput()
1096 uint32_t idx
= pop();
1097 uint32_t bbn
= pop();
1098 if (bbn
>= mBlackBoxCount
)
1100 gpe("getavginput: reference to black box which doesn't exist.");
1103 if (blackBoxes
[bbn
] == NULL
)
1105 gpe("getavginput: reference to black box which hasn't been initialised.");
1109 pushDouble(blackBoxes
[bbn
]->GetAverageInput(idx
));
1113 executeCallback(uint8_t* func
)
1115 uint32_t* stackSave
= mStack
;
1120 mVMFlags
&= ~VMFLAG_HALT
;
1125 take_numeric_derivative
1131 double saved_x
, value0
, value1
, value2
, delta
, slope1
, slope2
, ratio
;
1134 * Since we have only 52 bits of mantissa, we need delta to flip only the
1135 * last couple of bits.
1137 delta
= saved_x
* 1E-10;
1138 value0
= executeCallback(aFunc
);
1140 value1
= executeCallback(aFunc
);
1141 *aVal
= saved_x
+ delta
;
1142 value2
= executeCallback(aFunc
);
1144 /* We take two numeric derivatives, so we can compare them. This stops us
1145 * from getting trapped at around discontinuities(which otherwise produce
1146 * very steep trapping slopes).
1148 slope1
= (value0
- value1
) / delta
;
1149 slope2
= (value2
- value0
) / delta
;
1151 /* If one slope is zero, return the other... */
1152 if (slope1
== 0.0 || !isfinite(slope1
))
1154 if (slope2
== 0.0 || !isfinite(slope2
))
1157 ratio
= slope1
/ slope2
;
1158 /* If the slopes are similar, return the average... */
1159 if (ratio
> 0.5 && ratio
< 2)
1160 return (slope1
+ slope2
) / 2.0;
1161 /* Otherwise, return the least steep of the two... */
1162 if (fabs(slope1
) < fabs(slope2
))
1167 #define NR_RANDOM_STARTS 100
1168 #define NR_MAX_STEPS 1000
1169 #define NR_MAX_STEPS_INITIAL 10
1173 uint32_t minVar
= pop();
1174 uint32_t minFunc
= pop();
1176 if (minFunc
>= mData
- mCode
)
1178 gpe("Attempt to minimise a function which isn't in the code block.");
1181 uint8_t * func
= mCode
+ minFunc
;
1183 if (minVar
+ 2 > (mFileEnd
- mData
) * 4 ||
1184 minVar
> minVar
+ 2)
1186 gpe("Attempt to minimise a function over a variable not in the data block.");
1190 double * val
= reinterpret_cast<double*>(mData
+ minVar
* 4);
1192 double best_X
, best_fX
= INFINITY
;
1193 double current_X
, current_fX
, current_dfX_dX
;
1194 uint32_t steps
, maxsteps
;
1199 /* We use a 100 random start Newton-Raphson algorithm... */
1200 for (i
= 0; i
< NR_RANDOM_STARTS
; i
++)
1202 /* Choose a random X as a starting point, except for the first run. */
1203 if (i
> 0 || !isfinite(current_X
))
1204 current_X
= random_double_logUniform();
1206 maxsteps
= NR_MAX_STEPS_INITIAL
;
1207 for (steps
= 0; steps
< maxsteps
; steps
++)
1210 current_fX
= executeCallback(func
);
1211 if (!isfinite(current_fX
))
1216 if (best_fX
> current_fX
)
1218 /* We can go past NR_MAX_STEPS_INITIAL steps up to NR_MAX_STEPS steps,
1219 * but only if we keep improving on our previous answer.
1222 if (maxsteps
> NR_MAX_STEPS
)
1223 maxsteps
= NR_MAX_STEPS
;
1224 best_fX
= current_fX
;
1226 /* This is quite far from 0(relatively speaking for a double) to avoid
1227 * numerical instability issues when the minimum doesn't exist but the
1228 * limit at a point from a particular direction would otherwise be the
1231 if (best_fX
<= 1E-250)
1237 current_dfX_dX
= take_numeric_derivative(func
, val
);
1238 /* If it is completely flat, or infinite, we are done with this round. */
1239 if (!isfinite(current_dfX_dX
) || current_dfX_dX
== 0.0)
1244 current_X
-= current_fX
/ current_dfX_dX
;
1245 if (!isfinite(current_X
))
1250 if (best_fX
<= 1E-250)
1256 take_numeric_derivative(func
, val
);
1261 uint32_t sj
= pop();
1262 if (sj
>= mnSetJumps
)
1264 gpe("Attempt to setjmp to an index out of range.");
1268 mSetJumps
[sj
] = mEIP
;
1271 void opFetchDouble()
1273 uint32_t fetchVar
= getCodeLong();
1275 if (fetchVar
+ 2 > (mFileEnd
- mData
) * 4 ||
1276 fetchVar
> fetchVar
+ 2)
1278 gpe("Attempt to fetch a variable which isn't in the data block.");
1282 pushDouble(*reinterpret_cast<double*>(mData
+ fetchVar
* 4));
1287 uint32_t movInto
= pop();
1288 double movWhat
= popDouble();
1290 if (movInto
+ 2 > (mFileEnd
- mData
) * 4 ||
1291 movInto
> movInto
+ 2)
1293 gpe("Attempt to move into a variable which isn't in the data block.");
1297 *reinterpret_cast<double*>(mData
+ movInto
* 4) = movWhat
;
1301 MixedModelVM::OpcodeFunction
1302 MixedModelVM::opCodes
[256] =
1304 &MixedModelVM::invalidOpcode
/* 00 */,
1305 &MixedModelVM::pushImmed
/* 01 */,
1306 &MixedModelVM::opAcos
/* 02 */,
1307 &MixedModelVM::opAcosh
/* 03 */,
1308 &MixedModelVM::opAnd
/* 04 */,
1309 &MixedModelVM::opAsin
/* 05 */,
1310 &MixedModelVM::opAsinh
/* 06 */,
1311 &MixedModelVM::opAtan
/* 07 */,
1312 &MixedModelVM::opAtanh
/* 08 */,
1313 &MixedModelVM::opCeil
/* 09 */,
1314 &MixedModelVM::opCos
/* 0A */,
1315 &MixedModelVM::opCosh
/* 0B */,
1316 &MixedModelVM::opDivide
/* 0C */,
1317 &MixedModelVM::opEqual
/* 0D */,
1318 &MixedModelVM::opExp
/* 0E */,
1319 &MixedModelVM::opFabs
/* 0F */,
1320 &MixedModelVM::opFactorial
/* 10 */,
1321 &MixedModelVM::opFloor
/* 11 */,
1322 &MixedModelVM::opGcd
/* 12 */,
1323 &MixedModelVM::opGeq
/* 13 */,
1324 &MixedModelVM::opGt
/* 14 */,
1325 &MixedModelVM::opIntegrate
/* 15 */,
1326 &MixedModelVM::opLcm
/* 16 */,
1327 &MixedModelVM::opLeq
/* 17 */,
1328 &MixedModelVM::opLog
/* 18 */,
1329 &MixedModelVM::opLt
/* 19 */,
1330 &MixedModelVM::opMax
/* 1A */,
1331 &MixedModelVM::opMin
/* 1B */,
1332 &MixedModelVM::opMinus
/* 1C */,
1333 &MixedModelVM::opMod
/* 1D */,
1334 &MixedModelVM::opNeq
/* 1E */,
1335 &MixedModelVM::opNot
/* 1F */,
1336 &MixedModelVM::opOr
/* 20 */,
1337 &MixedModelVM::opPlus
/* 21 */,
1338 &MixedModelVM::opPow
/* 22 */,
1339 &MixedModelVM::opQuot
/* 23 */,
1340 &MixedModelVM::opReturn
/* 24 */,
1341 &MixedModelVM::opSin
/* 25 */,
1342 &MixedModelVM::opSinh
/* 26 */,
1343 &MixedModelVM::opTan
/* 27 */,
1344 &MixedModelVM::opTanh
/* 28 */,
1345 &MixedModelVM::opTimes
/* 29 */,
1346 &MixedModelVM::opUminus
/* 2A */,
1347 &MixedModelVM::opXor
/* 2B */,
1348 &MixedModelVM::opConverged
/* 2C */,
1349 &MixedModelVM::opJmpIf
/* 2D */,
1350 &MixedModelVM::opResetConvergence
/* 2E */,
1351 &MixedModelVM::opSavePoint
/* 2F */,
1352 &MixedModelVM::opCallTrain
/* 30 */,
1353 &MixedModelVM::opCallRun
/* 31 */,
1354 &MixedModelVM::opCreateBB
/* 32 */,
1355 &MixedModelVM::opGetAvgInput
/* 33 */,
1356 &MixedModelVM::opMinimise
/* 34 */,
1357 &MixedModelVM::opSetJmp
/* 35 */,
1358 &MixedModelVM::opFetchDouble
/* 36 */,
1359 &MixedModelVM::opMov
/* 37 */,
1360 &MixedModelVM::opReturn1
/* 38 */,
1361 &MixedModelVM::invalidOpcode
/* 39 */,
1362 &MixedModelVM::invalidOpcode
/* 3A */,
1363 &MixedModelVM::invalidOpcode
/* 3B */,
1364 &MixedModelVM::invalidOpcode
/* 3C */,
1365 &MixedModelVM::invalidOpcode
/* 3D */,
1366 &MixedModelVM::invalidOpcode
/* 3E */,
1367 &MixedModelVM::invalidOpcode
/* 3F */,
1368 &MixedModelVM::invalidOpcode
/* 40 */,
1369 &MixedModelVM::invalidOpcode
/* 41 */,
1370 &MixedModelVM::invalidOpcode
/* 42 */,
1371 &MixedModelVM::invalidOpcode
/* 43 */,
1372 &MixedModelVM::invalidOpcode
/* 44 */,
1373 &MixedModelVM::invalidOpcode
/* 45 */,
1374 &MixedModelVM::invalidOpcode
/* 46 */,
1375 &MixedModelVM::invalidOpcode
/* 47 */,
1376 &MixedModelVM::invalidOpcode
/* 48 */,
1377 &MixedModelVM::invalidOpcode
/* 49 */,
1378 &MixedModelVM::invalidOpcode
/* 4A */,
1379 &MixedModelVM::invalidOpcode
/* 4B */,
1380 &MixedModelVM::invalidOpcode
/* 4C */,
1381 &MixedModelVM::invalidOpcode
/* 4D */,
1382 &MixedModelVM::invalidOpcode
/* 4E */,
1383 &MixedModelVM::invalidOpcode
/* 4F */,
1384 &MixedModelVM::invalidOpcode
/* 50 */,
1385 &MixedModelVM::invalidOpcode
/* 51 */,
1386 &MixedModelVM::invalidOpcode
/* 52 */,
1387 &MixedModelVM::invalidOpcode
/* 53 */,
1388 &MixedModelVM::invalidOpcode
/* 54 */,
1389 &MixedModelVM::invalidOpcode
/* 55 */,
1390 &MixedModelVM::invalidOpcode
/* 56 */,
1391 &MixedModelVM::invalidOpcode
/* 57 */,
1392 &MixedModelVM::invalidOpcode
/* 58 */,
1393 &MixedModelVM::invalidOpcode
/* 59 */,
1394 &MixedModelVM::invalidOpcode
/* 5A */,
1395 &MixedModelVM::invalidOpcode
/* 5B */,
1396 &MixedModelVM::invalidOpcode
/* 5C */,
1397 &MixedModelVM::invalidOpcode
/* 5D */,
1398 &MixedModelVM::invalidOpcode
/* 5E */,
1399 &MixedModelVM::invalidOpcode
/* 5F */,
1400 &MixedModelVM::invalidOpcode
/* 60 */,
1401 &MixedModelVM::invalidOpcode
/* 61 */,
1402 &MixedModelVM::invalidOpcode
/* 62 */,
1403 &MixedModelVM::invalidOpcode
/* 63 */,
1404 &MixedModelVM::invalidOpcode
/* 64 */,
1405 &MixedModelVM::invalidOpcode
/* 65 */,
1406 &MixedModelVM::invalidOpcode
/* 66 */,
1407 &MixedModelVM::invalidOpcode
/* 67 */,
1408 &MixedModelVM::invalidOpcode
/* 68 */,
1409 &MixedModelVM::invalidOpcode
/* 69 */,
1410 &MixedModelVM::invalidOpcode
/* 6A */,
1411 &MixedModelVM::invalidOpcode
/* 6B */,
1412 &MixedModelVM::invalidOpcode
/* 6C */,
1413 &MixedModelVM::invalidOpcode
/* 6D */,
1414 &MixedModelVM::invalidOpcode
/* 6E */,
1415 &MixedModelVM::invalidOpcode
/* 6F */,
1416 &MixedModelVM::invalidOpcode
/* 70 */,
1417 &MixedModelVM::invalidOpcode
/* 71 */,
1418 &MixedModelVM::invalidOpcode
/* 72 */,
1419 &MixedModelVM::invalidOpcode
/* 73 */,
1420 &MixedModelVM::invalidOpcode
/* 74 */,
1421 &MixedModelVM::invalidOpcode
/* 75 */,
1422 &MixedModelVM::invalidOpcode
/* 76 */,
1423 &MixedModelVM::invalidOpcode
/* 77 */,
1424 &MixedModelVM::invalidOpcode
/* 78 */,
1425 &MixedModelVM::invalidOpcode
/* 79 */,
1426 &MixedModelVM::invalidOpcode
/* 7A */,
1427 &MixedModelVM::invalidOpcode
/* 7B */,
1428 &MixedModelVM::invalidOpcode
/* 7C */,
1429 &MixedModelVM::invalidOpcode
/* 7D */,
1430 &MixedModelVM::invalidOpcode
/* 7E */,
1431 &MixedModelVM::invalidOpcode
/* 7F */,
1432 &MixedModelVM::invalidOpcode
/* 80 */,
1433 &MixedModelVM::invalidOpcode
/* 81 */,
1434 &MixedModelVM::invalidOpcode
/* 82 */,
1435 &MixedModelVM::invalidOpcode
/* 83 */,
1436 &MixedModelVM::invalidOpcode
/* 84 */,
1437 &MixedModelVM::invalidOpcode
/* 85 */,
1438 &MixedModelVM::invalidOpcode
/* 86 */,
1439 &MixedModelVM::invalidOpcode
/* 87 */,
1440 &MixedModelVM::invalidOpcode
/* 88 */,
1441 &MixedModelVM::invalidOpcode
/* 89 */,
1442 &MixedModelVM::invalidOpcode
/* 8A */,
1443 &MixedModelVM::invalidOpcode
/* 8B */,
1444 &MixedModelVM::invalidOpcode
/* 8C */,
1445 &MixedModelVM::invalidOpcode
/* 8D */,
1446 &MixedModelVM::invalidOpcode
/* 8E */,
1447 &MixedModelVM::invalidOpcode
/* 8F */,
1448 &MixedModelVM::invalidOpcode
/* 90 */,
1449 &MixedModelVM::invalidOpcode
/* 91 */,
1450 &MixedModelVM::invalidOpcode
/* 92 */,
1451 &MixedModelVM::invalidOpcode
/* 93 */,
1452 &MixedModelVM::invalidOpcode
/* 94 */,
1453 &MixedModelVM::invalidOpcode
/* 95 */,
1454 &MixedModelVM::invalidOpcode
/* 96 */,
1455 &MixedModelVM::invalidOpcode
/* 97 */,
1456 &MixedModelVM::invalidOpcode
/* 98 */,
1457 &MixedModelVM::invalidOpcode
/* 99 */,
1458 &MixedModelVM::invalidOpcode
/* 9A */,
1459 &MixedModelVM::invalidOpcode
/* 9B */,
1460 &MixedModelVM::invalidOpcode
/* 9C */,
1461 &MixedModelVM::invalidOpcode
/* 9D */,
1462 &MixedModelVM::invalidOpcode
/* 9E */,
1463 &MixedModelVM::invalidOpcode
/* 9F */,
1464 &MixedModelVM::invalidOpcode
/* A0 */,
1465 &MixedModelVM::invalidOpcode
/* A1 */,
1466 &MixedModelVM::invalidOpcode
/* A2 */,
1467 &MixedModelVM::invalidOpcode
/* A3 */,
1468 &MixedModelVM::invalidOpcode
/* A4 */,
1469 &MixedModelVM::invalidOpcode
/* A5 */,
1470 &MixedModelVM::invalidOpcode
/* A6 */,
1471 &MixedModelVM::invalidOpcode
/* A7 */,
1472 &MixedModelVM::invalidOpcode
/* A8 */,
1473 &MixedModelVM::invalidOpcode
/* A9 */,
1474 &MixedModelVM::invalidOpcode
/* AA */,
1475 &MixedModelVM::invalidOpcode
/* AB */,
1476 &MixedModelVM::invalidOpcode
/* AC */,
1477 &MixedModelVM::invalidOpcode
/* AD */,
1478 &MixedModelVM::invalidOpcode
/* AE */,
1479 &MixedModelVM::invalidOpcode
/* AF */,
1480 &MixedModelVM::invalidOpcode
/* B0 */,
1481 &MixedModelVM::invalidOpcode
/* B1 */,
1482 &MixedModelVM::invalidOpcode
/* B2 */,
1483 &MixedModelVM::invalidOpcode
/* B3 */,
1484 &MixedModelVM::invalidOpcode
/* B4 */,
1485 &MixedModelVM::invalidOpcode
/* B5 */,
1486 &MixedModelVM::invalidOpcode
/* B6 */,
1487 &MixedModelVM::invalidOpcode
/* B7 */,
1488 &MixedModelVM::invalidOpcode
/* B8 */,
1489 &MixedModelVM::invalidOpcode
/* B9 */,
1490 &MixedModelVM::invalidOpcode
/* BA */,
1491 &MixedModelVM::invalidOpcode
/* BB */,
1492 &MixedModelVM::invalidOpcode
/* BC */,
1493 &MixedModelVM::invalidOpcode
/* BD */,
1494 &MixedModelVM::invalidOpcode
/* BE */,
1495 &MixedModelVM::invalidOpcode
/* BF */,
1496 &MixedModelVM::invalidOpcode
/* C0 */,
1497 &MixedModelVM::invalidOpcode
/* C1 */,
1498 &MixedModelVM::invalidOpcode
/* C2 */,
1499 &MixedModelVM::invalidOpcode
/* C3 */,
1500 &MixedModelVM::invalidOpcode
/* C4 */,
1501 &MixedModelVM::invalidOpcode
/* C5 */,
1502 &MixedModelVM::invalidOpcode
/* C6 */,
1503 &MixedModelVM::invalidOpcode
/* C7 */,
1504 &MixedModelVM::invalidOpcode
/* C8 */,
1505 &MixedModelVM::invalidOpcode
/* C9 */,
1506 &MixedModelVM::invalidOpcode
/* CA */,
1507 &MixedModelVM::invalidOpcode
/* CB */,
1508 &MixedModelVM::invalidOpcode
/* CC */,
1509 &MixedModelVM::invalidOpcode
/* CD */,
1510 &MixedModelVM::invalidOpcode
/* CE */,
1511 &MixedModelVM::invalidOpcode
/* CF */,
1512 &MixedModelVM::invalidOpcode
/* D0 */,
1513 &MixedModelVM::invalidOpcode
/* D1 */,
1514 &MixedModelVM::invalidOpcode
/* D2 */,
1515 &MixedModelVM::invalidOpcode
/* D3 */,
1516 &MixedModelVM::invalidOpcode
/* D4 */,
1517 &MixedModelVM::invalidOpcode
/* D5 */,
1518 &MixedModelVM::invalidOpcode
/* D6 */,
1519 &MixedModelVM::invalidOpcode
/* D7 */,
1520 &MixedModelVM::invalidOpcode
/* D8 */,
1521 &MixedModelVM::invalidOpcode
/* D9 */,
1522 &MixedModelVM::invalidOpcode
/* DA */,
1523 &MixedModelVM::invalidOpcode
/* DB */,
1524 &MixedModelVM::invalidOpcode
/* DC */,
1525 &MixedModelVM::invalidOpcode
/* DD */,
1526 &MixedModelVM::invalidOpcode
/* DE */,
1527 &MixedModelVM::invalidOpcode
/* DF */,
1528 &MixedModelVM::invalidOpcode
/* E0 */,
1529 &MixedModelVM::invalidOpcode
/* E1 */,
1530 &MixedModelVM::invalidOpcode
/* E2 */,
1531 &MixedModelVM::invalidOpcode
/* E3 */,
1532 &MixedModelVM::invalidOpcode
/* E4 */,
1533 &MixedModelVM::invalidOpcode
/* E5 */,
1534 &MixedModelVM::invalidOpcode
/* E6 */,
1535 &MixedModelVM::invalidOpcode
/* E7 */,
1536 &MixedModelVM::invalidOpcode
/* E8 */,
1537 &MixedModelVM::invalidOpcode
/* E9 */,
1538 &MixedModelVM::invalidOpcode
/* EA */,
1539 &MixedModelVM::invalidOpcode
/* EB */,
1540 &MixedModelVM::invalidOpcode
/* EC */,
1541 &MixedModelVM::invalidOpcode
/* ED */,
1542 &MixedModelVM::invalidOpcode
/* EE */,
1543 &MixedModelVM::invalidOpcode
/* EF */,
1544 &MixedModelVM::invalidOpcode
/* F0 */,
1545 &MixedModelVM::invalidOpcode
/* F1 */,
1546 &MixedModelVM::invalidOpcode
/* F2 */,
1547 &MixedModelVM::invalidOpcode
/* F3 */,
1548 &MixedModelVM::invalidOpcode
/* F4 */,
1549 &MixedModelVM::invalidOpcode
/* F5 */,
1550 &MixedModelVM::invalidOpcode
/* F6 */,
1551 &MixedModelVM::invalidOpcode
/* F7 */,
1552 &MixedModelVM::invalidOpcode
/* F8 */,
1553 &MixedModelVM::invalidOpcode
/* F9 */,
1554 &MixedModelVM::invalidOpcode
/* FA */,
1555 &MixedModelVM::invalidOpcode
/* FB */,
1556 &MixedModelVM::invalidOpcode
/* FC */,
1557 &MixedModelVM::invalidOpcode
/* FD */,
1558 &MixedModelVM::invalidOpcode
/* FE */,
1559 &MixedModelVM::invalidOpcode
/* FF */
1563 MixedModelVM::execute(uint8_t* aEIP
)
1569 while (!VM_HAD_HALT
)
1573 gpe("Instruction pointer outside code range.");
1577 (this->*opCodes
[*mEIP
++])();
1583 createMixedModelVM(const char* filename
)
1585 return new MixedModelVM(filename
);