Related
I have an image of mathematical formula and I need to parse symbols of it, but also save where they were (center of each symbol). For example image like this needs to be transformed into 15 different images 75x75, 1 per each symbol.
What I have tried is:
Transform to gray and then binary: pixels close to white(> 250) becomes 255 and other become 0
Use BNF to find all components and then transform them into images (with rescaling and everything else)
But I am sure it is not the best way to do it, maybe there is standard approach for this problem exist?
Here is my code:
class Parser:
def init(self, targetSizes=(75, 75), binaryThreshold=cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU,
scaleFully=False, scaleFullyRate=0.9, whiteThreshold=249, blackThreshold=0,
rescalingInterpolation=cv2.INTER_AREA, pixelsInImageThreshold=20,
rescaleOriginalImage=True, rescaleToAtLeast=200, rescaleToAtMaximum=1000):
self.targetWidth = targetSizes[0]
self.targetHeight = targetSizes[1]
self.binaryThreshold = binaryThreshold
self.scaleFully = scaleFully
self.scaleFullyRate = scaleFullyRate
self.whiteThreshold = whiteThreshold
self.blackThreshold = blackThreshold
self.rescalingInterpolation = rescalingInterpolation
self.pixelsInIMageThreshold = pixelsInImageThreshold
self.rescaleOriginalImage = rescaleOriginalImage
self.rescaleOriginalMin = rescaleToAtLeast
self.rescaleOriginalMax = rescaleToAtMaximum
self.parseMode = 1
def _imageToBinary(self, image, zeroValueTrash=0, oneValueTrash=253):
grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(grayImage, self.blackThreshold, self.whiteThreshold, self.binaryThreshold)
# cv2.imwrite("Test.png", binary)
return binary
def _BNF(self, binaryImage):
Q = MyQueue()
whitePixels = []
gg = 0
for i in range(len(binaryImage)):
for j in range(len(binaryImage[i])):
if binaryImage[i][j] > self.whiteThreshold-1:
Q.put((i, j))
binaryImage[i][j] = 0
obj = []
gg += 1
while not Q.empty():
i, j = Q.pop()
obj.append((i, j))
if i + 1 < len(binaryImage) and binaryImage[i + 1][j] != 0:
Q.put((i + 1, j))
binaryImage[i + 1][j] = 0
if j - 1 > 0 and binaryImage[i][j - 1] != 0:
Q.put((i, j - 1))
binaryImage[i][j - 1] = 0
if i - 1 > 0 and binaryImage[i - 1][j] != 0:
Q.put((i - 1, j))
binaryImage[i - 1][j] = 0
if j + 1 < len(binaryImage[i]) and binaryImage[i][j + 1] != 0:
Q.put((i, j + 1))
binaryImage[i][j + 1] = 0
if self.parseMode == 1:
if i + 1 < len(binaryImage) and j+1 < len(binaryImage[i+1]) and binaryImage[i + 1][j+1] != 0:
Q.put((i + 1, j+1))
binaryImage[i + 1][j+1] = 0
if i + 1 < len(binaryImage) and j - 1 > 0 and binaryImage[i + 1][j-1] != 0:
Q.put((i + 1, j-1))
binaryImage[i + 1][j-1] = 0
if i - 1 > 0 and j - 1 > 0 and binaryImage[i - 1][j - 1] != 0:
Q.put((i - 1, j - 1))
binaryImage[i - 1][j - 1] = 0
if i - 1 > 0 and j + 1 < len(binaryImage[i-1]) and binaryImage[i - 1][j + 1] != 0:
Q.put((i - 1, j + 1))
binaryImage[i - 1][j + 1] = 0
cv2.imwrite("tmp/{}.png".format(gg), binaryImage)
whitePixels.append(obj)
return whitePixels
def parseImage(self, image_path: str) -> list:
image = cv2.imread(image_path)
if self.rescaleOriginalImage:
image = self.scaleOriginal(image)
binary = self._imageToBinary(image)
whitePixels = self._BNF(binary)
return whitePixels
def isScaleable(self, imageShape):
return True
def scaleOriginal(self, image: np.ndarray):
# To be created
return image
#staticmethod
def _getImageAndCenterFromDotes(Dotes, originalImage=None):
i_mx, j_mx = -1, -1
i_mn, j_mn = 100500, 100500 # just big numbers
# finding upper right and lower left corner of image
for el in Dotes:
i, j = el
if i_mx < i:
i_mx = i
if j_mx < j:
j_mx = j
if j_mn > j:
j_mn = j
if i_mn > i:
i_mn = i
# updating image center
imageCenter = Point((i_mx + i_mn) // 2, (j_mx + j_mn) // 2)
# finding out size of image
width, height = i_mx - i_mn + 1, j_mx - j_mn + 1
image = np.zeros((width, height)) if originalImage is None else np.zeros((width, height, 3))
# recreating image from dotes
if originalImage is not None:
for el in Dotes:
i, j = el
image[i - i_mn][j - j_mn] = originalImage[i][j]
else:
for el in Dotes:
i, j = el
image[i - i_mn][j - j_mn] = 255
return image, imageCenter
def scaleParsedImage(self, image: np.ndarray):
"""
:param image: np.ndarray
:return: scaledImage np.ndarray
"""
width, height = image.shape if len(image.shape) == 2 else image.shape[0], image.shape[1]
newWidth = self.targetWidth if width > self.targetHeight else width
newHeight = self.targetHeight if height > self.targetHeight else height
if self.scaleFully and newHeight < self.targetHeight * self.scaleFullyRate and newWidth * self.scaleFullyRate:
scaleRate = min((self.targetWidth * self.scaleFullyRate / newWidth), (
self.targetHeight * self.scaleFullyRate / newHeight))
newWidth = math.ceil(newWidth * scaleRate)
newHeight = math.ceil(newHeight * scaleRate)
scaled = cv2.resize(image, (newHeight, newWidth), interpolation=self.rescalingInterpolation)
# pasting our scaled image in the middle
x_add, y_add = (self.targetWidth - newWidth) // 2, (self.targetHeight - newHeight) // 2
resized = np.zeros((self.targetWidth, self.targetHeight)) if len(image.shape) == 2 else np.zeros((self.targetWidth, self.targetHeight, 3))
for x in range(newWidth):
for y in range(newHeight):
resized[x + x_add][y + y_add] = scaled[x][y]
return resized
def parseAndConvert(self, image_name: str) -> list:
imagesInDotes = self.parseImage(image_name)
original = 255 - cv2.imread(image_name)
images = []
for dotes in imagesInDotes:
image = self._getImageAndCenterFromDotes(dotes, original)
images.append([self.scaleParsedImage(image[0]), image[1]])
rawImages = []
for image, center in images:
rawImages.append(RawImage(image, center))
return rawImages
Have a look at the (imho not all too intuitively named) function cv.findContours():
https://docs.opencv.org/3.4/d4/d73/tutorial_py_contours_begin.html
It should do most things that you are doing by hand right now out of the box, which is extracting and measuring binary objects.
If you encouter problems where a single symbol is made up of several objects (like i, % or "), look into the morphological operations to merge them into a single one: erode(), dilate(), or open and close via morphologyEx() (Tutorial here: https://docs.opencv.org/4.x/d9/d61/tutorial_py_morphological_ops.html).
I'm using this code to calculate pivot points.
def pivots_low(osc, LBR, LBL):
pivots = []
for i in range(len(osc) - LBR):
pivots.append(0)
pivot = True
if i > LBL:
for j in range(1, LBR + 1):
if osc[i] >= osc[i + j]:
pivot = False
for j in range(1, LBL + 1):
if osc[i] > osc[i - j]:
pivot = False
if pivot is True:
pivots[len(pivots) - 1] = osc[i]
for i in range(LBR):
pivots.append(0)
return pivots
This returns an array with 0's where there's no pivots and the value of the pivot if there is one.
When Comparing the results to TradingView (downloaded csv with pivot points), the only time it matches exactly is when lookback left and right are both 5. Otherwise it deviates in the number of total pivots and the location of some.
But using this code to calculate pivot highs:
def pivots_high(osc, LBR, LBL):
pivots = []
for i in range(len(osc)-LBR):
pivots.append(0)
pivot = True
if i > LBL:
for j in range(1,LBL + 1):
if osc[i] < osc[i-j]:
pivot = False
for j in range(1,LBR + 1):
if osc[i] <= osc[i+j]:
pivot = False
if pivot is True:
pivots[len(pivots)-1] = osc[i]
for i in range(LBR):
pivots.append(0)
return pivots
the results are perfect regardless of lookback values. But the code is almost exactly the same besides comparison.
What is going wrong here? This is day 3 of having this problem and I just cant fix it
To Reproduce:
Load Data:
Full_Data = pd.read_csv(file)
use this simple function to check matches between calculated pivots and TradingView pivots.
def match_pivs(data, pivs_h, pivs_l): //Data is a DataFrame loaded from tradingview csv
global lblh
global lbrh
global lbll
global lbrl
start = lbrh
if lbrl > lbrh:
start = lbrl
match_h = 0
tot_hd = 0
tot_hp = 0
match_l = 0
tot_ld = 0
tot_lp = 0
for i in range(start, len(data)):
if data['PivHigh'][i] != 0 and pivs_h[i-lbrh] != 0:
match_h += 1
if data['PivLow'][i] != 0 and pivs_l[i-lbrl] != 0:
match_l += 1
if data['PivHigh'][i] != 0:
tot_hd += 1
if data['PivLow'][i] != 0:
tot_ld += 1
if pivs_h[i] != 0:
tot_hp += 1
if pivs_l[i] != 0:
tot_lp += 1
print('PivsLow ' + str(tot_lp))
print('DataLows ' + str(tot_ld))
print('MatchesL ' + str(match_l))
print('PivsHigh ' + str(tot_hp))
print('DataHighs ' + str(tot_hd))
print('MatchesH ' + str(match_h))
and to get csv from TradingView:
//#version=5
indicator("Data Script", overlay=true, max_labels_count=500)
leftLenL = input.int(title="Pivot Low", defval=10, minval=1, inline="Pivot Low", group=lengthGroupTitle)
rightLenL = input.int(title="/", defval=10, minval=1, inline="Pivot Low", group=lengthGroupTitle)
leftLenH = input.int(title="Pivot High", defval=10, minval=1, inline="Pivot High", group=lengthGroupTitle)
rightLenH = input.int(title="/", defval=10, minval=1, inline="Pivot High", group=lengthGroupTitle)
ph = ta.pivothigh(leftLenH, rightLenH)
pl = ta.pivotlow(leftLenL, rightLenL)
if not na(ph)
plth := ph
else
plth := 0.0
if not na(pl)
pltl := pl
else
pltl := 0.0
plot(plth, 'PivHigh')
plot(pltl, 'PivLow')
then just download csv with this script loaded.
Run program with these three lines:
pl = pivots_low(Full_Data['low'], lbll, lbrl)
ph = pivots_high(Full_Data['high'], lbrh, lblh)
match_pivs(Full_Data, ph, pl)
Finally found a way.
I still have no idea why that code does not work but I've made a different way that seems to be doing the job 100% to tradingview data.
def checkhl(data_back, data_forward, hl):
if hl == 'high' or hl == 'High':
ref = data_back[len(data_back)-1]
for i in range(len(data_back)-1):
if ref < data_back[i]:
return 0
for i in range(len(data_forward)):
if ref <= data_forward[i]:
return 0
return 1
if hl == 'low' or hl == 'Low':
ref = data_back[len(data_back)-1]
for i in range(len(data_back)-1):
if ref > data_back[i]:
return 0
for i in range(len(data_forward)):
if ref >= data_forward[i]:
return 0
return 1
def pivot(osc, LBL, LBR, highlow)
left = []
right = []
for i in range(len(osc)):
pivots.append(0.0)
if i < LBL + 1:
left.append(osc[i])
if i > LBL:
right.append(osc[i])
if i > LBL + LBR:
left.append(right[0])
left.pop(0)
right.pop(0)
if checkhl(left, right, highlow):
pivots[i - LBR] = osc[i - LBR]
return pivots
then just do:
pivots_low = pivot(data, lbl, lbr, 'low')
pivots_high = pivot(data, lbl, lbr, 'high')
All the pivots will be in the actual position that they occur, not lbr bars after, otherwise the value will be 0.0
I'm not sure if this is efficient or not but it seems to work.
I am trying to calculate RSI using simple functions.
The general formula for it is:
RSI = 100/(1+RS), where RS = Exponential Moving Average of gains / -||- of losses.
Here is what I am getting:
enter image description here
Here it is how should it look like:
enter image description here
I have everything double checked or even triple checked, but I can't find any mistake.
Thus I need your help, I know that the question is very simple though I need some help, I have no idea where I have made the mistake.
The general idea of RSI is that it should be low where the price is "low" and high, where the price is high, and generally no matter what I try I have it upside down.
def EMA(close_price_arr, n):
a = (2/n + 1)
EMA_n = np.empty((1, len(close_price_arr)))
for i in range(len(close_price_arr)):
if i < n:
# creating NaN values where it is impossible to calculate EMA to drop it later after connecting the whole database
EMA_n[0, i] = 'NaN'
if i >= n:
# Calaculating nominator and denominator of EMA
for j in range(n):
nominator_ema += close_price_arr[i - j] * a**(j)
denominator_ema += a**(j)
EMA_n[0, i] = nominator_ema / denominator_ema
nominator_ema = 0
denominator_ema = 0
return EMA_n
def gains(close_price_arr):
gain_arr = np.empty((len(close_price_arr) - 1))
for i in range(len(close_price_arr)):
if i == 0:
pass
if i >= 1:
if close_price_arr[i] > close_price_arr[i - 1]:
gain_arr[i - 1] = (close_price_arr[i] - close_price_arr[i-1])
else:
gain_arr[i - 1] = 0
return gain_arr
def losses(close_price_arr):
loss_arr = np.empty((len(close_price_arr) - 1))
for i in range(len(close_price_arr)):
if i == 0:
pass
if i >= 1:
if close_price_arr[i] < close_price_arr[i - 1]:
loss_arr[i - 1] = abs(close_price_arr[i] - close_price_arr[i - 1])
else:
loss_arr[i - 1] = 0
return loss_arr
def RSI(gain_arr, loss_arr, n):
EMA_u = EMA(gain_arr, n)
EMA_d = EMA(loss_arr, n)
EMA_diff = EMA_u / EMA_d
x,y = EMA_diff.shape
print(x, y)
RSI_n = np.empty((1, y))
for i in range(y):
if EMA_diff[0, i] == 'NaN':
RSI_n[0, i] = 'NaN'
print(i)
else:
RSI_n[0, i] = 100 / (1 + EMA_diff[0, i])
return RSI_n
#contextmanager
def show_complete_array():
oldoptions = np.get_printoptions()
np.set_printoptions(threshold=np.inf)
try:
yield
finally:
np.set_printoptions(**oldoptions)
np.set_printoptions(linewidth=3000)
pd.set_option('display.max_columns', None)
# Specyfying root folder, file folder and file
FILE = 'TVC_SILVER, 5.csv'
FOLDER = 'src'
PROJECT_ROOT_DIR = '.'
csv_path = os.path.join(PROJECT_ROOT_DIR, FOLDER, FILE)
# reading csv
price_data = pd.read_csv(csv_path, delimiter=',')
price_data_copy = price_data.copy()
price_data_nodate = price_data.copy().drop('time', axis=1)
price_data_np = price_data_nodate.to_numpy(dtype='float32')
close_price = price_data_np[:, 3]
EMA15 = EMA(close_price_arr=close_price, n=15)
EMA55 = EMA(close_price_arr=close_price, n=55)
gain = gains(close_price_arr=close_price)
loss = losses(close_price_arr=close_price)
RSI14 = RSI(gain_arr=gain, loss_arr=loss, n=14)
Try this:
"""dataset is a dataframe"""
def RSI(dataset, n=14):
delta = dataset.diff()
dUp, dDown = delta.copy(), delta.copy()
dUp[dUp < 0] = 0
dDown[dDown > 0] = 0
RolUp = pd.Series(dUp).rolling(window=n).mean()
RolDown = pd.Series(dDown).rolling(window=n).mean().abs()
RS = RolUp / RolDown
rsi= 100.0 - (100.0 / (1.0 + RS))
return rsi
I have calcularBeta1 method. When I run the program, I've got this error:
ZeroDivisionError: float division by zero
resultadoB1 = (sumaXY - ((sumaX * sumaY ) / totalElementos )) / (sumaXCuadrada - math.pow(sumaX, 2) / totalElementos)
Method calcularBeta1
def calcularBeta1(self, lista):
actual = lista.nodoInicio
sumaXY = 0
sumaX = 0
sumaY = 0
sumaXCuadrada = 0
totalElementos = 0
while actual != None:
dato1 = actual.dato1
dato2 = actual.dato2
sumaXY += dato1 * dato2
sumaX += dato1
sumaY += dato2
sumaXCuadrada += math.pow(dato1, 2)
totalElementos += 1
actual = actual.siguienteNodo
resultadoB1 = (sumaXY - ((sumaX * sumaY ) / totalElementos )) / (sumaXCuadrada - math.pow(sumaX, 2) / totalElementos)
return resultadoB1
LecturaArchivo class
class LecturaArchivo:
datosArchivo = ListaEnlazada()
operaciones = Operaciones()
xTemporal = 0
yTemporal = 0
nombreArchivo = input('Nombre del archivo: ')
archivo = open(nombreArchivo, "r")
lineas = archivo.read()
datos = lineas.split(',')
datoProxy = float(input('Proxy: '))
while lineas:
lineas = archivo.readlines()
xTemporal = datos[0]
yTemporal = datos[1]
datosArchivo.agregarNodoFinal(float(xTemporal), float(yTemporal))
print(datos)
sumaElementos = sum(datosArchivo.obtenerNodos())
mediaElementos = operaciones.media(sumaElementos, datosArchivo.tamano())
beta1 = operaciones.calcularBeta1(datosArchivo)
print('Beta1: ', beta1)
beta0 = operaciones.calcularBeta0(beta1, media)
print('Beta0: ', beta0)
yk = operaciones.calcularYK(beta0, beta1, datoProxy)
print('Regresión Líneal: ', yk)
The ZeroDivisionError happens when you try to divide a number by 0, which as you know is a mathematical impossibility, just change the value of the dividend.
Python is unable to divide numbers by 0. If you ever attempt to divide by 0, python will throw a ZeroDivisionError, which is what happened to you. The best way to fix it is to just not divide by zero. You can use an if statement to ensure that the values are not zero.
Don't divide by zero.
In the expression it complains about
resultadoB1 = (sumaXY - ((sumaX * sumaY ) / totalElementos )) / (sumaXCuadrada - math.pow(sumaX, 2) / totalElementos)
it will be either totalElementos or the results of sumaXCuadrada - math.pow(sumaX, 2) that are zero.
You'll need to add code to handle the possibility of those situations before trying to calculate that formula.
I've set up numpy.seterr as follows:
np.seterr(invalid='raise', over ='raise', under='raise')
And I'm getting the following error:
c = beta[j,i] + oneminusbeta[j,i]
FloatingPointError: overflow encountered in double_scalars
I've checked what beta[j,i] and oneminusbeta[j,i] are at the point of crash, and these are their values:
beta: -131.340389182
oneminusbeta: 0.0
Please note, this line of addition (beta[j,i] + oneminusbeta[j,i]) has run for thousands of lines in a loop (that performs image classification) before crashing here at this point.
How can I deal with this? Is it necessary to change the type of the numpy arrays?
This is how I've initialized them:
beta = np.empty([m,n])
oneminusbeta = np.empty([m,n])
Is it possible to cast the individual values before adding them up? Rather than changing the entire array declarations? Or is this even a serious issue? Would it be safe to simply turn off the numpy.seterr configuration and let the calculations go ahead without raising the error?
Edit
Someone suggested below, and I suspected as well, that the values being added shouldn't cause an overflow. Then how can I find out where the overflow is really happening?
This is my code:
epthreshold = 709
enthreshold = -708
f.write("weights["+str(i)+", " + str(j)+"] = math.exp(beta: " +str(beta[j,i])+ " + oneminusbeta: " + str(oneminusbeta[j,i])+")\n" )
c = beta[j,i] + oneminusbeta[j,i]
weights[i,j] = math.exp(np.clip(c, enthreshold, epthreshold))
And when I check my log file, this is the line I get:
weights[5550, 13] = math.exp(beta: -131.340389182 + oneminusbeta: 0.0)
Edit 2
Here's the rest of my code, where variables n,m and H have already been initialized to integer values:
import numba
import numpy as np
import statsmodels.api as sm
weights = np.empty([n,m])
for curr_n in range(n):
for curr_m in range(m):
weights[curr_n,curr_m] = 1.0/(n)
beta = np.empty([m,n])
oneminusbeta = np.empty([m,n])
for curr_class in range(m):
for curr_sample in range(n):
beta[curr_class,curr_sample] = 1./m
epthreshold = 709 # positive exponential threshold
enthreshold = -708
for h in range(H):
print "Boosting round %d ... " % h
z = np.empty([n,m])
for j in range(m): # computing working responses and weights, Step 2(a)(i)
for i in range(no_samples):
i_class = y[i] #get the correct class for the current sample
if h == 0:
z[i,j] = (int(j==i_class) - beta[j,i])/((beta[j,i])*(1. - beta[j,i]))
weights[i,j] = beta[j,i]*(1. - beta[j,i])
else:
if j == i_class:
z[i,j] = math.exp(np.clip(-beta[j,i],enthreshold, epthreshold))
else:
z[i,j] = -math.exp(np.clip(oneminusbeta[j,i], enthreshold, epthreshold))
f.write("weights["+str(i)+", " + str(j)+"] = math.exp(beta: " +str(beta[j,i])+ " + oneminusbeta: " + str(oneminusbeta[j,i])+")\n" )
c = beta[j,i] + oneminusbeta[j,i]
weights[i,j] = math.exp(np.clip(c, enthreshold, epthreshold))
g_h = np.zeros([1,1])
j = 0
# Calculating regression coefficients per class
# building the parameters per j class
for y1_w in zip(z.T, weights.T):
y1, w = y1_w
temp_g = sm.WLS(y1, X, w).fit() # Step 2(a)(ii)
if np.allclose(g_h,0):
g_h = temp_g.params
else:
g_h = np.c_[g_h, temp_g.params]
j = j + 1
if np.allclose(g,0):
g = g_h
else:
g = g + g_h # Step(2)(a)(iii)
# now set g(x), function coefficients according to new formula, step (2)(b)
sum_g = g.sum(axis=1)
for j in range(m):
diff = (g[:,j] - ((1./m) * sum_g))
g[:,j] = ((m-1.)/m) * diff
g_per_round[h,:,j] = g[:,j]
#Now computing beta, Step 2(c)...."
Q = 0.
e = 0.
for j in range(m):
# Calculating beta and oneminusbeta for class j
aj = 0.0
for i in range(no_samples):
i_class = y[i]
X1 = X[i].reshape(1, no_features)
g1 = g[:,j].reshape(no_features, 1)
gc = g[:,i_class].reshape(no_features, 1)
dot = 1. + float(np.dot(X1, g1)) - float(np.dot(X1,gc))
aj = dot
sum_e = 0.
a_q = []
a_q.append(0.)
for j2 in range(m): # calculating sum of e's except for all j except where j=i_class
if j2 != i_class: # g based on j2, not necessarily g1?
g2 = g[:,j2].reshape(no_features, 1)
dot1 = 1. + float(np.dot(X1, g2)) - float(np.dot(X1,gc))
e2 = math.exp(np.clip(dot1,enthreshold, epthreshold))
sum_e = sum_e + e2
a_q.append(dot1)
if (int(j==i_class) == 1):
a_q_arr = np.array(a_q)
alpha = np.array(a_q_arr[1:])
Q = mylogsumexp(f,a_q_arr, 1, 0)
sumalpha = mylogsumexp(f,alpha, 1, 0)
beta[j,i] = -Q
oneminusbeta[j,i] = sumalpha - Q
else:
alpha = a_q
alpha = np.array(alpha[1:])
a_q_arr = np.array(a_q)
Q = mylogsumexp(f,a_q_arr, 0, aj)
sumalpha = log(math.exp(np.clip(Q, enthreshold, epthreshold)) - math.exp(np.clip(aj, enthreshold, epthreshold)))
beta[j,i] = aj - Q
oneminusbeta[j,i] = sumalpha - Q
and the function mylogsumexp is:
def mylogsumexp(f, a, is_class, maxaj, axis=None, b=None):
np.seterr(over="raise", under="raise", invalid="raise")
threshold = -sys.float_info.max
maxthreshold = sys.float_info.max
epthreshold = 709 # positive exponential threshold
enthreshold = -708
a = asarray(a)
if axis is None:
a = a.ravel()
else:
a = rollaxis(a, axis)
if is_class == 1:
a_max = a.max(axis=0)
else:
a_max = maxaj
#bnone = " none "
if b is not None:
a_max = maxaj
b = asarray(b)
if axis is None:
b = b.ravel()
else:
b = rollaxis(b, axis)
a = np.clip(a - a_max, enthreshold, epthreshold)
midout = np.sum(np.exp(a), axis=0)
midout = 1.0 + np.clip(midout - math.exp(a_max), threshold, maxthreshold)
out = np.log(midout)
else:
a = np.clip(a - a_max, enthreshold, epthreshold)
out = np.log(np.sum(np.exp(a)))
out += a_max
if out == float("inf"):
out = maxthreshold
if out == float("-inf"):
out = threshold
return out