高校数学の「2次関数グラフ」関連の問題をPythonで解く

# 概要

　2次関数（放物線）のグラフに関する問題（高校数学）を Python で解いていきます。練習問題と解答例の作成支援を目的としています（教員向けものです）。

- [高校数学の「ベクトルの内積」関連の問題をPythonで解く](https://qiita.com/code0327/items/b8614649757110c654b6)
- [高校数学の「高次方程式・恒等式」関連の問題をPythonで解く](https://qiita.com/code0327/items/66efb7ac56cdea5b0b0d)
- [高校数学の「2次関数グラフ」関連の問題をPythonで解く](https://qiita.com/code0327/items/83b87f3d490e740b2a95)
- [高校数学の「極限値」関連の問題をPythonで解く](https://qiita.com/code0327/items/1fd0df574c8c8357af5a)
- [高校数学の「微分」関連の問題をPythonで解く](https://qiita.com/code0327/items/97fcacc42ab44402eb35)


# 問1 

2次関数 $y=-2x^2+4x+1$ の頂点を求め、グラフをかけ。

## 問1の解答を与えるPythonプログラム

sympy と matplotlib で解決していきます。

頂点は、2次関数 $a(x-p)^2+q$ の頂点座標が $(p, q)$ となることを利用して求めています（**平方完成**）。
具体的には、
`solve( a*(x-p)**2+q - fx, [p, q, a])` により、$a(x-p)^2+q-(-2x^2+4x+1)=0$ を $p$、$q$、$a$ について解いて、その結果から頂点座標 $(p, q)$ を求めています。

```Python:Python
import numpy as np
import matplotlib.pyplot as plt
import sympy

# 頂点 (p,q) の座標を求める　
x,a,p,q = sympy.symbols('x a p q')

fx = -2*x**2 + 4*x + 1 

v = sympy.solve( a*(x-p)**2+q - fx, [p, q, a])
p = v[0][0]
q = v[0][1]
print(f'頂点は ({p},{q}) で、グラフは以下の通りである。')

# グラフを描く
xRange=(-4,4)                     # グラフ描画範囲
f = lambda x : -2*x**2 + 4*x + 1  # 関数

x = np.linspace(xRange[0], xRange[1], 100)
y = f(x)

plt.figure(dpi=120)
plt.plot(x, y, color='0.0')
plt.plot(p, q, marker='o')
plt.grid(color='0.8')
plt.show()
```

## 実行結果

```
頂点は (1,3) で、グラフは以下の通りである。
```

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/860c274c-4d11-7779-e7cb-bdb2aec027c5.png)


# 問2

2次関数 $y=x^2+x-6$ について以下の問いに答えよ。

 (1) $y=x^2+x-6$ のグラフをかけ。
 (2) 2次不等式を $y=x^2+x-6 < 0$ を満たす $x$ の範囲を求めよ。

## 問2の解答を与えるPythonプログラム

この問題では、$x$ 軸との交点、つまり、$y=0$ となるような $x$ を求める必要があります。これは、`sympy.solve( fx )` で求めることができます。なお、実数解のみを対象とするために、`sympy.symbols('x a p q', real=True)` のようなオプションをつけています。このオプションをつけないと、虚数を含んだ解がでてきてしまいます。

また、$y<0$ の範囲領域を図示するために、`plt.fill_between(x, y, 0, where=y<0, facecolor='b', alpha=0.2)` を行なってます。

```Python:Python
import numpy as np
import matplotlib.pyplot as plt
import sympy

# 頂点 (p,q) の座標を求める　
x,a,p,q = sympy.symbols('x a p q', real=True)

fx = x**2 + x - 6  # 関数

v = sympy.solve( a*(x-p)**2+q - fx, [p, q, a])
p = v[0][0]
q = v[0][1]

print(f'(1) 頂点は ({p},{q}) で、', end='' )

# x軸との交点を求める
sol = sympy.solve( fx )
if len(sol) == 0 : # 実数解が存在しない
    print('x軸とは交わらない。', end='' )
else :
    tx = ' と '.join(list(map(lambda x: '({0},0)'.format(x), sol)))
    print(f'x軸との交点は {tx} となる。', end='' )

print('グラフは以下の通りである')

# グラフを描く
xRange=(-4,4)                # グラフ描画範囲
f = lambda x : x**2 + x - 6  # 関数

x = np.linspace(xRange[0], xRange[1], 100)
y = f(x)

plt.figure(dpi=120)
plt.plot(x, y, color='0.0')
plt.plot(p, q, marker='o')

if len(sol) != 0 :
    plt.hlines([0], xRange[0], xRange[1], linewidth=0.75 )
    for s in sol :
        plt.plot(s, 0, marker='o', color='0.0')    
    plt.fill_between(x, y, 0, where=y<0, facecolor='b', alpha=0.2)

plt.grid(color='0.8')
plt.show()

print('(2) 不等式を満たす xの範囲は、',end='')
if len(sol) == 2 :
    if sol[0]>sol[1] :
        print(f'{sol[1]} < x < {sol[0]} である。')
    else :
        print(f'{sol[0]} < x < {sol[1]} である。')
else:
    print('存在しない')
```

## 実行結果

```
(1) 頂点は (-1/2,-25/4) で、x軸との交点は (-3,0) と (2,0) となる。グラフは以下の通りである
(2) 不等式を満たす xの範囲は、-3 < x < 2 である。
```
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/0223f4a9-e579-776d-880c-367bf8aff2e9.png)


# 問3

2次関数 $y=x^2+x+1$ について以下の問いに答えよ。

 (1) $y=x^2+x+1$ のグラフをかけ。
 (2) 2次不等式を $y=x^2+x+1 < 0$ を満たす $x$ の範囲を求めよ。

## 問3の解答を与えるPythonプログラム

問2のプログラムがそのまま利用できます（`#関数`のコメントが付いている2行については書き換えてください）。

## 実行結果

```
(1) 頂点は (-1/2,3/4) で、x軸とは交わらない。グラフは以下の通りである
(2) 不等式を満たす xの範囲は、存在しない
```

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/34b5aa43-a38f-d03b-2ba2-f46f5586ada4.png)

# グラフをきれいに描画

印刷物などでも使えるような整形したグラフ(SVG)を出力するように手を加えたものです。ただし、問題毎に範囲などを細かく微調整する必要があります。

![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152805/a89cbdcf-4c52-c5b5-aa37-54b01725a0e9.png)


```Python:Python
import numpy as np
import matplotlib.pyplot as plt
import sympy

# 頂点 (p,q) の座標を求める　
x,a,p,q = sympy.symbols('x a p q', real=True)

fx = x**2 + x - 6  # 関数

v = sympy.solve( a*(x-p)**2+q - fx, [p, q, a])
p = v[0][0]
q = v[0][1]

print(f'(1) 頂点は ({p},{q}) で、', end='' )

# x軸との交点を求める
sol = sympy.solve( fx )
if len(sol) == 0 : # 実数解が存在しない
    print('x軸とは交わらない。', end='' )
else :
    tx = ' と '.join(list(map(lambda x: '({0},0)'.format(x), sol)))
    print(f'x軸との交点は {tx} となる。', end='' )

print('グラフは以下の通りである')

# グラフを描く
xRange=(-5,5)                # グラフ描画範囲 x
yRange=(-8,2)               # グラフ描画範囲 y

f = lambda x :  x**2 + x - 6 # 関数

x = np.linspace(xRange[0], xRange[1], 100)
y = f(x)

plt.figure(figsize=(5,5), dpi=120)
plt.plot(x, y, color='0.0')
plt.plot(p, q, marker='o')

plt.hlines([0], xRange[0], xRange[1], linewidth=0.75 )
plt.vlines([0], yRange[0], yRange[1], linewidth=0.75 )


if len(sol) != 0 :
    for s in sol :
        plt.plot(s, 0, marker='o', color='0.0')    
    plt.fill_between(x, y, 0, where=y<0, facecolor='b', alpha=0.2)

plt.grid(color='0.8')

plt.xlim(xRange[0], xRange[1])
plt.xticks(range(xRange[0], xRange[1]+1, 1))  

plt.ylim(yRange[0], yRange[1])
plt.yticks(range(yRange[0], yRange[1]+1, 1))  

plt.savefig('test.svg',format = 'svg'); # SVG形式で出力

plt.show()

print('(2) 不等式を満たす xの範囲は、',end='')
if len(sol) == 2 :
    if sol[0]>sol[1] :
        print(f'{sol[1]} < x < {sol[0]} である。')
    else :
        print(f'{sol[0]} < x < {sol[1]} である。')
else:
    print('存在しない')
```